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