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