comparison gen/tocall.cpp @ 414:ac1fcc138e42

Fixed issue with internal real representation, incorrect for non x86-32 architectures. Cleaned up CallExp::toElem, moved implementation to tocall.cpp providing a single procedure to call arbitrary D functions fairly easily.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 28 Jul 2008 02:11:34 +0200
parents 6057fdf797d8
children fa91b03d9cd7
comparison
equal deleted inserted replaced
413:1a9bdbd4ac60 414:ac1fcc138e42
11 11
12 #include "gen/logger.h" 12 #include "gen/logger.h"
13 13
14 ////////////////////////////////////////////////////////////////////////////////////////// 14 //////////////////////////////////////////////////////////////////////////////////////////
15 15
16 DValue* DtoCallDFunc(FuncDeclaration* fdecl, Array* arguments, TypeClass* type, LLValue* thismem) 16 TypeFunction* DtoTypeFunction(Type* type)
17 { 17 {
18 Logger::println("Calling function: %s", fdecl->toPrettyChars()); 18 TypeFunction* tf = 0;
19 LOG_SCOPE; 19 type = type->toBasetype();
20 20 if (type->ty == Tfunction)
21 assert(fdecl); 21 {
22 DtoForceDeclareDsymbol(fdecl); 22 tf = (TypeFunction*)type;
23 llvm::Function* fn = fdecl->ir.irFunc->func; 23 }
24 TypeFunction* tf = (TypeFunction*)DtoDType(fdecl->type); 24 else if (type->ty == Tdelegate)
25 25 {
26 assert(type->next->ty == Tfunction);
27 tf = (TypeFunction*)type->next;
28 }
29 return tf;
30 }
31
32 //////////////////////////////////////////////////////////////////////////////////////////
33
34 unsigned DtoCallingConv(LINK l)
35 {
36 if (l == LINKc || l == LINKcpp)
37 return llvm::CallingConv::C;
38 else if (l == LINKd || l == LINKdefault)
39 return llvm::CallingConv::Fast;
40 else if (l == LINKwindows)
41 return llvm::CallingConv::X86_StdCall;
42 else
43 assert(0 && "Unsupported calling convention");
44 }
45
46 //////////////////////////////////////////////////////////////////////////////////////////
47
48 DValue* DtoVaArg(Loc& loc, Type* type, Expression* valistArg)
49 {
50 DValue* expelem = valistArg->toElem(gIR);
51 const LLType* llt = DtoType(type);
52 if (DtoIsPassedByRef(type))
53 llt = getPtrToType(llt);
54 // issue a warning for broken va_arg instruction.
55 if (global.params.cpu != ARCHx86)
56 warning("%s: va_arg for C variadic functions is probably broken for anything but x86", loc.toChars());
57 // done
58 return new DImValue(type, gIR->ir->CreateVAArg(expelem->getLVal(), llt, "tmp"));
59 }
60
61 //////////////////////////////////////////////////////////////////////////////////////////
62
63 LLValue* DtoCallableValue(DValue* fn)
64 {
65 Type* type = fn->getType()->toBasetype();
66 if (type->ty == Tfunction)
67 {
68 return fn->getRVal();
69 }
70 else if (type->ty == Tdelegate)
71 {
72 LLValue* dg = fn->getRVal();
73 LLValue* funcptr = DtoGEPi(dg, 0, 1);
74 return DtoLoad(funcptr);
75 }
76 else
77 {
78 assert(0 && "not a callable type");
79 return NULL;
80 }
81 }
82
83 //////////////////////////////////////////////////////////////////////////////////////////
84
85 const LLFunctionType* DtoExtractFunctionType(const LLType* type)
86 {
87 if (const LLFunctionType* fty = isaFunction(type))
88 return fty;
89 else if (const LLPointerType* pty = isaPointer(type))
90 {
91 if (const LLFunctionType* fty = isaFunction(pty->getElementType()))
92 return fty;
93 }
94 return NULL;
95 }
96
97 //////////////////////////////////////////////////////////////////////////////////////////
98
99 void DtoBuildDVarArgList(std::vector<LLValue*>& args, llvm::PAListPtr& palist, TypeFunction* tf, Expressions* arguments, size_t argidx)
100 {
101 Logger::println("doing d-style variadic arguments");
102
103 std::vector<const LLType*> vtypes;
104
105 // number of non variadic args
106 int begin = tf->parameters->dim;
107 Logger::println("num non vararg params = %d", begin);
108
109 // build struct with argument types (non variadic args)
110 for (int i=begin; i<arguments->dim; i++)
111 {
112 Expression* argexp = (Expression*)arguments->data[i];
113 vtypes.push_back(DtoType(argexp->type));
114 size_t sz = getABITypeSize(vtypes.back());
115 if (sz < PTRSIZE)
116 vtypes.back() = DtoSize_t();
117 }
118 const LLStructType* vtype = LLStructType::get(vtypes);
119 Logger::cout() << "d-variadic argument struct type:\n" << *vtype << '\n';
120 LLValue* mem = new llvm::AllocaInst(vtype,"_argptr_storage",gIR->topallocapoint());
121
122 // store arguments in the struct
123 for (int i=begin,k=0; i<arguments->dim; i++,k++)
124 {
125 Expression* argexp = (Expression*)arguments->data[i];
126 if (global.params.llvmAnnotate)
127 DtoAnnotation(argexp->toChars());
128 LLValue* argdst = DtoGEPi(mem,0,k);
129 argdst = DtoBitCast(argdst, getPtrToType(DtoType(argexp->type)));
130 DtoVariadicArgument(argexp, argdst);
131 }
132
133 // build type info array
134 assert(Type::typeinfo->ir.irStruct->constInit);
135 const LLType* typeinfotype = DtoType(Type::typeinfo->type);
136 const LLArrayType* typeinfoarraytype = LLArrayType::get(typeinfotype,vtype->getNumElements());
137
138 llvm::GlobalVariable* typeinfomem =
139 new llvm::GlobalVariable(typeinfoarraytype, true, llvm::GlobalValue::InternalLinkage, NULL, "._arguments.storage", gIR->module);
140 Logger::cout() << "_arguments storage: " << *typeinfomem << '\n';
141
142 std::vector<LLConstant*> vtypeinfos;
143 for (int i=begin,k=0; i<arguments->dim; i++,k++)
144 {
145 Expression* argexp = (Expression*)arguments->data[i];
146 vtypeinfos.push_back(DtoTypeInfoOf(argexp->type));
147 }
148
149 // apply initializer
150 LLConstant* tiinits = llvm::ConstantArray::get(typeinfoarraytype, vtypeinfos);
151 typeinfomem->setInitializer(tiinits);
152
153 // put data in d-array
154 std::vector<LLConstant*> pinits;
155 pinits.push_back(DtoConstSize_t(vtype->getNumElements()));
156 pinits.push_back(llvm::ConstantExpr::getBitCast(typeinfomem, getPtrToType(typeinfotype)));
157 const LLType* tiarrty = DtoType(Type::typeinfo->type->arrayOf());
158 tiinits = llvm::ConstantStruct::get(pinits);
159 LLValue* typeinfoarrayparam = new llvm::GlobalVariable(tiarrty,
160 true, llvm::GlobalValue::InternalLinkage, tiinits, "._arguments.array", gIR->module);
161
162 // specify arguments
163 args.push_back(typeinfoarrayparam);
164 ++argidx;
165 args.push_back(gIR->ir->CreateBitCast(mem, getPtrToType(LLType::Int8Ty), "tmp"));
166 ++argidx;
167
168 // pass non variadic args
169 for (int i=0; i<begin; i++)
170 {
171 Argument* fnarg = Argument::getNth(tf->parameters, i);
172 DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
173 args.push_back(argval->getRVal());
174
175 if (fnarg->llvmByVal)
176 palist = palist.addAttr(argidx, llvm::ParamAttr::ByVal);
177
178 ++argidx;
179 }
180 }
181
182
183 DValue* DtoCallFunction(Type* resulttype, DValue* fnval, Expressions* arguments)
184 {
185 // the callee D type
186 Type* calleeType = fnval->getType();
187
188 // get func value if any
189 DFuncValue* dfnval = fnval->isFunc();
190
191 // handle special va_copy / va_end intrinsics
192 bool va_intrinsic = (dfnval && dfnval->func && (dfnval->func->llvmInternal == LLVMva_intrinsic));
193
194 // get function type info
195 TypeFunction* tf = DtoTypeFunction(calleeType);
196 assert(tf);
197
198 // misc
199 bool retinptr = tf->llvmRetInPtr;
200 bool usesthis = tf->llvmUsesThis;
201 bool delegatecall = (calleeType->toBasetype()->ty == Tdelegate);
202 bool nestedcall = (dfnval && dfnval->func && dfnval->func->isNested());
203 bool dvarargs = (tf->linkage == LINKd && tf->varargs == 1);
204
205 unsigned callconv = DtoCallingConv(tf->linkage);
206
207 // get callee llvm value
208 LLValue* callable = DtoCallableValue(fnval);
209 const LLFunctionType* callableTy = DtoExtractFunctionType(callable->getType());
210 assert(callableTy);
211
212 // get llvm argument iterator, for types
213 LLFunctionType::param_iterator argbegin = callableTy->param_begin();
214 LLFunctionType::param_iterator argiter = argbegin;
215
216 // handle implicit arguments
217 std::vector<LLValue*> args;
218
219 // return in hidden ptr is first
220 if (retinptr)
221 {
222 LLValue* retvar = new llvm::AllocaInst(argiter->get()->getContainedType(0), ".rettmp", gIR->topallocapoint());
223 ++argiter;
224 args.push_back(retvar);
225 }
226
227 // then comes the 'this' argument
228 if (dfnval && dfnval->vthis)
229 {
230 LLValue* thisarg = DtoBitCast(dfnval->vthis, argiter->get());
231 ++argiter;
232 args.push_back(thisarg);
233 }
234 // or a delegate context arg
235 else if (delegatecall)
236 {
237 LLValue* ctxarg = DtoLoad(DtoGEPi(fnval->getRVal(), 0,0));
238 assert(ctxarg->getType() == argiter->get());
239 ++argiter;
240 args.push_back(ctxarg);
241 }
242 // or a nested function context arg
243 else if (nestedcall)
244 {
245 LLValue* contextptr = DtoNestedContext(dfnval->func->toParent2()->isFuncDeclaration());
246 if (!contextptr)
247 contextptr = getNullPtr(getVoidPtrType());
248 else
249 contextptr = DtoBitCast(contextptr, getVoidPtrType());
250 ++argiter;
251 args.push_back(contextptr);
252 }
253
254 // handle the rest of the arguments based on param passing style
26 llvm::PAListPtr palist; 255 llvm::PAListPtr palist;
27 256
28 int thisOffset = 0; 257 // variadic instrinsics need some custom casts
29 if (type || thismem) 258 if (va_intrinsic)
30 { 259 {
31 assert(type && thismem); 260 size_t n = arguments->dim;
32 thisOffset = 1; 261 for (int i=0; i<n; i++)
33 }
34
35 std::vector<LLValue*> args;
36 if (thisOffset)
37 args.push_back(thismem);
38 for (size_t i=0; i<arguments->dim; ++i)
39 {
40 Expression* ex = (Expression*)arguments->data[i];
41 Argument* fnarg = Argument::getNth(tf->parameters, i);
42 DValue* argval = DtoArgument(fnarg, ex);
43 LLValue* a = argval->getRVal();
44 const LLType* aty = fn->getFunctionType()->getParamType(i+thisOffset);
45 if (a->getType() != aty)
46 { 262 {
47 Logger::cout() << "expected: " << *aty << '\n'; 263 Expression* exp = (Expression*)arguments->data[i];
48 Logger::cout() << "got: " << *a->getType() << '\n'; 264 DValue* expelem = exp->toElem(gIR);
49 a = DtoBitCast(a, aty); 265 // cast to va_list*
266 LLValue* val = DtoBitCast(expelem->getLVal(), getVoidPtrType());
267 ++argiter;
268 args.push_back(val);
50 } 269 }
51 args.push_back(a); 270 }
52 if (fnarg && fnarg->llvmByVal) 271
53 palist = palist.addAttr(i+thisOffset+1, llvm::ParamAttr::ByVal); // return,this,args... 272 // d style varargs needs a few more hidden arguments as well as special passing
54 } 273 else if (dvarargs)
55 274 {
56 CallOrInvoke* call = gIR->CreateCallOrInvoke(fn, args.begin(), args.end(), "tmp"); 275 DtoBuildDVarArgList(args, palist, tf, arguments, argiter-argbegin+1);
57 call->setCallingConv(DtoCallingConv(LINKd)); 276 }
277
278 // otherwise we're looking at a normal function call
279 else
280 {
281 Logger::println("doing normal arguments");
282 for (int i=0; i<arguments->dim; i++) {
283 int j = argiter-argbegin;
284 Argument* fnarg = Argument::getNth(tf->parameters, i);
285 DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
286 LLValue* arg = argval->getRVal();
287 if (fnarg && arg->getType() != callableTy->getParamType(j))
288 arg = DtoBitCast(arg, callableTy->getParamType(j));
289 if (fnarg && fnarg->llvmByVal)
290 palist = palist.addAttr(j+1, llvm::ParamAttr::ByVal);
291 ++argiter;
292 args.push_back(arg);
293 }
294 }
295
296 #if 0
297 Logger::println("%d params passed", n);
298 for (int i=0; i<args.size(); ++i) {
299 assert(args[i]);
300 Logger::cout() << "arg["<<i<<"] = " << *args[i] << '\n';
301 }
302 #endif
303
304 // void returns cannot not be named
305 const char* varname = "";
306 if (callableTy->getReturnType() != LLType::VoidTy)
307 varname = "tmp";
308
309 //Logger::cout() << "Calling: " << *funcval << '\n';
310
311 // call the function
312 CallOrInvoke* call = gIR->CreateCallOrInvoke(callable, args.begin(), args.end(), varname);
313
314 // get return value
315 LLValue* retllval = (retinptr) ? args[0] : call->get();
316
317 // if the type of retllval is abstract, refine to concrete
318 if (retllval->getType()->isAbstract())
319 retllval = DtoBitCast(retllval, getPtrToType(DtoType(resulttype)), "retval");
320
321 // set calling convention
322 if (dfnval && dfnval->func)
323 {
324 int li = dfnval->func->llvmInternal;
325 if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic)
326 {
327 call->setCallingConv(callconv);
328 }
329 }
330 else
331 {
332 call->setCallingConv(callconv);
333 }
334
335 // param attrs
58 call->setParamAttrs(palist); 336 call->setParamAttrs(palist);
59 337
60 return new DImValue(type, call->get(), false); 338 return new DImValue(resulttype, retllval, false);
61 } 339 }
340
341
342
343
344
345
346
347
348
349
350
351
352