slang_rs_backend.cpp revision 592a954aae4cb946970b557e94afd5ee453fd57e
1#include "slang_rs_backend.h" 2 3#include <vector> 4#include <string> 5 6#include "llvm/Metadata.h" 7#include "llvm/Constant.h" 8#include "llvm/Constants.h" 9#include "llvm/Module.h" 10#include "llvm/Function.h" 11#include "llvm/DerivedTypes.h" 12 13#include "llvm/System/Path.h" 14 15#include "llvm/Support/IRBuilder.h" 16 17#include "llvm/ADT/Twine.h" 18#include "llvm/ADT/StringExtras.h" 19 20#include "clang/AST/DeclGroup.h" 21 22#include "slang_rs.h" 23#include "slang_rs_context.h" 24#include "slang_rs_metadata.h" 25#include "slang_rs_export_var.h" 26#include "slang_rs_export_func.h" 27#include "slang_rs_export_type.h" 28 29using namespace slang; 30 31RSBackend::RSBackend(RSContext *Context, 32 clang::Diagnostic &Diags, 33 const clang::CodeGenOptions &CodeGenOpts, 34 const clang::TargetOptions &TargetOpts, 35 const PragmaList &Pragmas, 36 llvm::raw_ostream *OS, 37 Slang::OutputType OT, 38 clang::SourceManager &SourceMgr, 39 bool AllowRSPrefix) 40 : Backend(Diags, 41 CodeGenOpts, 42 TargetOpts, 43 Pragmas, 44 OS, 45 OT), 46 mContext(Context), 47 mSourceMgr(SourceMgr), 48 mAllowRSPrefix(AllowRSPrefix), 49 mExportVarMetadata(NULL), 50 mExportFuncMetadata(NULL), 51 mExportTypeMetadata(NULL) { 52 return; 53} 54 55void RSBackend::HandleTopLevelDecl(clang::DeclGroupRef D) { 56 // Disallow user-defined functions with prefix "rs" 57 if (!mAllowRSPrefix) { 58 // Iterate all function declarations in the program. 59 for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); 60 I != E; I++) { 61 clang::FunctionDecl *FD = dyn_cast<clang::FunctionDecl>(*I); 62 if (FD == NULL) 63 continue; 64 if (FD->getName().startswith("rs")) { // Check prefix 65 clang::FullSourceLoc FSL(FD->getLocStart(), mSourceMgr); 66 clang::PresumedLoc PLoc = mSourceMgr.getPresumedLoc(FSL); 67 llvm::sys::Path HeaderFilename(PLoc.getFilename()); 68 69 // Skip if that function declared in the RS default header. 70 if (SlangRS::IsRSHeaderFile(HeaderFilename.getLast().data())) 71 continue; 72 mDiags.Report(FSL, mDiags.getCustomDiagID(clang::Diagnostic::Error, 73 "invalid function name prefix, \"rs\" is reserved: '%0'")) 74 << FD->getName(); 75 } 76 } 77 } 78 79 Backend::HandleTopLevelDecl(D); 80 return; 81} 82 83void RSBackend::HandleTranslationUnitEx(clang::ASTContext &Ctx) { 84 assert((&Ctx == mContext->getASTContext()) && "Unexpected AST context change" 85 " during LLVM IR generation"); 86 mContext->processExport(); 87 88 // Dump export variable info 89 if (mContext->hasExportVar()) { 90 if (mExportVarMetadata == NULL) 91 mExportVarMetadata = mpModule->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN); 92 93 llvm::SmallVector<llvm::Value*, 2> ExportVarInfo; 94 95 for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(), 96 E = mContext->export_vars_end(); 97 I != E; 98 I++) { 99 const RSExportVar *EV = *I; 100 const RSExportType *ET = EV->getType(); 101 102 // Variable name 103 ExportVarInfo.push_back( 104 llvm::MDString::get(mLLVMContext, EV->getName().c_str())); 105 106 // Type name 107 if (ET->getClass() == RSExportType::ExportClassPrimitive) 108 ExportVarInfo.push_back( 109 llvm::MDString::get( 110 mLLVMContext, llvm::utostr_32( 111 static_cast<const RSExportPrimitiveType*>(ET)->getType()))); 112 else if (ET->getClass() == RSExportType::ExportClassPointer) 113 ExportVarInfo.push_back( 114 llvm::MDString::get( 115 mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET) 116 ->getPointeeType()->getName()).c_str())); 117 else 118 ExportVarInfo.push_back( 119 llvm::MDString::get(mLLVMContext, 120 EV->getType()->getName().c_str())); 121 122 mExportVarMetadata->addOperand( 123 llvm::MDNode::get(mLLVMContext, 124 ExportVarInfo.data(), 125 ExportVarInfo.size()) ); 126 127 ExportVarInfo.clear(); 128 } 129 } 130 131 // Dump export function info 132 if (mContext->hasExportFunc()) { 133 if (mExportFuncMetadata == NULL) 134 mExportFuncMetadata = 135 mpModule->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN); 136 137 llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo; 138 139 for (RSContext::const_export_func_iterator 140 I = mContext->export_funcs_begin(), 141 E = mContext->export_funcs_end(); 142 I != E; 143 I++) { 144 const RSExportFunc *EF = *I; 145 146 // Function name 147 if (!EF->hasParam()) { 148 ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext, 149 EF->getName().c_str())); 150 } else { 151 llvm::Function *F = mpModule->getFunction(EF->getName()); 152 llvm::Function *HelperFunction; 153 const std::string HelperFunctionName(".helper_" + EF->getName()); 154 155 assert(F && "Function marked as exported disappeared in Bitcode"); 156 157 // Create helper function 158 { 159 llvm::StructType *HelperFunctionParameterTy = NULL; 160 161 if (!F->getArgumentList().empty()) { 162 std::vector<const llvm::Type*> HelperFunctionParameterTys; 163 for (llvm::Function::arg_iterator AI = F->arg_begin(), 164 AE = F->arg_end(); AI != AE; AI++) 165 HelperFunctionParameterTys.push_back(AI->getType()); 166 167 HelperFunctionParameterTy = 168 llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys); 169 } 170 171 if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) { 172 fprintf(stderr, "Failed to export function %s: parameter type " 173 "mismatch during creation of helper function.\n", 174 EF->getName().c_str()); 175 176 const RSExportRecordType *Expected = EF->getParamPacketType(); 177 if (Expected) { 178 fprintf(stderr, "Expected:\n"); 179 Expected->getLLVMType()->dump(); 180 } 181 if (HelperFunctionParameterTy) { 182 fprintf(stderr, "Got:\n"); 183 HelperFunctionParameterTy->dump(); 184 } 185 } 186 187 std::vector<const llvm::Type*> Params; 188 if (HelperFunctionParameterTy) { 189 llvm::PointerType *HelperFunctionParameterTyP = 190 llvm::PointerType::getUnqual(HelperFunctionParameterTy); 191 Params.push_back(HelperFunctionParameterTyP); 192 } 193 194 llvm::FunctionType * HelperFunctionType = 195 llvm::FunctionType::get(F->getReturnType(), 196 Params, 197 /* IsVarArgs = */false); 198 199 HelperFunction = 200 llvm::Function::Create(HelperFunctionType, 201 llvm::GlobalValue::ExternalLinkage, 202 HelperFunctionName, 203 mpModule); 204 205 HelperFunction->addFnAttr(llvm::Attribute::NoInline); 206 HelperFunction->setCallingConv(F->getCallingConv()); 207 208 // Create helper function body 209 { 210 llvm::Argument *HelperFunctionParameter = 211 &(*HelperFunction->arg_begin()); 212 llvm::BasicBlock *BB = 213 llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction); 214 llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB); 215 llvm::SmallVector<llvm::Value*, 6> Params; 216 llvm::Value *Idx[2]; 217 218 Idx[0] = 219 llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0); 220 221 // getelementptr and load instruction for all elements in 222 // parameter .p 223 for (size_t i = 0; i < EF->getNumParameters(); i++) { 224 // getelementptr 225 Idx[1] = 226 llvm::ConstantInt::get( 227 llvm::Type::getInt32Ty(mLLVMContext), i); 228 llvm::Value *Ptr = IB->CreateInBoundsGEP(HelperFunctionParameter, 229 Idx, 230 Idx + 2); 231 232 // load 233 llvm::Value *V = IB->CreateLoad(Ptr); 234 Params.push_back(V); 235 } 236 237 // Call and pass the all elements as paramter to F 238 llvm::CallInst *CI = IB->CreateCall(F, 239 Params.data(), 240 Params.data() + Params.size()); 241 242 CI->setCallingConv(F->getCallingConv()); 243 244 if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext)) 245 IB->CreateRetVoid(); 246 else 247 IB->CreateRet(CI); 248 249 delete IB; 250 } 251 } 252 253 ExportFuncInfo.push_back( 254 llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str())); 255 } 256 257 mExportFuncMetadata->addOperand( 258 llvm::MDNode::get(mLLVMContext, 259 ExportFuncInfo.data(), 260 ExportFuncInfo.size())); 261 262 ExportFuncInfo.clear(); 263 } 264 } 265 266 // Dump export type info 267 if (mContext->hasExportType()) { 268 llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo; 269 270 for (RSContext::const_export_type_iterator 271 I = mContext->export_types_begin(), 272 E = mContext->export_types_end(); 273 I != E; 274 I++) { 275 // First, dump type name list to export 276 const RSExportType *ET = I->getValue(); 277 278 ExportTypeInfo.clear(); 279 // Type name 280 ExportTypeInfo.push_back( 281 llvm::MDString::get(mLLVMContext, ET->getName().c_str())); 282 283 if (ET->getClass() == RSExportType::ExportClassRecord) { 284 const RSExportRecordType *ERT = 285 static_cast<const RSExportRecordType*>(ET); 286 287 if (mExportTypeMetadata == NULL) 288 mExportTypeMetadata = 289 mpModule->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN); 290 291 mExportTypeMetadata->addOperand( 292 llvm::MDNode::get(mLLVMContext, 293 ExportTypeInfo.data(), 294 ExportTypeInfo.size())); 295 296 // Now, export struct field information to %[struct name] 297 std::string StructInfoMetadataName("%"); 298 StructInfoMetadataName.append(ET->getName()); 299 llvm::NamedMDNode *StructInfoMetadata = 300 mpModule->getOrInsertNamedMetadata(StructInfoMetadataName); 301 llvm::SmallVector<llvm::Value*, 3> FieldInfo; 302 303 assert(StructInfoMetadata->getNumOperands() == 0 && 304 "Metadata with same name was created before"); 305 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(), 306 FE = ERT->fields_end(); 307 FI != FE; 308 FI++) { 309 const RSExportRecordType::Field *F = *FI; 310 311 // 1. field name 312 FieldInfo.push_back(llvm::MDString::get(mLLVMContext, 313 F->getName().c_str())); 314 315 // 2. field type name 316 FieldInfo.push_back( 317 llvm::MDString::get(mLLVMContext, 318 F->getType()->getName().c_str())); 319 320 // 3. field kind 321 switch (F->getType()->getClass()) { 322 case RSExportType::ExportClassPrimitive: 323 case RSExportType::ExportClassVector: { 324 const RSExportPrimitiveType *EPT = 325 static_cast<const RSExportPrimitiveType*>(F->getType()); 326 FieldInfo.push_back( 327 llvm::MDString::get(mLLVMContext, 328 llvm::itostr(EPT->getKind()))); 329 break; 330 } 331 332 default: { 333 FieldInfo.push_back( 334 llvm::MDString::get(mLLVMContext, 335 llvm::itostr( 336 RSExportPrimitiveType::DataKindUser))); 337 break; 338 } 339 } 340 341 StructInfoMetadata->addOperand(llvm::MDNode::get(mLLVMContext, 342 FieldInfo.data(), 343 FieldInfo.size())); 344 345 FieldInfo.clear(); 346 } 347 } // ET->getClass() == RSExportType::ExportClassRecord 348 } 349 } 350 351 return; 352} 353 354RSBackend::~RSBackend() { 355 return; 356} 357