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