slang_rs_export_foreach.cpp revision 0f2a2397df53a1bb74609abe3c27719bc7e3c328
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 Hinesnamespace { 36b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 379207a2e495c8363606861e4f034504ec5c153dabLogan Chienstatic void ReportNameError(clang::DiagnosticsEngine *DiagEngine, 389207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::ParmVarDecl const *PVD) { 399207a2e495c8363606861e4f034504ec5c153dabLogan Chien slangAssert(DiagEngine && PVD); 409207a2e495c8363606861e4f034504ec5c153dabLogan Chien const clang::SourceManager &SM = DiagEngine->getSourceManager(); 419207a2e495c8363606861e4f034504ec5c153dabLogan Chien 429207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->Report( 439207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::FullSourceLoc(PVD->getLocation(), SM), 449207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 459207a2e495c8363606861e4f034504ec5c153dabLogan Chien "Duplicate parameter entry " 469207a2e495c8363606861e4f034504ec5c153dabLogan Chien "(by position/name): '%0'")) 479207a2e495c8363606861e4f034504ec5c153dabLogan Chien << PVD->getName(); 48b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines return; 49b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines} 50b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 51b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines} // namespace 52b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 539ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 54b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines// This function takes care of additional validation and construction of 55b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines// parameters related to forEach_* reflection. 56b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hinesbool RSExportForEach::validateAndConstructParams( 57b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines RSContext *Context, const clang::FunctionDecl *FD) { 58b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines slangAssert(Context && FD); 59b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines bool valid = true; 609207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics(); 61b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 62b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines numParams = FD->getNumParams(); 63b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 647b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines if (Context->getTargetAPI() < SLANG_JB_TARGET_API) { 657b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines if (!isRootRSFunc(FD)) { 667b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines DiagEngine->Report( 677b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines clang::FullSourceLoc(FD->getLocation(), DiagEngine->getSourceManager()), 687b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 697b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "Non-root compute kernel %0() is " 707b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "not supported in SDK levels %1-%2")) 717b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines << FD->getName() 727b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines << SLANG_MINIMUM_TARGET_API 737b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines << (SLANG_JB_TARGET_API - 1); 747b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines return false; 757b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines } 767b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines } 777b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines 789ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mResultType = FD->getResultType().getCanonicalType(); 790f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet // Compute kernel functions are defined differently when the 800f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet // "__attribute__((kernel))" is set. 819ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (FD->hasAttr<clang::KernelAttr>()) { 820f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet valid |= validateAndConstructKernelParams(Context, FD); 830f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet } else { 840f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet valid |= validateAndConstructOldStyleParams(Context, FD); 859ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 860f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet valid |= setSignatureMetadata(Context, FD); 870f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet return valid; 880f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet} 899ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 900f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouilletbool RSExportForEach::validateAndConstructOldStyleParams(RSContext *Context, 910f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet const clang::FunctionDecl *FD) { 920f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet slangAssert(Context && FD); 939ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // If numParams is 0, we already marked this as a graphics root(). 949ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines slangAssert(numParams > 0); 959ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 960f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet bool valid = true; 970f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics(); 980f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet 990f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet // Compute kernel functions of this style are required to return a void type. 1000f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet clang::ASTContext &C = Context->getASTContext(); 1019ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (mResultType != C.VoidTy) { 1029207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->Report( 1039207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::FullSourceLoc(FD->getLocation(), DiagEngine->getSourceManager()), 1049207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 1057b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "Compute kernel %0() is required to return a " 1067b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "void type")) << FD->getName(); 107b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines valid = false; 108b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 109b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 110b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines // Validate remaining parameter types 111b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines // TODO(all): Add support for LOD/face when we have them 112b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 1134ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines size_t i = 0; 1144ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines const clang::ParmVarDecl *PVD = FD->getParamDecl(i); 1154ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines clang::QualType QT = PVD->getType().getCanonicalType(); 1164ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines 1174ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines // Check for const T1 *in 1184ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines if (QT->isPointerType() && QT->getPointeeType().isConstQualified()) { 1194ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines mIn = PVD; 1204ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines i++; // advance parameter pointer 1214ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines } 1224ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines 1234ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines // Check for T2 *out 1244ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines if (i < numParams) { 1254ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines PVD = FD->getParamDecl(i); 1264ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines QT = PVD->getType().getCanonicalType(); 1274ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines if (QT->isPointerType() && !QT->getPointeeType().isConstQualified()) { 1284ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines mOut = PVD; 1294ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines i++; // advance parameter pointer 1304ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines } 1314ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines } 1324ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines 1334ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines if (!mIn && !mOut) { 1349207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->Report( 1359207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::FullSourceLoc(FD->getLocation(), 1369207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getSourceManager()), 1379207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 1387b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "Compute kernel %0() must have at least one " 1397b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "parameter for in or out")) << FD->getName(); 1404ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines valid = false; 1414ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines } 1424ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines 1434ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines // Check for T3 *usrData 1444ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines if (i < numParams) { 1454ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines PVD = FD->getParamDecl(i); 1464ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines QT = PVD->getType().getCanonicalType(); 1474ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines if (QT->isPointerType() && QT->getPointeeType().isConstQualified()) { 1484ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines mUsrData = PVD; 1494ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines i++; // advance parameter pointer 1504ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines } 1514ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines } 1524ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines 1534ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines while (i < numParams) { 1544ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines PVD = FD->getParamDecl(i); 1554ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines QT = PVD->getType().getCanonicalType(); 1564ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines 1574ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines if (QT.getUnqualifiedType() != C.UnsignedIntTy) { 1589207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->Report( 1599207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::FullSourceLoc(PVD->getLocation(), 1609207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getSourceManager()), 1619207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 1627b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "Unexpected kernel %0() parameter '%1' " 1637b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "of type '%2'")) 1647b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines << FD->getName() << PVD->getName() << PVD->getType().getAsString(); 1654ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines valid = false; 1664ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines } else { 1674ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines llvm::StringRef ParamName = PVD->getName(); 168b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines if (ParamName.equals("x")) { 169b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines if (mX) { 1709207a2e495c8363606861e4f034504ec5c153dabLogan Chien ReportNameError(DiagEngine, PVD); 171b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines valid = false; 1724ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines } else if (mY) { 1734ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines // Can't go back to X after skipping Y 1749207a2e495c8363606861e4f034504ec5c153dabLogan Chien ReportNameError(DiagEngine, PVD); 1754ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines valid = false; 176b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } else { 177b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines mX = PVD; 178b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 179b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } else if (ParamName.equals("y")) { 180b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines if (mY) { 1819207a2e495c8363606861e4f034504ec5c153dabLogan Chien ReportNameError(DiagEngine, PVD); 182b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines valid = false; 183b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } else { 184b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines mY = PVD; 185b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 186b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } else { 1874ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines if (!mX && !mY) { 188b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines mX = PVD; 189b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } else if (!mY) { 190b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines mY = PVD; 191b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } else { 1929207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->Report( 1939207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::FullSourceLoc(PVD->getLocation(), 1949207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getSourceManager()), 1959207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 1967b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "Unexpected kernel %0() parameter '%1' " 1977b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines "of type '%2'")) 1987b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines << FD->getName() << PVD->getName() << PVD->getType().getAsString(); 199b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines valid = false; 200b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 201b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 202b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 2034ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines 2044ccf75e55fe460a8daa49247d7e5a797329c71a6Stephen Hines i++; 205b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 206b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 207b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines return valid; 208b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines} 209b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 2109ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2119ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hinesbool RSExportForEach::validateAndConstructKernelParams(RSContext *Context, 2129ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines const clang::FunctionDecl *FD) { 2139ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines slangAssert(Context && FD); 2149ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines bool valid = true; 2159ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::ASTContext &C = Context->getASTContext(); 2169ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics(); 2179ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2189ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) { 2199ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->Report( 2209ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::FullSourceLoc(FD->getLocation(), 2219ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getSourceManager()), 2229ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 2239ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "Compute kernel %0() targeting SDK levels " 2249ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "%1-%2 may not use pass-by-value with " 2259ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "__attribute__((kernel))")) 2269ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines << FD->getName() << SLANG_MINIMUM_TARGET_API 2279ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines << (SLANG_JB_MR1_TARGET_API - 1); 2289ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines return false; 2299ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 2309ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2319ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // Denote that we are indeed a pass-by-value kernel. 2320f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mIsKernelStyle = true; 2339ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2349ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (mResultType != C.VoidTy) { 2350f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mHasReturnType = true; 2369ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 2379ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2389ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (mResultType->isPointerType()) { 2399ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->Report( 2409ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::FullSourceLoc(FD->getTypeSpecStartLoc(), 2419ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getSourceManager()), 2429ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 2439ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "Compute kernel %0() cannot return a " 2449ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "pointer type: '%1'")) 2459ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines << FD->getName() << mResultType.getAsString(); 2469ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines valid = false; 2479ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 2489ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2499ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // Validate remaining parameter types 2509ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // TODO(all): Add support for LOD/face when we have them 2519ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2529ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines size_t i = 0; 2539ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines const clang::ParmVarDecl *PVD = NULL; 2549ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::QualType QT; 2559ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2569ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (i < numParams) { 2579ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines PVD = FD->getParamDecl(i); 2589ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines QT = PVD->getType().getCanonicalType(); 2599ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2609ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (QT->isPointerType()) { 2619ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->Report( 2629ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::FullSourceLoc(PVD->getLocation(), 2639ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getSourceManager()), 2649ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 2659ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "Compute kernel %0() cannot have " 2669ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "parameter '%1' of pointer type: '%2'")) 2679ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines << FD->getName() << PVD->getName() << PVD->getType().getAsString(); 2689ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines valid = false; 2699ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else if (QT.getUnqualifiedType() == C.UnsignedIntTy) { 2709ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // First parameter is either input or x, y (iff it is uint32_t). 2719ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines llvm::StringRef ParamName = PVD->getName(); 2729ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (ParamName.equals("x")) { 2739ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mX = PVD; 2749ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else if (ParamName.equals("y")) { 2759ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mY = PVD; 2769ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else { 2779ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mIn = PVD; 2789ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 2799ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else { 2809ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mIn = PVD; 2819ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 2829ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2839ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines i++; // advance parameter pointer 2849ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 2859ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2869ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // Check that we have at least one allocation to use for dimensions. 2870f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet if (valid && !mIn && !mHasReturnType) { 2889ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->Report( 2899ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::FullSourceLoc(FD->getLocation(), 2909ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getSourceManager()), 2919ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 2929ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "Compute kernel %0() must have at least one " 2939ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "input parameter or a non-void return " 2949ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "type")) << FD->getName(); 2959ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines valid = false; 2969ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 2979ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 2989ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // TODO: Abstract this block away, since it is duplicate code. 2999ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines while (i < numParams) { 3009ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines PVD = FD->getParamDecl(i); 3019ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines QT = PVD->getType().getCanonicalType(); 3029ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 3039ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (QT.getUnqualifiedType() != C.UnsignedIntTy) { 3049ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->Report( 3059ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::FullSourceLoc(PVD->getLocation(), 3069ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getSourceManager()), 3079ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 3089ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "Unexpected kernel %0() parameter '%1' " 3099ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "of type '%2'")) 3109ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines << FD->getName() << PVD->getName() << PVD->getType().getAsString(); 3119ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines valid = false; 3129ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else { 3139ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines llvm::StringRef ParamName = PVD->getName(); 3149ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (ParamName.equals("x")) { 3159ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (mX) { 3169ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines ReportNameError(DiagEngine, PVD); 3179ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines valid = false; 3189ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else if (mY) { 3199ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // Can't go back to X after skipping Y 3209ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines ReportNameError(DiagEngine, PVD); 3219ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines valid = false; 3229ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else { 3239ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mX = PVD; 3249ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 3259ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else if (ParamName.equals("y")) { 3269ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (mY) { 3279ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines ReportNameError(DiagEngine, PVD); 3289ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines valid = false; 3299ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else { 3309ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mY = PVD; 3319ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 3329ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else { 3339ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (!mX && !mY) { 3349ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mX = PVD; 3359ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else if (!mY) { 3369ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mY = PVD; 3379ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else { 3389ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->Report( 3399ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines clang::FullSourceLoc(PVD->getLocation(), 3409ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getSourceManager()), 3419ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 3429ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "Unexpected kernel %0() parameter '%1' " 3439ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines "of type '%2'")) 3449ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines << FD->getName() << PVD->getName() << PVD->getType().getAsString(); 3459ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines valid = false; 3469ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 3479ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 3489ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 3499ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 3509ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines i++; // advance parameter pointer 3519ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 3520f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet return valid; 3530f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet} 3549ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 3550f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouilletbool RSExportForEach::setSignatureMetadata(RSContext *Context, 3560f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet const clang::FunctionDecl *FD) { 3579ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines mSignatureMetadata = 0; 3580f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet bool valid = true; 3590f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet 3600f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet if (mIsKernelStyle) { 3619ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines slangAssert(mOut == NULL); 3629ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines slangAssert(mUsrData == NULL); 3630f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet } else { 3640f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet slangAssert(!mHasReturnType); 3659ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 3669ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 3670f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet // Set up the bitwise metadata encoding for runtime argument passing. 3680f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet // TODO: If this bit field is re-used from C++ code, define the values in a header. 3690f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet const bool HasOut = mOut || mHasReturnType; 3700f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata |= (mIn ? 0x01 : 0); 3710f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata |= (HasOut ? 0x02 : 0); 3720f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata |= (mUsrData ? 0x04 : 0); 3730f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata |= (mX ? 0x08 : 0); 3740f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata |= (mY ? 0x10 : 0); 3750f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata |= (mIsKernelStyle ? 0x20 : 0); // pass-by-value 3760f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet 3770f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) { 3780f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet // APIs before ICS cannot skip between parameters. It is ok, however, for 3790f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet // them to omit further parameters (i.e. skipping X is ok if you skip Y). 3800f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet if (mSignatureMetadata != 0x1f && // In, Out, UsrData, X, Y 3810f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata != 0x0f && // In, Out, UsrData, X 3820f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata != 0x07 && // In, Out, UsrData 3830f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata != 0x03 && // In, Out 3840f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet mSignatureMetadata != 0x01) { // In 3850f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics(); 3860f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet DiagEngine->Report(clang::FullSourceLoc(FD->getLocation(), 3870f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet DiagEngine->getSourceManager()), 3880f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet DiagEngine->getCustomDiagID( 3890f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet clang::DiagnosticsEngine::Error, 3900f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet "Compute kernel %0() targeting SDK levels " 3910f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet "%1-%2 may not skip parameters")) 3920f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet << FD->getName() << SLANG_MINIMUM_TARGET_API 3930f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet << (SLANG_ICS_TARGET_API - 1); 3940f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet valid = false; 3950f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet } 3960f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet } 3979ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines return valid; 3989ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines} 3999ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 400593a894650e81be54173106ec266f0311cebebd3Stephen HinesRSExportForEach *RSExportForEach::Create(RSContext *Context, 401593a894650e81be54173106ec266f0311cebebd3Stephen Hines const clang::FunctionDecl *FD) { 402b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines slangAssert(Context && FD); 403593a894650e81be54173106ec266f0311cebebd3Stephen Hines llvm::StringRef Name = FD->getName(); 404b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines RSExportForEach *FE; 405593a894650e81be54173106ec266f0311cebebd3Stephen Hines 406593a894650e81be54173106ec266f0311cebebd3Stephen Hines slangAssert(!Name.empty() && "Function must have a name"); 407593a894650e81be54173106ec266f0311cebebd3Stephen Hines 408c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines FE = new RSExportForEach(Context, Name); 409593a894650e81be54173106ec266f0311cebebd3Stephen Hines 410b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines if (!FE->validateAndConstructParams(Context, FD)) { 411b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines return NULL; 412593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 413593a894650e81be54173106ec266f0311cebebd3Stephen Hines 414593a894650e81be54173106ec266f0311cebebd3Stephen Hines clang::ASTContext &Ctx = Context->getASTContext(); 415593a894650e81be54173106ec266f0311cebebd3Stephen Hines 416593a894650e81be54173106ec266f0311cebebd3Stephen Hines std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_foreach_param:"); 417b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines Id.append(FE->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX); 418593a894650e81be54173106ec266f0311cebebd3Stephen Hines 419593a894650e81be54173106ec266f0311cebebd3Stephen Hines // Extract the usrData parameter (if we have one) 420b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines if (FE->mUsrData) { 421b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines const clang::ParmVarDecl *PVD = FE->mUsrData; 422593a894650e81be54173106ec266f0311cebebd3Stephen Hines clang::QualType QT = PVD->getType().getCanonicalType(); 423593a894650e81be54173106ec266f0311cebebd3Stephen Hines slangAssert(QT->isPointerType() && 424593a894650e81be54173106ec266f0311cebebd3Stephen Hines QT->getPointeeType().isConstQualified()); 425593a894650e81be54173106ec266f0311cebebd3Stephen Hines 426593a894650e81be54173106ec266f0311cebebd3Stephen Hines const clang::ASTContext &C = Context->getASTContext(); 427593a894650e81be54173106ec266f0311cebebd3Stephen Hines if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() == 428593a894650e81be54173106ec266f0311cebebd3Stephen Hines C.VoidTy) { 429593a894650e81be54173106ec266f0311cebebd3Stephen Hines // In the case of using const void*, we can't reflect an appopriate 430593a894650e81be54173106ec266f0311cebebd3Stephen Hines // Java type, so we fall back to just reflecting the ain/aout parameters 431b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines FE->mUsrData = NULL; 432593a894650e81be54173106ec266f0311cebebd3Stephen Hines } else { 433b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines clang::RecordDecl *RD = 434b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines clang::RecordDecl::Create(Ctx, clang::TTK_Struct, 435b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines Ctx.getTranslationUnitDecl(), 436b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines clang::SourceLocation(), 437b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines clang::SourceLocation(), 438b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines &Ctx.Idents.get(Id)); 439b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 440593a894650e81be54173106ec266f0311cebebd3Stephen Hines clang::FieldDecl *FD = 441593a894650e81be54173106ec266f0311cebebd3Stephen Hines clang::FieldDecl::Create(Ctx, 442593a894650e81be54173106ec266f0311cebebd3Stephen Hines RD, 443593a894650e81be54173106ec266f0311cebebd3Stephen Hines clang::SourceLocation(), 444593a894650e81be54173106ec266f0311cebebd3Stephen Hines clang::SourceLocation(), 445593a894650e81be54173106ec266f0311cebebd3Stephen Hines PVD->getIdentifier(), 446593a894650e81be54173106ec266f0311cebebd3Stephen Hines QT->getPointeeType(), 447593a894650e81be54173106ec266f0311cebebd3Stephen Hines NULL, 4481688a3c56851f235866d6870c89ddb20650cc030Shih-wei Liao /* BitWidth = */ NULL, 4491688a3c56851f235866d6870c89ddb20650cc030Shih-wei Liao /* Mutable = */ false, 45043730fe3c839af391efe6bdf56b0479860121924Shih-wei Liao /* HasInit = */ clang::ICIS_NoInit); 451593a894650e81be54173106ec266f0311cebebd3Stephen Hines RD->addDecl(FD); 452b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines RD->completeDefinition(); 453b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 454b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines // Create an export type iff we have a valid usrData type 455b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines clang::QualType T = Ctx.getTagDeclType(RD); 456b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines slangAssert(!T.isNull()); 457b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 458b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines RSExportType *ET = RSExportType::Create(Context, T.getTypePtr()); 459b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 460b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines if (ET == NULL) { 461b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines fprintf(stderr, "Failed to export the function %s. There's at least " 462b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines "one parameter whose type is not supported by the " 463b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines "reflection\n", FE->getName().c_str()); 464b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines return NULL; 465b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 466b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 467b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines slangAssert((ET->getClass() == RSExportType::ExportClassRecord) && 468b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines "Parameter packet must be a record"); 469b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines 470b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines FE->mParamPacketType = static_cast<RSExportRecordType *>(ET); 471593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 472593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 473593a894650e81be54173106ec266f0311cebebd3Stephen Hines 474b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines if (FE->mIn) { 475b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines const clang::Type *T = FE->mIn->getType().getCanonicalType().getTypePtr(); 476b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines FE->mInType = RSExportType::Create(Context, T); 4770f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet if (FE->mIsKernelStyle) { 4789ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines slangAssert(FE->mInType); 4799ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 480b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines } 481593a894650e81be54173106ec266f0311cebebd3Stephen Hines 4820f2a2397df53a1bb74609abe3c27719bc7e3c328Jean-Luc Brouillet if (FE->mIsKernelStyle && FE->mHasReturnType) { 4839ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines const clang::Type *T = FE->mResultType.getTypePtr(); 4849ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines FE->mOutType = RSExportType::Create(Context, T); 4859ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines slangAssert(FE->mOutType); 4869ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } else if (FE->mOut) { 487b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr(); 488b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines FE->mOutType = RSExportType::Create(Context, T); 489593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 490593a894650e81be54173106ec266f0311cebebd3Stephen Hines 491b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines return FE; 492593a894650e81be54173106ec266f0311cebebd3Stephen Hines} 493593a894650e81be54173106ec266f0311cebebd3Stephen Hines 494c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen HinesRSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) { 495c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines slangAssert(Context); 496c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines llvm::StringRef Name = "root"; 497c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines RSExportForEach *FE = new RSExportForEach(Context, Name); 498c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines FE->mDummyRoot = true; 499c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines return FE; 500c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines} 501c17e198ffcd37bfc57e3add1f6eee952ae2a2eabStephen Hines 5029999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hinesbool RSExportForEach::isGraphicsRootRSFunc(int targetAPI, 5039999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines const clang::FunctionDecl *FD) { 5049ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines if (FD->hasAttr<clang::KernelAttr>()) { 5059ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines return false; 5069ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 5079ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 508593a894650e81be54173106ec266f0311cebebd3Stephen Hines if (!isRootRSFunc(FD)) { 509593a894650e81be54173106ec266f0311cebebd3Stephen Hines return false; 510593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 511593a894650e81be54173106ec266f0311cebebd3Stephen Hines 512b5a89fbfcba6d8817c1c3700ed78bd6482cf1a5dStephen Hines if (FD->getNumParams() == 0) { 5139999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines // Graphics root function 5149999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines return true; 515593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 516f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines 5179999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines // Check for legacy graphics root function (with single parameter). 518f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) { 519f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines const clang::QualType &IntType = FD->getASTContext().IntTy; 5209999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines if (FD->getResultType().getCanonicalType() == IntType) { 5219999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines return true; 522f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines } 523f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines } 524f736d5a12269e7e74740b130cdca98d9839b31e6Stephen Hines 5259999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines return false; 5269999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines} 5279999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines 5289999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hinesbool RSExportForEach::isRSForEachFunc(int targetAPI, 529089cde338148fbb75825aea4539ccdae8211ffefStephen Hines clang::DiagnosticsEngine *DiagEngine, 5309999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines const clang::FunctionDecl *FD) { 531089cde338148fbb75825aea4539ccdae8211ffefStephen Hines slangAssert(DiagEngine && FD); 532089cde338148fbb75825aea4539ccdae8211ffefStephen Hines bool hasKernelAttr = FD->hasAttr<clang::KernelAttr>(); 533089cde338148fbb75825aea4539ccdae8211ffefStephen Hines 534089cde338148fbb75825aea4539ccdae8211ffefStephen Hines if (FD->getStorageClass() == clang::SC_Static) { 535089cde338148fbb75825aea4539ccdae8211ffefStephen Hines if (hasKernelAttr) { 536089cde338148fbb75825aea4539ccdae8211ffefStephen Hines DiagEngine->Report( 537089cde338148fbb75825aea4539ccdae8211ffefStephen Hines clang::FullSourceLoc(FD->getLocation(), 538089cde338148fbb75825aea4539ccdae8211ffefStephen Hines DiagEngine->getSourceManager()), 539089cde338148fbb75825aea4539ccdae8211ffefStephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 540089cde338148fbb75825aea4539ccdae8211ffefStephen Hines "Invalid use of attribute kernel with " 541089cde338148fbb75825aea4539ccdae8211ffefStephen Hines "static function declaration: %0")) 542089cde338148fbb75825aea4539ccdae8211ffefStephen Hines << FD->getName(); 543089cde338148fbb75825aea4539ccdae8211ffefStephen Hines } 544089cde338148fbb75825aea4539ccdae8211ffefStephen Hines return false; 545089cde338148fbb75825aea4539ccdae8211ffefStephen Hines } 546089cde338148fbb75825aea4539ccdae8211ffefStephen Hines 5479ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines // Anything tagged as a kernel is definitely used with ForEach. 548089cde338148fbb75825aea4539ccdae8211ffefStephen Hines if (hasKernelAttr) { 5499ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines return true; 5509ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines } 5519ca96e70657cf5437a294213f56ba4768dc08ad2Stephen Hines 5527b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines if (isGraphicsRootRSFunc(targetAPI, FD)) { 5539999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines return false; 5549999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines } 5559999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines 5567b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines // Check if first parameter is a pointer (which is required for ForEach). 5577b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines unsigned int numParams = FD->getNumParams(); 5587b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines 5597b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines if (numParams > 0) { 5607b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines const clang::ParmVarDecl *PVD = FD->getParamDecl(0); 5617b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines clang::QualType QT = PVD->getType().getCanonicalType(); 5627b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines 5637b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines if (QT->isPointerType()) { 5647b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines return true; 5657b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines } 5667b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines 5677b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines // Any non-graphics root() is automatically a ForEach candidate. 5687b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines // At this point, however, we know that it is not going to be a valid 5697b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines // compute root() function (due to not having a pointer parameter). We 5707b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines // still want to return true here, so that we can issue appropriate 5717b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines // diagnostics. 5727b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines if (isRootRSFunc(FD)) { 5737b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines return true; 5747b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines } 5759999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines } 5769999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines 5777b51b55e4467605a599e868a0dde7cb95c5ab76eStephen Hines return false; 578593a894650e81be54173106ec266f0311cebebd3Stephen Hines} 579593a894650e81be54173106ec266f0311cebebd3Stephen Hines 5809207a2e495c8363606861e4f034504ec5c153dabLogan Chienbool 581fbfd7f5fd97458b6b23437556025ac1d55e98fd4Stephen HinesRSExportForEach::validateSpecialFuncDecl(int targetAPI, 582fbfd7f5fd97458b6b23437556025ac1d55e98fd4Stephen Hines clang::DiagnosticsEngine *DiagEngine, 5839207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::FunctionDecl const *FD) { 5849207a2e495c8363606861e4f034504ec5c153dabLogan Chien slangAssert(DiagEngine && FD); 585593a894650e81be54173106ec266f0311cebebd3Stephen Hines bool valid = true; 586593a894650e81be54173106ec266f0311cebebd3Stephen Hines const clang::ASTContext &C = FD->getASTContext(); 5879999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines const clang::QualType &IntType = FD->getASTContext().IntTy; 588593a894650e81be54173106ec266f0311cebebd3Stephen Hines 5899999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines if (isGraphicsRootRSFunc(targetAPI, FD)) { 5909999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) { 5919999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines // Legacy graphics root function 5929999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines const clang::ParmVarDecl *PVD = FD->getParamDecl(0); 5939999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines clang::QualType QT = PVD->getType().getCanonicalType(); 5949999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines if (QT != IntType) { 5959207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->Report( 5969999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines clang::FullSourceLoc(PVD->getLocation(), 5979207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getSourceManager()), 5989207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 5999999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines "invalid parameter type for legacy " 6009999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines "graphics root() function: %0")) 6019999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines << PVD->getType(); 602593a894650e81be54173106ec266f0311cebebd3Stephen Hines valid = false; 603593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 6049999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines } 6059999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines 6069999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines // Graphics root function, so verify that it returns an int 6079999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines if (FD->getResultType().getCanonicalType() != IntType) { 6089999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines DiagEngine->Report( 6099999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines clang::FullSourceLoc(FD->getLocation(), 6109999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines DiagEngine->getSourceManager()), 6119999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 6129999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines "root() is required to return " 6139999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines "an int for graphics usage")); 6149999ec3aa0c4d7a6befd3a300dc07f0cea91cb6cStephen Hines valid = false; 615593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 616688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) { 617593a894650e81be54173106ec266f0311cebebd3Stephen Hines if (FD->getNumParams() != 0) { 6189207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->Report( 6199207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::FullSourceLoc(FD->getLocation(), 6209207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getSourceManager()), 6219207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 6229207a2e495c8363606861e4f034504ec5c153dabLogan Chien "%0(void) is required to have no " 6239207a2e495c8363606861e4f034504ec5c153dabLogan Chien "parameters")) << FD->getName(); 624593a894650e81be54173106ec266f0311cebebd3Stephen Hines valid = false; 625593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 626593a894650e81be54173106ec266f0311cebebd3Stephen Hines 627593a894650e81be54173106ec266f0311cebebd3Stephen Hines if (FD->getResultType().getCanonicalType() != C.VoidTy) { 6289207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->Report( 6299207a2e495c8363606861e4f034504ec5c153dabLogan Chien clang::FullSourceLoc(FD->getLocation(), 6309207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getSourceManager()), 6319207a2e495c8363606861e4f034504ec5c153dabLogan Chien DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, 6329207a2e495c8363606861e4f034504ec5c153dabLogan Chien "%0(void) is required to have a void " 6339207a2e495c8363606861e4f034504ec5c153dabLogan Chien "return type")) << FD->getName(); 634593a894650e81be54173106ec266f0311cebebd3Stephen Hines valid = false; 635593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 636593a894650e81be54173106ec266f0311cebebd3Stephen Hines } else { 637688e64b2d56e4218c680b9d6523c5de672f55757Stephen Hines slangAssert(false && "must be called on root, init or .rs.dtor function!"); 638593a894650e81be54173106ec266f0311cebebd3Stephen Hines } 639593a894650e81be54173106ec266f0311cebebd3Stephen Hines 640593a894650e81be54173106ec266f0311cebebd3Stephen Hines return valid; 641593a894650e81be54173106ec266f0311cebebd3Stephen Hines} 642593a894650e81be54173106ec266f0311cebebd3Stephen Hines 643593a894650e81be54173106ec266f0311cebebd3Stephen Hines} // namespace slang 644