Mercurial > projects > ldc
annotate gen/functions.cpp @ 109:5ab8e92611f9 trunk
[svn r113] Added initial support for associative arrays (AAs).
Fixed some problems with the string runtime support functions.
Fixed initialization of array of structs.
Fixed slice assignment where LHS is slice but RHS is dynamic array.
Fixed problems with result of assignment expressions.
Fixed foreach problems with key type mismatches.
author | lindquist |
---|---|
date | Wed, 21 Nov 2007 04:13:15 +0100 |
parents | 288fe1029e1f |
children | 27b9f749d9fe |
rev | line source |
---|---|
100 | 1 #include "gen/llvm.h" |
2 | |
3 #include "mtype.h" | |
4 #include "aggregate.h" | |
5 #include "init.h" | |
6 #include "declaration.h" | |
7 #include "template.h" | |
8 #include "module.h" | |
9 #include "statement.h" | |
10 | |
11 #include "gen/irstate.h" | |
12 #include "gen/tollvm.h" | |
13 #include "gen/runtime.h" | |
14 #include "gen/arrays.h" | |
15 #include "gen/logger.h" | |
16 #include "gen/functions.h" | |
17 #include "gen/todebug.h" | |
18 #include "gen/classes.h" | |
19 | |
20 const llvm::FunctionType* DtoFunctionType(Type* type, const llvm::Type* thistype, bool ismain) | |
21 { | |
22 TypeFunction* f = (TypeFunction*)type; | |
23 assert(f != 0); | |
24 | |
25 if (type->llvmType != NULL) { | |
26 return llvm::cast<llvm::FunctionType>(type->llvmType->get()); | |
27 } | |
28 | |
29 bool typesafeVararg = false; | |
30 if (f->linkage == LINKd && f->varargs == 1) { | |
31 typesafeVararg = true; | |
32 } | |
33 | |
34 // return value type | |
35 const llvm::Type* rettype; | |
36 const llvm::Type* actualRettype; | |
37 Type* rt = f->next; | |
38 bool retinptr = false; | |
39 bool usesthis = false; | |
40 | |
41 if (ismain) { | |
42 rettype = llvm::Type::Int32Ty; | |
43 actualRettype = rettype; | |
44 } | |
45 else { | |
46 assert(rt); | |
109
5ab8e92611f9
[svn r113] Added initial support for associative arrays (AAs).
lindquist
parents:
108
diff
changeset
|
47 Type* rtfin = DtoDType(rt); |
100 | 48 if (DtoIsPassedByRef(rt)) { |
49 rettype = llvm::PointerType::get(DtoType(rt)); | |
50 actualRettype = llvm::Type::VoidTy; | |
51 f->llvmRetInPtr = retinptr = true; | |
52 } | |
53 else { | |
54 rettype = DtoType(rt); | |
55 actualRettype = rettype; | |
56 } | |
57 } | |
58 | |
59 // parameter types | |
60 std::vector<const llvm::Type*> paramvec; | |
61 | |
62 if (retinptr) { | |
63 Logger::cout() << "returning through pointer parameter: " << *rettype << '\n'; | |
64 paramvec.push_back(rettype); | |
65 } | |
66 | |
67 if (thistype) { | |
68 paramvec.push_back(thistype); | |
69 usesthis = true; | |
70 } | |
71 | |
72 if (typesafeVararg) { | |
73 ClassDeclaration* ti = Type::typeinfo; | |
74 ti->toObjFile(); | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
75 DtoForceConstInitDsymbol(ti); |
100 | 76 assert(ti->llvmInitZ); |
77 std::vector<const llvm::Type*> types; | |
78 types.push_back(DtoSize_t()); | |
79 types.push_back(llvm::PointerType::get(llvm::PointerType::get(ti->llvmInitZ->getType()))); | |
80 const llvm::Type* t1 = llvm::StructType::get(types); | |
81 paramvec.push_back(llvm::PointerType::get(t1)); | |
82 paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty)); | |
83 } | |
84 | |
85 size_t n = Argument::dim(f->parameters); | |
86 | |
87 for (int i=0; i < n; ++i) { | |
88 Argument* arg = Argument::getNth(f->parameters, i); | |
89 // ensure scalar | |
90 Type* argT = DtoDType(arg->type); | |
91 assert(argT); | |
92 | |
93 if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) { | |
94 //assert(arg->vardecl); | |
95 //arg->vardecl->refparam = true; | |
96 } | |
97 else | |
98 arg->llvmCopy = true; | |
99 | |
100 const llvm::Type* at = DtoType(argT); | |
101 if (isaStruct(at)) { | |
102 Logger::println("struct param"); | |
103 paramvec.push_back(llvm::PointerType::get(at)); | |
104 } | |
105 else if (isaArray(at)) { | |
106 Logger::println("sarray param"); | |
107 assert(argT->ty == Tsarray); | |
108 //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0))); | |
109 paramvec.push_back(llvm::PointerType::get(at)); | |
110 } | |
111 else if (llvm::isa<llvm::OpaqueType>(at)) { | |
112 Logger::println("opaque param"); | |
113 assert(argT->ty == Tstruct || argT->ty == Tclass); | |
114 paramvec.push_back(llvm::PointerType::get(at)); | |
115 } | |
116 else { | |
117 if (!arg->llvmCopy) { | |
118 Logger::println("ref param"); | |
119 at = llvm::PointerType::get(at); | |
120 } | |
121 else { | |
122 Logger::println("in param"); | |
123 } | |
124 paramvec.push_back(at); | |
125 } | |
126 } | |
127 | |
128 // construct function type | |
129 bool isvararg = !typesafeVararg && f->varargs; | |
130 llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); | |
131 | |
132 f->llvmRetInPtr = retinptr; | |
133 f->llvmUsesThis = usesthis; | |
134 | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
135 //if (!f->llvmType) |
100 | 136 f->llvmType = new llvm::PATypeHolder(functype); |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
137 //else |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
138 //assert(functype == f->llvmType->get()); |
100 | 139 |
140 return functype; | |
141 } | |
142 | |
143 ////////////////////////////////////////////////////////////////////////////////////////// | |
144 | |
145 static const llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl) | |
146 { | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
147 // type has already been resolved |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
148 if (fdecl->type->llvmType != 0) { |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
149 return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType->get()); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
150 } |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
151 |
100 | 152 TypeFunction* f = (TypeFunction*)fdecl->type; |
153 assert(f != 0); | |
154 | |
155 const llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty); | |
156 std::vector<const llvm::Type*> args; | |
157 | |
158 if (fdecl->llvmInternal == LLVMva_start) { | |
159 args.push_back(i8pty); | |
160 } | |
161 else if (fdecl->llvmInternal == LLVMva_intrinsic) { | |
162 size_t n = Argument::dim(f->parameters); | |
163 for (size_t i=0; i<n; ++i) { | |
164 args.push_back(i8pty); | |
165 } | |
166 } | |
167 else | |
168 assert(0); | |
169 | |
170 const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, args, false); | |
171 | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
172 f->llvmType = new llvm::PATypeHolder(fty); |
100 | 173 |
174 return fty; | |
175 } | |
176 | |
177 ////////////////////////////////////////////////////////////////////////////////////////// | |
178 | |
179 const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) | |
180 { | |
181 if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) { | |
182 return DtoVaFunctionType(fdecl); | |
183 } | |
184 | |
185 // type has already been resolved | |
186 if (fdecl->type->llvmType != 0) { | |
187 return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType->get()); | |
188 } | |
189 | |
190 const llvm::Type* thisty = NULL; | |
191 if (fdecl->needThis()) { | |
192 if (AggregateDeclaration* ad = fdecl->isMember()) { | |
193 Logger::print("isMember = this is: %s\n", ad->type->toChars()); | |
194 thisty = DtoType(ad->type); | |
195 Logger::cout() << "this llvm type: " << *thisty << '\n'; | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
196 if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->recty.get())) |
100 | 197 thisty = llvm::PointerType::get(thisty); |
198 } | |
199 else | |
200 assert(0); | |
201 } | |
202 else if (fdecl->isNested()) { | |
203 thisty = llvm::PointerType::get(llvm::Type::Int8Ty); | |
204 } | |
205 | |
206 const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, fdecl->isMain()); | |
207 | |
208 return functype; | |
209 } | |
210 | |
211 ////////////////////////////////////////////////////////////////////////////////////////// | |
212 | |
213 static llvm::Function* DtoDeclareVaFunction(FuncDeclaration* fdecl) | |
214 { | |
215 TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type); | |
216 const llvm::FunctionType* fty = DtoVaFunctionType(fdecl); | |
217 llvm::Constant* fn = 0; | |
218 | |
219 if (fdecl->llvmInternal == LLVMva_start) { | |
220 fn = gIR->module->getOrInsertFunction("llvm.va_start", fty); | |
221 assert(fn); | |
222 } | |
223 else if (fdecl->llvmInternal == LLVMva_intrinsic) { | |
224 fn = gIR->module->getOrInsertFunction(fdecl->llvmInternal1, fty); | |
225 assert(fn); | |
226 } | |
227 else | |
228 assert(0); | |
229 | |
230 llvm::Function* func = llvm::dyn_cast<llvm::Function>(fn); | |
231 assert(func); | |
232 assert(func->isIntrinsic()); | |
233 fdecl->llvmValue = func; | |
234 return func; | |
235 } | |
236 | |
237 ////////////////////////////////////////////////////////////////////////////////////////// | |
238 | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
239 void DtoResolveFunction(FuncDeclaration* fdecl) |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
240 { |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
241 if (fdecl->llvmResolved) return; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
242 fdecl->llvmResolved = true; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
243 |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
244 Logger::println("DtoResolveFunction(%s)", fdecl->toPrettyChars()); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
245 LOG_SCOPE; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
246 |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
247 if (fdecl->llvmRunTimeHack) { |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
248 gIR->declareList.push_back(fdecl); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
249 return; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
250 } |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
251 |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
252 if (fdecl->isUnitTestDeclaration()) { |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
253 Logger::attention("ignoring unittest declaration: %s", fdecl->toChars()); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
254 return; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
255 } |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
256 |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
257 if (fdecl->parent) |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
258 if (TemplateInstance* tinst = fdecl->parent->isTemplateInstance()) |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
259 { |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
260 TemplateDeclaration* tempdecl = tinst->tempdecl; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
261 if (tempdecl->llvmInternal == LLVMva_arg) |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
262 { |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
263 Logger::println("magic va_arg found"); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
264 fdecl->llvmInternal = LLVMva_arg; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
265 fdecl->llvmDeclared = true; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
266 fdecl->llvmInitialized = true; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
267 fdecl->llvmDefined = true; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
268 return; // this gets mapped to an instruction so a declaration makes no sence |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
269 } |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
270 else if (tempdecl->llvmInternal == LLVMva_start) |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
271 { |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
272 Logger::println("magic va_start found"); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
273 fdecl->llvmInternal = LLVMva_start; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
274 } |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
275 } |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
276 |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
277 DtoFunctionType(fdecl); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
278 |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
279 // queue declaration |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
280 gIR->declareList.push_back(fdecl); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
281 } |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
282 |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
283 ////////////////////////////////////////////////////////////////////////////////////////// |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
284 |
100 | 285 void DtoDeclareFunction(FuncDeclaration* fdecl) |
286 { | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
287 if (fdecl->llvmDeclared) return; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
288 fdecl->llvmDeclared = true; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
289 |
100 | 290 Logger::println("DtoDeclareFunction(%s)", fdecl->toPrettyChars()); |
291 LOG_SCOPE; | |
292 | |
293 if (fdecl->llvmRunTimeHack) { | |
294 Logger::println("runtime hack func chars: %s", fdecl->toChars()); | |
295 if (!fdecl->llvmValue) | |
296 fdecl->llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, fdecl->toChars()); | |
297 return; | |
298 } | |
299 | |
300 bool declareOnly = false; | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
301 bool templInst = fdecl->parent && DtoIsTemplateInstance(fdecl->parent); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
302 if (!templInst && fdecl->getModule() != gIR->dmodule) |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
303 declareOnly = true; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
304 else if (fdecl->llvmInternal == LLVMva_start) |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
305 declareOnly = true; |
100 | 306 |
307 if (!fdecl->llvmIRFunc) { | |
308 fdecl->llvmIRFunc = new IRFunction(fdecl); | |
309 } | |
310 | |
311 // mangled name | |
312 char* mangled_name; | |
313 if (fdecl->llvmInternal == LLVMintrinsic) | |
314 mangled_name = fdecl->llvmInternal1; | |
315 else | |
316 mangled_name = fdecl->mangle(); | |
317 | |
318 // unit test special handling | |
319 if (fdecl->isUnitTestDeclaration()) | |
320 { | |
321 assert(0 && "no unittests yet"); | |
322 /*const llvm::FunctionType* fnty = llvm::FunctionType::get(llvm::Type::VoidTy, std::vector<const llvm::Type*>(), false); | |
323 // make the function | |
324 llvm::Function* func = gIR->module->getFunction(mangled_name); | |
325 if (func == 0) | |
326 func = new llvm::Function(fnty,llvm::GlobalValue::InternalLinkage,mangled_name,gIR->module); | |
327 func->setCallingConv(llvm::CallingConv::Fast); | |
328 fdecl->llvmValue = func; | |
329 return func; | |
330 */ | |
331 } | |
332 | |
333 if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) { | |
334 error("intrinsics cannot have function bodies"); | |
335 fatal(); | |
336 } | |
337 | |
338 llvm::Function* vafunc = 0; | |
339 if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) { | |
340 vafunc = DtoDeclareVaFunction(fdecl); | |
341 } | |
342 | |
343 Type* t = DtoDType(fdecl->type); | |
344 TypeFunction* f = (TypeFunction*)t; | |
345 | |
346 // construct function | |
347 const llvm::FunctionType* functype = DtoFunctionType(fdecl); | |
348 llvm::Function* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name); | |
349 if (!func) | |
350 func = new llvm::Function(functype, DtoLinkage(fdecl->protection, fdecl->storage_class), mangled_name, gIR->module); | |
351 else | |
352 assert(func->getFunctionType() == functype); | |
353 | |
354 // add func to IRFunc | |
355 fdecl->llvmIRFunc->func = func; | |
356 | |
357 // calling convention | |
358 if (!vafunc && fdecl->llvmInternal != LLVMintrinsic) | |
359 func->setCallingConv(DtoCallingConv(f->linkage)); | |
360 | |
361 // template instances should have weak linkage | |
362 if (!vafunc && fdecl->llvmInternal != LLVMintrinsic && fdecl->parent && DtoIsTemplateInstance(fdecl->parent)) | |
363 func->setLinkage(llvm::GlobalValue::WeakLinkage); | |
364 | |
365 fdecl->llvmValue = func; | |
366 assert(llvm::isa<llvm::FunctionType>(f->llvmType->get())); | |
367 | |
368 if (fdecl->isMain()) { | |
369 gIR->mainFunc = func; | |
370 } | |
371 | |
372 // name parameters | |
373 llvm::Function::arg_iterator iarg = func->arg_begin(); | |
374 int k = 0; | |
375 if (f->llvmRetInPtr) { | |
376 iarg->setName("retval"); | |
377 f->llvmRetArg = iarg; | |
378 ++iarg; | |
379 } | |
380 if (f->llvmUsesThis) { | |
381 iarg->setName("this"); | |
108
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
382 fdecl->llvmThisVar = iarg; |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
383 assert(fdecl->llvmThisVar); |
100 | 384 ++iarg; |
385 } | |
386 int varargs = -1; | |
387 if (f->linkage == LINKd && f->varargs == 1) | |
388 varargs = 0; | |
389 for (; iarg != func->arg_end(); ++iarg) | |
390 { | |
391 Argument* arg = Argument::getNth(f->parameters, k++); | |
392 //arg->llvmValue = iarg; | |
393 //Logger::println("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident); | |
394 if (arg && arg->ident != 0) { | |
395 if (arg->vardecl) { | |
396 arg->vardecl->llvmValue = iarg; | |
397 } | |
398 iarg->setName(arg->ident->toChars()); | |
399 } | |
400 else if (!arg && varargs >= 0) { | |
401 if (varargs == 0) { | |
402 iarg->setName("_arguments"); | |
403 fdecl->llvmArguments = iarg; | |
404 } | |
405 else if (varargs == 1) { | |
406 iarg->setName("_argptr"); | |
407 fdecl->llvmArgPtr = iarg; | |
408 } | |
409 else | |
410 assert(0); | |
411 varargs++; | |
412 } | |
413 else { | |
414 iarg->setName("unnamed"); | |
415 } | |
416 } | |
417 | |
418 if (!declareOnly) | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
419 gIR->defineList.push_back(fdecl); |
100 | 420 |
421 Logger::cout() << "func decl: " << *func << '\n'; | |
422 } | |
423 | |
424 ////////////////////////////////////////////////////////////////////////////////////////// | |
425 | |
426 // TODO split this monster up | |
427 void DtoDefineFunc(FuncDeclaration* fd) | |
428 { | |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
429 if (fd->llvmDefined) return; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
430 fd->llvmDefined = true; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
431 |
108
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
432 assert(fd->llvmDeclared); |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
433 |
102
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
434 Logger::println("DtoDefineFunc(%s)", fd->toPrettyChars()); |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
435 LOG_SCOPE; |
027b8d8b71ec
[svn r106] Turns out the last commit wasn't enough, now the D->LLVM process is even more split up.
lindquist
parents:
100
diff
changeset
|
436 |
100 | 437 // debug info |
438 if (global.params.symdebug) { | |
439 Module* mo = fd->getModule(); | |
440 if (!mo->llvmCompileUnit) { | |
441 mo->llvmCompileUnit = DtoDwarfCompileUnit(mo,false); | |
442 } | |
443 fd->llvmDwarfSubProgram = DtoDwarfSubProgram(fd, mo->llvmCompileUnit); | |
444 } | |
445 | |
446 Type* t = DtoDType(fd->type); | |
447 TypeFunction* f = (TypeFunction*)t; | |
448 | |
449 assert(f->llvmType); | |
450 llvm::Function* func = fd->llvmIRFunc->func; | |
451 const llvm::FunctionType* functype = func->getFunctionType(); | |
452 | |
453 // only members of the current module or template instances maybe be defined | |
454 if (fd->getModule() == gIR->dmodule || DtoIsTemplateInstance(fd->parent)) | |
455 { | |
456 fd->llvmDModule = gIR->dmodule; | |
457 | |
458 // handle static constructor / destructor | |
459 if (fd->isStaticCtorDeclaration() || fd->isStaticDtorDeclaration()) { | |
460 const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1); | |
461 //Logger::cout() << "static ctor type: " << *sctor_type << '\n'; | |
462 | |
463 llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(fd->llvmValue); | |
464 //Logger::cout() << "static ctor func: " << *sctor_func << '\n'; | |
465 | |
466 llvm::Constant* sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1); | |
467 | |
468 //Logger::cout() << "static ctor init: " << *sctor_init << '\n'; | |
469 | |
470 // output the llvm.global_ctors array | |
471 const char* varname = fd->isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array"; | |
472 llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module); | |
473 } | |
474 | |
475 // function definition | |
476 if (fd->fbody != 0) | |
477 { | |
478 Logger::println("Doing function body for: %s", fd->toChars()); | |
479 assert(fd->llvmIRFunc); | |
480 gIR->functions.push_back(fd->llvmIRFunc); | |
481 | |
108
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
482 /* // moved to declaration |
100 | 483 // this handling |
484 if (f->llvmUsesThis) { | |
485 Logger::println("uses this"); | |
486 if (f->llvmRetInPtr) | |
487 fd->llvmThisVar = ++func->arg_begin(); | |
488 else | |
489 fd->llvmThisVar = func->arg_begin(); | |
490 assert(fd->llvmThisVar != 0); | |
491 } | |
108
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
492 */ |
100 | 493 |
494 if (fd->isMain()) | |
495 gIR->emitMain = true; | |
496 | |
497 llvm::BasicBlock* beginbb = new llvm::BasicBlock("entry",func); | |
498 llvm::BasicBlock* endbb = new llvm::BasicBlock("endentry",func); | |
499 | |
500 //assert(gIR->scopes.empty()); | |
501 gIR->scopes.push_back(IRScope(beginbb, endbb)); | |
502 | |
503 // create alloca point | |
504 f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb()); | |
505 gIR->func()->allocapoint = f->llvmAllocaPoint; | |
506 | |
108
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
507 // need result variable? (not nested) |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
508 if (fd->vresult && !fd->vresult->nestedref) { |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
509 Logger::println("non-nested vresult value"); |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
510 fd->vresult->llvmValue = new llvm::AllocaInst(DtoType(fd->vresult->type),"function_vresult",f->llvmAllocaPoint); |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
511 } |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
512 |
100 | 513 // give arguments storage |
514 size_t n = Argument::dim(f->parameters); | |
515 for (int i=0; i < n; ++i) { | |
516 Argument* arg = Argument::getNth(f->parameters, i); | |
517 if (arg && arg->vardecl) { | |
518 VarDeclaration* vd = arg->vardecl; | |
519 if (!vd->llvmNeedsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)) | |
520 continue; | |
521 llvm::Value* a = vd->llvmValue; | |
522 assert(a); | |
523 std::string s(a->getName()); | |
524 Logger::println("giving argument '%s' storage", s.c_str()); | |
525 s.append("_storage"); | |
526 llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint); | |
527 gIR->ir->CreateStore(a,v); | |
528 vd->llvmValue = v; | |
529 } | |
530 else { | |
531 Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0); | |
532 } | |
533 } | |
534 | |
535 // debug info | |
536 if (global.params.symdebug) DtoDwarfFuncStart(fd); | |
537 | |
538 llvm::Value* parentNested = NULL; | |
539 if (FuncDeclaration* fd2 = fd->toParent()->isFuncDeclaration()) { | |
108
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
540 if (!fd->isStatic()) |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
541 parentNested = fd2->llvmNested; |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
542 } |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
543 |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
544 // need result variable? (nested) |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
545 if (fd->vresult && fd->vresult->nestedref) { |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
546 Logger::println("nested vresult value: %s", fd->vresult->toChars()); |
288fe1029e1f
[svn r112] Fixed 'case 1,2,3:' style case statements.
lindquist
parents:
102
diff
changeset
|
547 fd->llvmNestedVars.insert(fd->vresult); |
100 | 548 } |
549 | |
550 // construct nested variables struct | |
551 if (!fd->llvmNestedVars.empty() || parentNested) { | |
552 std::vector<const llvm::Type*> nestTypes; | |
553 int j = 0; | |
554 if (parentNested) { | |
555 nestTypes.push_back(parentNested->getType()); | |
556 j++; | |
557 } | |
558 for (std::set<VarDeclaration*>::iterator i=fd->llvmNestedVars.begin(); i!=fd->llvmNestedVars.end(); ++i) { | |
559 VarDeclaration* vd = *i; | |
560 vd->llvmNestedIndex = j++; | |
561 if (vd->isParameter()) { | |
562 assert(vd->llvmValue); | |
563 nestTypes.push_back(vd->llvmValue->getType()); | |
564 } | |
565 else { | |
566 nestTypes.push_back(DtoType(vd->type)); | |
567 } | |
568 } | |
569 const llvm::StructType* nestSType = llvm::StructType::get(nestTypes); | |
570 Logger::cout() << "nested var struct has type:" << '\n' << *nestSType; | |
571 fd->llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint); | |
572 if (parentNested) { | |
573 assert(fd->llvmThisVar); | |
574 llvm::Value* ptr = gIR->ir->CreateBitCast(fd->llvmThisVar, parentNested->getType(), "tmp"); | |
575 gIR->ir->CreateStore(ptr, DtoGEPi(fd->llvmNested, 0,0, "tmp")); | |
576 } | |
577 for (std::set<VarDeclaration*>::iterator i=fd->llvmNestedVars.begin(); i!=fd->llvmNestedVars.end(); ++i) { | |
578 VarDeclaration* vd = *i; | |
579 if (vd->isParameter()) { | |
580 gIR->ir->CreateStore(vd->llvmValue, DtoGEPi(fd->llvmNested, 0, vd->llvmNestedIndex, "tmp")); | |
581 vd->llvmValue = fd->llvmNested; | |
582 } | |
583 } | |
584 } | |
585 | |
586 // copy _argptr to a memory location | |
587 if (f->linkage == LINKd && f->varargs == 1) | |
588 { | |
589 llvm::Value* argptrmem = new llvm::AllocaInst(fd->llvmArgPtr->getType(), "_argptrmem", gIR->topallocapoint()); | |
590 new llvm::StoreInst(fd->llvmArgPtr, argptrmem, gIR->scopebb()); | |
591 fd->llvmArgPtr = argptrmem; | |
592 } | |
593 | |
594 // output function body | |
595 fd->fbody->toIR(gIR); | |
596 | |
597 // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement | |
598 // in automatically, so we do it here. | |
599 if (!fd->isMain()) { | |
600 if (!gIR->scopereturned()) { | |
601 // pass the previous block into this block | |
602 if (global.params.symdebug) DtoDwarfFuncEnd(fd); | |
603 if (func->getReturnType() == llvm::Type::VoidTy) { | |
604 new llvm::ReturnInst(gIR->scopebb()); | |
605 } | |
606 else { | |
607 new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb()); | |
608 } | |
609 } | |
610 } | |
611 | |
612 // erase alloca point | |
613 f->llvmAllocaPoint->eraseFromParent(); | |
614 f->llvmAllocaPoint = 0; | |
615 gIR->func()->allocapoint = 0; | |
616 | |
617 gIR->scopes.pop_back(); | |
618 | |
619 // get rid of the endentry block, it's never used | |
620 assert(!func->getBasicBlockList().empty()); | |
621 func->getBasicBlockList().pop_back(); | |
622 | |
623 // if the last block is empty now, it must be unreachable or it's a bug somewhere else | |
624 // would be nice to figure out how to assert that this is correct | |
625 llvm::BasicBlock* lastbb = &func->getBasicBlockList().back(); | |
626 if (lastbb->empty()) { | |
627 if (lastbb->getNumUses() == 0) | |
628 lastbb->eraseFromParent(); | |
629 else { | |
630 new llvm::UnreachableInst(lastbb); | |
631 /*if (func->getReturnType() == llvm::Type::VoidTy) { | |
632 new llvm::ReturnInst(lastbb); | |
633 } | |
634 else { | |
635 new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), lastbb); | |
636 }*/ | |
637 } | |
638 } | |
639 | |
640 gIR->functions.pop_back(); | |
641 } | |
642 } | |
643 } | |
644 | |
645 ////////////////////////////////////////////////////////////////////////////////////////// | |
646 | |
647 void DtoMain() | |
648 { | |
649 // emit main function llvm style | |
650 // int main(int argc, char**argv, char**env); | |
651 | |
652 assert(gIR != 0); | |
653 IRState& ir = *gIR; | |
654 | |
655 assert(ir.emitMain && ir.mainFunc); | |
656 | |
657 // parameter types | |
658 std::vector<const llvm::Type*> pvec; | |
659 pvec.push_back((const llvm::Type*)llvm::Type::Int32Ty); | |
660 const llvm::Type* chPtrType = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty); | |
661 pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType)); | |
662 pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType)); | |
663 const llvm::Type* rettype = (const llvm::Type*)llvm::Type::Int32Ty; | |
664 | |
665 llvm::FunctionType* functype = llvm::FunctionType::get(rettype, pvec, false); | |
666 llvm::Function* func = new llvm::Function(functype,llvm::GlobalValue::ExternalLinkage,"main",ir.module); | |
667 | |
668 llvm::BasicBlock* bb = new llvm::BasicBlock("entry",func); | |
669 | |
670 // call static ctors | |
671 llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_ctors"); | |
672 llvm::Instruction* apt = new llvm::CallInst(fn,"",bb); | |
673 | |
674 // call user main function | |
675 const llvm::FunctionType* mainty = ir.mainFunc->getFunctionType(); | |
676 llvm::CallInst* call; | |
677 if (mainty->getNumParams() > 0) | |
678 { | |
679 // main with arguments | |
680 assert(mainty->getNumParams() == 1); | |
681 std::vector<llvm::Value*> args; | |
682 llvm::Function* mfn = LLVM_D_GetRuntimeFunction(ir.module,"_d_main_args"); | |
683 | |
684 llvm::Function::arg_iterator argi = func->arg_begin(); | |
685 args.push_back(argi++); | |
686 args.push_back(argi++); | |
687 | |
688 const llvm::Type* at = mainty->getParamType(0)->getContainedType(0); | |
689 llvm::Value* arr = new llvm::AllocaInst(at->getContainedType(1)->getContainedType(0), func->arg_begin(), "argstorage", apt); | |
690 llvm::Value* a = new llvm::AllocaInst(at, "argarray", apt); | |
691 llvm::Value* ptr = DtoGEPi(a,0,0,"tmp",bb); | |
692 llvm::Value* v = args[0]; | |
693 if (v->getType() != DtoSize_t()) | |
694 v = new llvm::ZExtInst(v, DtoSize_t(), "tmp", bb); | |
695 new llvm::StoreInst(v,ptr,bb); | |
696 ptr = DtoGEPi(a,0,1,"tmp",bb); | |
697 new llvm::StoreInst(arr,ptr,bb); | |
698 args.push_back(a); | |
699 new llvm::CallInst(mfn, args.begin(), args.end(), "", bb); | |
700 call = new llvm::CallInst(ir.mainFunc,a,"ret",bb); | |
701 } | |
702 else | |
703 { | |
704 // main with no arguments | |
705 call = new llvm::CallInst(ir.mainFunc,"ret",bb); | |
706 } | |
707 call->setCallingConv(ir.mainFunc->getCallingConv()); | |
708 | |
709 // call static dtors | |
710 fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_dtors"); | |
711 new llvm::CallInst(fn,"",bb); | |
712 | |
713 // return | |
714 new llvm::ReturnInst(call,bb); | |
715 } | |
716 | |
717 ////////////////////////////////////////////////////////////////////////////////////////// |