slang_rs_export_foreach.cpp revision c9454afec1649846512993d0ef65a9f868976bb4
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
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 Hines// This function takes care of additional validation and construction of
36b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines// parameters related to forEach_* reflection.
37b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hinesbool RSExportForEach::validateAndConstructParams(
38b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    RSContext *Context, const clang::FunctionDecl *FD) {
39b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  slangAssert(Context && FD);
40b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  bool valid = true;
41b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
42b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  numParams = FD->getNumParams();
43b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
447b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (Context->getTargetAPI() < SLANG_JB_TARGET_API) {
45482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet    // Before JellyBean, we allowed only one kernel per file.  It must be called "root".
467b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (!isRootRSFunc(FD)) {
47d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
48d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "Non-root compute kernel %0() is "
49d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "not supported in SDK levels %1-%2")
50d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName() << SLANG_MINIMUM_TARGET_API
51d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << (SLANG_JB_TARGET_API - 1);
527b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return false;
537b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
547b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  }
557b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
56ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray  mResultType = FD->getReturnType().getCanonicalType();
570f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // Compute kernel functions are defined differently when the
580f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // "__attribute__((kernel))" is set.
599ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (FD->hasAttr<clang::KernelAttr>()) {
600f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    valid |= validateAndConstructKernelParams(Context, FD);
610f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  } else {
620f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    valid |= validateAndConstructOldStyleParams(Context, FD);
639ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
64c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
650f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  valid |= setSignatureMetadata(Context, FD);
660f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  return valid;
670f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet}
689ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
6942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouilletbool RSExportForEach::validateAndConstructOldStyleParams(
7042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    RSContext *Context, const clang::FunctionDecl *FD) {
710f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  slangAssert(Context && FD);
729ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // If numParams is 0, we already marked this as a graphics root().
739ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  slangAssert(numParams > 0);
749ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
750f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  bool valid = true;
760f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet
770f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // Compute kernel functions of this style are required to return a void type.
780f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  clang::ASTContext &C = Context->getASTContext();
799ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (mResultType != C.VoidTy) {
80d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet    Context->ReportError(FD->getLocation(),
81d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "Compute kernel %0() is required to return a "
82d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "void type")
83d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName();
84b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    valid = false;
85b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  }
86b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
87b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  // Validate remaining parameter types
88b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  // TODO(all): Add support for LOD/face when we have them
89b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
9042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  size_t IndexOfFirstIterator = numParams;
9142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  valid |= validateIterationParameters(Context, FD, &IndexOfFirstIterator);
924ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
9342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  // Validate the non-iterator parameters, which should all be found before the
9442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  // first iterator.
9542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  for (size_t i = 0; i < IndexOfFirstIterator; i++) {
9642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
9742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    clang::QualType QT = PVD->getType().getCanonicalType();
984ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
9942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    if (!QT->isPointerType()) {
10042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      Context->ReportError(PVD->getLocation(),
10142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                           "Compute kernel %0() cannot have non-pointer "
10242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                           "parameters besides 'x' and 'y'. Parameter '%1' is "
10342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                           "of type: '%2'")
10442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet          << FD->getName() << PVD->getName() << PVD->getType().getAsString();
10542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      valid = false;
10642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      continue;
10742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    }
1084ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
10942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    // The only non-const pointer should be out.
11042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    if (!QT->getPointeeType().isConstQualified()) {
11142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      if (mOut == NULL) {
11242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        mOut = PVD;
11342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      } else {
11442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        Context->ReportError(PVD->getLocation(),
11542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "Compute kernel %0() can only have one non-const "
11642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "pointer parameter. Parameters '%1' and '%2' are "
11742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "both non-const.")
11842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            << FD->getName() << mOut->getName() << PVD->getName();
11942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        valid = false;
12042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      }
12142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    } else {
122c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      if (mIns.empty() && mOut == NULL) {
123c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes        mIns.push_back(PVD);
12442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      } else if (mUsrData == NULL) {
12542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        mUsrData = PVD;
12642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      } else {
12742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        Context->ReportError(
12842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            PVD->getLocation(),
12942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            "Unexpected parameter '%0' for compute kernel %1()")
13042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            << PVD->getName() << FD->getName();
13142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        valid = false;
13242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      }
1334ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    }
1344ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  }
1354ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
136c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes  if (mIns.empty() && !mOut) {
137d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet    Context->ReportError(FD->getLocation(),
138d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "Compute kernel %0() must have at least one "
139d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "parameter for in or out")
140d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName();
1414ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines    valid = false;
1424ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines  }
1434ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines
144b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  return valid;
145b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines}
146b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
14742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouilletbool RSExportForEach::validateAndConstructKernelParams(
14842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    RSContext *Context, const clang::FunctionDecl *FD) {
1499ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  slangAssert(Context && FD);
1509ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  bool valid = true;
1519ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  clang::ASTContext &C = Context->getASTContext();
1529ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
1539ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) {
154d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet    Context->ReportError(FD->getLocation(),
155d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "Compute kernel %0() targeting SDK levels "
156d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "%1-%2 may not use pass-by-value with "
157d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "__attribute__((kernel))")
158d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName() << SLANG_MINIMUM_TARGET_API
159d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << (SLANG_JB_MR1_TARGET_API - 1);
1609ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    return false;
1619ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
1629ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
1639ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // Denote that we are indeed a pass-by-value kernel.
1640f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  mIsKernelStyle = true;
165d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet  mHasReturnType = (mResultType != C.VoidTy);
1669ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
1679ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (mResultType->isPointerType()) {
16842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    Context->ReportError(
16942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        FD->getTypeSpecStartLoc(),
17042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        "Compute kernel %0() cannot return a pointer type: '%1'")
171d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName() << mResultType.getAsString();
1729ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    valid = false;
1739ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
1749ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
1759ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // Validate remaining parameter types
1769ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // TODO(all): Add support for LOD/face when we have them
1779ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
17842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  size_t IndexOfFirstIterator = numParams;
17942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  valid |= validateIterationParameters(Context, FD, &IndexOfFirstIterator);
1809ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
18142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  // Validate the non-iterator parameters, which should all be found before the
18242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  // first iterator.
18342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  for (size_t i = 0; i < IndexOfFirstIterator; i++) {
18442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
185c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
186c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes    /*
187c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes     * FIXME: Change this to a test against an actual API version when the
188c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes     *        multi-input feature is officially supported.
189c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes     */
190c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes    if (Context->getTargetAPI() == SLANG_DEVELOPMENT_TARGET_API || i == 0) {
191c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      mIns.push_back(PVD);
19242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    } else {
19342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      Context->ReportError(PVD->getLocation(),
194c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           "Invalid parameter '%0' for compute kernel %1(). "
195c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           "Kernels targeting SDK levels %2-%3 may not use "
196c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           "multiple input parameters.") << PVD->getName() <<
197c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           FD->getName() << SLANG_MINIMUM_TARGET_API <<
198c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                           SLANG_MAXIMUM_TARGET_API;
19942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      valid = false;
20042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    }
20142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    clang::QualType QT = PVD->getType().getCanonicalType();
2029ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    if (QT->isPointerType()) {
203d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(PVD->getLocation(),
204d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "Compute kernel %0() cannot have "
205d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "parameter '%1' of pointer type: '%2'")
206d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName() << PVD->getName() << PVD->getType().getAsString();
2079ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines      valid = false;
2089ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    }
2099ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
2109ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
2119ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // Check that we have at least one allocation to use for dimensions.
212c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes  if (valid && mIns.empty() && !mHasReturnType) {
213d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet    Context->ReportError(FD->getLocation(),
214d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "Compute kernel %0() must have at least one "
215d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "input parameter or a non-void return "
216d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                         "type")
217d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        << FD->getName();
2189ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    valid = false;
2199ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
2209ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
22142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  return valid;
22242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet}
2239ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
22442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet// Search for the optional x and y parameters.  Returns true if valid.   Also
22542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet// sets *IndexOfFirstIterator to the index of the first iterator parameter, or
22642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet// FD->getNumParams() if none are found.
22742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouilletbool RSExportForEach::validateIterationParameters(
22842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    RSContext *Context, const clang::FunctionDecl *FD,
22942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    size_t *IndexOfFirstIterator) {
23042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  slangAssert(IndexOfFirstIterator != NULL);
23142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  slangAssert(mX == NULL && mY == NULL);
23242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  clang::ASTContext &C = Context->getASTContext();
23342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet
23442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  // Find the x and y parameters if present.
23542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  size_t NumParams = FD->getNumParams();
23642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  *IndexOfFirstIterator = NumParams;
23742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  bool valid = true;
23842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet  for (size_t i = 0; i < NumParams; i++) {
23942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
24042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    llvm::StringRef ParamName = PVD->getName();
24142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    if (ParamName.equals("x")) {
24242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      slangAssert(mX == NULL);  // We won't be invoked if two 'x' are present.
24342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      mX = PVD;
24442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      if (mY != NULL) {
24542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        Context->ReportError(PVD->getLocation(),
24642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "In compute kernel %0(), parameter 'x' should "
24742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "be defined before parameter 'y'")
24842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            << FD->getName();
24942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        valid = false;
25042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      }
25142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    } else if (ParamName.equals("y")) {
25242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      slangAssert(mY == NULL);  // We won't be invoked if two 'y' are present.
25342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      mY = PVD;
2549ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    } else {
25542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      // It's neither x nor y.
25642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      if (*IndexOfFirstIterator < NumParams) {
25742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        Context->ReportError(PVD->getLocation(),
25842f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "In compute kernel %0(), parameter '%1' cannot "
25942f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet                             "appear after the 'x' and 'y' parameters")
26042f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet            << FD->getName() << ParamName;
26142f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet        valid = false;
2629ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines      }
26342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      continue;
26442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    }
26542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    // Validate the data type of x and y.
26642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    clang::QualType QT = PVD->getType().getCanonicalType();
267482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet    clang::QualType UT = QT.getUnqualifiedType();
268482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet    if (UT != C.UnsignedIntTy && UT != C.IntTy) {
269482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet      Context->ReportError(PVD->getLocation(),
270482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet                           "Parameter '%0' must be of type 'int' or "
271482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet                           "'unsigned int'. It is of type '%1'")
27242f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet          << ParamName << PVD->getType().getAsString();
27342f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      valid = false;
27442f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    }
27542f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    // If this is the first time we find an iterator, save it.
27642f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet    if (*IndexOfFirstIterator >= NumParams) {
27742f81b2b44205f421c6bd4727ce8c25b0effcb55Jean-Luc Brouillet      *IndexOfFirstIterator = i;
2789ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    }
2799ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
280482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet  // Check that x and y have the same type.
281482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet  if (mX != NULL and mY != NULL) {
282482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet    clang::QualType XType = mX->getType();
283482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet    clang::QualType YType = mY->getType();
284482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet
285482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet    if (XType != YType) {
286482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet      Context->ReportError(mY->getLocation(),
287482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet                           "Parameter 'x' and 'y' must be of the same type. "
288482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet                           "'x' is of type '%0' while 'y' is of type '%1'")
289482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet          << XType.getAsString() << YType.getAsString();
290482caac59574f980cc78b2ac63e01a926da86a96Jean-Luc Brouillet      valid = false;
2919ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    }
2929ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
2930f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  return valid;
2940f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet}
2959ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
2960f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouilletbool RSExportForEach::setSignatureMetadata(RSContext *Context,
2970f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet                                           const clang::FunctionDecl *FD) {
2989ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  mSignatureMetadata = 0;
2990f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  bool valid = true;
3000f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet
3010f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  if (mIsKernelStyle) {
3029ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    slangAssert(mOut == NULL);
3039ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    slangAssert(mUsrData == NULL);
3040f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  } else {
3050f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    slangAssert(!mHasReturnType);
3069ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
3079ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
3080f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // Set up the bitwise metadata encoding for runtime argument passing.
3090f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  // TODO: If this bit field is re-used from C++ code, define the values in a header.
3100f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  const bool HasOut = mOut || mHasReturnType;
311c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes  mSignatureMetadata |= (hasIns() ?       0x01 : 0);
3120f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  mSignatureMetadata |= (HasOut ?         0x02 : 0);
3130f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  mSignatureMetadata |= (mUsrData ?       0x04 : 0);
3140f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  mSignatureMetadata |= (mX ?             0x08 : 0);
3150f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  mSignatureMetadata |= (mY ?             0x10 : 0);
3160f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  mSignatureMetadata |= (mIsKernelStyle ? 0x20 : 0);  // pass-by-value
3170f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet
3180f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
3190f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    // APIs before ICS cannot skip between parameters. It is ok, however, for
3200f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    // them to omit further parameters (i.e. skipping X is ok if you skip Y).
3210f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    if (mSignatureMetadata != 0x1f &&  // In, Out, UsrData, X, Y
3220f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet        mSignatureMetadata != 0x0f &&  // In, Out, UsrData, X
3230f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet        mSignatureMetadata != 0x07 &&  // In, Out, UsrData
3240f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet        mSignatureMetadata != 0x03 &&  // In, Out
3250f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet        mSignatureMetadata != 0x01) {  // In
326d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
327d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "Compute kernel %0() targeting SDK levels "
328d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "%1-%2 may not skip parameters")
3290f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet          << FD->getName() << SLANG_MINIMUM_TARGET_API
3300f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet          << (SLANG_ICS_TARGET_API - 1);
3310f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet      valid = false;
3320f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet    }
3330f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  }
3349ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  return valid;
3359ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines}
3369ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
337593a894650e81be54173106ec266f0311cebebd3Stephen HinesRSExportForEach *RSExportForEach::Create(RSContext *Context,
338593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                         const clang::FunctionDecl *FD) {
339b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  slangAssert(Context && FD);
340593a894650e81be54173106ec266f0311cebebd3Stephen Hines  llvm::StringRef Name = FD->getName();
341b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  RSExportForEach *FE;
342593a894650e81be54173106ec266f0311cebebd3Stephen Hines
343593a894650e81be54173106ec266f0311cebebd3Stephen Hines  slangAssert(!Name.empty() && "Function must have a name");
344593a894650e81be54173106ec266f0311cebebd3Stephen Hines
345c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  FE = new RSExportForEach(Context, Name);
346593a894650e81be54173106ec266f0311cebebd3Stephen Hines
347b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (!FE->validateAndConstructParams(Context, FD)) {
348b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    return NULL;
349593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
350593a894650e81be54173106ec266f0311cebebd3Stephen Hines
351593a894650e81be54173106ec266f0311cebebd3Stephen Hines  clang::ASTContext &Ctx = Context->getASTContext();
352593a894650e81be54173106ec266f0311cebebd3Stephen Hines
353eca0534a31b6185d6ab758f5e97acd7a4cb21e8eJean-Luc Brouillet  std::string Id = CreateDummyName("helper_foreach_param", FE->getName());
354593a894650e81be54173106ec266f0311cebebd3Stephen Hines
355593a894650e81be54173106ec266f0311cebebd3Stephen Hines  // Extract the usrData parameter (if we have one)
356b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FE->mUsrData) {
357b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    const clang::ParmVarDecl *PVD = FE->mUsrData;
358593a894650e81be54173106ec266f0311cebebd3Stephen Hines    clang::QualType QT = PVD->getType().getCanonicalType();
359593a894650e81be54173106ec266f0311cebebd3Stephen Hines    slangAssert(QT->isPointerType() &&
360593a894650e81be54173106ec266f0311cebebd3Stephen Hines                QT->getPointeeType().isConstQualified());
361593a894650e81be54173106ec266f0311cebebd3Stephen Hines
362593a894650e81be54173106ec266f0311cebebd3Stephen Hines    const clang::ASTContext &C = Context->getASTContext();
363593a894650e81be54173106ec266f0311cebebd3Stephen Hines    if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
364593a894650e81be54173106ec266f0311cebebd3Stephen Hines        C.VoidTy) {
365593a894650e81be54173106ec266f0311cebebd3Stephen Hines      // In the case of using const void*, we can't reflect an appopriate
366593a894650e81be54173106ec266f0311cebebd3Stephen Hines      // Java type, so we fall back to just reflecting the ain/aout parameters
367b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      FE->mUsrData = NULL;
368593a894650e81be54173106ec266f0311cebebd3Stephen Hines    } else {
369b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      clang::RecordDecl *RD =
370b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines          clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
371b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    Ctx.getTranslationUnitDecl(),
372b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    clang::SourceLocation(),
373b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    clang::SourceLocation(),
374b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                                    &Ctx.Idents.get(Id));
375b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
376593a894650e81be54173106ec266f0311cebebd3Stephen Hines      clang::FieldDecl *FD =
377593a894650e81be54173106ec266f0311cebebd3Stephen Hines          clang::FieldDecl::Create(Ctx,
378593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   RD,
379593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   clang::SourceLocation(),
380593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   clang::SourceLocation(),
381593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   PVD->getIdentifier(),
382593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   QT->getPointeeType(),
383593a894650e81be54173106ec266f0311cebebd3Stephen Hines                                   NULL,
3841688a3c56851f235866d6870c89ddb20650cc030Shih-wei Liao                                   /* BitWidth = */ NULL,
3851688a3c56851f235866d6870c89ddb20650cc030Shih-wei Liao                                   /* Mutable = */ false,
38643730fe3c839af391efe6bdf56b0479860121924Shih-wei Liao                                   /* HasInit = */ clang::ICIS_NoInit);
387593a894650e81be54173106ec266f0311cebebd3Stephen Hines      RD->addDecl(FD);
388b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      RD->completeDefinition();
389b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
390b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      // Create an export type iff we have a valid usrData type
391b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      clang::QualType T = Ctx.getTagDeclType(RD);
392b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      slangAssert(!T.isNull());
393b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
394b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
395b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
396b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      if (ET == NULL) {
397b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        fprintf(stderr, "Failed to export the function %s. There's at least "
398b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                        "one parameter whose type is not supported by the "
399b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                        "reflection\n", FE->getName().c_str());
400b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines        return NULL;
401b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      }
402b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
403b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
404b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines                  "Parameter packet must be a record");
405b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines
406b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines      FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
407593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
408593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
409593a894650e81be54173106ec266f0311cebebd3Stephen Hines
410c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes  if (FE->hasIns()) {
411c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
412c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes    for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) {
413c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr();
414c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      RSExportType *InExportType = RSExportType::Create(Context, T);
415c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
416c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      if (FE->mIsKernelStyle) {
417c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes        slangAssert(InExportType != NULL);
418c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      }
419c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes
420c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes      FE->mInTypes.push_back(InExportType);
4219ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    }
422b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  }
423593a894650e81be54173106ec266f0311cebebd3Stephen Hines
4240f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet  if (FE->mIsKernelStyle && FE->mHasReturnType) {
4259ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    const clang::Type *T = FE->mResultType.getTypePtr();
4269ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    FE->mOutType = RSExportType::Create(Context, T);
4279ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    slangAssert(FE->mOutType);
4289ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  } else if (FE->mOut) {
429b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr();
430b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines    FE->mOutType = RSExportType::Create(Context, T);
431593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
432593a894650e81be54173106ec266f0311cebebd3Stephen Hines
433b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  return FE;
434593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
435593a894650e81be54173106ec266f0311cebebd3Stephen Hines
436c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen HinesRSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) {
437c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  slangAssert(Context);
438c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  llvm::StringRef Name = "root";
439c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  RSExportForEach *FE = new RSExportForEach(Context, Name);
440c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  FE->mDummyRoot = true;
441c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines  return FE;
442c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines}
443c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines
444c9454afec1649846512993d0ef65a9f868976bb4Chris Wailesbool RSExportForEach::isGraphicsRootRSFunc(unsigned int targetAPI,
4459999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines                                           const clang::FunctionDecl *FD) {
4469ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  if (FD->hasAttr<clang::KernelAttr>()) {
4479ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    return false;
4489ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
4499ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
450593a894650e81be54173106ec266f0311cebebd3Stephen Hines  if (!isRootRSFunc(FD)) {
451593a894650e81be54173106ec266f0311cebebd3Stephen Hines    return false;
452593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
453593a894650e81be54173106ec266f0311cebebd3Stephen Hines
454b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines  if (FD->getNumParams() == 0) {
4559999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    // Graphics root function
4569999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    return true;
457593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
458f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines
4599999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  // Check for legacy graphics root function (with single parameter).
460f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines  if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
461f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines    const clang::QualType &IntType = FD->getASTContext().IntTy;
462ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray    if (FD->getReturnType().getCanonicalType() == IntType) {
4639999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      return true;
464f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines    }
465f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines  }
466f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines
4679999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  return false;
4689999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines}
4699999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
470c9454afec1649846512993d0ef65a9f868976bb4Chris Wailesbool RSExportForEach::isRSForEachFunc(unsigned int targetAPI,
471c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                                      slang::RSContext* Context,
472c9454afec1649846512993d0ef65a9f868976bb4Chris Wailes                                      const clang::FunctionDecl *FD) {
473d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet  slangAssert(Context && FD);
474089cde338148fbb75825aea4539ccdae8211ffefStephen Hines  bool hasKernelAttr = FD->hasAttr<clang::KernelAttr>();
475089cde338148fbb75825aea4539ccdae8211ffefStephen Hines
476089cde338148fbb75825aea4539ccdae8211ffefStephen Hines  if (FD->getStorageClass() == clang::SC_Static) {
477089cde338148fbb75825aea4539ccdae8211ffefStephen Hines    if (hasKernelAttr) {
478d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
479d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "Invalid use of attribute kernel with "
480d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "static function declaration: %0")
481d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName();
482089cde338148fbb75825aea4539ccdae8211ffefStephen Hines    }
483089cde338148fbb75825aea4539ccdae8211ffefStephen Hines    return false;
484089cde338148fbb75825aea4539ccdae8211ffefStephen Hines  }
485089cde338148fbb75825aea4539ccdae8211ffefStephen Hines
4869ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  // Anything tagged as a kernel is definitely used with ForEach.
487089cde338148fbb75825aea4539ccdae8211ffefStephen Hines  if (hasKernelAttr) {
4889ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines    return true;
4899ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines  }
4909ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines
4917b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (isGraphicsRootRSFunc(targetAPI, FD)) {
4929999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    return false;
4939999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  }
4949999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
4957b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  // Check if first parameter is a pointer (which is required for ForEach).
4967b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  unsigned int numParams = FD->getNumParams();
4977b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
4987b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  if (numParams > 0) {
4997b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
5007b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    clang::QualType QT = PVD->getType().getCanonicalType();
5017b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
5027b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (QT->isPointerType()) {
5037b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return true;
5047b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
5057b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines
5067b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // Any non-graphics root() is automatically a ForEach candidate.
5077b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // At this point, however, we know that it is not going to be a valid
5087b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // compute root() function (due to not having a pointer parameter). We
5097b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // still want to return true here, so that we can issue appropriate
5107b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    // diagnostics.
5117b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    if (isRootRSFunc(FD)) {
5127b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines      return true;
5137b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines    }
5149999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  }
5159999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
5167b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines  return false;
517593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
518593a894650e81be54173106ec266f0311cebebd3Stephen Hines
5199207a2e495c8363606861e4f034504ec5c153dabLogan Chienbool
520c9454afec1649846512993d0ef65a9f868976bb4Chris WailesRSExportForEach::validateSpecialFuncDecl(unsigned int targetAPI,
521d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                                         slang::RSContext *Context,
5229207a2e495c8363606861e4f034504ec5c153dabLogan Chien                                         clang::FunctionDecl const *FD) {
523d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet  slangAssert(Context && FD);
524593a894650e81be54173106ec266f0311cebebd3Stephen Hines  bool valid = true;
525593a894650e81be54173106ec266f0311cebebd3Stephen Hines  const clang::ASTContext &C = FD->getASTContext();
5269999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  const clang::QualType &IntType = FD->getASTContext().IntTy;
527593a894650e81be54173106ec266f0311cebebd3Stephen Hines
5289999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines  if (isGraphicsRootRSFunc(targetAPI, FD)) {
5299999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
5309999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      // Legacy graphics root function
5319999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
5329999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      clang::QualType QT = PVD->getType().getCanonicalType();
5339999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      if (QT != IntType) {
534d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet        Context->ReportError(PVD->getLocation(),
535d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                             "invalid parameter type for legacy "
536d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                             "graphics root() function: %0")
537d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet            << PVD->getType();
538593a894650e81be54173106ec266f0311cebebd3Stephen Hines        valid = false;
539593a894650e81be54173106ec266f0311cebebd3Stephen Hines      }
5409999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    }
5419999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines
5429999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines    // Graphics root function, so verify that it returns an int
543ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray    if (FD->getReturnType().getCanonicalType() != IntType) {
544d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
545d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "root() is required to return "
546d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "an int for graphics usage");
5479999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines      valid = false;
548593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
549688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines  } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) {
550593a894650e81be54173106ec266f0311cebebd3Stephen Hines    if (FD->getNumParams() != 0) {
551d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
552d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "%0(void) is required to have no "
553d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "parameters")
554d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName();
555593a894650e81be54173106ec266f0311cebebd3Stephen Hines      valid = false;
556593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
557593a894650e81be54173106ec266f0311cebebd3Stephen Hines
558ee4016d1247d3fbe50822de279d3da273d8aef4cTim Murray    if (FD->getReturnType().getCanonicalType() != C.VoidTy) {
559d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet      Context->ReportError(FD->getLocation(),
560d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "%0(void) is required to have a void "
561d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet                           "return type")
562d3f7527b105d21f1c69d3473eb88a762f2c3ab5aJean-Luc Brouillet          << FD->getName();
563593a894650e81be54173106ec266f0311cebebd3Stephen Hines      valid = false;
564593a894650e81be54173106ec266f0311cebebd3Stephen Hines    }
565593a894650e81be54173106ec266f0311cebebd3Stephen Hines  } else {
566688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines    slangAssert(false && "must be called on root, init or .rs.dtor function!");
567593a894650e81be54173106ec266f0311cebebd3Stephen Hines  }
568593a894650e81be54173106ec266f0311cebebd3Stephen Hines
569593a894650e81be54173106ec266f0311cebebd3Stephen Hines  return valid;
570593a894650e81be54173106ec266f0311cebebd3Stephen Hines}
571593a894650e81be54173106ec266f0311cebebd3Stephen Hines
572593a894650e81be54173106ec266f0311cebebd3Stephen Hines}  // namespace slang
573