slang_rs_export_func.cpp revision 641558f02fe6ce0ee3ae5076eb366c25e2ad5903
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_export_func.h" 18 19#include "llvm/DerivedTypes.h" 20#include "llvm/Target/TargetData.h" 21 22#include "clang/AST/ASTContext.h" 23#include "clang/AST/Decl.h" 24 25#include "slang_rs_context.h" 26 27using namespace slang; 28 29RSExportFunc *RSExportFunc::Create(RSContext *Context, 30 const clang::FunctionDecl *FD) { 31 llvm::StringRef Name = FD->getName(); 32 RSExportFunc *F; 33 34 assert(!Name.empty() && "Function must have a name"); 35 36 F = new RSExportFunc(Context, Name); 37 38 // Initialize mParamPacketType 39 if (FD->getNumParams() <= 0) { 40 F->mParamPacketType = NULL; 41 } else { 42 clang::ASTContext *Ctx = Context->getASTContext(); 43 44 std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_func_param:"); 45 Id.append(F->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX); 46 47 clang::RecordDecl *RD = 48 clang::RecordDecl::Create(*Ctx, clang::TTK_Struct, 49 Ctx->getTranslationUnitDecl(), 50 clang::SourceLocation(), 51 &Ctx->Idents.get(Id)); 52 53 for (unsigned i = 0; i < FD->getNumParams(); i++) { 54 const clang::ParmVarDecl *PVD = FD->getParamDecl(i); 55 llvm::StringRef ParamName = PVD->getName(); 56 57 if (PVD->hasDefaultArg()) 58 fprintf(stderr, "Note: parameter '%s' in function '%s' has default " 59 "value which is not supported\n", 60 ParamName.str().c_str(), 61 F->getName().c_str()); 62 63 clang::FieldDecl *FD = 64 clang::FieldDecl::Create(*Ctx, 65 RD, 66 clang::SourceLocation(), 67 PVD->getIdentifier(), 68 PVD->getOriginalType(), 69 NULL, 70 /* BitWidth = */NULL, 71 /* Mutable = */false); 72 RD->addDecl(FD); 73 } 74 75 RD->completeDefinition(); 76 77 clang::QualType T = Ctx->getTagDeclType(RD); 78 assert(!T.isNull()); 79 80 RSExportType *ET = 81 RSExportType::Create(Context, T.getTypePtr()); 82 83 if (ET == NULL) { 84 fprintf(stderr, "Failed to export the function %s. There's at least one " 85 "parameter whose type is not supported by the " 86 "reflection", F->getName().c_str()); 87 delete F; 88 return NULL; 89 } 90 91 assert((ET->getClass() == RSExportType::ExportClassRecord) && 92 "Parameter packet must be a record"); 93 94 F->mParamPacketType = static_cast<RSExportRecordType *>(ET); 95 } 96 97 return F; 98} 99 100bool 101RSExportFunc::checkParameterPacketType(const llvm::StructType *ParamTy) const { 102 if (ParamTy == NULL) 103 return !hasParam(); 104 else if (!hasParam()) 105 return false; 106 107 assert(mParamPacketType != NULL); 108 109 const RSExportRecordType *ERT = mParamPacketType; 110 // must have same number of elements 111 if (ERT->getFields().size() != ParamTy->getNumElements()) 112 return false; 113 114 const llvm::StructLayout *ParamTySL = 115 getRSContext()->getTargetData()->getStructLayout(ParamTy); 116 117 unsigned Index = 0; 118 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(), 119 FE = ERT->fields_end(); FI != FE; FI++, Index++) { 120 const RSExportRecordType::Field *F = *FI; 121 122 const llvm::Type *T1 = F->getType()->getLLVMType(); 123 const llvm::Type *T2 = ParamTy->getTypeAtIndex(Index); 124 125 // Fast check 126 if (T1 == T2) 127 continue; 128 129 // Check offset 130 size_t T1Offset = F->getOffsetInParent(); 131 size_t T2Offset = ParamTySL->getElementOffset(Index); 132 133 if (T1Offset != T2Offset) 134 return false; 135 136 // Check size 137 size_t T1Size = RSExportType::GetTypeAllocSize(F->getType()); 138 size_t T2Size = getRSContext()->getTargetData()->getTypeAllocSize(T2); 139 140 if (T1Size != T2Size) 141 return false; 142 } 143 144 return true; 145} 146