This machine mirrors various open-source projects.
20 Gbit/s uplink.
If there are any issues or you want another project mirrored, please contact
mirror-service -=AT=- netcologne DOT de !
00001 //===-- codegen/CommaRT.cpp ----------------------------------- -*- C++ -*-===// 00002 // 00003 // This file is distributed under the MIT license. See LICENSE.txt for details. 00004 // 00005 // Copyright (C) 2009-2010, Stephen Wilson 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 // Define the types within the Module. 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 // Builds a declaration in LLVM IR for the get_domain runtime function. 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 // get_domain takes a pointer to a domain_instance_t as first argument, and 00129 // then a variable number of domain_instance_t args corresponding to the 00130 // parameters. 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 // This function is never called directly, as does not need a full 00139 // definition. 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 // This function takes a simple i8* object denoting the uncaught exception 00148 // object. 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 // _comma_raise_exception takes an i8* holding the exinfo object, an i8* 00162 // designating the file name, an i32 designating the line number, and an i8* 00163 // denoting the message. 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 // _comma_raise_nexception is as _comma_raise_exception except that an 00177 // additional i32 is given yielding the message length. 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 // _comma_reraise_exception take an i8* pointing to the exception object. 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 // Comma's predefined exception info objects are just external i8*'s with 00196 // definitions in libruntime (see lib/runtime/crt_exceptions.c). 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 // int32_t _comma_pow_i32_i32(int32_t, int32_t); 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 // int64_t _comma_pow_i64_i32(int64_t, int32_t); 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 // void _comma_vstack_alloc(int32_t); 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 // void _comma_vstack_push(char *, int32_t); 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 // void _comma_vstack_pop(); 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 // comma_alloc takes a size argument of the C type uintptr_t and an 00283 // alignment of type i32. Returns a generic i8*. 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 // FIXME: Wrap the following sanity check in a DEBUG macro. 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 // Always perform a volatile load of the vstack pointer as it is most often 00507 // accessed between calls to _comma_vstack_pop. 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 // FIXME: Check for null and raise PROGRAM_ERROR when needed. 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 // FIXME: Check for null and raise PROGRAM_ERROR when needed. 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 // FIXME: exinfo's are just global null terminated strings. We should be 00560 // doing a bit of pretty printing here to get a readable qualified name for 00561 // the exception. 00562 llvm::LLVMContext &ctx = CG.getLLVMContext(); 00563 return llvm::ConstantArray::get(ctx, exception->getString(), true); 00564 } 00565