slang_rs_backend.cpp revision 4b32ffdfc1ac766f8932e7effbcdf7484e804a8e
1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "slang_rs_backend.h"
18
19#include <vector>
20#include <string>
21
22#include "llvm/Metadata.h"
23#include "llvm/Constant.h"
24#include "llvm/Constants.h"
25#include "llvm/Module.h"
26#include "llvm/Function.h"
27#include "llvm/DerivedTypes.h"
28
29#include "llvm/Support/IRBuilder.h"
30
31#include "llvm/ADT/Twine.h"
32#include "llvm/ADT/StringExtras.h"
33
34#include "slang_rs.h"
35#include "slang_rs_context.h"
36#include "slang_rs_metadata.h"
37#include "slang_rs_export_var.h"
38#include "slang_rs_export_func.h"
39#include "slang_rs_export_type.h"
40
41using namespace slang;
42
43RSBackend::RSBackend(RSContext *Context,
44                     clang::Diagnostic &Diags,
45                     const clang::CodeGenOptions &CodeGenOpts,
46                     const clang::TargetOptions &TargetOpts,
47                     const PragmaList &Pragmas,
48                     llvm::raw_ostream *OS,
49                     Slang::OutputType OT,
50                     clang::SourceManager &SourceMgr,
51                     bool AllowRSPrefix)
52    : Backend(Diags,
53              CodeGenOpts,
54              TargetOpts,
55              Pragmas,
56              OS,
57              OT),
58      mContext(Context),
59      mSourceMgr(SourceMgr),
60      mAllowRSPrefix(AllowRSPrefix),
61      mExportVarMetadata(NULL),
62      mExportFuncMetadata(NULL),
63      mExportTypeMetadata(NULL) {
64  return;
65}
66
67// 1) Add zero initialization of local RS object types
68void RSBackend::AnnotateFunction(clang::FunctionDecl *FD) {
69  if (FD &&
70      FD->hasBody() &&
71      !SlangRS::IsFunctionInRSHeaderFile(FD, mSourceMgr)) {
72    mRefCount.Visit(FD->getBody());
73  }
74  return;
75}
76
77void RSBackend::HandleTopLevelDecl(clang::DeclGroupRef D) {
78  // Disallow user-defined functions with prefix "rs"
79  if (!mAllowRSPrefix) {
80    // Iterate all function declarations in the program.
81    for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end();
82         I != E; I++) {
83      clang::FunctionDecl *FD = dyn_cast<clang::FunctionDecl>(*I);
84      if (FD == NULL)
85        continue;
86      if (!FD->getName().startswith("rs"))  // Check prefix
87        continue;
88      if (!SlangRS::IsFunctionInRSHeaderFile(FD, mSourceMgr))
89        mDiags.Report(clang::FullSourceLoc(FD->getLocation(), mSourceMgr),
90                      mDiags.getCustomDiagID(clang::Diagnostic::Error,
91                                             "invalid function name prefix, "
92                                             "\"rs\" is reserved: '%0'"))
93            << FD->getName();
94    }
95  }
96
97  // Process any non-static function declarations
98  for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; I++) {
99    AnnotateFunction(dyn_cast<clang::FunctionDecl>(*I));
100  }
101
102  Backend::HandleTopLevelDecl(D);
103  return;
104}
105
106void RSBackend::HandleTranslationUnitPre(clang::ASTContext& C) {
107  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
108
109  // Process any static function declarations
110  for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
111          E = TUDecl->decls_end(); I != E; I++) {
112    if ((I->getKind() >= clang::Decl::firstFunction) &&
113        (I->getKind() <= clang::Decl::lastFunction)) {
114      AnnotateFunction(static_cast<clang::FunctionDecl*>(*I));
115    }
116  }
117
118  return;
119}
120
121///////////////////////////////////////////////////////////////////////////////
122void RSBackend::HandleTranslationUnitPost(llvm::Module *M) {
123  mContext->processExport();
124
125  // Dump export variable info
126  if (mContext->hasExportVar()) {
127    if (mExportVarMetadata == NULL)
128      mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
129
130    llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
131
132    for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(),
133            E = mContext->export_vars_end();
134         I != E;
135         I++) {
136      const RSExportVar *EV = *I;
137      const RSExportType *ET = EV->getType();
138
139      // Variable name
140      ExportVarInfo.push_back(
141          llvm::MDString::get(mLLVMContext, EV->getName().c_str()));
142
143      // Type name
144      switch (ET->getClass()) {
145        case RSExportType::ExportClassPrimitive: {
146          ExportVarInfo.push_back(
147              llvm::MDString::get(
148                mLLVMContext, llvm::utostr_32(
149                  static_cast<const RSExportPrimitiveType*>(ET)->getType())));
150          break;
151        }
152        case RSExportType::ExportClassPointer: {
153          ExportVarInfo.push_back(
154              llvm::MDString::get(
155                mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET)
156                  ->getPointeeType()->getName()).c_str()));
157          break;
158        }
159        case RSExportType::ExportClassMatrix: {
160          ExportVarInfo.push_back(
161              llvm::MDString::get(
162                mLLVMContext, llvm::utostr_32(
163                  RSExportPrimitiveType::DataTypeRSMatrix2x2 +
164                  static_cast<const RSExportMatrixType*>(ET)->getDim() - 2)));
165          break;
166        }
167        case RSExportType::ExportClassVector:
168        case RSExportType::ExportClassConstantArray:
169        case RSExportType::ExportClassRecord: {
170          ExportVarInfo.push_back(
171              llvm::MDString::get(mLLVMContext,
172                EV->getType()->getName().c_str()));
173          break;
174        }
175      }
176
177      mExportVarMetadata->addOperand(
178          llvm::MDNode::get(mLLVMContext,
179                            ExportVarInfo.data(),
180                            ExportVarInfo.size()) );
181
182      ExportVarInfo.clear();
183    }
184  }
185
186  // Dump export function info
187  if (mContext->hasExportFunc()) {
188    if (mExportFuncMetadata == NULL)
189      mExportFuncMetadata =
190          M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
191
192    llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo;
193
194    for (RSContext::const_export_func_iterator
195            I = mContext->export_funcs_begin(),
196            E = mContext->export_funcs_end();
197         I != E;
198         I++) {
199      const RSExportFunc *EF = *I;
200
201      // Function name
202      if (!EF->hasParam()) {
203        ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext,
204                                                     EF->getName().c_str()));
205      } else {
206        llvm::Function *F = M->getFunction(EF->getName());
207        llvm::Function *HelperFunction;
208        const std::string HelperFunctionName(".helper_" + EF->getName());
209
210        assert(F && "Function marked as exported disappeared in Bitcode");
211
212        // Create helper function
213        {
214          llvm::StructType *HelperFunctionParameterTy = NULL;
215
216          if (!F->getArgumentList().empty()) {
217            std::vector<const llvm::Type*> HelperFunctionParameterTys;
218            for (llvm::Function::arg_iterator AI = F->arg_begin(),
219                 AE = F->arg_end(); AI != AE; AI++)
220              HelperFunctionParameterTys.push_back(AI->getType());
221
222            HelperFunctionParameterTy =
223                llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
224          }
225
226          if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
227            fprintf(stderr, "Failed to export function %s: parameter type "
228                            "mismatch during creation of helper function.\n",
229                    EF->getName().c_str());
230
231            const RSExportRecordType *Expected = EF->getParamPacketType();
232            if (Expected) {
233              fprintf(stderr, "Expected:\n");
234              Expected->getLLVMType()->dump();
235            }
236            if (HelperFunctionParameterTy) {
237              fprintf(stderr, "Got:\n");
238              HelperFunctionParameterTy->dump();
239            }
240          }
241
242          std::vector<const llvm::Type*> Params;
243          if (HelperFunctionParameterTy) {
244            llvm::PointerType *HelperFunctionParameterTyP =
245                llvm::PointerType::getUnqual(HelperFunctionParameterTy);
246            Params.push_back(HelperFunctionParameterTyP);
247          }
248
249          llvm::FunctionType * HelperFunctionType =
250              llvm::FunctionType::get(F->getReturnType(),
251                                      Params,
252                                      /* IsVarArgs = */false);
253
254          HelperFunction =
255              llvm::Function::Create(HelperFunctionType,
256                                     llvm::GlobalValue::ExternalLinkage,
257                                     HelperFunctionName,
258                                     M);
259
260          HelperFunction->addFnAttr(llvm::Attribute::NoInline);
261          HelperFunction->setCallingConv(F->getCallingConv());
262
263          // Create helper function body
264          {
265            llvm::Argument *HelperFunctionParameter =
266                &(*HelperFunction->arg_begin());
267            llvm::BasicBlock *BB =
268                llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
269            llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
270            llvm::SmallVector<llvm::Value*, 6> Params;
271            llvm::Value *Idx[2];
272
273            Idx[0] =
274                llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
275
276            // getelementptr and load instruction for all elements in
277            // parameter .p
278            for (size_t i = 0; i < EF->getNumParameters(); i++) {
279              // getelementptr
280              Idx[1] =
281                  llvm::ConstantInt::get(
282                      llvm::Type::getInt32Ty(mLLVMContext), i);
283              llvm::Value *Ptr = IB->CreateInBoundsGEP(HelperFunctionParameter,
284                                                       Idx,
285                                                       Idx + 2);
286
287              // load
288              llvm::Value *V = IB->CreateLoad(Ptr);
289              Params.push_back(V);
290            }
291
292            // Call and pass the all elements as paramter to F
293            llvm::CallInst *CI = IB->CreateCall(F,
294                                                Params.data(),
295                                                Params.data() + Params.size());
296
297            CI->setCallingConv(F->getCallingConv());
298
299            if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
300              IB->CreateRetVoid();
301            else
302              IB->CreateRet(CI);
303
304            delete IB;
305          }
306        }
307
308        ExportFuncInfo.push_back(
309            llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
310      }
311
312      mExportFuncMetadata->addOperand(
313          llvm::MDNode::get(mLLVMContext,
314                            ExportFuncInfo.data(),
315                            ExportFuncInfo.size()));
316
317      ExportFuncInfo.clear();
318    }
319  }
320
321  // Dump export type info
322  if (mContext->hasExportType()) {
323    llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
324
325    for (RSContext::const_export_type_iterator
326            I = mContext->export_types_begin(),
327            E = mContext->export_types_end();
328         I != E;
329         I++) {
330      // First, dump type name list to export
331      const RSExportType *ET = I->getValue();
332
333      ExportTypeInfo.clear();
334      // Type name
335      ExportTypeInfo.push_back(
336          llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
337
338      if (ET->getClass() == RSExportType::ExportClassRecord) {
339        const RSExportRecordType *ERT =
340            static_cast<const RSExportRecordType*>(ET);
341
342        if (mExportTypeMetadata == NULL)
343          mExportTypeMetadata =
344              M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
345
346        mExportTypeMetadata->addOperand(
347            llvm::MDNode::get(mLLVMContext,
348                              ExportTypeInfo.data(),
349                              ExportTypeInfo.size()));
350
351        // Now, export struct field information to %[struct name]
352        std::string StructInfoMetadataName("%");
353        StructInfoMetadataName.append(ET->getName());
354        llvm::NamedMDNode *StructInfoMetadata =
355            M->getOrInsertNamedMetadata(StructInfoMetadataName);
356        llvm::SmallVector<llvm::Value*, 3> FieldInfo;
357
358        assert(StructInfoMetadata->getNumOperands() == 0 &&
359               "Metadata with same name was created before");
360        for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
361                FE = ERT->fields_end();
362             FI != FE;
363             FI++) {
364          const RSExportRecordType::Field *F = *FI;
365
366          // 1. field name
367          FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
368                                                  F->getName().c_str()));
369
370          // 2. field type name
371          FieldInfo.push_back(
372              llvm::MDString::get(mLLVMContext,
373                                  F->getType()->getName().c_str()));
374
375          // 3. field kind
376          switch (F->getType()->getClass()) {
377            case RSExportType::ExportClassPrimitive:
378            case RSExportType::ExportClassVector: {
379              const RSExportPrimitiveType *EPT =
380                  static_cast<const RSExportPrimitiveType*>(F->getType());
381              FieldInfo.push_back(
382                  llvm::MDString::get(mLLVMContext,
383                                      llvm::itostr(EPT->getKind())));
384              break;
385            }
386
387            default: {
388              FieldInfo.push_back(
389                  llvm::MDString::get(mLLVMContext,
390                                      llvm::itostr(
391                                        RSExportPrimitiveType::DataKindUser)));
392              break;
393            }
394          }
395
396          StructInfoMetadata->addOperand(llvm::MDNode::get(mLLVMContext,
397                                                           FieldInfo.data(),
398                                                           FieldInfo.size()));
399
400          FieldInfo.clear();
401        }
402      }   // ET->getClass() == RSExportType::ExportClassRecord
403    }
404  }
405
406  return;
407}
408
409RSBackend::~RSBackend() {
410  return;
411}
412