00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "CodeGenTypes.h"
00010 #include "CommaRT.h"
00011 #include "DomainInfo.h"
00012 #include "DomainInstance.h"
00013 #include "Frame.h"
00014 #include "comma/ast/Decl.h"
00015 #include "comma/codegen/Mangle.h"
00016
00017 #include "llvm/ADT/IndexedMap.h"
00018 #include "llvm/Module.h"
00019 #include "llvm/Value.h"
00020 #include "llvm/Support/IRBuilder.h"
00021
00022 using namespace comma;
00023
00024 using llvm::dyn_cast;
00025 using llvm::cast;
00026 using llvm::isa;
00027
00028 CommaRT::CommaRT(CodeGen &CG)
00029 : CG(CG),
00030 ITableName("_comma_itable_t"),
00031 DomainCtorName("_comma_domain_ctor_t"),
00032
00033 DInfo(0),
00034 DomainInfoPtrTy(0),
00035
00036 DInstance(0),
00037 DomainInstancePtrTy(0),
00038
00039 ITablePtrTy(getITablePtrTy()),
00040 DomainCtorPtrTy(0)
00041 {
00042 DInfo = new DomainInfo(*this);
00043 DomainInfoPtrTy = DInfo->getPointerTypeTo();
00044
00045 DInstance = new DomainInstance(*this);
00046 DomainInstancePtrTy = DInstance->getPointerTypeTo();
00047
00048 DomainCtorPtrTy = DInfo->getCtorPtrType();
00049
00050 DInfo->init();
00051 DInstance->init();
00052
00053 generateRuntimeTypes();
00054 generateRuntimeFunctions();
00055 }
00056
00057 CommaRT::~CommaRT()
00058 {
00059 delete DInfo;
00060 delete DInstance;
00061 }
00062
00063 const std::string &CommaRT::getTypeName(TypeId id) const
00064 {
00065 switch (id) {
00066 default:
00067 assert(false && "Invalid type id!");
00068 return InvalidName;
00069 case CRT_ITable:
00070 return ITableName;
00071 case CRT_DomainInfo:
00072 return DInfo->getTypeName();
00073 case CRT_DomainInstance:
00074 return DInstance->getTypeName();
00075 case CRT_DomainCtor:
00076 return DomainCtorName;
00077 }
00078 }
00079
00080 void CommaRT::generateRuntimeTypes()
00081 {
00082
00083 llvm::Module *M = CG.getModule();
00084 M->addTypeName(getTypeName(CRT_DomainInfo), getType<CRT_DomainInfo>());
00085 M->addTypeName(getTypeName(CRT_DomainInstance), getType<CRT_DomainInstance>());
00086 }
00087
00088 const llvm::PointerType *CommaRT::getDomainCtorPtrTy()
00089 {
00090 std::vector<const llvm::Type*> args;
00091
00092 args.push_back(DomainInstancePtrTy);
00093
00094 const llvm::Type *ctorTy
00095 = llvm::FunctionType::get(CG.getVoidTy(), args, false);
00096 return CG.getPointerType(ctorTy);
00097 }
00098
00099 const llvm::PointerType *CommaRT::getITablePtrTy()
00100 {
00101 return CG.getInt8PtrTy();
00102 }
00103
00104 void CommaRT::generateRuntimeFunctions()
00105 {
00106 defineGetDomain();
00107 defineEHPersonality();
00108 defineUnhandledException();
00109 defineRaiseException();
00110 defineExinfos();
00111 define_pow_i32_i32();
00112 define_pow_i64_i32();
00113 define_vstack();
00114 define_vstack_alloc();
00115 define_vstack_push();
00116 define_vstack_pop();
00117 define_alloc();
00118 }
00119
00120
00121 void CommaRT::defineGetDomain()
00122 {
00123 const llvm::Type *retTy = getType<CRT_DomainInstance>();
00124 std::vector<const llvm::Type *> args;
00125
00126 args.push_back(getType<CRT_DomainInfo>());
00127
00128
00129
00130
00131 llvm::FunctionType *fnTy = llvm::FunctionType::get(retTy, args, true);
00132
00133 getDomainFn = CG.makeFunction(fnTy, "_comma_get_domain");
00134 }
00135
00136 void CommaRT::defineEHPersonality()
00137 {
00138
00139
00140 const llvm::Type *retTy = CG.getInt32Ty();
00141 llvm::FunctionType *fnTy = llvm::FunctionType::get(retTy, false);
00142 EHPersonalityFn = CG.makeFunction(fnTy, "_comma_eh_personality");
00143 }
00144
00145 void CommaRT::defineUnhandledException()
00146 {
00147
00148
00149 const llvm::Type *retTy = CG.getVoidTy();
00150
00151 std::vector<const llvm::Type *> args;
00152 args.push_back(CG.getInt8PtrTy());
00153 llvm::FunctionType *fnTy = llvm::FunctionType::get(retTy, args, false);
00154
00155 unhandledExceptionFn = CG.makeFunction(fnTy, "_comma_unhandled_exception");
00156 unhandledExceptionFn->setDoesNotReturn();
00157 }
00158
00159 void CommaRT::defineRaiseException()
00160 {
00161
00162
00163
00164 const llvm::Type *retTy = CG.getVoidTy();
00165
00166 std::vector<const llvm::Type *> args;
00167 args.push_back(CG.getInt8PtrTy());
00168 args.push_back(CG.getInt8PtrTy());
00169 args.push_back(CG.getInt32Ty());
00170 args.push_back(CG.getInt8PtrTy());
00171 llvm::FunctionType *fnTy = llvm::FunctionType::get(retTy, args, false);
00172
00173 raiseStaticExceptionFn = CG.makeFunction(fnTy, "_comma_raise_exception");
00174 raiseStaticExceptionFn->setDoesNotReturn();
00175
00176
00177
00178 args.push_back(CG.getInt32Ty());
00179 fnTy = llvm::FunctionType::get(retTy, args, false);
00180
00181 raiseUserExceptionFn = CG.makeFunction(fnTy, "_comma_raise_nexception");
00182 raiseUserExceptionFn->setDoesNotReturn();
00183
00184
00185 args.clear();
00186 args.push_back(CG.getInt8PtrTy());
00187 fnTy = llvm::FunctionType::get(retTy, args, false);
00188
00189 reraiseExceptionFn = CG.makeFunction(fnTy, "_comma_reraise_exception");
00190 reraiseExceptionFn->setDoesNotReturn();
00191 }
00192
00193 void CommaRT::defineExinfos()
00194 {
00195
00196
00197 const llvm::Type *exinfoTy = CG.getInt8Ty();
00198 llvm::Module *M = CG.getModule();
00199
00200 theProgramErrorExinfo =
00201 new llvm::GlobalVariable(*M, exinfoTy, true,
00202 llvm::GlobalValue::ExternalLinkage,
00203 0, "_comma_exinfo_program_error");
00204 theConstraintErrorExinfo =
00205 new llvm::GlobalVariable(*M, exinfoTy, true,
00206 llvm::GlobalValue::ExternalLinkage,
00207 0, "_comma_exinfo_constraint_error");
00208 theAssertErrorExinfo =
00209 new llvm::GlobalVariable(*M, exinfoTy, true,
00210 llvm::GlobalValue::ExternalLinkage,
00211 0, "_comma_exinfo_assertion_error");
00212 }
00213
00214 void CommaRT::define_pow_i32_i32()
00215 {
00216
00217 const llvm::Type *i32Ty = CG.getInt32Ty();
00218
00219 std::vector<const llvm::Type*> args;
00220 args.push_back(i32Ty);
00221 args.push_back(i32Ty);
00222 llvm::FunctionType *fnTy = llvm::FunctionType::get(i32Ty, args, false);
00223 pow_i32_i32_Fn = CG.makeFunction(fnTy, "_comma_pow_i32_i32");
00224 }
00225
00226 void CommaRT::define_pow_i64_i32()
00227 {
00228
00229 const llvm::Type *i32Ty = CG.getInt32Ty();
00230 const llvm::Type *i64Ty = CG.getInt64Ty();
00231
00232 std::vector<const llvm::Type*> args;
00233 args.push_back(i64Ty);
00234 args.push_back(i32Ty);
00235 llvm::FunctionType *fnTy = llvm::FunctionType::get(i64Ty, args, false);
00236 pow_i64_i32_Fn = CG.makeFunction(fnTy, "_comma_pow_i64_i32");
00237 }
00238
00239 void CommaRT::define_vstack_alloc()
00240 {
00241
00242 std::vector<const llvm::Type*> args;
00243 args.push_back(CG.getInt32Ty());
00244 llvm::FunctionType *fnTy =
00245 llvm::FunctionType::get(CG.getVoidTy(), args, false);
00246 vstack_alloc_Fn = CG.makeFunction(fnTy, "_comma_vstack_alloc");
00247 vstack_alloc_Fn->setDoesNotThrow();
00248 }
00249
00250 void CommaRT::define_vstack_push()
00251 {
00252
00253 std::vector<const llvm::Type*> args;
00254 args.push_back(CG.getInt8PtrTy());
00255 args.push_back(CG.getInt32Ty());
00256 llvm::FunctionType *fnTy =
00257 llvm::FunctionType::get(CG.getVoidTy(), args, false);
00258 vstack_push_Fn = CG.makeFunction(fnTy, "_comma_vstack_push");
00259 vstack_push_Fn->setDoesNotThrow();
00260 }
00261
00262 void CommaRT::define_vstack_pop()
00263 {
00264
00265 std::vector<const llvm::Type*> args;
00266 llvm::FunctionType *fnTy =
00267 llvm::FunctionType::get(CG.getVoidTy(), args, false);
00268 vstack_pop_Fn = CG.makeFunction(fnTy, "_comma_vstack_pop");
00269 vstack_pop_Fn->setDoesNotThrow();
00270 }
00271
00272 void CommaRT::define_vstack()
00273 {
00274 vstack_Var =
00275 new llvm::GlobalVariable(*CG.getModule(), CG.getInt8PtrTy(), true,
00276 llvm::GlobalValue::ExternalLinkage,
00277 0, "_comma_vstack");
00278 }
00279
00280 void CommaRT::define_alloc()
00281 {
00282
00283
00284 std::vector<const llvm::Type*>args;
00285 args.push_back(CG.getIntPtrTy());
00286 args.push_back(CG.getInt32Ty());
00287 llvm::FunctionType *fnTy =
00288 llvm::FunctionType::get(CG.getInt8PtrTy(), args, false);
00289 alloc_Fn = CG.makeFunction(fnTy, "_comma_alloc");
00290 }
00291
00292
00293 llvm::GlobalVariable *CommaRT::registerCapsule(Domoid *domoid)
00294 {
00295 return DInfo->emit(domoid);
00296 }
00297
00298 llvm::Value *CommaRT::getDomain(llvm::IRBuilder<> &builder,
00299 llvm::GlobalValue *capsuleInfo) const
00300 {
00301 return builder.CreateCall(getDomainFn, capsuleInfo);
00302 }
00303
00304 llvm::Value *CommaRT::getDomain(llvm::IRBuilder<> &builder,
00305 std::vector<llvm::Value *> &args) const
00306 {
00307 assert(args.front()->getType() == getType<CRT_DomainInfo>()
00308 && "First argument is not a domain_info_t!");
00309 return builder.CreateCall(getDomainFn, args.begin(), args.end());
00310 }
00311
00312 void CommaRT::unhandledException(llvm::IRBuilder<> &builder,
00313 llvm::Value *exception) const
00314 {
00315 builder.CreateCall(unhandledExceptionFn, exception);
00316 builder.CreateUnreachable();
00317 }
00318
00319 llvm::Constant *
00320 CommaRT::checkAndConvertMessage(llvm::GlobalVariable *message) const
00321 {
00322 llvm::Constant *result;
00323 if (message) {
00324
00325 if (llvm::Constant *init = message->getInitializer()) {
00326 llvm::ConstantArray *arr = cast<llvm::ConstantArray>(init);
00327 assert(arr->isCString() && "Message is not null terminated!");
00328 ((void*)arr);
00329 }
00330 result = CG.getPointerCast(message, CG.getInt8PtrTy());
00331 }
00332 else
00333 result = llvm::ConstantPointerNull::get(CG.getInt8PtrTy());
00334 return result;
00335 }
00336
00337 void CommaRT::raise(SRFrame *frame, const ExceptionDecl *exception,
00338 llvm::Value *fileName, llvm::Value *lineNum,
00339 llvm::GlobalVariable *message)
00340 {
00341 llvm::Value *exinfo = registerException(exception);
00342 raiseExinfo(frame, exinfo, fileName, lineNum, message);
00343 }
00344
00345 void CommaRT::raise(SRFrame *frame, const ExceptionDecl *exception,
00346 llvm::Value *fileName, llvm::Value *lineNum,
00347 llvm::Value *message, llvm::Value *length)
00348 {
00349 llvm::Value *exinfo = registerException(exception);
00350 raiseExinfo(frame, exinfo, fileName, lineNum, message, length);
00351 }
00352
00353 void CommaRT::raiseExinfo(SRFrame *frame, llvm::Value *exinfo,
00354 llvm::Value *fileName, llvm::Value *lineNum,
00355 llvm::GlobalVariable *message) const
00356 {
00357 llvm::IRBuilder<> &builder = frame->getIRBuilder();
00358 llvm::Constant *msgPtr = checkAndConvertMessage(message);
00359 if (llvm::BasicBlock *lpad = frame->getLandingPad()) {
00360 llvm::BasicBlock *norm = frame->makeBasicBlock("invoke.normal");
00361 llvm::Value *args[4] = { exinfo, fileName, lineNum, msgPtr };
00362 builder.CreateInvoke(raiseStaticExceptionFn, norm, lpad, args, args+4);
00363 builder.SetInsertPoint(norm);
00364 }
00365 else
00366 builder.CreateCall4(raiseStaticExceptionFn, exinfo,
00367 fileName, lineNum, msgPtr);
00368 builder.CreateUnreachable();
00369 }
00370
00371 void CommaRT::raiseExinfo(SRFrame *frame, llvm::Value *exinfo,
00372 llvm::Value *fileName, llvm::Value *lineNum,
00373 llvm::Value *message, llvm::Value *length) const
00374 {
00375 llvm::IRBuilder<> &builder = frame->getIRBuilder();
00376
00377 if (message)
00378 message = builder.CreatePointerCast(message, CG.getInt8PtrTy());
00379 else {
00380 message = llvm::ConstantPointerNull::get(CG.getInt8PtrTy());
00381 length = llvm::ConstantInt::get(CG.getInt32Ty(), 0);
00382 }
00383
00384 llvm::Value *args[5] = { exinfo, fileName, lineNum, message, length };
00385
00386 if (llvm::BasicBlock *lpad = frame->getLandingPad()) {
00387 llvm::BasicBlock *norm = frame->makeBasicBlock("invoke.normal");
00388 builder.CreateInvoke(raiseUserExceptionFn, norm, lpad, args, args+5);
00389 builder.SetInsertPoint(norm);
00390 }
00391 else
00392 builder.CreateCall(raiseUserExceptionFn, args, args+5);
00393 builder.CreateUnreachable();
00394 }
00395
00396 void CommaRT::reraise(SRFrame *frame, llvm::Value *exception)
00397 {
00398 llvm::IRBuilder<> &builder = frame->getIRBuilder();
00399
00400 if (llvm::BasicBlock *lpad = frame->getLandingPad()) {
00401 llvm::BasicBlock *norm = frame->makeBasicBlock("invoke.normal");
00402 llvm::Value *args[1] = { exception };
00403 builder.CreateInvoke(reraiseExceptionFn, norm, lpad, args, args+1);
00404 builder.SetInsertPoint(norm);
00405 }
00406 else
00407 builder.CreateCall(reraiseExceptionFn, exception);
00408 builder.CreateUnreachable();
00409 }
00410
00411 void CommaRT::raiseProgramError(SRFrame *frame,
00412 llvm::Value *fileName, llvm::Value *lineNum,
00413 llvm::GlobalVariable *message) const
00414 {
00415 raiseExinfo(frame, theProgramErrorExinfo, fileName, lineNum, message);
00416 }
00417
00418 void CommaRT::raiseConstraintError(SRFrame *frame,
00419 llvm::Value *fileName, llvm::Value *lineNum,
00420 llvm::GlobalVariable *message) const
00421 {
00422 raiseExinfo(frame, theConstraintErrorExinfo, fileName, lineNum, message);
00423 }
00424
00425 void
00426 CommaRT::raiseAssertionError(SRFrame *frame,
00427 llvm::Value *fileName, llvm::Value *lineNum,
00428 llvm::Value *message, llvm::Value *length) const
00429 {
00430 raiseExinfo(frame, theAssertErrorExinfo,
00431 fileName, lineNum, message, length);
00432 }
00433
00434 llvm::Constant *CommaRT::getEHPersonality() const
00435 {
00436 return CG.getPointerCast(EHPersonalityFn, CG.getInt8PtrTy());
00437 }
00438
00439 llvm::Constant *CommaRT::registerException(const ExceptionDecl *except)
00440 {
00441 llvm::Constant *exinfo = 0;
00442
00443 switch (except->getID()) {
00444
00445 case ExceptionDecl::User: {
00446 llvm::GlobalVariable *&entry = registeredExceptions[except];
00447 if (!entry) {
00448 llvm::Constant *init = genExinfoInitializer(except);
00449 const llvm::Type *exinfoTy = init->getType();
00450 entry = new llvm::GlobalVariable(*CG.getModule(), exinfoTy, true,
00451 llvm::GlobalValue::ExternalLinkage,
00452 init, mangle::getLinkName(except));
00453 exinfo = CG.getPointerCast(entry, CG.getInt8PtrTy());
00454 }
00455 else
00456 exinfo = entry;
00457 }
00458
00459 case ExceptionDecl::Program_Error:
00460 exinfo = theProgramErrorExinfo;
00461 break;
00462
00463 case ExceptionDecl::Constraint_Error:
00464 exinfo = theConstraintErrorExinfo;
00465 break;
00466
00467 case ExceptionDecl::Assertion_Error:
00468 exinfo = theAssertErrorExinfo;
00469 break;
00470 }
00471 return exinfo;
00472 }
00473
00474 llvm::Value *CommaRT::pow_i32_i32(llvm::IRBuilder<> &builder,
00475 llvm::Value *x, llvm::Value *n) const
00476 {
00477 return builder.CreateCall2(pow_i32_i32_Fn, x, n);
00478 }
00479
00480 llvm::Value *CommaRT::pow_i64_i32(llvm::IRBuilder<> &builder,
00481 llvm::Value *x, llvm::Value *n) const
00482 {
00483 return builder.CreateCall2(pow_i64_i32_Fn, x, n);
00484 }
00485
00486 void CommaRT::vstack_alloc(llvm::IRBuilder<> &builder, llvm::Value *size) const
00487 {
00488 builder.CreateCall(vstack_alloc_Fn, size);
00489 }
00490
00491 void CommaRT::vstack_push(llvm::IRBuilder<> &builder,
00492 llvm::Value *data, llvm::Value *size) const
00493 {
00494 data = builder.CreatePointerCast(data, CG.getInt8PtrTy());
00495 builder.CreateCall2(vstack_push_Fn, data, size);
00496 }
00497
00498 void CommaRT::vstack_pop(llvm::IRBuilder<> &builder) const
00499 {
00500 builder.CreateCall(vstack_pop_Fn);
00501 }
00502
00503 llvm::Value *CommaRT::vstack(llvm::IRBuilder<> &builder,
00504 const llvm::Type *type) const
00505 {
00506
00507
00508 const llvm::PointerType *ptrTy = cast<llvm::PointerType>(type);
00509 llvm::Value *stack_data = builder.CreateLoad(vstack_Var, true);
00510 return builder.CreatePointerCast(stack_data, ptrTy);
00511 }
00512
00513 llvm::Value *CommaRT::comma_alloc(llvm::IRBuilder<> &builder,
00514 uint64_t size, unsigned alignment) const
00515 {
00516 const llvm::FunctionType *allocTy = alloc_Fn->getFunctionType();
00517 const llvm::Type *sizeTy = allocTy->getParamType(0);
00518 const llvm::Type *alignTy = allocTy->getParamType(1);
00519
00520 llvm::Value *sizeVal = llvm::ConstantInt::get(sizeTy, size);
00521 llvm::Value *alignVal = llvm::ConstantInt::get(alignTy, alignment);
00522
00523
00524 return builder.CreateCall2(alloc_Fn, sizeVal, alignVal);
00525 }
00526
00527 llvm::Value *CommaRT::comma_alloc(llvm::IRBuilder<> &builder,
00528 llvm::Value *size, unsigned alignment) const
00529 {
00530 const llvm::FunctionType *allocTy = alloc_Fn->getFunctionType();
00531 const llvm::Type *sizeTy = allocTy->getParamType(0);
00532 const llvm::Type *alignTy = allocTy->getParamType(1);
00533
00534 if (size->getType() != sizeTy)
00535 size = builder.CreateZExt(size, sizeTy);
00536
00537 llvm::Value *align = llvm::ConstantInt::get(alignTy, alignment);
00538
00539
00540 return builder.CreateCall2(alloc_Fn, size, align);
00541 }
00542
00543 llvm::Value *CommaRT::getLocalCapsule(llvm::IRBuilder<> &builder,
00544 llvm::Value *percent, unsigned ID) const
00545 {
00546 return DInstance->loadLocalInstance(builder, percent, ID);
00547 }
00548
00550 llvm::Value *CommaRT::getCapsuleParameter(llvm::IRBuilder<> &builder,
00551 llvm::Value *instance,
00552 unsigned index) const
00553 {
00554 return DInstance->loadParam(builder, instance, index);
00555 }
00556
00557 llvm::Constant *CommaRT::genExinfoInitializer(const ExceptionDecl *exception)
00558 {
00559
00560
00561
00562 llvm::LLVMContext &ctx = CG.getLLVMContext();
00563 return llvm::ConstantArray::get(ctx, exception->getString(), true);
00564 }
00565