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