slang_rs_export_foreach.cpp revision 7b51b55e4467605a599e868a0dde7cb95c5ab76e
1593a894650e81be54173106ec266f0311cebebd3Stephen Hines/*
29999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines * Copyright 2011-2012, The Android Open Source Project
3593a894650e81be54173106ec266f0311cebebd3Stephen Hines *
4593a894650e81be54173106ec266f0311cebebd3Stephen Hines * Licensed under the Apache License, Version 2.0 (the "License");
5593a894650e81be54173106ec266f0311cebebd3Stephen Hines * you may not use this file except in compliance with the License.
6593a894650e81be54173106ec266f0311cebebd3Stephen Hines * You may obtain a copy of the License at
7593a894650e81be54173106ec266f0311cebebd3Stephen Hines *
8593a894650e81be54173106ec266f0311cebebd3Stephen Hines *     http://www.apache.org/licenses/LICENSE-2.0
9593a894650e81be54173106ec266f0311cebebd3Stephen Hines *
10593a894650e81be54173106ec266f0311cebebd3Stephen Hines * Unless required by applicable law or agreed to in writing, software
11593a894650e81be54173106ec266f0311cebebd3Stephen Hines * distributed under the License is distributed on an "AS IS" BASIS,
12593a894650e81be54173106ec266f0311cebebd3Stephen Hines * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13593a894650e81be54173106ec266f0311cebebd3Stephen Hines * See the License for the specific language governing permissions and
14593a894650e81be54173106ec266f0311cebebd3Stephen Hines * limitations under the License.
15593a894650e81be54173106ec266f0311cebebd3Stephen Hines */
16593a894650e81be54173106ec266f0311cebebd3Stephen Hines
17593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "slang_rs_export_foreach.h"
18593a894650e81be54173106ec266f0311cebebd3Stephen Hines
19593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include <string>
20593a894650e81be54173106ec266f0311cebebd3Stephen Hines
21593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "clang/AST/ASTContext.h"
22593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "clang/AST/Decl.h"
23b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines#include "clang/AST/TypeLoc.h"
24593a894650e81be54173106ec266f0311cebebd3Stephen Hines
25593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "llvm/DerivedTypes.h"
26593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "llvm/Target/TargetData.h"
27593a894650e81be54173106ec266f0311cebebd3Stephen Hines
28593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "slang_assert.h"
29593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "slang_rs_context.h"
30593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "slang_rs_export_type.h"
3112580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines#include "slang_version.h"
32593a894650e81be54173106ec266f0311cebebd3Stephen Hines
33593a894650e81be54173106ec266f0311cebebd3Stephen Hinesnamespace slang {
34593a894650e81be54173106ec266f0311cebebd3Stephen Hines
35b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hinesnamespace {
36b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
379207a2e495c8363606861e4f034504ec5c153dabLogan Chienstatic void ReportNameError(clang::DiagnosticsEngine *DiagEngine,
389207a2e495c8363606861e4f034504ec5c153dabLogan Chien                            clang::ParmVarDecl const *PVD) {
399207a2e495c8363606861e4f034504ec5c153dabLogan Chien  slangAssert(DiagEngine && PVD);
409207a2e495c8363606861e4f034504ec5c153dabLogan Chien  const clang::SourceManager &SM = DiagEngine->getSourceManager();
419207a2e495c8363606861e4f034504ec5c153dabLogan Chien
429207a2e495c8363606861e4f034504ec5c153dabLogan Chien  DiagEngine->Report(
439207a2e495c8363606861e4f034504ec5c153dabLogan Chien    clang::FullSourceLoc(PVD->getLocation(), SM),
449207a2e495c8363606861e4f034504ec5c153dabLogan Chien    DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
459207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                "Duplicate parameter entry "
469207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                "(by position/name): '%0'"))
479207a2e495c8363606861e4f034504ec5c153dabLogan Chien    << PVD->getName();
48b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  return;
49b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines}
50b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
51b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines}  // namespace
52b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
53b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines// This function takes care of additional validation and construction of
54b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines// parameters related to forEach_* reflection.
55b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hinesbool RSExportForEach::validateAndConstructParams(
56b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    RSContext *Context, const clang::FunctionDecl *FD) {
57b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  slangAssert(Context && FD);
58b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  bool valid = true;
59b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  clang::ASTContext &C = Context->getASTContext();
609207a2e495c8363606861e4f034504ec5c153dabLogan Chien  clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
61b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
62b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  numParams = FD->getNumParams();
63b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  slangAssert(numParams > 0);
64b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
657b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (Context->getTargetAPI() < SLANG_JB_TARGET_API) {
667b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (!isRootRSFunc(FD)) {
677b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      DiagEngine->Report(
687b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        clang::FullSourceLoc(FD->getLocation(), DiagEngine->getSourceManager()),
697b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
707b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                    "Non-root compute kernel %0() is "
717b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                    "not supported in SDK levels %1-%2"))
727b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        << FD->getName()
737b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        << SLANG_MINIMUM_TARGET_API
747b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        << (SLANG_JB_TARGET_API - 1);
757b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return false;
767b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
777b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  }
787b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
797b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  // Compute kernel functions are required to return a void type for now
80b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FD->getResultType().getCanonicalType() != C.VoidTy) {
819207a2e495c8363606861e4f034504ec5c153dabLogan Chien    DiagEngine->Report(
829207a2e495c8363606861e4f034504ec5c153dabLogan Chien      clang::FullSourceLoc(FD->getLocation(), DiagEngine->getSourceManager()),
839207a2e495c8363606861e4f034504ec5c153dabLogan Chien      DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
847b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                  "Compute kernel %0() is required to return a "
857b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                  "void type")) << FD->getName();
86b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    valid = false;
87b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  }
88b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
89b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  // Validate remaining parameter types
90b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  // TODO(all): Add support for LOD/face when we have them
91b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
924ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  size_t i = 0;
934ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
944ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  clang::QualType QT = PVD->getType().getCanonicalType();
954ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
964ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  // Check for const T1 *in
974ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  if (QT->isPointerType() && QT->getPointeeType().isConstQualified()) {
984ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    mIn = PVD;
994ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    i++;  // advance parameter pointer
1004ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  }
1014ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
1024ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  // Check for T2 *out
1034ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  if (i < numParams) {
1044ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    PVD = FD->getParamDecl(i);
1054ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    QT = PVD->getType().getCanonicalType();
1064ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    if (QT->isPointerType() && !QT->getPointeeType().isConstQualified()) {
1074ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines      mOut = PVD;
1084ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines      i++;  // advance parameter pointer
1094ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    }
1104ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  }
1114ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
1124ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  if (!mIn && !mOut) {
1139207a2e495c8363606861e4f034504ec5c153dabLogan Chien    DiagEngine->Report(
1149207a2e495c8363606861e4f034504ec5c153dabLogan Chien      clang::FullSourceLoc(FD->getLocation(),
1159207a2e495c8363606861e4f034504ec5c153dabLogan Chien                           DiagEngine->getSourceManager()),
1169207a2e495c8363606861e4f034504ec5c153dabLogan Chien      DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1177b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                  "Compute kernel %0() must have at least one "
1187b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                  "parameter for in or out")) << FD->getName();
1194ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    valid = false;
1204ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  }
1214ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
1224ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  // Check for T3 *usrData
1234ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  if (i < numParams) {
1244ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    PVD = FD->getParamDecl(i);
1254ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    QT = PVD->getType().getCanonicalType();
1264ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    if (QT->isPointerType() && QT->getPointeeType().isConstQualified()) {
1274ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines      mUsrData = PVD;
1284ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines      i++;  // advance parameter pointer
1294ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    }
1304ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  }
1314ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
1324ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  while (i < numParams) {
1334ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    PVD = FD->getParamDecl(i);
1344ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    QT = PVD->getType().getCanonicalType();
1354ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
1364ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    if (QT.getUnqualifiedType() != C.UnsignedIntTy) {
1379207a2e495c8363606861e4f034504ec5c153dabLogan Chien      DiagEngine->Report(
1389207a2e495c8363606861e4f034504ec5c153dabLogan Chien        clang::FullSourceLoc(PVD->getLocation(),
1399207a2e495c8363606861e4f034504ec5c153dabLogan Chien                             DiagEngine->getSourceManager()),
1409207a2e495c8363606861e4f034504ec5c153dabLogan Chien        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1417b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                    "Unexpected kernel %0() parameter '%1' "
1427b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                    "of type '%2'"))
1437b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        << FD->getName() << PVD->getName() << PVD->getType().getAsString();
1444ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines      valid = false;
1454ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    } else {
1464ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines      llvm::StringRef ParamName = PVD->getName();
147b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      if (ParamName.equals("x")) {
148b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        if (mX) {
1499207a2e495c8363606861e4f034504ec5c153dabLogan Chien          ReportNameError(DiagEngine, PVD);
150b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          valid = false;
1514ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines        } else if (mY) {
1524ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines          // Can't go back to X after skipping Y
1539207a2e495c8363606861e4f034504ec5c153dabLogan Chien          ReportNameError(DiagEngine, PVD);
1544ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines          valid = false;
155b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        } else {
156b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          mX = PVD;
157b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        }
158b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      } else if (ParamName.equals("y")) {
159b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        if (mY) {
1609207a2e495c8363606861e4f034504ec5c153dabLogan Chien          ReportNameError(DiagEngine, PVD);
161b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          valid = false;
162b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        } else {
163b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          mY = PVD;
164b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        }
165b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      } else {
1664ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines        if (!mX && !mY) {
167b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          mX = PVD;
168b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        } else if (!mY) {
169b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          mY = PVD;
170b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        } else {
1719207a2e495c8363606861e4f034504ec5c153dabLogan Chien          DiagEngine->Report(
1729207a2e495c8363606861e4f034504ec5c153dabLogan Chien            clang::FullSourceLoc(PVD->getLocation(),
1739207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                 DiagEngine->getSourceManager()),
1749207a2e495c8363606861e4f034504ec5c153dabLogan Chien            DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1757b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                        "Unexpected kernel %0() parameter '%1' "
1767b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                        "of type '%2'"))
1777b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines            << FD->getName() << PVD->getName() << PVD->getType().getAsString();
178b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          valid = false;
179b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        }
180b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      }
181b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    }
1824ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
1834ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    i++;
184b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  }
185b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
1867b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  mSignatureMetadata = 0;
1874ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  if (valid) {
1884ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    // Set up the bitwise metadata encoding for runtime argument passing.
1897b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    mSignatureMetadata |= (mIn ?       0x01 : 0);
1907b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    mSignatureMetadata |= (mOut ?      0x02 : 0);
1917b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    mSignatureMetadata |= (mUsrData ?  0x04 : 0);
1927b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    mSignatureMetadata |= (mX ?        0x08 : 0);
1937b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    mSignatureMetadata |= (mY ?        0x10 : 0);
194b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  }
195b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
19612580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines  if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
19712580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines    // APIs before ICS cannot skip between parameters. It is ok, however, for
19812580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines    // them to omit further parameters (i.e. skipping X is ok if you skip Y).
1997b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (mSignatureMetadata != 0x1f &&  // In, Out, UsrData, X, Y
2007b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        mSignatureMetadata != 0x0f &&  // In, Out, UsrData, X
2017b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        mSignatureMetadata != 0x07 &&  // In, Out, UsrData
2027b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        mSignatureMetadata != 0x03 &&  // In, Out
2037b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        mSignatureMetadata != 0x01) {  // In
2049207a2e495c8363606861e4f034504ec5c153dabLogan Chien      DiagEngine->Report(
2059207a2e495c8363606861e4f034504ec5c153dabLogan Chien        clang::FullSourceLoc(FD->getLocation(),
2069207a2e495c8363606861e4f034504ec5c153dabLogan Chien                             DiagEngine->getSourceManager()),
2079207a2e495c8363606861e4f034504ec5c153dabLogan Chien        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
2087b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                    "Compute kernel %0() targeting SDK levels "
2097b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines                                    "%1-%2 may not skip parameters"))
2107b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        << FD->getName() << SLANG_MINIMUM_TARGET_API
2117b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines        << (SLANG_ICS_TARGET_API - 1);
21212580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines      valid = false;
21312580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines    }
21412580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines  }
21512580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines
216b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  return valid;
217b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines}
218b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
219593a894650e81be54173106ec266f0311cebebd3Stephen HinesRSExportForEach *RSExportForEach::Create(RSContext *Context,
220593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                         const clang::FunctionDecl *FD) {
221b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  slangAssert(Context && FD);
222593a894650e81be54173106ec266f0311cebebd3Stephen Hines  llvm::StringRef Name = FD->getName();
223b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  RSExportForEach *FE;
224593a894650e81be54173106ec266f0311cebebd3Stephen Hines
225593a894650e81be54173106ec266f0311cebebd3Stephen Hines  slangAssert(!Name.empty() && "Function must have a name");
226593a894650e81be54173106ec266f0311cebebd3Stephen Hines
227b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  FE = new RSExportForEach(Context, Name, FD);
228593a894650e81be54173106ec266f0311cebebd3Stephen Hines
229b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (!FE->validateAndConstructParams(Context, FD)) {
230b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    return NULL;
231593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
232593a894650e81be54173106ec266f0311cebebd3Stephen Hines
233593a894650e81be54173106ec266f0311cebebd3Stephen Hines  clang::ASTContext &Ctx = Context->getASTContext();
234593a894650e81be54173106ec266f0311cebebd3Stephen Hines
235593a894650e81be54173106ec266f0311cebebd3Stephen Hines  std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_foreach_param:");
236b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  Id.append(FE->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX);
237593a894650e81be54173106ec266f0311cebebd3Stephen Hines
238593a894650e81be54173106ec266f0311cebebd3Stephen Hines  // Extract the usrData parameter (if we have one)
239b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FE->mUsrData) {
240b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    const clang::ParmVarDecl *PVD = FE->mUsrData;
241593a894650e81be54173106ec266f0311cebebd3Stephen Hines    clang::QualType QT = PVD->getType().getCanonicalType();
242593a894650e81be54173106ec266f0311cebebd3Stephen Hines    slangAssert(QT->isPointerType() &&
243593a894650e81be54173106ec266f0311cebebd3Stephen Hines                QT->getPointeeType().isConstQualified());
244593a894650e81be54173106ec266f0311cebebd3Stephen Hines
245593a894650e81be54173106ec266f0311cebebd3Stephen Hines    const clang::ASTContext &C = Context->getASTContext();
246593a894650e81be54173106ec266f0311cebebd3Stephen Hines    if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
247593a894650e81be54173106ec266f0311cebebd3Stephen Hines        C.VoidTy) {
248593a894650e81be54173106ec266f0311cebebd3Stephen Hines      // In the case of using const void*, we can't reflect an appopriate
249593a894650e81be54173106ec266f0311cebebd3Stephen Hines      // Java type, so we fall back to just reflecting the ain/aout parameters
250b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      FE->mUsrData = NULL;
251593a894650e81be54173106ec266f0311cebebd3Stephen Hines    } else {
252b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      clang::RecordDecl *RD =
253b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
254b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    Ctx.getTranslationUnitDecl(),
255b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    clang::SourceLocation(),
256b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    clang::SourceLocation(),
257b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    &Ctx.Idents.get(Id));
258b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
259593a894650e81be54173106ec266f0311cebebd3Stephen Hines      clang::FieldDecl *FD =
260593a894650e81be54173106ec266f0311cebebd3Stephen Hines          clang::FieldDecl::Create(Ctx,
261593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   RD,
262593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   clang::SourceLocation(),
263593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   clang::SourceLocation(),
264593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   PVD->getIdentifier(),
265593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   QT->getPointeeType(),
266593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   NULL,
2671688a3c56851f235866d6870c89ddb20650cc030Shih-wei Liao                                   /* BitWidth = */ NULL,
2681688a3c56851f235866d6870c89ddb20650cc030Shih-wei Liao                                   /* Mutable = */ false,
2691688a3c56851f235866d6870c89ddb20650cc030Shih-wei Liao                                   /* HasInit = */ false);
270593a894650e81be54173106ec266f0311cebebd3Stephen Hines      RD->addDecl(FD);
271b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      RD->completeDefinition();
272b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
273b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      // Create an export type iff we have a valid usrData type
274b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      clang::QualType T = Ctx.getTagDeclType(RD);
275b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      slangAssert(!T.isNull());
276b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
277b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
278b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
279b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      if (ET == NULL) {
280b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        fprintf(stderr, "Failed to export the function %s. There's at least "
281b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                        "one parameter whose type is not supported by the "
282b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                        "reflection\n", FE->getName().c_str());
283b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        return NULL;
284b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      }
285b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
286b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
287b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                  "Parameter packet must be a record");
288b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
289b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
290593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
291593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
292593a894650e81be54173106ec266f0311cebebd3Stephen Hines
293b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FE->mIn) {
294b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    const clang::Type *T = FE->mIn->getType().getCanonicalType().getTypePtr();
295b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    FE->mInType = RSExportType::Create(Context, T);
296b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  }
297593a894650e81be54173106ec266f0311cebebd3Stephen Hines
298b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FE->mOut) {
299b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr();
300b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    FE->mOutType = RSExportType::Create(Context, T);
301593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
302593a894650e81be54173106ec266f0311cebebd3Stephen Hines
303b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  return FE;
304593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
305593a894650e81be54173106ec266f0311cebebd3Stephen Hines
3069999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hinesbool RSExportForEach::isGraphicsRootRSFunc(int targetAPI,
3079999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines                                           const clang::FunctionDecl *FD) {
308593a894650e81be54173106ec266f0311cebebd3Stephen Hines  if (!isRootRSFunc(FD)) {
309593a894650e81be54173106ec266f0311cebebd3Stephen Hines    return false;
310593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
311593a894650e81be54173106ec266f0311cebebd3Stephen Hines
312b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FD->getNumParams() == 0) {
3139999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    // Graphics root function
3149999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    return true;
315593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
316f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines
3179999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  // Check for legacy graphics root function (with single parameter).
318f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines  if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
319f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines    const clang::QualType &IntType = FD->getASTContext().IntTy;
3209999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    if (FD->getResultType().getCanonicalType() == IntType) {
3219999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      return true;
322f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines    }
323f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines  }
324f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines
3259999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  return false;
3269999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines}
3279999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
3289999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hinesbool RSExportForEach::isRSForEachFunc(int targetAPI,
3299999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    const clang::FunctionDecl *FD) {
3307b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (isGraphicsRootRSFunc(targetAPI, FD)) {
3319999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    return false;
3329999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  }
3339999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
3347b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  // Check if first parameter is a pointer (which is required for ForEach).
3357b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  unsigned int numParams = FD->getNumParams();
3367b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
3377b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (numParams > 0) {
3387b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
3397b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    clang::QualType QT = PVD->getType().getCanonicalType();
3407b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
3417b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (QT->isPointerType()) {
3427b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return true;
3437b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
3447b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
3457b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // Any non-graphics root() is automatically a ForEach candidate.
3467b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // At this point, however, we know that it is not going to be a valid
3477b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // compute root() function (due to not having a pointer parameter). We
3487b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // still want to return true here, so that we can issue appropriate
3497b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // diagnostics.
3507b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (isRootRSFunc(FD)) {
3517b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return true;
3527b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
3539999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  }
3549999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
3557b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  return false;
356593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
357593a894650e81be54173106ec266f0311cebebd3Stephen Hines
3589207a2e495c8363606861e4f034504ec5c153dabLogan Chienbool
359fbfd7f5fd97458b6b23437556025ac1d55e98fd4Stephen HinesRSExportForEach::validateSpecialFuncDecl(int targetAPI,
360fbfd7f5fd97458b6b23437556025ac1d55e98fd4Stephen Hines                                         clang::DiagnosticsEngine *DiagEngine,
3619207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                         clang::FunctionDecl const *FD) {
3629207a2e495c8363606861e4f034504ec5c153dabLogan Chien  slangAssert(DiagEngine && FD);
363593a894650e81be54173106ec266f0311cebebd3Stephen Hines  bool valid = true;
364593a894650e81be54173106ec266f0311cebebd3Stephen Hines  const clang::ASTContext &C = FD->getASTContext();
3659999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  const clang::QualType &IntType = FD->getASTContext().IntTy;
366593a894650e81be54173106ec266f0311cebebd3Stephen Hines
3679999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  if (isGraphicsRootRSFunc(targetAPI, FD)) {
3689999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
3699999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      // Legacy graphics root function
3709999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
3719999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      clang::QualType QT = PVD->getType().getCanonicalType();
3729999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      if (QT != IntType) {
3739207a2e495c8363606861e4f034504ec5c153dabLogan Chien        DiagEngine->Report(
3749999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines          clang::FullSourceLoc(PVD->getLocation(),
3759207a2e495c8363606861e4f034504ec5c153dabLogan Chien                               DiagEngine->getSourceManager()),
3769207a2e495c8363606861e4f034504ec5c153dabLogan Chien          DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
3779999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines                                      "invalid parameter type for legacy "
3789999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines                                      "graphics root() function: %0"))
3799999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines          << PVD->getType();
380593a894650e81be54173106ec266f0311cebebd3Stephen Hines        valid = false;
381593a894650e81be54173106ec266f0311cebebd3Stephen Hines      }
3829999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    }
3839999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
3849999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    // Graphics root function, so verify that it returns an int
3859999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    if (FD->getResultType().getCanonicalType() != IntType) {
3869999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      DiagEngine->Report(
3879999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines        clang::FullSourceLoc(FD->getLocation(),
3889999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines                             DiagEngine->getSourceManager()),
3899999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines        DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
3909999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines                                    "root() is required to return "
3919999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines                                    "an int for graphics usage"));
3929999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      valid = false;
393593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
394688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines  } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) {
395593a894650e81be54173106ec266f0311cebebd3Stephen Hines    if (FD->getNumParams() != 0) {
3969207a2e495c8363606861e4f034504ec5c153dabLogan Chien      DiagEngine->Report(
3979207a2e495c8363606861e4f034504ec5c153dabLogan Chien          clang::FullSourceLoc(FD->getLocation(),
3989207a2e495c8363606861e4f034504ec5c153dabLogan Chien                               DiagEngine->getSourceManager()),
3999207a2e495c8363606861e4f034504ec5c153dabLogan Chien          DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
4009207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                      "%0(void) is required to have no "
4019207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                      "parameters")) << FD->getName();
402593a894650e81be54173106ec266f0311cebebd3Stephen Hines      valid = false;
403593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
404593a894650e81be54173106ec266f0311cebebd3Stephen Hines
405593a894650e81be54173106ec266f0311cebebd3Stephen Hines    if (FD->getResultType().getCanonicalType() != C.VoidTy) {
4069207a2e495c8363606861e4f034504ec5c153dabLogan Chien      DiagEngine->Report(
4079207a2e495c8363606861e4f034504ec5c153dabLogan Chien          clang::FullSourceLoc(FD->getLocation(),
4089207a2e495c8363606861e4f034504ec5c153dabLogan Chien                               DiagEngine->getSourceManager()),
4099207a2e495c8363606861e4f034504ec5c153dabLogan Chien          DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
4109207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                      "%0(void) is required to have a void "
4119207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                      "return type")) << FD->getName();
412593a894650e81be54173106ec266f0311cebebd3Stephen Hines      valid = false;
413593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
414593a894650e81be54173106ec266f0311cebebd3Stephen Hines  } else {
415688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines    slangAssert(false && "must be called on root, init or .rs.dtor function!");
416593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
417593a894650e81be54173106ec266f0311cebebd3Stephen Hines
418593a894650e81be54173106ec266f0311cebebd3Stephen Hines  return valid;
419593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
420593a894650e81be54173106ec266f0311cebebd3Stephen Hines
421593a894650e81be54173106ec266f0311cebebd3Stephen Hines}  // namespace slang
422