slang_rs_export_foreach.cpp revision 593a894650e81be54173106ec266f0311cebebd3
1/* 2 * Copyright 2011, 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_foreach.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#include "slang_rs_export_type.h" 30 31namespace slang { 32 33RSExportForEach *RSExportForEach::Create(RSContext *Context, 34 const clang::FunctionDecl *FD) { 35 llvm::StringRef Name = FD->getName(); 36 RSExportForEach *F; 37 38 slangAssert(!Name.empty() && "Function must have a name"); 39 40 F = new RSExportForEach(Context, Name, FD); 41 42 F->numParams = FD->getNumParams(); 43 44 if (F->numParams == 0) { 45 slangAssert(false && "Should have at least one parameter for root"); 46 } 47 48 clang::ASTContext &Ctx = Context->getASTContext(); 49 50 std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_foreach_param:"); 51 Id.append(F->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX); 52 53 clang::RecordDecl *RD = 54 clang::RecordDecl::Create(Ctx, clang::TTK_Struct, 55 Ctx.getTranslationUnitDecl(), 56 clang::SourceLocation(), 57 clang::SourceLocation(), 58 &Ctx.Idents.get(Id)); 59 60 // Extract the usrData parameter (if we have one) 61 if (F->numParams >= 3) { 62 const clang::ParmVarDecl *PVD = FD->getParamDecl(2); 63 clang::QualType QT = PVD->getType().getCanonicalType(); 64 slangAssert(QT->isPointerType() && 65 QT->getPointeeType().isConstQualified()); 66 67 const clang::ASTContext &C = Context->getASTContext(); 68 if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() == 69 C.VoidTy) { 70 // In the case of using const void*, we can't reflect an appopriate 71 // Java type, so we fall back to just reflecting the ain/aout parameters 72 F->numParams = 2; 73 } else { 74 llvm::StringRef ParamName = PVD->getName(); 75 clang::FieldDecl *FD = 76 clang::FieldDecl::Create(Ctx, 77 RD, 78 clang::SourceLocation(), 79 clang::SourceLocation(), 80 PVD->getIdentifier(), 81 QT->getPointeeType(), 82 NULL, 83 /* BitWidth = */NULL, 84 /* Mutable = */false); 85 RD->addDecl(FD); 86 } 87 } 88 RD->completeDefinition(); 89 90 if (F->numParams >= 3) { 91 // Create an export type iff we have a valid usrData type 92 clang::QualType T = Ctx.getTagDeclType(RD); 93 slangAssert(!T.isNull()); 94 95 RSExportType *ET = 96 RSExportType::Create(Context, T.getTypePtr()); 97 98 if (ET == NULL) { 99 fprintf(stderr, "Failed to export the function %s. There's at least one " 100 "parameter whose type is not supported by the " 101 "reflection\n", F->getName().c_str()); 102 delete F; 103 return NULL; 104 } 105 106 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) && 107 "Parameter packet must be a record"); 108 109 F->mParamPacketType = static_cast<RSExportRecordType *>(ET); 110 } 111 112 return F; 113} 114 115bool RSExportForEach::isRSForEachFunc(const clang::FunctionDecl *FD) { 116 // We currently support only compute root() being exported via forEach 117 if (!isRootRSFunc(FD)) { 118 return false; 119 } 120 121 const clang::ASTContext &C = FD->getASTContext(); 122 if (FD->getNumParams() == 0 && 123 FD->getResultType().getCanonicalType() == C.IntTy) { 124 // Graphics compute function 125 return false; 126 } 127 return true; 128} 129 130bool RSExportForEach::validateSpecialFuncDecl(clang::Diagnostic *Diags, 131 const clang::FunctionDecl *FD) { 132 if (!FD) { 133 return false; 134 } 135 136 bool valid = true; 137 const clang::ASTContext &C = FD->getASTContext(); 138 139 if (isRootRSFunc(FD)) { 140 unsigned int numParams = FD->getNumParams(); 141 if (numParams == 0) { 142 // Graphics root function, so verify that it returns an int 143 if (FD->getResultType().getCanonicalType() != C.IntTy) { 144 Diags->Report( 145 clang::FullSourceLoc(FD->getLocation(), Diags->getSourceManager()), 146 Diags->getCustomDiagID(clang::Diagnostic::Error, 147 "root(void) is required to return " 148 "an int for graphics usage")); 149 valid = false; 150 } 151 } else { 152 // Compute root functions are required to return a void type for now 153 if (FD->getResultType().getCanonicalType() != C.VoidTy) { 154 Diags->Report( 155 clang::FullSourceLoc(FD->getLocation(), Diags->getSourceManager()), 156 Diags->getCustomDiagID(clang::Diagnostic::Error, 157 "compute root() is required to return a " 158 "void type")); 159 valid = false; 160 } 161 162 // Validate remaining parameter types 163 const clang::ParmVarDecl *tooManyParams = NULL; 164 for (unsigned int i = 0; i < numParams; i++) { 165 const clang::ParmVarDecl *PVD = FD->getParamDecl(i); 166 clang::QualType QT = PVD->getType().getCanonicalType(); 167 switch (i) { 168 case 0: // const T1 *ain 169 case 2: { // const T3 *usrData 170 if (!QT->isPointerType() || 171 !QT->getPointeeType().isConstQualified()) { 172 Diags->Report( 173 clang::FullSourceLoc(PVD->getLocation(), 174 Diags->getSourceManager()), 175 Diags->getCustomDiagID(clang::Diagnostic::Error, 176 "compute root() parameter must be a " 177 "const pointer type")); 178 valid = false; 179 } 180 break; 181 } 182 case 1: { // T2 *aout 183 if (!QT->isPointerType()) { 184 Diags->Report( 185 clang::FullSourceLoc(PVD->getLocation(), 186 Diags->getSourceManager()), 187 Diags->getCustomDiagID(clang::Diagnostic::Error, 188 "compute root() parameter must be a " 189 "pointer type")); 190 valid = false; 191 } 192 break; 193 } 194 case 3: // unsigned int x 195 case 4: // unsigned int y 196 case 5: // unsigned int z 197 case 6: { // unsigned int ar 198 if (QT.getUnqualifiedType() != C.UnsignedIntTy) { 199 Diags->Report( 200 clang::FullSourceLoc(PVD->getLocation(), 201 Diags->getSourceManager()), 202 Diags->getCustomDiagID(clang::Diagnostic::Error, 203 "compute root() parameter must be a " 204 "uint32_t type")); 205 valid = false; 206 } 207 break; 208 } 209 default: { 210 if (!tooManyParams) { 211 tooManyParams = PVD; 212 } 213 break; 214 } 215 } 216 } 217 if (tooManyParams) { 218 Diags->Report( 219 clang::FullSourceLoc(tooManyParams->getLocation(), 220 Diags->getSourceManager()), 221 Diags->getCustomDiagID(clang::Diagnostic::Error, 222 "too many compute root() parameters " 223 "specified")); 224 valid = false; 225 } 226 } 227 } else if (isInitRSFunc(FD)) { 228 if (FD->getNumParams() != 0) { 229 Diags->Report( 230 clang::FullSourceLoc(FD->getLocation(), Diags->getSourceManager()), 231 Diags->getCustomDiagID(clang::Diagnostic::Error, 232 "init(void) is required to have no " 233 "parameters")); 234 valid = false; 235 } 236 237 if (FD->getResultType().getCanonicalType() != C.VoidTy) { 238 Diags->Report( 239 clang::FullSourceLoc(FD->getLocation(), Diags->getSourceManager()), 240 Diags->getCustomDiagID(clang::Diagnostic::Error, 241 "init(void) is required to have a void " 242 "return type")); 243 valid = false; 244 } 245 } else { 246 slangAssert(false && "must be called on init or root function!"); 247 } 248 249 return valid; 250} 251 252} // namespace slang 253