146e146e0cef555379699f06edb3b2d9673978703David Gross/*
246e146e0cef555379699f06edb3b2d9673978703David Gross * Copyright 2015, The Android Open Source Project
346e146e0cef555379699f06edb3b2d9673978703David Gross *
446e146e0cef555379699f06edb3b2d9673978703David Gross * Licensed under the Apache License, Version 2.0 (the "License");
546e146e0cef555379699f06edb3b2d9673978703David Gross * you may not use this file except in compliance with the License.
646e146e0cef555379699f06edb3b2d9673978703David Gross * You may obtain a copy of the License at
746e146e0cef555379699f06edb3b2d9673978703David Gross *
846e146e0cef555379699f06edb3b2d9673978703David Gross *     http://www.apache.org/licenses/LICENSE-2.0
946e146e0cef555379699f06edb3b2d9673978703David Gross *
1046e146e0cef555379699f06edb3b2d9673978703David Gross * Unless required by applicable law or agreed to in writing, software
1146e146e0cef555379699f06edb3b2d9673978703David Gross * distributed under the License is distributed on an "AS IS" BASIS,
1246e146e0cef555379699f06edb3b2d9673978703David Gross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1346e146e0cef555379699f06edb3b2d9673978703David Gross * See the License for the specific language governing permissions and
1446e146e0cef555379699f06edb3b2d9673978703David Gross * limitations under the License.
1546e146e0cef555379699f06edb3b2d9673978703David Gross */
1646e146e0cef555379699f06edb3b2d9673978703David Gross
1746e146e0cef555379699f06edb3b2d9673978703David Gross#include "slang_rs_special_kernel_param.h"
1846e146e0cef555379699f06edb3b2d9673978703David Gross
1946e146e0cef555379699f06edb3b2d9673978703David Gross#include "clang/AST/ASTContext.h"
2046e146e0cef555379699f06edb3b2d9673978703David Gross
2146e146e0cef555379699f06edb3b2d9673978703David Gross#include "bcinfo/MetadataExtractor.h"
2246e146e0cef555379699f06edb3b2d9673978703David Gross
2346e146e0cef555379699f06edb3b2d9673978703David Gross#include "slang_assert.h"
2446e146e0cef555379699f06edb3b2d9673978703David Gross#include "slang_rs_context.h"
2546e146e0cef555379699f06edb3b2d9673978703David Gross#include "slang_version.h"
2646e146e0cef555379699f06edb3b2d9673978703David Gross
2746e146e0cef555379699f06edb3b2d9673978703David Grossnamespace {
2846e146e0cef555379699f06edb3b2d9673978703David Gross
2946e146e0cef555379699f06edb3b2d9673978703David Grossenum SpecialParameterKind {
3046e146e0cef555379699f06edb3b2d9673978703David Gross  SPK_LOCATION, // 'int' or 'unsigned int'
3146e146e0cef555379699f06edb3b2d9673978703David Gross  SPK_CONTEXT,  // rs_kernel_context
3246e146e0cef555379699f06edb3b2d9673978703David Gross};
3346e146e0cef555379699f06edb3b2d9673978703David Gross
3446e146e0cef555379699f06edb3b2d9673978703David Grossstruct SpecialParameter {
3546e146e0cef555379699f06edb3b2d9673978703David Gross  const char *name;
3646e146e0cef555379699f06edb3b2d9673978703David Gross  bcinfo::MetadataSignatureBitval bitval;
3746e146e0cef555379699f06edb3b2d9673978703David Gross  SpecialParameterKind kind;
3846e146e0cef555379699f06edb3b2d9673978703David Gross  SlangTargetAPI minAPI;
3946e146e0cef555379699f06edb3b2d9673978703David Gross};
4046e146e0cef555379699f06edb3b2d9673978703David Gross
4146e146e0cef555379699f06edb3b2d9673978703David Gross// Table entries are in the order parameters must occur in a kernel parameter list.
4246e146e0cef555379699f06edb3b2d9673978703David Grossconst SpecialParameter specialParameterTable[] = {
4346e146e0cef555379699f06edb3b2d9673978703David Gross  { "context", bcinfo::MD_SIG_Ctxt, SPK_CONTEXT, SLANG_M_TARGET_API },
4446e146e0cef555379699f06edb3b2d9673978703David Gross  { "x", bcinfo::MD_SIG_X, SPK_LOCATION, SLANG_MINIMUM_TARGET_API },
4546e146e0cef555379699f06edb3b2d9673978703David Gross  { "y", bcinfo::MD_SIG_Y, SPK_LOCATION, SLANG_MINIMUM_TARGET_API },
4646e146e0cef555379699f06edb3b2d9673978703David Gross  { "z", bcinfo::MD_SIG_Z, SPK_LOCATION, SLANG_M_TARGET_API },
4746e146e0cef555379699f06edb3b2d9673978703David Gross  { nullptr, bcinfo::MD_SIG_None, SPK_LOCATION, SLANG_MINIMUM_TARGET_API }, // marks end of table
4846e146e0cef555379699f06edb3b2d9673978703David Gross};
4946e146e0cef555379699f06edb3b2d9673978703David Gross
5046e146e0cef555379699f06edb3b2d9673978703David Gross// If the specified name matches the name of an entry in
5146e146e0cef555379699f06edb3b2d9673978703David Gross// specialParameterTable, return the corresponding table index.
5246e146e0cef555379699f06edb3b2d9673978703David Gross// Return -1 if not found.
5346e146e0cef555379699f06edb3b2d9673978703David Grossint lookupSpecialKernelParameter(const llvm::StringRef name) {
5446e146e0cef555379699f06edb3b2d9673978703David Gross  for (int i = 0; specialParameterTable[i].name != nullptr; ++i) {
5546e146e0cef555379699f06edb3b2d9673978703David Gross    if (name.equals(specialParameterTable[i].name)) {
5646e146e0cef555379699f06edb3b2d9673978703David Gross      return i;
5746e146e0cef555379699f06edb3b2d9673978703David Gross    }
5846e146e0cef555379699f06edb3b2d9673978703David Gross  }
5946e146e0cef555379699f06edb3b2d9673978703David Gross
6046e146e0cef555379699f06edb3b2d9673978703David Gross  return -1;
6146e146e0cef555379699f06edb3b2d9673978703David Gross}
6246e146e0cef555379699f06edb3b2d9673978703David Gross
6346e146e0cef555379699f06edb3b2d9673978703David Gross} // end anonymous namespace
6446e146e0cef555379699f06edb3b2d9673978703David Gross
6546e146e0cef555379699f06edb3b2d9673978703David Grossnamespace slang {
6646e146e0cef555379699f06edb3b2d9673978703David Gross
6746e146e0cef555379699f06edb3b2d9673978703David Gross// Is the specified name the name of an entry in the specialParameterTable?
6846e146e0cef555379699f06edb3b2d9673978703David Grossbool isSpecialKernelParameter(const llvm::StringRef Name) {
6946e146e0cef555379699f06edb3b2d9673978703David Gross  return lookupSpecialKernelParameter(Name) >= 0;
7046e146e0cef555379699f06edb3b2d9673978703David Gross}
7146e146e0cef555379699f06edb3b2d9673978703David Gross
7246e146e0cef555379699f06edb3b2d9673978703David Gross// Return a comma-separated list of names in specialParameterTable
7346e146e0cef555379699f06edb3b2d9673978703David Gross// that are available at the specified API level.
7446e146e0cef555379699f06edb3b2d9673978703David Grossstd::string listSpecialKernelParameters(unsigned int api) {
7546e146e0cef555379699f06edb3b2d9673978703David Gross  std::string ret;
7646e146e0cef555379699f06edb3b2d9673978703David Gross  bool first = true;
7746e146e0cef555379699f06edb3b2d9673978703David Gross  for (int i = 0; specialParameterTable[i].name != nullptr; ++i) {
7846e146e0cef555379699f06edb3b2d9673978703David Gross    if (specialParameterTable[i].minAPI > api)
7946e146e0cef555379699f06edb3b2d9673978703David Gross      continue;
8046e146e0cef555379699f06edb3b2d9673978703David Gross    if (first)
8146e146e0cef555379699f06edb3b2d9673978703David Gross      first = false;
8246e146e0cef555379699f06edb3b2d9673978703David Gross    else
8346e146e0cef555379699f06edb3b2d9673978703David Gross      ret += ", ";
8446e146e0cef555379699f06edb3b2d9673978703David Gross    ret += "'";
8546e146e0cef555379699f06edb3b2d9673978703David Gross    ret += specialParameterTable[i].name;
8646e146e0cef555379699f06edb3b2d9673978703David Gross    ret += "'";
8746e146e0cef555379699f06edb3b2d9673978703David Gross  }
8846e146e0cef555379699f06edb3b2d9673978703David Gross  return ret;
8946e146e0cef555379699f06edb3b2d9673978703David Gross}
9046e146e0cef555379699f06edb3b2d9673978703David Gross
9146e146e0cef555379699f06edb3b2d9673978703David Gross// Process the optional special parameters:
9246e146e0cef555379699f06edb3b2d9673978703David Gross// - Sets *IndexOfFirstSpecialParameter to the index of the first special parameter, or
9346e146e0cef555379699f06edb3b2d9673978703David Gross//     FD->getNumParams() if none are found.
9446e146e0cef555379699f06edb3b2d9673978703David Gross// - Add bits to *SignatureMetadata for the found special parameters.
9546e146e0cef555379699f06edb3b2d9673978703David Gross// Returns true if no errors.
9646e146e0cef555379699f06edb3b2d9673978703David Grossbool processSpecialKernelParameters(
9746e146e0cef555379699f06edb3b2d9673978703David Gross  slang::RSContext *Context,
9846e146e0cef555379699f06edb3b2d9673978703David Gross  std::function<std::string ()> DiagnosticDescription,
9946e146e0cef555379699f06edb3b2d9673978703David Gross  const clang::FunctionDecl *FD,
10046e146e0cef555379699f06edb3b2d9673978703David Gross  size_t *IndexOfFirstSpecialParameter,
10146e146e0cef555379699f06edb3b2d9673978703David Gross  unsigned int *SignatureMetadata) {
10246e146e0cef555379699f06edb3b2d9673978703David Gross  slangAssert(IndexOfFirstSpecialParameter != nullptr);
10346e146e0cef555379699f06edb3b2d9673978703David Gross  slangAssert(SignatureMetadata != nullptr);
10446e146e0cef555379699f06edb3b2d9673978703David Gross  slangAssert(*SignatureMetadata == 0);
10546e146e0cef555379699f06edb3b2d9673978703David Gross  clang::ASTContext &C = Context->getASTContext();
10646e146e0cef555379699f06edb3b2d9673978703David Gross
10746e146e0cef555379699f06edb3b2d9673978703David Gross  // Find all special parameters if present.
10846e146e0cef555379699f06edb3b2d9673978703David Gross  int LastSpecialParameterIdx = -1; // index into specialParameterTable
10946e146e0cef555379699f06edb3b2d9673978703David Gross  int FirstLocationSpecialParameterIdx = -1; // index into specialParameterTable
11046e146e0cef555379699f06edb3b2d9673978703David Gross  clang::QualType FirstLocationSpecialParameterType;
11146e146e0cef555379699f06edb3b2d9673978703David Gross  size_t NumParams = FD->getNumParams();
11246e146e0cef555379699f06edb3b2d9673978703David Gross  *IndexOfFirstSpecialParameter = NumParams;
11346e146e0cef555379699f06edb3b2d9673978703David Gross  bool valid = true;
11446e146e0cef555379699f06edb3b2d9673978703David Gross  for (size_t i = 0; i < NumParams; i++) {
11546e146e0cef555379699f06edb3b2d9673978703David Gross    const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
11646e146e0cef555379699f06edb3b2d9673978703David Gross    const llvm::StringRef ParamName = PVD->getName();
11746e146e0cef555379699f06edb3b2d9673978703David Gross    const clang::QualType Type = PVD->getType();
11846e146e0cef555379699f06edb3b2d9673978703David Gross    const clang::QualType QT = Type.getCanonicalType();
11946e146e0cef555379699f06edb3b2d9673978703David Gross    const clang::QualType UT = QT.getUnqualifiedType();
12046e146e0cef555379699f06edb3b2d9673978703David Gross    int SpecialParameterIdx = lookupSpecialKernelParameter(ParamName);
12146e146e0cef555379699f06edb3b2d9673978703David Gross
12246e146e0cef555379699f06edb3b2d9673978703David Gross    static const char KernelContextUnqualifiedTypeName[] =
12346e146e0cef555379699f06edb3b2d9673978703David Gross        "const struct rs_kernel_context_t *";
12446e146e0cef555379699f06edb3b2d9673978703David Gross    static const char KernelContextTypeName[] = "rs_kernel_context";
12546e146e0cef555379699f06edb3b2d9673978703David Gross
12646e146e0cef555379699f06edb3b2d9673978703David Gross    // If the type is rs_context, it should have been named "context" and classified
12746e146e0cef555379699f06edb3b2d9673978703David Gross    // as a special parameter.
12846e146e0cef555379699f06edb3b2d9673978703David Gross    if (SpecialParameterIdx < 0 && UT.getAsString() == KernelContextUnqualifiedTypeName) {
12946e146e0cef555379699f06edb3b2d9673978703David Gross      Context->ReportError(
13046e146e0cef555379699f06edb3b2d9673978703David Gross          PVD->getLocation(),
13146e146e0cef555379699f06edb3b2d9673978703David Gross          "The special parameter of type '%0' must be called "
13246e146e0cef555379699f06edb3b2d9673978703David Gross          "'context' instead of '%1'.")
13346e146e0cef555379699f06edb3b2d9673978703David Gross          << KernelContextTypeName << ParamName;
13446e146e0cef555379699f06edb3b2d9673978703David Gross      SpecialParameterIdx = lookupSpecialKernelParameter("context");
13546e146e0cef555379699f06edb3b2d9673978703David Gross    }
13646e146e0cef555379699f06edb3b2d9673978703David Gross
13746e146e0cef555379699f06edb3b2d9673978703David Gross    // If it's not a special parameter, check that it appears before any special
13846e146e0cef555379699f06edb3b2d9673978703David Gross    // parameter.
13946e146e0cef555379699f06edb3b2d9673978703David Gross    if (SpecialParameterIdx < 0) {
14046e146e0cef555379699f06edb3b2d9673978703David Gross      if (*IndexOfFirstSpecialParameter < NumParams) {
14146e146e0cef555379699f06edb3b2d9673978703David Gross        Context->ReportError(PVD->getLocation(),
14246e146e0cef555379699f06edb3b2d9673978703David Gross                             "In %0, parameter '%1' cannot "
14346e146e0cef555379699f06edb3b2d9673978703David Gross                             "appear after any of the special parameters (%2).")
14446e146e0cef555379699f06edb3b2d9673978703David Gross            << DiagnosticDescription()
14546e146e0cef555379699f06edb3b2d9673978703David Gross            << ParamName
14646e146e0cef555379699f06edb3b2d9673978703David Gross            << listSpecialKernelParameters(Context->getTargetAPI());
14746e146e0cef555379699f06edb3b2d9673978703David Gross        valid = false;
14846e146e0cef555379699f06edb3b2d9673978703David Gross      }
14946e146e0cef555379699f06edb3b2d9673978703David Gross      continue;
15046e146e0cef555379699f06edb3b2d9673978703David Gross    }
15146e146e0cef555379699f06edb3b2d9673978703David Gross
15246e146e0cef555379699f06edb3b2d9673978703David Gross    const SpecialParameter &SP = specialParameterTable[SpecialParameterIdx];
15346e146e0cef555379699f06edb3b2d9673978703David Gross
15446e146e0cef555379699f06edb3b2d9673978703David Gross    // Verify that this special parameter is OK for the current API level.
15546e146e0cef555379699f06edb3b2d9673978703David Gross    if (Context->getTargetAPI() < SP.minAPI) {
15646e146e0cef555379699f06edb3b2d9673978703David Gross      Context->ReportError(PVD->getLocation(),
15746e146e0cef555379699f06edb3b2d9673978703David Gross                           "%0 targeting SDK levels "
15846e146e0cef555379699f06edb3b2d9673978703David Gross                           "%1-%2 may not use special parameter '%3'.")
15946e146e0cef555379699f06edb3b2d9673978703David Gross          << DiagnosticDescription()
16046e146e0cef555379699f06edb3b2d9673978703David Gross          << SLANG_MINIMUM_TARGET_API << (SP.minAPI - 1)
16146e146e0cef555379699f06edb3b2d9673978703David Gross          << SP.name;
16246e146e0cef555379699f06edb3b2d9673978703David Gross      valid = false;
16346e146e0cef555379699f06edb3b2d9673978703David Gross    }
16446e146e0cef555379699f06edb3b2d9673978703David Gross
16546e146e0cef555379699f06edb3b2d9673978703David Gross    // Check that the order of the special parameters is correct.
16646e146e0cef555379699f06edb3b2d9673978703David Gross    if (SpecialParameterIdx < LastSpecialParameterIdx) {
16746e146e0cef555379699f06edb3b2d9673978703David Gross      Context->ReportError(
16846e146e0cef555379699f06edb3b2d9673978703David Gross          PVD->getLocation(),
16946e146e0cef555379699f06edb3b2d9673978703David Gross          "In %0, special parameter '%1' must "
17046e146e0cef555379699f06edb3b2d9673978703David Gross          "be defined before special parameter '%2'.")
17146e146e0cef555379699f06edb3b2d9673978703David Gross          << DiagnosticDescription()
17246e146e0cef555379699f06edb3b2d9673978703David Gross          << SP.name
17346e146e0cef555379699f06edb3b2d9673978703David Gross          << specialParameterTable[LastSpecialParameterIdx].name;
17446e146e0cef555379699f06edb3b2d9673978703David Gross      valid = false;
17546e146e0cef555379699f06edb3b2d9673978703David Gross    }
17646e146e0cef555379699f06edb3b2d9673978703David Gross
17746e146e0cef555379699f06edb3b2d9673978703David Gross    // Validate the data type of the special parameter.
17846e146e0cef555379699f06edb3b2d9673978703David Gross    switch (SP.kind) {
17946e146e0cef555379699f06edb3b2d9673978703David Gross    case SPK_LOCATION: {
18046e146e0cef555379699f06edb3b2d9673978703David Gross      // Location special parameters can only be int or uint.
18146e146e0cef555379699f06edb3b2d9673978703David Gross      if (UT != C.UnsignedIntTy && UT != C.IntTy) {
18246e146e0cef555379699f06edb3b2d9673978703David Gross        Context->ReportError(PVD->getLocation(),
18346e146e0cef555379699f06edb3b2d9673978703David Gross                             "Special parameter '%0' must be of type 'int' or "
18446e146e0cef555379699f06edb3b2d9673978703David Gross                             "'unsigned int'. It is of type '%1'.")
18546e146e0cef555379699f06edb3b2d9673978703David Gross            << ParamName << Type.getAsString();
18646e146e0cef555379699f06edb3b2d9673978703David Gross        valid = false;
18746e146e0cef555379699f06edb3b2d9673978703David Gross      }
18846e146e0cef555379699f06edb3b2d9673978703David Gross
18946e146e0cef555379699f06edb3b2d9673978703David Gross      // Ensure that all location special parameters have the same type.
19046e146e0cef555379699f06edb3b2d9673978703David Gross      if (FirstLocationSpecialParameterIdx >= 0) {
19146e146e0cef555379699f06edb3b2d9673978703David Gross        if (Type != FirstLocationSpecialParameterType) {
19246e146e0cef555379699f06edb3b2d9673978703David Gross          Context->ReportError(
19346e146e0cef555379699f06edb3b2d9673978703David Gross              PVD->getLocation(),
19446e146e0cef555379699f06edb3b2d9673978703David Gross              "Special parameters '%0' and '%1' must be of the same type. "
19546e146e0cef555379699f06edb3b2d9673978703David Gross              "'%0' is of type '%2' while '%1' is of type '%3'.")
19646e146e0cef555379699f06edb3b2d9673978703David Gross              << specialParameterTable[FirstLocationSpecialParameterIdx].name
19746e146e0cef555379699f06edb3b2d9673978703David Gross              << SP.name << FirstLocationSpecialParameterType.getAsString()
19846e146e0cef555379699f06edb3b2d9673978703David Gross              << Type.getAsString();
19946e146e0cef555379699f06edb3b2d9673978703David Gross          valid = false;
20046e146e0cef555379699f06edb3b2d9673978703David Gross        }
20146e146e0cef555379699f06edb3b2d9673978703David Gross      } else {
20246e146e0cef555379699f06edb3b2d9673978703David Gross        FirstLocationSpecialParameterIdx = SpecialParameterIdx;
20346e146e0cef555379699f06edb3b2d9673978703David Gross        FirstLocationSpecialParameterType = Type;
20446e146e0cef555379699f06edb3b2d9673978703David Gross      }
20546e146e0cef555379699f06edb3b2d9673978703David Gross    } break;
20646e146e0cef555379699f06edb3b2d9673978703David Gross    case SPK_CONTEXT: {
20746e146e0cef555379699f06edb3b2d9673978703David Gross      // Check that variables named "context" are of type rs_context.
20846e146e0cef555379699f06edb3b2d9673978703David Gross      if (UT.getAsString() != KernelContextUnqualifiedTypeName) {
20946e146e0cef555379699f06edb3b2d9673978703David Gross        Context->ReportError(PVD->getLocation(),
21046e146e0cef555379699f06edb3b2d9673978703David Gross                             "Special parameter '%0' must be of type '%1'. "
21146e146e0cef555379699f06edb3b2d9673978703David Gross                             "It is of type '%2'.")
21246e146e0cef555379699f06edb3b2d9673978703David Gross            << ParamName << KernelContextTypeName
21346e146e0cef555379699f06edb3b2d9673978703David Gross            << Type.getAsString();
21446e146e0cef555379699f06edb3b2d9673978703David Gross        valid = false;
21546e146e0cef555379699f06edb3b2d9673978703David Gross      }
21646e146e0cef555379699f06edb3b2d9673978703David Gross    } break;
21746e146e0cef555379699f06edb3b2d9673978703David Gross    default:
21846e146e0cef555379699f06edb3b2d9673978703David Gross      slangAssert(!"Unexpected special parameter type");
21946e146e0cef555379699f06edb3b2d9673978703David Gross    }
22046e146e0cef555379699f06edb3b2d9673978703David Gross
22146e146e0cef555379699f06edb3b2d9673978703David Gross    // We should not be invoked if two parameters of the same name are present.
22246e146e0cef555379699f06edb3b2d9673978703David Gross    slangAssert(!(*SignatureMetadata & SP.bitval));
22346e146e0cef555379699f06edb3b2d9673978703David Gross    *SignatureMetadata |= SP.bitval;
22446e146e0cef555379699f06edb3b2d9673978703David Gross
22546e146e0cef555379699f06edb3b2d9673978703David Gross    LastSpecialParameterIdx = SpecialParameterIdx;
22646e146e0cef555379699f06edb3b2d9673978703David Gross    // If this is the first time we find a special parameter, save it.
22746e146e0cef555379699f06edb3b2d9673978703David Gross    if (*IndexOfFirstSpecialParameter >= NumParams) {
22846e146e0cef555379699f06edb3b2d9673978703David Gross      *IndexOfFirstSpecialParameter = i;
22946e146e0cef555379699f06edb3b2d9673978703David Gross    }
23046e146e0cef555379699f06edb3b2d9673978703David Gross  }
23146e146e0cef555379699f06edb3b2d9673978703David Gross  return valid;
23246e146e0cef555379699f06edb3b2d9673978703David Gross}
23346e146e0cef555379699f06edb3b2d9673978703David Gross
23446e146e0cef555379699f06edb3b2d9673978703David Gross} // namespace slang
235