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