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