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