slang_rs_export_foreach.cpp revision fb78d4c6604bd243578ce8071e31f68c023d82cf
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"
2223c4358f12bd9d0ba7166eceebd683db95a41b3fStephen Hines#include "clang/AST/Attr.h"
23593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "clang/AST/Decl.h"
24b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines#include "clang/AST/TypeLoc.h"
25593a894650e81be54173106ec266f0311cebebd3Stephen Hines
2623c4358f12bd9d0ba7166eceebd683db95a41b3fStephen Hines#include "llvm/IR/DerivedTypes.h"
27593a894650e81be54173106ec266f0311cebebd3Stephen Hines
2818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross#include "bcinfo/MetadataExtractor.h"
2918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
30593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "slang_assert.h"
31593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "slang_rs_context.h"
32593a894650e81be54173106ec266f0311cebebd3Stephen Hines#include "slang_rs_export_type.h"
3312580dcd125d958bff87385ab13599ad01bd8aeaStephen Hines#include "slang_version.h"
34593a894650e81be54173106ec266f0311cebebd3Stephen Hines
3518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Grossnamespace {
3618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
37cd7d3128f41a59692e5c59a2b81969616579aae4David Grossconst size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h
38cd7d3128f41a59692e5c59a2b81969616579aae4David Gross
3918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Grossenum SpecialParameterKind {
4018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  SPK_INT,  // 'int' or 'unsigned int'
4118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  SPK_CTXT, // rs_kernel_context
4218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross};
4318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
4418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Grossstruct SpecialParameter {
4518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  const char *name;
4618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  bcinfo::MetadataSignatureBitval bitval;
4718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  SpecialParameterKind kind;
4818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  SlangTargetAPI minAPI;
4918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross};
5018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
5118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross// Table entries are in the order parameters must occur in a kernel parameter list.
5218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Grossconst SpecialParameter specialParameterTable[] = {
5318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  { "ctxt", bcinfo::MD_SIG_Ctxt, SPK_CTXT, SLANG_23_TARGET_API },
5418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  { "x", bcinfo::MD_SIG_X, SPK_INT, SLANG_MINIMUM_TARGET_API },
5518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  { "y", bcinfo::MD_SIG_Y, SPK_INT, SLANG_MINIMUM_TARGET_API },
5618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  { "z", bcinfo::MD_SIG_Z, SPK_INT, SLANG_23_TARGET_API },
5718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  { nullptr, bcinfo::MD_SIG_None, SPK_INT, SLANG_MINIMUM_TARGET_API }, // marks end of table
5818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross};
5918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
6018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross// If the specified name matches the name of an entry in
6118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross// specialParameterTable, return the corresponding table index;
6218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross// otherwise return -1.
6318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Grossint lookupSpecialParameter(const llvm::StringRef name) {
6418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  for (int i = 0; specialParameterTable[i].name != nullptr; ++i)
6518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    if (name.equals(specialParameterTable[i].name))
6618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      return i;
6718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  return -1;
6818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross}
6918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
7018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross// Return a comma-separated list of names in specialParameterTable
7118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross// that are available at the specified API level.
7218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Grossstd::string listSpecialParameters(unsigned int api) {
7318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  std::string ret;
7418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  bool first = true;
7518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  for (int i = 0; specialParameterTable[i].name != nullptr; ++i) {
7618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    if (specialParameterTable[i].minAPI > api)
7718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      continue;
7818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    if (first)
7918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      first = false;
8018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    else
8118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      ret += ", ";
8218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    ret += "'";
8318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    ret += specialParameterTable[i].name;
8418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    ret += "'";
8518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  }
8618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  return ret;
8718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross}
8818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
897cc6876212646f91cd718a72a1845a0563838fe9David Gross}
9018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
91593a894650e81be54173106ec266f0311cebebd3Stephen Hinesnamespace slang {
92593a894650e81be54173106ec266f0311cebebd3Stephen Hines
93b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines// This function takes care of additional validation and construction of
94b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines// parameters related to forEach_* reflection.
95b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hinesbool RSExportForEach::validateAndConstructParams(
96b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    RSContext *Context, const clang::FunctionDecl *FD) {
97b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  slangAssert(Context && FD);
98b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  bool valid = true;
99b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
100b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  numParams = FD->getNumParams();
101b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
1027b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (Context->getTargetAPI() < SLANG_JB_TARGET_API) {
103482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet    // Before JellyBean, we allowed only one kernel per file.  It must be called "root".
1047b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (!isRootRSFunc(FD)) {
105d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
106d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "Non-root compute kernel %0() is "
107d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "not supported in SDK levels %1-%2")
108d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName() << SLANG_MINIMUM_TARGET_API
109d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << (SLANG_JB_TARGET_API - 1);
1107b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return false;
1117b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
1127b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  }
1137b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
114ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray  mResultType = FD->getReturnType().getCanonicalType();
1150f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // Compute kernel functions are defined differently when the
1160f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // "__attribute__((kernel))" is set.
1179ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (FD->hasAttr<clang::KernelAttr>()) {
1180f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    valid |= validateAndConstructKernelParams(Context, FD);
1190f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  } else {
1200f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    valid |= validateAndConstructOldStyleParams(Context, FD);
1219ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
122c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
1230f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  valid |= setSignatureMetadata(Context, FD);
1240f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  return valid;
1250f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet}
1269ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
12742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouilletbool RSExportForEach::validateAndConstructOldStyleParams(
12842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    RSContext *Context, const clang::FunctionDecl *FD) {
1290f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  slangAssert(Context && FD);
1309ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // If numParams is 0, we already marked this as a graphics root().
1319ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  slangAssert(numParams > 0);
1329ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
1330f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  bool valid = true;
1340f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet
1350f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // Compute kernel functions of this style are required to return a void type.
1360f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  clang::ASTContext &C = Context->getASTContext();
1379ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (mResultType != C.VoidTy) {
138d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet    Context->ReportError(FD->getLocation(),
139d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "Compute kernel %0() is required to return a "
140d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "void type")
141d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName();
142b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    valid = false;
143b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  }
144b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
145b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  // Validate remaining parameter types
146b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
14718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  size_t IndexOfFirstSpecialParameter = numParams;
14818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  valid |= validateSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
1494ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
15018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  // Validate the non-special parameters, which should all be found before the
15118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  // first special parameter.
15218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
15342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
15442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    clang::QualType QT = PVD->getType().getCanonicalType();
1554ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
15642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    if (!QT->isPointerType()) {
15742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      Context->ReportError(PVD->getLocation(),
15842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                           "Compute kernel %0() cannot have non-pointer "
15918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                           "parameters besides (%1). Parameter '%2' is "
16018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                           "of type: '%3'")
16118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          << FD->getName() << listSpecialParameters(Context->getTargetAPI())
16218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          << PVD->getName() << PVD->getType().getAsString();
16342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      valid = false;
16442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      continue;
16542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    }
1664ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
16742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    // The only non-const pointer should be out.
16842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    if (!QT->getPointeeType().isConstQualified()) {
1695abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes      if (mOut == nullptr) {
17042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        mOut = PVD;
17142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      } else {
17242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        Context->ReportError(PVD->getLocation(),
17342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "Compute kernel %0() can only have one non-const "
17442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "pointer parameter. Parameters '%1' and '%2' are "
17542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "both non-const.")
17642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            << FD->getName() << mOut->getName() << PVD->getName();
17742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        valid = false;
17842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      }
17942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    } else {
1805abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes      if (mIns.empty() && mOut == nullptr) {
181c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes        mIns.push_back(PVD);
1825abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes      } else if (mUsrData == nullptr) {
18342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        mUsrData = PVD;
18442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      } else {
18542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        Context->ReportError(
18642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            PVD->getLocation(),
18742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            "Unexpected parameter '%0' for compute kernel %1()")
18842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            << PVD->getName() << FD->getName();
18942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        valid = false;
19042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      }
1914ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    }
1924ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  }
1934ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
194c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes  if (mIns.empty() && !mOut) {
195d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet    Context->ReportError(FD->getLocation(),
196d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "Compute kernel %0() must have at least one "
197d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "parameter for in or out")
198d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName();
1994ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    valid = false;
2004ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  }
2014ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
202b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  return valid;
203b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines}
204b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
20542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouilletbool RSExportForEach::validateAndConstructKernelParams(
20642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    RSContext *Context, const clang::FunctionDecl *FD) {
2079ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  slangAssert(Context && FD);
2089ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  bool valid = true;
2099ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  clang::ASTContext &C = Context->getASTContext();
2109ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
2119ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) {
212d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet    Context->ReportError(FD->getLocation(),
213d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "Compute kernel %0() targeting SDK levels "
214d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "%1-%2 may not use pass-by-value with "
215d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "__attribute__((kernel))")
216d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName() << SLANG_MINIMUM_TARGET_API
217d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << (SLANG_JB_MR1_TARGET_API - 1);
2189ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    return false;
2199ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
2209ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
2219ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // Denote that we are indeed a pass-by-value kernel.
2220f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  mIsKernelStyle = true;
223d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet  mHasReturnType = (mResultType != C.VoidTy);
2249ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
2259ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (mResultType->isPointerType()) {
22642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    Context->ReportError(
22742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        FD->getTypeSpecStartLoc(),
22842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        "Compute kernel %0() cannot return a pointer type: '%1'")
229d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName() << mResultType.getAsString();
2309ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    valid = false;
2319ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
2329ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
2339ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // Validate remaining parameter types
2349ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
23518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  size_t IndexOfFirstSpecialParameter = numParams;
23618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  valid |= validateSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
2379ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
23818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  // Validate the non-special parameters, which should all be found before the
23918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  // first special.
24018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
24142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
242c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
243c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes    /*
244c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes     * FIXME: Change this to a test against an actual API version when the
245c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes     *        multi-input feature is officially supported.
246c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes     */
247c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes    if (Context->getTargetAPI() == SLANG_DEVELOPMENT_TARGET_API || i == 0) {
248cd7d3128f41a59692e5c59a2b81969616579aae4David Gross      if (i >= RS_KERNEL_INPUT_LIMIT) {
249cd7d3128f41a59692e5c59a2b81969616579aae4David Gross        Context->ReportError(PVD->getLocation(),
250cd7d3128f41a59692e5c59a2b81969616579aae4David Gross                             "Invalid parameter '%0' for compute kernel %1(). "
251cd7d3128f41a59692e5c59a2b81969616579aae4David Gross                             "Kernels targeting SDK levels %2-%3 may not use "
252cd7d3128f41a59692e5c59a2b81969616579aae4David Gross                             "more than %4 input parameters.") << PVD->getName() <<
253cd7d3128f41a59692e5c59a2b81969616579aae4David Gross                             FD->getName() << SLANG_MINIMUM_TARGET_API <<
254cd7d3128f41a59692e5c59a2b81969616579aae4David Gross                             SLANG_MAXIMUM_TARGET_API << int(RS_KERNEL_INPUT_LIMIT);
255cd7d3128f41a59692e5c59a2b81969616579aae4David Gross
256cd7d3128f41a59692e5c59a2b81969616579aae4David Gross      } else {
257cd7d3128f41a59692e5c59a2b81969616579aae4David Gross        mIns.push_back(PVD);
258cd7d3128f41a59692e5c59a2b81969616579aae4David Gross      }
25942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    } else {
26042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      Context->ReportError(PVD->getLocation(),
261c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           "Invalid parameter '%0' for compute kernel %1(). "
262c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           "Kernels targeting SDK levels %2-%3 may not use "
263c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           "multiple input parameters.") << PVD->getName() <<
264c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           FD->getName() << SLANG_MINIMUM_TARGET_API <<
265c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           SLANG_MAXIMUM_TARGET_API;
26642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      valid = false;
26742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    }
26842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    clang::QualType QT = PVD->getType().getCanonicalType();
2699ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    if (QT->isPointerType()) {
270d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(PVD->getLocation(),
271d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "Compute kernel %0() cannot have "
272d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "parameter '%1' of pointer type: '%2'")
273d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName() << PVD->getName() << PVD->getType().getAsString();
2749ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines      valid = false;
2759ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    }
2769ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
2779ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
2789ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // Check that we have at least one allocation to use for dimensions.
279fb78d4c6604bd243578ce8071e31f68c023d82cfDavid Gross  if (valid && mIns.empty() && !mHasReturnType && Context->getTargetAPI() < SLANG_23_TARGET_API) {
280d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet    Context->ReportError(FD->getLocation(),
281fb78d4c6604bd243578ce8071e31f68c023d82cfDavid Gross                         "Compute kernel %0() targeting SDK levels "
282fb78d4c6604bd243578ce8071e31f68c023d82cfDavid Gross                         "%1-%2 must have at least one "
283d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "input parameter or a non-void return "
284d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "type")
285fb78d4c6604bd243578ce8071e31f68c023d82cfDavid Gross        << FD->getName() << SLANG_MINIMUM_TARGET_API
286fb78d4c6604bd243578ce8071e31f68c023d82cfDavid Gross        << (SLANG_23_TARGET_API - 1);
2879ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    valid = false;
2889ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
2899ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
29042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  return valid;
29142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet}
2929ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
29318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross// Search for the optional special parameters.  Returns true if valid.   Also
29418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross// sets *IndexOfFirstSpecialParameter to the index of the first special parameter, or
29542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet// FD->getNumParams() if none are found.
29618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Grossbool RSExportForEach::validateSpecialParameters(
29742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    RSContext *Context, const clang::FunctionDecl *FD,
29818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    size_t *IndexOfFirstSpecialParameter) {
29918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  slangAssert(IndexOfFirstSpecialParameter != nullptr);
30018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  slangAssert(mSpecialParameterSignatureMetadata == 0);
30142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  clang::ASTContext &C = Context->getASTContext();
30242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet
30318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  // Find all special parameters if present.
30418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  int LastSpecialParameterIdx = -1;     // index into specialParameterTable
30518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  int FirstIntSpecialParameterIdx = -1; // index into specialParameterTable
30618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  clang::QualType FirstIntSpecialParameterType;
30742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  size_t NumParams = FD->getNumParams();
30818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  *IndexOfFirstSpecialParameter = NumParams;
30942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  bool valid = true;
31042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  for (size_t i = 0; i < NumParams; i++) {
31142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
31242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    llvm::StringRef ParamName = PVD->getName();
31318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    int SpecialParameterIdx = lookupSpecialParameter(ParamName);
31418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    if (SpecialParameterIdx >= 0) {
31518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      const SpecialParameter &SP = specialParameterTable[SpecialParameterIdx];
31618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      // We won't be invoked if two parameters of the same name are present.
31718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      slangAssert(!(mSpecialParameterSignatureMetadata & SP.bitval));
31818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
31918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      if (Context->getTargetAPI() < SP.minAPI) {
32042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        Context->ReportError(PVD->getLocation(),
32118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                             "Compute kernel %0() targeting SDK levels "
32218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                             "%1-%2 may not use parameter '%3'.")
32318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            << FD->getName()
32418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            << SLANG_MINIMUM_TARGET_API
32518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            << (SP.minAPI - 1)
32618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            << SP.name;
32742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        valid = false;
32842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      }
32918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
33018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      mSpecialParameterSignatureMetadata |= SP.bitval;
33118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      if (SpecialParameterIdx < LastSpecialParameterIdx) {
33218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        Context->ReportError(PVD->getLocation(),
33318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                             "In compute kernel %0(), parameter '%1' must "
33418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                             "be defined before parameter '%2'.")
33518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            << FD->getName()
33618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            << SP.name
33718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            << specialParameterTable[LastSpecialParameterIdx].name;
33818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        valid = false;
33918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      }
34018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      LastSpecialParameterIdx = SpecialParameterIdx;
34118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross
34218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      // Ensure that all SPK_INT special parameters have the same type.
34318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      if (SP.kind == SPK_INT) {
34418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        clang::QualType SpecialParameterType = PVD->getType();
34518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        if (FirstIntSpecialParameterIdx >= 0) {
34618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          if (SpecialParameterType != FirstIntSpecialParameterType) {
34718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            Context->ReportError(PVD->getLocation(),
34818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                                 "Parameters '%0' and '%1' must be of the same type. "
34918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                                 "'%0' is of type '%2' while '%1' is of type '%3'.")
35018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                << specialParameterTable[FirstIntSpecialParameterIdx].name
35118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                << SP.name
35218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                << FirstIntSpecialParameterType.getAsString()
35318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                << SpecialParameterType.getAsString();
35418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            valid = false;
35518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          }
35618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        } else {
35718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          FirstIntSpecialParameterIdx = SpecialParameterIdx;
35818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          FirstIntSpecialParameterType = SpecialParameterType;
35918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        }
36018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      }
3619ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    } else {
36218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      // It's not a special parameter.
36318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      if (*IndexOfFirstSpecialParameter < NumParams) {
36442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        Context->ReportError(PVD->getLocation(),
36542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "In compute kernel %0(), parameter '%1' cannot "
36618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                             "appear after any of the (%2) parameters.")
36718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross            << FD->getName() << ParamName << listSpecialParameters(Context->getTargetAPI());
36842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        valid = false;
3699ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines      }
37042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      continue;
37142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    }
37218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    // Validate the data type of the special parameter.
37318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    switch (specialParameterTable[SpecialParameterIdx].kind) {
37418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      case SPK_INT: {
37518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        clang::QualType QT = PVD->getType().getCanonicalType();
37618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        clang::QualType UT = QT.getUnqualifiedType();
37718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        if (UT != C.UnsignedIntTy && UT != C.IntTy) {
37818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          Context->ReportError(PVD->getLocation(),
37918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                               "Parameter '%0' must be of type 'int' or "
38018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                               "'unsigned int'. It is of type '%1'.")
38118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross              << ParamName << PVD->getType().getAsString();
38218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          valid = false;
38318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        }
38418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        break;
38518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      }
38618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      case SPK_CTXT: {
38718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        static const char ExpectedTypeNameMatch[] = "const struct rs_kernel_context_t *";
38818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        static const char ExpectedTypeNamePrint[] = "rs_kernel_context";
38918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        clang::QualType QT = PVD->getType().getCanonicalType();
39018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        clang::QualType UT = QT.getUnqualifiedType();
39118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        if (UT.getAsString() != ExpectedTypeNameMatch) {
39218c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          Context->ReportError(PVD->getLocation(),
39318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                               "Parameter '%0' must be of type '%1'. "
39418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                               "It is of type '%2'.")
39518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross              << ParamName << ExpectedTypeNamePrint << PVD->getType().getAsString();
39618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross          valid = false;
39718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        }
39818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        break;
39918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      }
40018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      default:
40118c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        slangAssert(!"Unexpected special parameter type");
4029ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    }
40318c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    // If this is the first time we find a special parameter, save it.
40418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    if (*IndexOfFirstSpecialParameter >= NumParams) {
40518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross      *IndexOfFirstSpecialParameter = i;
4069ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    }
4079ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
4080f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  return valid;
4090f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet}
4109ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
4110f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouilletbool RSExportForEach::setSignatureMetadata(RSContext *Context,
4120f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet                                           const clang::FunctionDecl *FD) {
4139ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  mSignatureMetadata = 0;
4140f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  bool valid = true;
4150f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet
4160f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  if (mIsKernelStyle) {
4175abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes    slangAssert(mOut == nullptr);
4185abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes    slangAssert(mUsrData == nullptr);
4190f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  } else {
4200f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    slangAssert(!mHasReturnType);
4219ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
4229ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
4230f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // Set up the bitwise metadata encoding for runtime argument passing.
4240f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  const bool HasOut = mOut || mHasReturnType;
42518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  mSignatureMetadata |= (hasIns() ?       bcinfo::MD_SIG_In     : 0);
42618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  mSignatureMetadata |= (HasOut ?         bcinfo::MD_SIG_Out    : 0);
42718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  mSignatureMetadata |= (mUsrData ?       bcinfo::MD_SIG_Usr    : 0);
42818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  mSignatureMetadata |= (mIsKernelStyle ? bcinfo::MD_SIG_Kernel : 0);  // pass-by-value
42918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross  mSignatureMetadata |= mSpecialParameterSignatureMetadata;
4300f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet
4310f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
4320f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    // APIs before ICS cannot skip between parameters. It is ok, however, for
4330f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    // them to omit further parameters (i.e. skipping X is ok if you skip Y).
43418c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross    if (mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
43518c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                               bcinfo::MD_SIG_X | bcinfo::MD_SIG_Y) &&
43618c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
43718c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross                               bcinfo::MD_SIG_X) &&
43818c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr) &&
43918c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out) &&
44018c50ebf6e87a6f51de8f21dce6282d1096e50c2David Gross        mSignatureMetadata != (bcinfo::MD_SIG_In)) {
441d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
442d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "Compute kernel %0() targeting SDK levels "
443d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "%1-%2 may not skip parameters")
4440f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet          << FD->getName() << SLANG_MINIMUM_TARGET_API
4450f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet          << (SLANG_ICS_TARGET_API - 1);
4460f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet      valid = false;
4470f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    }
4480f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  }
4499ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  return valid;
4509ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines}
4519ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
452593a894650e81be54173106ec266f0311cebebd3Stephen HinesRSExportForEach *RSExportForEach::Create(RSContext *Context,
453593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                         const clang::FunctionDecl *FD) {
454b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  slangAssert(Context && FD);
455593a894650e81be54173106ec266f0311cebebd3Stephen Hines  llvm::StringRef Name = FD->getName();
456b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  RSExportForEach *FE;
457593a894650e81be54173106ec266f0311cebebd3Stephen Hines
458593a894650e81be54173106ec266f0311cebebd3Stephen Hines  slangAssert(!Name.empty() && "Function must have a name");
459593a894650e81be54173106ec266f0311cebebd3Stephen Hines
460c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  FE = new RSExportForEach(Context, Name);
461593a894650e81be54173106ec266f0311cebebd3Stephen Hines
462b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (!FE->validateAndConstructParams(Context, FD)) {
4635abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes    return nullptr;
464593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
465593a894650e81be54173106ec266f0311cebebd3Stephen Hines
466593a894650e81be54173106ec266f0311cebebd3Stephen Hines  clang::ASTContext &Ctx = Context->getASTContext();
467593a894650e81be54173106ec266f0311cebebd3Stephen Hines
468eca0534a31b6185d6ab758f5e97acd7a4cb21e8eJean-Luc Brouillet  std::string Id = CreateDummyName("helper_foreach_param", FE->getName());
469593a894650e81be54173106ec266f0311cebebd3Stephen Hines
470593a894650e81be54173106ec266f0311cebebd3Stephen Hines  // Extract the usrData parameter (if we have one)
471b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FE->mUsrData) {
472b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    const clang::ParmVarDecl *PVD = FE->mUsrData;
473593a894650e81be54173106ec266f0311cebebd3Stephen Hines    clang::QualType QT = PVD->getType().getCanonicalType();
474593a894650e81be54173106ec266f0311cebebd3Stephen Hines    slangAssert(QT->isPointerType() &&
475593a894650e81be54173106ec266f0311cebebd3Stephen Hines                QT->getPointeeType().isConstQualified());
476593a894650e81be54173106ec266f0311cebebd3Stephen Hines
477593a894650e81be54173106ec266f0311cebebd3Stephen Hines    const clang::ASTContext &C = Context->getASTContext();
478593a894650e81be54173106ec266f0311cebebd3Stephen Hines    if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
479593a894650e81be54173106ec266f0311cebebd3Stephen Hines        C.VoidTy) {
480593a894650e81be54173106ec266f0311cebebd3Stephen Hines      // In the case of using const void*, we can't reflect an appopriate
481593a894650e81be54173106ec266f0311cebebd3Stephen Hines      // Java type, so we fall back to just reflecting the ain/aout parameters
4825abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes      FE->mUsrData = nullptr;
483593a894650e81be54173106ec266f0311cebebd3Stephen Hines    } else {
484b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      clang::RecordDecl *RD =
485b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
486b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    Ctx.getTranslationUnitDecl(),
487b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    clang::SourceLocation(),
488b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    clang::SourceLocation(),
489b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    &Ctx.Idents.get(Id));
490b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
491593a894650e81be54173106ec266f0311cebebd3Stephen Hines      clang::FieldDecl *FD =
492593a894650e81be54173106ec266f0311cebebd3Stephen Hines          clang::FieldDecl::Create(Ctx,
493593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   RD,
494593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   clang::SourceLocation(),
495593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   clang::SourceLocation(),
496593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   PVD->getIdentifier(),
497593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   QT->getPointeeType(),
4985abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes                                   nullptr,
4995abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes                                   /* BitWidth = */ nullptr,
5001688a3c56851f235866d6870c89ddb20650cc030Shih-wei Liao                                   /* Mutable = */ false,
50143730fe3c839af391efe6bdf56b0479860121924Shih-wei Liao                                   /* HasInit = */ clang::ICIS_NoInit);
502593a894650e81be54173106ec266f0311cebebd3Stephen Hines      RD->addDecl(FD);
503b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      RD->completeDefinition();
504b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
505b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      // Create an export type iff we have a valid usrData type
506b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      clang::QualType T = Ctx.getTagDeclType(RD);
507b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      slangAssert(!T.isNull());
508b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
509b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
510b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
5115abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes      if (ET == nullptr) {
512b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        fprintf(stderr, "Failed to export the function %s. There's at least "
513b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                        "one parameter whose type is not supported by the "
514b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                        "reflection\n", FE->getName().c_str());
5155abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes        return nullptr;
516b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      }
517b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
518b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
519b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                  "Parameter packet must be a record");
520b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
521b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
522593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
523593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
524593a894650e81be54173106ec266f0311cebebd3Stephen Hines
525c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes  if (FE->hasIns()) {
526c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
527c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes    for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) {
528c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr();
529c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      RSExportType *InExportType = RSExportType::Create(Context, T);
530c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
531c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      if (FE->mIsKernelStyle) {
5325abbe0e9ca2508260b627ffef2bf01e2554e8357Chris Wailes        slangAssert(InExportType != nullptr);
533c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      }
534c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
535c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      FE->mInTypes.push_back(InExportType);
5369ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    }
537b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  }
538593a894650e81be54173106ec266f0311cebebd3Stephen Hines
5390f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  if (FE->mIsKernelStyle && FE->mHasReturnType) {
5409ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    const clang::Type *T = FE->mResultType.getTypePtr();
5419ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    FE->mOutType = RSExportType::Create(Context, T);
5429ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    slangAssert(FE->mOutType);
5439ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  } else if (FE->mOut) {
544b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr();
545b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    FE->mOutType = RSExportType::Create(Context, T);
546593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
547593a894650e81be54173106ec266f0311cebebd3Stephen Hines
548b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  return FE;
549593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
550593a894650e81be54173106ec266f0311cebebd3Stephen Hines
551c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen HinesRSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) {
552c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  slangAssert(Context);
553c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  llvm::StringRef Name = "root";
554c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  RSExportForEach *FE = new RSExportForEach(Context, Name);
555c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  FE->mDummyRoot = true;
556c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  return FE;
557c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines}
558c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines
559c9454afec1649846512993d0ef65a9f868976bb4Chris Wailesbool RSExportForEach::isGraphicsRootRSFunc(unsigned int targetAPI,
5609999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines                                           const clang::FunctionDecl *FD) {
5619ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (FD->hasAttr<clang::KernelAttr>()) {
5629ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    return false;
5639ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
5649ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
565593a894650e81be54173106ec266f0311cebebd3Stephen Hines  if (!isRootRSFunc(FD)) {
566593a894650e81be54173106ec266f0311cebebd3Stephen Hines    return false;
567593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
568593a894650e81be54173106ec266f0311cebebd3Stephen Hines
569b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FD->getNumParams() == 0) {
5709999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    // Graphics root function
5719999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    return true;
572593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
573f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines
5749999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  // Check for legacy graphics root function (with single parameter).
575f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines  if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
576f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines    const clang::QualType &IntType = FD->getASTContext().IntTy;
577ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray    if (FD->getReturnType().getCanonicalType() == IntType) {
5789999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      return true;
579f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines    }
580f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines  }
581f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines
5829999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  return false;
5839999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines}
5849999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
585c9454afec1649846512993d0ef65a9f868976bb4Chris Wailesbool RSExportForEach::isRSForEachFunc(unsigned int targetAPI,
586c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                                      slang::RSContext* Context,
587c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                                      const clang::FunctionDecl *FD) {
588d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet  slangAssert(Context && FD);
589089cde338148fbb75825aea4539ccdae8211ffefStephen Hines  bool hasKernelAttr = FD->hasAttr<clang::KernelAttr>();
590089cde338148fbb75825aea4539ccdae8211ffefStephen Hines
591089cde338148fbb75825aea4539ccdae8211ffefStephen Hines  if (FD->getStorageClass() == clang::SC_Static) {
592089cde338148fbb75825aea4539ccdae8211ffefStephen Hines    if (hasKernelAttr) {
593d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
594d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "Invalid use of attribute kernel with "
595d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "static function declaration: %0")
596d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName();
597089cde338148fbb75825aea4539ccdae8211ffefStephen Hines    }
598089cde338148fbb75825aea4539ccdae8211ffefStephen Hines    return false;
599089cde338148fbb75825aea4539ccdae8211ffefStephen Hines  }
600089cde338148fbb75825aea4539ccdae8211ffefStephen Hines
6019ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // Anything tagged as a kernel is definitely used with ForEach.
602089cde338148fbb75825aea4539ccdae8211ffefStephen Hines  if (hasKernelAttr) {
6039ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    return true;
6049ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
6059ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
6067b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (isGraphicsRootRSFunc(targetAPI, FD)) {
6079999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    return false;
6089999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  }
6099999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
6107b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  // Check if first parameter is a pointer (which is required for ForEach).
6117b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  unsigned int numParams = FD->getNumParams();
6127b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
6137b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (numParams > 0) {
6147b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
6157b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    clang::QualType QT = PVD->getType().getCanonicalType();
6167b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
6177b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (QT->isPointerType()) {
6187b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return true;
6197b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
6207b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
6217b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // Any non-graphics root() is automatically a ForEach candidate.
6227b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // At this point, however, we know that it is not going to be a valid
6237b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // compute root() function (due to not having a pointer parameter). We
6247b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // still want to return true here, so that we can issue appropriate
6257b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // diagnostics.
6267b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (isRootRSFunc(FD)) {
6277b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return true;
6287b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
6299999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  }
6309999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
6317b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  return false;
632593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
633593a894650e81be54173106ec266f0311cebebd3Stephen Hines
6349207a2e495c8363606861e4f034504ec5c153dabLogan Chienbool
635c9454afec1649846512993d0ef65a9f868976bb4Chris WailesRSExportForEach::validateSpecialFuncDecl(unsigned int targetAPI,
636d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                                         slang::RSContext *Context,
6379207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                         clang::FunctionDecl const *FD) {
638d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet  slangAssert(Context && FD);
639593a894650e81be54173106ec266f0311cebebd3Stephen Hines  bool valid = true;
640593a894650e81be54173106ec266f0311cebebd3Stephen Hines  const clang::ASTContext &C = FD->getASTContext();
6419999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  const clang::QualType &IntType = FD->getASTContext().IntTy;
642593a894650e81be54173106ec266f0311cebebd3Stephen Hines
6439999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  if (isGraphicsRootRSFunc(targetAPI, FD)) {
6449999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
6459999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      // Legacy graphics root function
6469999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
6479999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      clang::QualType QT = PVD->getType().getCanonicalType();
6489999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      if (QT != IntType) {
649d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        Context->ReportError(PVD->getLocation(),
650d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                             "invalid parameter type for legacy "
651d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                             "graphics root() function: %0")
652d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet            << PVD->getType();
653593a894650e81be54173106ec266f0311cebebd3Stephen Hines        valid = false;
654593a894650e81be54173106ec266f0311cebebd3Stephen Hines      }
6559999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    }
6569999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
6579999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    // Graphics root function, so verify that it returns an int
658ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray    if (FD->getReturnType().getCanonicalType() != IntType) {
659d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
660d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "root() is required to return "
661d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "an int for graphics usage");
6629999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      valid = false;
663593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
664688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines  } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) {
665593a894650e81be54173106ec266f0311cebebd3Stephen Hines    if (FD->getNumParams() != 0) {
666d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
667d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "%0(void) is required to have no "
668d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "parameters")
669d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName();
670593a894650e81be54173106ec266f0311cebebd3Stephen Hines      valid = false;
671593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
672593a894650e81be54173106ec266f0311cebebd3Stephen Hines
673ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray    if (FD->getReturnType().getCanonicalType() != C.VoidTy) {
674d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
675d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "%0(void) is required to have a void "
676d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "return type")
677d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName();
678593a894650e81be54173106ec266f0311cebebd3Stephen Hines      valid = false;
679593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
680593a894650e81be54173106ec266f0311cebebd3Stephen Hines  } else {
681688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines    slangAssert(false && "must be called on root, init or .rs.dtor function!");
682593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
683593a894650e81be54173106ec266f0311cebebd3Stephen Hines
684593a894650e81be54173106ec266f0311cebebd3Stephen Hines  return valid;
685593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
686593a894650e81be54173106ec266f0311cebebd3Stephen Hines
687593a894650e81be54173106ec266f0311cebebd3Stephen Hines}  // namespace slang
688