slang_rs_backend.cpp revision fa6ef56a6ca3dc3061218a75a7e68e5357fcb82c
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 <string>
20#include <vector>
21
22#include "llvm/ADT/Twine.h"
23#include "llvm/ADT/StringExtras.h"
24
25#include "llvm/Constant.h"
26#include "llvm/Constants.h"
27#include "llvm/DerivedTypes.h"
28#include "llvm/Function.h"
29#include "llvm/Metadata.h"
30#include "llvm/Module.h"
31
32#include "llvm/Support/IRBuilder.h"
33
34#include "slang_assert.h"
35#include "slang_rs.h"
36#include "slang_rs_context.h"
37#include "slang_rs_export_foreach.h"
38#include "slang_rs_export_func.h"
39#include "slang_rs_export_type.h"
40#include "slang_rs_export_var.h"
41#include "slang_rs_metadata.h"
42
43namespace slang {
44
45RSBackend::RSBackend(RSContext *Context,
46                     clang::DiagnosticsEngine *DiagEngine,
47                     const clang::CodeGenOptions &CodeGenOpts,
48                     const clang::TargetOptions &TargetOpts,
49                     PragmaList *Pragmas,
50                     llvm::raw_ostream *OS,
51                     Slang::OutputType OT,
52                     clang::SourceManager &SourceMgr,
53                     bool AllowRSPrefix)
54  : Backend(DiagEngine, CodeGenOpts, TargetOpts, Pragmas, OS, OT),
55    mContext(Context),
56    mSourceMgr(SourceMgr),
57    mAllowRSPrefix(AllowRSPrefix),
58    mExportVarMetadata(NULL),
59    mExportFuncMetadata(NULL),
60    mExportForEachMetadata(NULL),
61    mExportTypeMetadata(NULL),
62    mRSObjectSlotsMetadata(NULL),
63    mRefCount(mContext->getASTContext()) {
64}
65
66// 1) Add zero initialization of local RS object types
67void RSBackend::AnnotateFunction(clang::FunctionDecl *FD) {
68  if (FD &&
69      FD->hasBody() &&
70      !SlangRS::IsFunctionInRSHeaderFile(FD, mSourceMgr)) {
71    mRefCount.Init();
72    mRefCount.Visit(FD->getBody());
73  }
74  return;
75}
76
77bool 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 = llvm::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        mDiagEngine.Report(
90          clang::FullSourceLoc(FD->getLocation(), mSourceMgr),
91          mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
92                                      "invalid function name prefix, "
93                                      "\"rs\" is reserved: '%0'"))
94          << FD->getName();
95    }
96  }
97
98  // Process any non-static function declarations
99  for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; I++) {
100    clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
101    if (FD && FD->isGlobal()) {
102      AnnotateFunction(FD);
103    }
104  }
105
106  return Backend::HandleTopLevelDecl(D);
107}
108
109namespace {
110
111static bool ValidateVarDecl(clang::VarDecl *VD) {
112  if (!VD) {
113    return true;
114  }
115
116  clang::ASTContext &C = VD->getASTContext();
117  const clang::Type *T = VD->getType().getTypePtr();
118  bool valid = true;
119
120  if (VD->getLinkage() == clang::ExternalLinkage) {
121    llvm::StringRef TypeName;
122    if (!RSExportType::NormalizeType(T, TypeName, &C.getDiagnostics(), VD)) {
123      valid = false;
124    }
125  }
126  valid &= RSExportType::ValidateVarDecl(VD);
127
128  return valid;
129}
130
131static bool ValidateASTContext(clang::ASTContext &C) {
132  bool valid = true;
133  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
134  for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
135          DE = TUDecl->decls_end();
136       DI != DE;
137       DI++) {
138    clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI);
139    if (VD && !ValidateVarDecl(VD)) {
140      valid = false;
141    }
142  }
143
144  return valid;
145}
146
147}  // namespace
148
149void RSBackend::HandleTranslationUnitPre(clang::ASTContext &C) {
150  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
151
152  if (!ValidateASTContext(C)) {
153    return;
154  }
155
156  int version = mContext->getVersion();
157  if (version == 0) {
158    // Not setting a version is an error
159    mDiagEngine.Report(mDiagEngine.getCustomDiagID(
160      clang::DiagnosticsEngine::Error,
161      "Missing pragma for version in source file"));
162  } else if (version > 1) {
163    mDiagEngine.Report(mDiagEngine.getCustomDiagID(
164      clang::DiagnosticsEngine::Error,
165      "Pragma for version in source file must be set to 1"));
166  }
167
168  // Create a static global destructor if necessary (to handle RS object
169  // runtime cleanup).
170  clang::FunctionDecl *FD = mRefCount.CreateStaticGlobalDtor();
171  if (FD) {
172    HandleTopLevelDecl(clang::DeclGroupRef(FD));
173  }
174
175  // Process any static function declarations
176  for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
177          E = TUDecl->decls_end(); I != E; I++) {
178    if ((I->getKind() >= clang::Decl::firstFunction) &&
179        (I->getKind() <= clang::Decl::lastFunction)) {
180      clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
181      if (FD && !FD->isGlobal()) {
182        AnnotateFunction(FD);
183      }
184    }
185  }
186
187  return;
188}
189
190///////////////////////////////////////////////////////////////////////////////
191void RSBackend::HandleTranslationUnitPost(llvm::Module *M) {
192  if (!mContext->processExport()) {
193    return;
194  }
195
196  // Dump export variable info
197  if (mContext->hasExportVar()) {
198    int slotCount = 0;
199    if (mExportVarMetadata == NULL)
200      mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
201
202    llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
203
204    // We emit slot information (#rs_object_slots) for any reference counted
205    // RS type or pointer (which can also be bound).
206
207    for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(),
208            E = mContext->export_vars_end();
209         I != E;
210         I++) {
211      const RSExportVar *EV = *I;
212      const RSExportType *ET = EV->getType();
213      bool countsAsRSObject = false;
214
215      // Variable name
216      ExportVarInfo.push_back(
217          llvm::MDString::get(mLLVMContext, EV->getName().c_str()));
218
219      // Type name
220      switch (ET->getClass()) {
221        case RSExportType::ExportClassPrimitive: {
222          const RSExportPrimitiveType *PT =
223              static_cast<const RSExportPrimitiveType*>(ET);
224          ExportVarInfo.push_back(
225              llvm::MDString::get(
226                mLLVMContext, llvm::utostr_32(PT->getType())));
227          if (PT->isRSObjectType()) {
228            countsAsRSObject = true;
229          }
230          break;
231        }
232        case RSExportType::ExportClassPointer: {
233          ExportVarInfo.push_back(
234              llvm::MDString::get(
235                mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET)
236                  ->getPointeeType()->getName()).c_str()));
237          break;
238        }
239        case RSExportType::ExportClassMatrix: {
240          ExportVarInfo.push_back(
241              llvm::MDString::get(
242                mLLVMContext, llvm::utostr_32(
243                  RSExportPrimitiveType::DataTypeRSMatrix2x2 +
244                  static_cast<const RSExportMatrixType*>(ET)->getDim() - 2)));
245          break;
246        }
247        case RSExportType::ExportClassVector:
248        case RSExportType::ExportClassConstantArray:
249        case RSExportType::ExportClassRecord: {
250          ExportVarInfo.push_back(
251              llvm::MDString::get(mLLVMContext,
252                EV->getType()->getName().c_str()));
253          break;
254        }
255      }
256
257      mExportVarMetadata->addOperand(
258          llvm::MDNode::get(mLLVMContext, ExportVarInfo));
259      ExportVarInfo.clear();
260
261      if (mRSObjectSlotsMetadata == NULL) {
262        mRSObjectSlotsMetadata =
263            M->getOrInsertNamedMetadata(RS_OBJECT_SLOTS_MN);
264      }
265
266      if (countsAsRSObject) {
267        mRSObjectSlotsMetadata->addOperand(llvm::MDNode::get(mLLVMContext,
268            llvm::MDString::get(mLLVMContext, llvm::utostr_32(slotCount))));
269      }
270
271      slotCount++;
272    }
273  }
274
275  // Dump export function info
276  if (mContext->hasExportFunc()) {
277    if (mExportFuncMetadata == NULL)
278      mExportFuncMetadata =
279          M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
280
281    llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo;
282
283    for (RSContext::const_export_func_iterator
284            I = mContext->export_funcs_begin(),
285            E = mContext->export_funcs_end();
286         I != E;
287         I++) {
288      const RSExportFunc *EF = *I;
289
290      // Function name
291      if (!EF->hasParam()) {
292        ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext,
293                                                     EF->getName().c_str()));
294      } else {
295        llvm::Function *F = M->getFunction(EF->getName());
296        llvm::Function *HelperFunction;
297        const std::string HelperFunctionName(".helper_" + EF->getName());
298
299        slangAssert(F && "Function marked as exported disappeared in Bitcode");
300
301        // Create helper function
302        {
303          llvm::StructType *HelperFunctionParameterTy = NULL;
304
305          if (!F->getArgumentList().empty()) {
306            std::vector<llvm::Type*> HelperFunctionParameterTys;
307            for (llvm::Function::arg_iterator AI = F->arg_begin(),
308                 AE = F->arg_end(); AI != AE; AI++)
309              HelperFunctionParameterTys.push_back(AI->getType());
310
311            HelperFunctionParameterTy =
312                llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
313          }
314
315          if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
316            fprintf(stderr, "Failed to export function %s: parameter type "
317                            "mismatch during creation of helper function.\n",
318                    EF->getName().c_str());
319
320            const RSExportRecordType *Expected = EF->getParamPacketType();
321            if (Expected) {
322              fprintf(stderr, "Expected:\n");
323              Expected->getLLVMType()->dump();
324            }
325            if (HelperFunctionParameterTy) {
326              fprintf(stderr, "Got:\n");
327              HelperFunctionParameterTy->dump();
328            }
329          }
330
331          std::vector<llvm::Type*> Params;
332          if (HelperFunctionParameterTy) {
333            llvm::PointerType *HelperFunctionParameterTyP =
334                llvm::PointerType::getUnqual(HelperFunctionParameterTy);
335            Params.push_back(HelperFunctionParameterTyP);
336          }
337
338          llvm::FunctionType * HelperFunctionType =
339              llvm::FunctionType::get(F->getReturnType(),
340                                      Params,
341                                      /* IsVarArgs = */false);
342
343          HelperFunction =
344              llvm::Function::Create(HelperFunctionType,
345                                     llvm::GlobalValue::ExternalLinkage,
346                                     HelperFunctionName,
347                                     M);
348
349          HelperFunction->addFnAttr(llvm::Attribute::NoInline);
350          HelperFunction->setCallingConv(F->getCallingConv());
351
352          // Create helper function body
353          {
354            llvm::Argument *HelperFunctionParameter =
355                &(*HelperFunction->arg_begin());
356            llvm::BasicBlock *BB =
357                llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
358            llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
359            llvm::SmallVector<llvm::Value*, 6> Params;
360            llvm::Value *Idx[2];
361
362            Idx[0] =
363                llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
364
365            // getelementptr and load instruction for all elements in
366            // parameter .p
367            for (size_t i = 0; i < EF->getNumParameters(); i++) {
368              // getelementptr
369              Idx[1] = llvm::ConstantInt::get(
370                llvm::Type::getInt32Ty(mLLVMContext), i);
371
372              llvm::Value *Ptr =
373                IB->CreateInBoundsGEP(HelperFunctionParameter, Idx);
374
375              // load
376              llvm::Value *V = IB->CreateLoad(Ptr);
377              Params.push_back(V);
378            }
379
380            // Call and pass the all elements as parameter to F
381            llvm::CallInst *CI = IB->CreateCall(F, Params);
382
383            CI->setCallingConv(F->getCallingConv());
384
385            if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
386              IB->CreateRetVoid();
387            else
388              IB->CreateRet(CI);
389
390            delete IB;
391          }
392        }
393
394        ExportFuncInfo.push_back(
395            llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
396      }
397
398      mExportFuncMetadata->addOperand(
399          llvm::MDNode::get(mLLVMContext, ExportFuncInfo));
400      ExportFuncInfo.clear();
401    }
402  }
403
404  // Dump export function info
405  if (mContext->hasExportForEach()) {
406    if (mExportForEachMetadata == NULL)
407      mExportForEachMetadata =
408          M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
409
410    llvm::SmallVector<llvm::Value*, 1> ExportForEachInfo;
411
412    for (RSContext::const_export_foreach_iterator
413            I = mContext->export_foreach_begin(),
414            E = mContext->export_foreach_end();
415         I != E;
416         I++) {
417      const RSExportForEach *EFE = *I;
418
419      ExportForEachInfo.push_back(
420          llvm::MDString::get(mLLVMContext,
421                              llvm::utostr_32(EFE->getMetadataEncoding())));
422
423      mExportForEachMetadata->addOperand(
424          llvm::MDNode::get(mLLVMContext, ExportForEachInfo));
425      ExportForEachInfo.clear();
426    }
427  }
428
429  // Dump export type info
430  if (mContext->hasExportType()) {
431    llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
432
433    for (RSContext::const_export_type_iterator
434            I = mContext->export_types_begin(),
435            E = mContext->export_types_end();
436         I != E;
437         I++) {
438      // First, dump type name list to export
439      const RSExportType *ET = I->getValue();
440
441      ExportTypeInfo.clear();
442      // Type name
443      ExportTypeInfo.push_back(
444          llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
445
446      if (ET->getClass() == RSExportType::ExportClassRecord) {
447        const RSExportRecordType *ERT =
448            static_cast<const RSExportRecordType*>(ET);
449
450        if (mExportTypeMetadata == NULL)
451          mExportTypeMetadata =
452              M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
453
454        mExportTypeMetadata->addOperand(
455            llvm::MDNode::get(mLLVMContext, ExportTypeInfo));
456
457        // Now, export struct field information to %[struct name]
458        std::string StructInfoMetadataName("%");
459        StructInfoMetadataName.append(ET->getName());
460        llvm::NamedMDNode *StructInfoMetadata =
461            M->getOrInsertNamedMetadata(StructInfoMetadataName);
462        llvm::SmallVector<llvm::Value*, 3> FieldInfo;
463
464        slangAssert(StructInfoMetadata->getNumOperands() == 0 &&
465                    "Metadata with same name was created before");
466        for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
467                FE = ERT->fields_end();
468             FI != FE;
469             FI++) {
470          const RSExportRecordType::Field *F = *FI;
471
472          // 1. field name
473          FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
474                                                  F->getName().c_str()));
475
476          // 2. field type name
477          FieldInfo.push_back(
478              llvm::MDString::get(mLLVMContext,
479                                  F->getType()->getName().c_str()));
480
481          // 3. field kind
482          switch (F->getType()->getClass()) {
483            case RSExportType::ExportClassPrimitive:
484            case RSExportType::ExportClassVector: {
485              const RSExportPrimitiveType *EPT =
486                  static_cast<const RSExportPrimitiveType*>(F->getType());
487              FieldInfo.push_back(
488                  llvm::MDString::get(mLLVMContext,
489                                      llvm::itostr(EPT->getKind())));
490              break;
491            }
492
493            default: {
494              FieldInfo.push_back(
495                  llvm::MDString::get(mLLVMContext,
496                                      llvm::itostr(
497                                        RSExportPrimitiveType::DataKindUser)));
498              break;
499            }
500          }
501
502          StructInfoMetadata->addOperand(
503              llvm::MDNode::get(mLLVMContext, FieldInfo));
504          FieldInfo.clear();
505        }
506      }   // ET->getClass() == RSExportType::ExportClassRecord
507    }
508  }
509
510  return;
511}
512
513RSBackend::~RSBackend() {
514  return;
515}
516
517}  // namespace slang
518