slang_rs_backend.cpp revision 9ef2f785e0cc490af678dfd685995dec787321ff
1#include "slang_rs_backend.hpp" 2#include "slang_rs_context.hpp" 3#include "slang_rs_export_var.hpp" 4#include "slang_rs_export_func.hpp" 5#include "slang_rs_export_type.hpp" 6 7#include "llvm/Metadata.h" 8 9#include "llvm/ADT/Twine.h" 10#include "llvm/ADT/StringExtras.h" 11 12#include "llvm/Support/IRBuilder.h" 13#include "llvm/Constant.h" 14#include "llvm/Constants.h" 15#include "llvm/Module.h" 16#include "llvm/Function.h" 17#include "llvm/DerivedTypes.h" 18 19#include "clang/AST/DeclGroup.h" 20 21#include <vector> 22#include <string> 23 24using namespace slang; 25 26RSBackend::RSBackend(RSContext *Context, 27 clang::Diagnostic &Diags, 28 const clang::CodeGenOptions &CodeGenOpts, 29 const clang::TargetOptions &TargetOpts, 30 const PragmaList &Pragmas, 31 llvm::raw_ostream *OS, 32 SlangCompilerOutputTy OutputType, 33 clang::SourceManager &SourceMgr, 34 bool AllowRSPrefix) : 35 Backend(Diags, 36 CodeGenOpts, 37 TargetOpts, 38 Pragmas, 39 OS, 40 OutputType, 41 SourceMgr, 42 AllowRSPrefix), 43 mContext(Context), 44 mExportVarMetadata(NULL), 45 mExportFuncMetadata(NULL), 46 mExportTypeMetadata(NULL) { 47 return; 48} 49 50void RSBackend::HandleTopLevelDecl(clang::DeclGroupRef D) { 51 Backend::HandleTopLevelDecl(D); 52 return; 53} 54 55void RSBackend::HandleTranslationUnitEx(clang::ASTContext &Ctx) { 56 assert((&Ctx == mContext->getASTContext()) && "Unexpected AST context change" 57 " during LLVM IR generation"); 58 mContext->processExport(); 59 60 // Dump export variable info 61 if (mContext->hasExportVar()) { 62 if (mExportVarMetadata == NULL) 63 mExportVarMetadata = mpModule->getOrInsertNamedMetadata("#rs_export_var"); 64 65 llvm::SmallVector<llvm::Value*, 2> ExportVarInfo; 66 67 for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(); 68 I != mContext->export_vars_end(); 69 I++) 70 { 71 const RSExportVar* EV = *I; 72 const RSExportType* ET = EV->getType(); 73 74 // Variable name 75 ExportVarInfo.push_back( 76 llvm::MDString::get(mLLVMContext, EV->getName().c_str())); 77 78 // Type name 79 if (ET->getClass() == RSExportType::ExportClassPrimitive) 80 ExportVarInfo.push_back( 81 llvm::MDString::get( 82 mLLVMContext, llvm::utostr_32( 83 static_cast<const RSExportPrimitiveType*>(ET)->getType() 84 ))); 85 else if (ET->getClass() == RSExportType::ExportClassPointer) 86 ExportVarInfo.push_back( 87 llvm::MDString::get( 88 mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET) 89 ->getPointeeType()->getName() 90 ).c_str() 91 )); 92 else 93 ExportVarInfo.push_back( 94 llvm::MDString::get(mLLVMContext, 95 EV->getType()->getName().c_str())); 96 97 mExportVarMetadata->addOperand( 98 llvm::MDNode::get(mLLVMContext, 99 ExportVarInfo.data(), 100 ExportVarInfo.size()) ); 101 102 ExportVarInfo.clear(); 103 } 104 } 105 106 // Dump export function info 107 if (mContext->hasExportFunc()) { 108 if (mExportFuncMetadata == NULL) 109 mExportFuncMetadata = 110 mpModule->getOrInsertNamedMetadata("#rs_export_func"); 111 112 llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo; 113 114 for (RSContext::const_export_func_iterator I=mContext->export_funcs_begin(), 115 E = mContext->export_funcs_end(); 116 I != E; 117 I++) { 118 const RSExportFunc* EF = *I; 119 120 // Function name 121 if (!EF->hasParam()) 122 ExportFuncInfo.push_back( llvm::MDString::get(mLLVMContext, 123 EF->getName().c_str())); 124 else { 125 llvm::Function *F = mpModule->getFunction(EF->getName()); 126 llvm::Function *HelperFunction; 127 const std::string HelperFunctionName(".helper_" + EF->getName()); 128 129 assert(F && "Function marked as exported disappeared in Bitcode"); 130 131 // Create helper function 132 { 133 llvm::PointerType *HelperFunctionParameterTypeP = 134 llvm::PointerType::getUnqual( 135 EF->getParamPacketType()->getLLVMType()); 136 llvm::FunctionType *HelperFunctionType; 137 std::vector<const llvm::Type*> Params; 138 139 Params.push_back(HelperFunctionParameterTypeP); 140 HelperFunctionType = llvm::FunctionType::get(F->getReturnType(), 141 Params, 142 false); 143 144 HelperFunction = 145 llvm::Function::Create(HelperFunctionType, 146 llvm::GlobalValue::ExternalLinkage, 147 HelperFunctionName, 148 mpModule); 149 150 HelperFunction->addFnAttr(llvm::Attribute::NoInline); 151 HelperFunction->setCallingConv(F->getCallingConv()); 152 153 // Create helper function body 154 { 155 llvm::Argument *HelperFunctionParameter = 156 &(*HelperFunction->arg_begin()); 157 llvm::BasicBlock *BB = 158 llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction); 159 llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB); 160 llvm::SmallVector<llvm::Value*, 6> Params; 161 llvm::Value *Idx[2]; 162 163 Idx[0] = 164 llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0); 165 166 // getelementptr and load instruction for all elements in 167 // parameter .p 168 for (int i = 0; i < EF->getNumParameters(); i++) { 169 // getelementptr 170 Idx[1] = 171 llvm::ConstantInt::get( 172 llvm::Type::getInt32Ty(mLLVMContext), i); 173 llvm::Value *Ptr = IB->CreateInBoundsGEP(HelperFunctionParameter, 174 Idx, 175 Idx + 2); 176 177 // load 178 llvm::Value *V = IB->CreateLoad(Ptr); 179 Params.push_back(V); 180 } 181 182 // Call and pass the all elements as paramter to F 183 llvm::CallInst *CI = IB->CreateCall(F, 184 Params.data(), 185 Params.data() + Params.size()); 186 187 CI->setCallingConv(F->getCallingConv()); 188 189 if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext)) 190 IB->CreateRetVoid(); 191 else 192 IB->CreateRet(CI); 193 194 delete IB; 195 } 196 } 197 198 ExportFuncInfo.push_back( 199 llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str())); 200 } 201 202 mExportFuncMetadata->addOperand( 203 llvm::MDNode::get(mLLVMContext, 204 ExportFuncInfo.data(), 205 ExportFuncInfo.size())); 206 207 ExportFuncInfo.clear(); 208 } 209 } 210 211 // Dump export type info 212 if (mContext->hasExportType()) { 213 llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo; 214 215 for (RSContext::const_export_type_iterator I=mContext->export_types_begin(), 216 E = mContext->export_types_end(); 217 I != E; 218 I++) { 219 // First, dump type name list to export 220 const RSExportType *ET = I->getValue(); 221 222 ExportTypeInfo.clear(); 223 // Type name 224 ExportTypeInfo.push_back( 225 llvm::MDString::get(mLLVMContext, ET->getName().c_str())); 226 227 if (ET->getClass() == RSExportType::ExportClassRecord) { 228 const RSExportRecordType *ERT = 229 static_cast<const RSExportRecordType*>(ET); 230 231 if (mExportTypeMetadata == NULL) 232 mExportTypeMetadata = 233 mpModule->getOrInsertNamedMetadata("#rs_export_type"); 234 235 mExportTypeMetadata->addOperand( 236 llvm::MDNode::get(mLLVMContext, 237 ExportTypeInfo.data(), 238 ExportTypeInfo.size())); 239 240 // Now, export struct field information to %[struct name] 241 std::string StructInfoMetadataName("%"); 242 StructInfoMetadataName.append(ET->getName()); 243 llvm::NamedMDNode *StructInfoMetadata = 244 mpModule->getOrInsertNamedMetadata(StructInfoMetadataName); 245 llvm::SmallVector<llvm::Value*, 3> FieldInfo; 246 247 assert(StructInfoMetadata->getNumOperands() == 0 && 248 "Metadata with same name was created before"); 249 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(); 250 FI != ERT->fields_end(); 251 FI++) { 252 const RSExportRecordType::Field *F = *FI; 253 254 // 1. field name 255 FieldInfo.push_back(llvm::MDString::get(mLLVMContext, 256 F->getName().c_str())); 257 258 // 2. field type name 259 FieldInfo.push_back( 260 llvm::MDString::get(mLLVMContext, 261 F->getType()->getName().c_str())); 262 263 // 3. field kind 264 switch (F->getType()->getClass()) { 265 case RSExportType::ExportClassPrimitive: 266 case RSExportType::ExportClassVector: { 267 const RSExportPrimitiveType *EPT = 268 static_cast<const RSExportPrimitiveType*>(F->getType()); 269 FieldInfo.push_back( 270 llvm::MDString::get(mLLVMContext, 271 llvm::itostr(EPT->getKind()))); 272 break; 273 } 274 275 default: { 276 FieldInfo.push_back( 277 llvm::MDString::get(mLLVMContext, 278 llvm::itostr( 279 RSExportPrimitiveType::DataKindUser 280 ))); 281 break; 282 } 283 } 284 285 StructInfoMetadata->addOperand( llvm::MDNode::get(mLLVMContext, 286 FieldInfo.data(), 287 FieldInfo.size())); 288 289 FieldInfo.clear(); 290 } 291 } // ET->getClass() == RSExportType::ExportClassRecord 292 } 293 } 294 295 return; 296} 297 298RSBackend::~RSBackend() { 299 return; 300} 301