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