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