• 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/Support/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(mContext->getASTContext(), mContext->getTargetAPI(),
72                 IsFilterscript) {
73 }
74 
75 // 1) Add zero initialization of local RS object types
AnnotateFunction(clang::FunctionDecl * FD)76 void RSBackend::AnnotateFunction(clang::FunctionDecl *FD) {
77   if (FD &&
78       FD->hasBody() &&
79       !SlangRS::IsLocInRSHeaderFile(FD->getLocation(), mSourceMgr)) {
80     mRefCount.Init();
81     mRefCount.Visit(FD->getBody());
82   }
83   return;
84 }
85 
HandleTopLevelDecl(clang::DeclGroupRef D)86 bool RSBackend::HandleTopLevelDecl(clang::DeclGroupRef D) {
87   // Disallow user-defined functions with prefix "rs"
88   if (!mAllowRSPrefix) {
89     // Iterate all function declarations in the program.
90     for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end();
91          I != E; I++) {
92       clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
93       if (FD == NULL)
94         continue;
95       if (!FD->getName().startswith("rs"))  // Check prefix
96         continue;
97       if (!SlangRS::IsLocInRSHeaderFile(FD->getLocation(), mSourceMgr))
98         mDiagEngine.Report(
99           clang::FullSourceLoc(FD->getLocation(), mSourceMgr),
100           mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
101                                       "invalid function name prefix, "
102                                       "\"rs\" is reserved: '%0'"))
103           << FD->getName();
104     }
105   }
106 
107   // Process any non-static function declarations
108   for (clang::DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; I++) {
109     clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
110     if (FD && FD->isGlobal()) {
111       // Check that we don't have any array parameters being misintrepeted as
112       // kernel pointers due to the C type system's array to pointer decay.
113       size_t numParams = FD->getNumParams();
114       for (size_t i = 0; i < numParams; i++) {
115         const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
116         clang::QualType QT = PVD->getOriginalType();
117         if (QT->isArrayType()) {
118           mDiagEngine.Report(
119             clang::FullSourceLoc(PVD->getTypeSpecStartLoc(), mSourceMgr),
120             mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
121                                         "exported function parameters may "
122                                         "not have array type: %0")) << QT;
123         }
124       }
125       AnnotateFunction(FD);
126     }
127   }
128 
129   return Backend::HandleTopLevelDecl(D);
130 }
131 
132 
HandleTranslationUnitPre(clang::ASTContext & C)133 void RSBackend::HandleTranslationUnitPre(clang::ASTContext &C) {
134   clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
135 
136   // If we have an invalid RS/FS AST, don't check further.
137   if (!mASTChecker.Validate()) {
138     return;
139   }
140 
141   if (mIsFilterscript) {
142     mContext->addPragma("rs_fp_relaxed", "");
143   }
144 
145   int version = mContext->getVersion();
146   if (version == 0) {
147     // Not setting a version is an error
148     mDiagEngine.Report(
149         mSourceMgr.getLocForEndOfFile(mSourceMgr.getMainFileID()),
150         mDiagEngine.getCustomDiagID(
151             clang::DiagnosticsEngine::Error,
152             "missing pragma for version in source file"));
153   } else {
154     slangAssert(version == 1);
155   }
156 
157   if (mContext->getReflectJavaPackageName().empty()) {
158     mDiagEngine.Report(
159         mSourceMgr.getLocForEndOfFile(mSourceMgr.getMainFileID()),
160         mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
161                                     "missing \"#pragma rs "
162                                     "java_package_name(com.foo.bar)\" "
163                                     "in source file"));
164     return;
165   }
166 
167   // Create a static global destructor if necessary (to handle RS object
168   // runtime cleanup).
169   clang::FunctionDecl *FD = mRefCount.CreateStaticGlobalDtor();
170   if (FD) {
171     HandleTopLevelDecl(clang::DeclGroupRef(FD));
172   }
173 
174   // Process any static function declarations
175   for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
176           E = TUDecl->decls_end(); I != E; I++) {
177     if ((I->getKind() >= clang::Decl::firstFunction) &&
178         (I->getKind() <= clang::Decl::lastFunction)) {
179       clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I);
180       if (FD && !FD->isGlobal()) {
181         AnnotateFunction(FD);
182       }
183     }
184   }
185 
186   return;
187 }
188 
189 ///////////////////////////////////////////////////////////////////////////////
dumpExportVarInfo(llvm::Module * M)190 void RSBackend::dumpExportVarInfo(llvm::Module *M) {
191   int slotCount = 0;
192   if (mExportVarMetadata == NULL)
193     mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
194 
195   llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
196 
197   // We emit slot information (#rs_object_slots) for any reference counted
198   // RS type or pointer (which can also be bound).
199 
200   for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(),
201           E = mContext->export_vars_end();
202        I != E;
203        I++) {
204     const RSExportVar *EV = *I;
205     const RSExportType *ET = EV->getType();
206     bool countsAsRSObject = false;
207 
208     // Variable name
209     ExportVarInfo.push_back(
210         llvm::MDString::get(mLLVMContext, EV->getName().c_str()));
211 
212     // Type name
213     switch (ET->getClass()) {
214       case RSExportType::ExportClassPrimitive: {
215         const RSExportPrimitiveType *PT =
216             static_cast<const RSExportPrimitiveType*>(ET);
217         ExportVarInfo.push_back(
218             llvm::MDString::get(
219               mLLVMContext, llvm::utostr_32(PT->getType())));
220         if (PT->isRSObjectType()) {
221           countsAsRSObject = true;
222         }
223         break;
224       }
225       case RSExportType::ExportClassPointer: {
226         ExportVarInfo.push_back(
227             llvm::MDString::get(
228               mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET)
229                 ->getPointeeType()->getName()).c_str()));
230         break;
231       }
232       case RSExportType::ExportClassMatrix: {
233         ExportVarInfo.push_back(
234             llvm::MDString::get(
235               mLLVMContext, llvm::utostr_32(
236                 RSExportPrimitiveType::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 
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             HelperFunctionParameterTys.push_back(AI->getType());
302 
303           HelperFunctionParameterTy =
304               llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
305         }
306 
307         if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
308           fprintf(stderr, "Failed to export function %s: parameter type "
309                           "mismatch during creation of helper function.\n",
310                   EF->getName().c_str());
311 
312           const RSExportRecordType *Expected = EF->getParamPacketType();
313           if (Expected) {
314             fprintf(stderr, "Expected:\n");
315             Expected->getLLVMType()->dump();
316           }
317           if (HelperFunctionParameterTy) {
318             fprintf(stderr, "Got:\n");
319             HelperFunctionParameterTy->dump();
320           }
321         }
322 
323         std::vector<llvm::Type*> Params;
324         if (HelperFunctionParameterTy) {
325           llvm::PointerType *HelperFunctionParameterTyP =
326               llvm::PointerType::getUnqual(HelperFunctionParameterTy);
327           Params.push_back(HelperFunctionParameterTyP);
328         }
329 
330         llvm::FunctionType * HelperFunctionType =
331             llvm::FunctionType::get(F->getReturnType(),
332                                     Params,
333                                     /* IsVarArgs = */false);
334 
335         HelperFunction =
336             llvm::Function::Create(HelperFunctionType,
337                                    llvm::GlobalValue::ExternalLinkage,
338                                    HelperFunctionName,
339                                    M);
340 
341         HelperFunction->addFnAttr(llvm::Attribute::NoInline);
342         HelperFunction->setCallingConv(F->getCallingConv());
343 
344         // Create helper function body
345         {
346           llvm::Argument *HelperFunctionParameter =
347               &(*HelperFunction->arg_begin());
348           llvm::BasicBlock *BB =
349               llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
350           llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
351           llvm::SmallVector<llvm::Value*, 6> Params;
352           llvm::Value *Idx[2];
353 
354           Idx[0] =
355               llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
356 
357           // getelementptr and load instruction for all elements in
358           // parameter .p
359           for (size_t i = 0; i < EF->getNumParameters(); i++) {
360             // getelementptr
361             Idx[1] = llvm::ConstantInt::get(
362               llvm::Type::getInt32Ty(mLLVMContext), i);
363 
364             llvm::Value *Ptr =
365               IB->CreateInBoundsGEP(HelperFunctionParameter, Idx);
366 
367             // load
368             llvm::Value *V = IB->CreateLoad(Ptr);
369             Params.push_back(V);
370           }
371 
372           // Call and pass the all elements as parameter to F
373           llvm::CallInst *CI = IB->CreateCall(F, Params);
374 
375           CI->setCallingConv(F->getCallingConv());
376 
377           if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
378             IB->CreateRetVoid();
379           else
380             IB->CreateRet(CI);
381 
382           delete IB;
383         }
384       }
385 
386       ExportFuncInfo.push_back(
387           llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
388     }
389 
390     mExportFuncMetadata->addOperand(
391         llvm::MDNode::get(mLLVMContext, ExportFuncInfo));
392     ExportFuncInfo.clear();
393   }
394 }
395 
dumpExportForEachInfo(llvm::Module * M)396 void RSBackend::dumpExportForEachInfo(llvm::Module *M) {
397   if (mExportForEachNameMetadata == NULL) {
398     mExportForEachNameMetadata =
399         M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_NAME_MN);
400   }
401   if (mExportForEachSignatureMetadata == NULL) {
402     mExportForEachSignatureMetadata =
403         M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
404   }
405 
406   llvm::SmallVector<llvm::Value*, 1> ExportForEachName;
407   llvm::SmallVector<llvm::Value*, 1> ExportForEachInfo;
408 
409   for (RSContext::const_export_foreach_iterator
410           I = mContext->export_foreach_begin(),
411           E = mContext->export_foreach_end();
412        I != E;
413        I++) {
414     const RSExportForEach *EFE = *I;
415 
416     ExportForEachName.push_back(
417         llvm::MDString::get(mLLVMContext, EFE->getName().c_str()));
418 
419     mExportForEachNameMetadata->addOperand(
420         llvm::MDNode::get(mLLVMContext, ExportForEachName));
421     ExportForEachName.clear();
422 
423     ExportForEachInfo.push_back(
424         llvm::MDString::get(mLLVMContext,
425                             llvm::utostr_32(EFE->getSignatureMetadata())));
426 
427     mExportForEachSignatureMetadata->addOperand(
428         llvm::MDNode::get(mLLVMContext, ExportForEachInfo));
429     ExportForEachInfo.clear();
430   }
431 }
432 
dumpExportTypeInfo(llvm::Module * M)433 void RSBackend::dumpExportTypeInfo(llvm::Module *M) {
434   llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
435 
436   for (RSContext::const_export_type_iterator
437           I = mContext->export_types_begin(),
438           E = mContext->export_types_end();
439        I != E;
440        I++) {
441     // First, dump type name list to export
442     const RSExportType *ET = I->getValue();
443 
444     ExportTypeInfo.clear();
445     // Type name
446     ExportTypeInfo.push_back(
447         llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
448 
449     if (ET->getClass() == RSExportType::ExportClassRecord) {
450       const RSExportRecordType *ERT =
451           static_cast<const RSExportRecordType*>(ET);
452 
453       if (mExportTypeMetadata == NULL)
454         mExportTypeMetadata =
455             M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
456 
457       mExportTypeMetadata->addOperand(
458           llvm::MDNode::get(mLLVMContext, ExportTypeInfo));
459 
460       // Now, export struct field information to %[struct name]
461       std::string StructInfoMetadataName("%");
462       StructInfoMetadataName.append(ET->getName());
463       llvm::NamedMDNode *StructInfoMetadata =
464           M->getOrInsertNamedMetadata(StructInfoMetadataName);
465       llvm::SmallVector<llvm::Value*, 3> FieldInfo;
466 
467       slangAssert(StructInfoMetadata->getNumOperands() == 0 &&
468                   "Metadata with same name was created before");
469       for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
470               FE = ERT->fields_end();
471            FI != FE;
472            FI++) {
473         const RSExportRecordType::Field *F = *FI;
474 
475         // 1. field name
476         FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
477                                                 F->getName().c_str()));
478 
479         // 2. field type name
480         FieldInfo.push_back(
481             llvm::MDString::get(mLLVMContext,
482                                 F->getType()->getName().c_str()));
483 
484         StructInfoMetadata->addOperand(
485             llvm::MDNode::get(mLLVMContext, FieldInfo));
486         FieldInfo.clear();
487       }
488     }   // ET->getClass() == RSExportType::ExportClassRecord
489   }
490 }
491 
HandleTranslationUnitPost(llvm::Module * M)492 void RSBackend::HandleTranslationUnitPost(llvm::Module *M) {
493   if (!mContext->processExport()) {
494     return;
495   }
496 
497   if (mContext->hasExportVar())
498     dumpExportVarInfo(M);
499 
500   if (mContext->hasExportFunc())
501     dumpExportFunctionInfo(M);
502 
503   if (mContext->hasExportForEach())
504     dumpExportForEachInfo(M);
505 
506   if (mContext->hasExportType())
507     dumpExportTypeInfo(M);
508 
509   return;
510 }
511 
~RSBackend()512 RSBackend::~RSBackend() {
513   return;
514 }
515 
516 }  // namespace slang
517