slang_rs_reflection_state.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128
  1. /*
  2. * Copyright 2017, The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <algorithm>
  17. #include <iostream>
  18. #include <string>
  19. #include "clang/AST/APValue.h"
  20. #include "slang_assert.h"
  21. #include "slang_rs_export_foreach.h"
  22. #include "slang_rs_export_func.h"
  23. #include "slang_rs_export_reduce.h"
  24. #include "slang_rs_export_type.h"
  25. #include "slang_rs_export_var.h"
  26. #include "slang_rs_reflection.h"
  27. #include "slang_rs_reflection_state.h"
  28. #include "bcinfo/MetadataExtractor.h"
  29. namespace slang {
  30. static bool equal(const clang::APValue &a, const clang::APValue &b) {
  31. if (a.getKind() != b.getKind())
  32. return false;
  33. switch (a.getKind()) {
  34. case clang::APValue::Float:
  35. return a.getFloat().bitwiseIsEqual(b.getFloat());
  36. case clang::APValue::Int:
  37. return a.getInt() == b.getInt();
  38. case clang::APValue::Vector: {
  39. unsigned NumElements = a.getVectorLength();
  40. if (NumElements != b.getVectorLength())
  41. return false;
  42. for (unsigned i = 0; i < NumElements; ++i) {
  43. if (!equal(a.getVectorElt(i), b.getVectorElt(i)))
  44. return false;
  45. }
  46. return true;
  47. }
  48. default:
  49. slangAssert(false && "unexpected APValue kind");
  50. return false;
  51. }
  52. }
  53. ReflectionState::~ReflectionState() {
  54. slangAssert(mState==S_Initial || mState==S_ClosedJava64 || mState==S_Bad);
  55. delete mStringSet;
  56. }
  57. void ReflectionState::openJava32(size_t NumFiles) {
  58. if (kDisabled)
  59. return;
  60. slangAssert(mState==S_Initial);
  61. mState = S_OpenJava32;
  62. mStringSet = new llvm::StringSet<>;
  63. mFiles.BeginCollecting(NumFiles);
  64. }
  65. void ReflectionState::closeJava32() {
  66. if (kDisabled)
  67. return;
  68. slangAssert(mState==S_OpenJava32 && (mForEachOpen < 0) && !mOutputClassOpen && (mRecordsState != RS_Open));
  69. mState = S_ClosedJava32;
  70. mRSC = nullptr;
  71. }
  72. void ReflectionState::openJava64() {
  73. if (kDisabled)
  74. return;
  75. slangAssert(mState==S_ClosedJava32);
  76. mState = S_OpenJava64;
  77. mFiles.BeginUsing();
  78. }
  79. void ReflectionState::closeJava64() {
  80. if (kDisabled)
  81. return;
  82. slangAssert(mState==S_OpenJava64 && (mForEachOpen < 0) && !mOutputClassOpen && (mRecordsState != RS_Open));
  83. mState = S_ClosedJava64;
  84. mRSC = nullptr;
  85. }
  86. llvm::StringRef ReflectionState::canon(const std::string &String) {
  87. slangAssert(isCollecting());
  88. // NOTE: llvm::StringSet does not permit the empty string as a member
  89. return String.empty() ? llvm::StringRef() : mStringSet->insert(String).first->getKey();
  90. }
  91. std::string ReflectionState::getUniqueTypeName(const RSExportType *T) {
  92. return RSReflectionJava::GetTypeName(T, RSReflectionJava::TypeNamePseudoC);
  93. }
  94. void ReflectionState::nextFile(const RSContext *RSC,
  95. const std::string &PackageName,
  96. const std::string &RSSourceFileName) {
  97. slangAssert(!isClosed());
  98. if (!isActive())
  99. return;
  100. mRSC = RSC;
  101. slangAssert(mRecordsState != RS_Open);
  102. mRecordsState = RS_Initial;
  103. if (isCollecting()) {
  104. File &file = mFiles.CollectNext();
  105. file.mPackageName = PackageName;
  106. file.mRSSourceFileName = RSSourceFileName;
  107. }
  108. if (isUsing()) {
  109. File &file = mFiles.UseNext();
  110. slangAssert(file.mRSSourceFileName == RSSourceFileName);
  111. if (file.mPackageName != PackageName)
  112. mRSC->ReportError("in file '%0' Java package name is '%1' for 32-bit targets "
  113. "but '%2' for 64-bit targets")
  114. << RSSourceFileName << file.mPackageName << PackageName;
  115. }
  116. }
  117. void ReflectionState::dump() {
  118. const size_t NumFiles = mFiles.Size();
  119. for (int i = 0; i < NumFiles; ++i) {
  120. const File &file = mFiles[i];
  121. std::cout << "file = \"" << file.mRSSourceFileName << "\", "
  122. << "package = \"" << file.mPackageName << "\"" << std::endl;
  123. // NOTE: "StringMap iteration order, however, is not guaranteed to
  124. // be deterministic". So sort before dumping.
  125. typedef const llvm::StringMap<File::Record>::MapEntryTy *RecordsEntryTy;
  126. std::vector<RecordsEntryTy> Records;
  127. Records.reserve(file.mRecords.size());
  128. for (auto I = file.mRecords.begin(), E = file.mRecords.end(); I != E; I++)
  129. Records.push_back(&(*I));
  130. std::sort(Records.begin(), Records.end(),
  131. [](RecordsEntryTy a, RecordsEntryTy b) { return a->getKey().compare(b->getKey())==-1; });
  132. for (auto Record : Records) {
  133. const auto &Val = Record->getValue();
  134. std::cout << " (Record) name=\"" << Record->getKey().str() << "\""
  135. << " allocSize=" << Val.mAllocSize
  136. << " postPadding=" << Val.mPostPadding
  137. << " ordinary=" << Val.mOrdinary
  138. << " matchedByName=" << Val.mMatchedByName
  139. << std::endl;
  140. const size_t NumFields = Val.mFieldCount;
  141. for (int fieldIdx = 0; fieldIdx < NumFields; ++fieldIdx) {
  142. const auto &field = Val.mFields[fieldIdx];
  143. std::cout << " (Field) name=\"" << field.mName << "\" ("
  144. << field.mPrePadding << ", \"" << field.mType.str()
  145. << "\"(" << field.mStoreSize << ")@" << field.mOffset
  146. << ", " << field.mPostPadding << ")" << std::endl;
  147. }
  148. }
  149. const size_t NumVars = file.mVariables.Size();
  150. for (int varIdx = 0; varIdx < NumVars; ++varIdx) {
  151. const auto &var = file.mVariables[varIdx];
  152. std::cout << " (Var) name=\"" << var.mName << "\" type=\"" << var.mType.str()
  153. << "\" const=" << var.mIsConst << " initialized=" << (var.mInitializerCount != 0)
  154. << " allocSize=" << var.mAllocSize << std::endl;
  155. }
  156. for (int feIdx = 0; feIdx < file.mForEachCount; ++feIdx) {
  157. const auto &fe = file.mForEaches[feIdx];
  158. std::cout << " (ForEach) ordinal=" << feIdx << " state=";
  159. switch (fe.mState) {
  160. case File::ForEach::S_Initial:
  161. std::cout << "initial" << std::endl;
  162. continue;
  163. case File::ForEach::S_Collected:
  164. std::cout << "collected";
  165. break;
  166. case File::ForEach::S_UseMatched:
  167. std::cout << "usematched";
  168. break;
  169. default:
  170. std::cout << fe.mState;
  171. break;
  172. }
  173. std::cout << " name=\"" << fe.mName << "\" kernel=" << fe.mIsKernel
  174. << " hasOut=" << fe.mHasOut << " out=\"" << fe.mOut.str()
  175. << "\" metadata=0x" << std::hex << fe.mSignatureMetadata << std::dec
  176. << std::endl;
  177. const size_t NumIns = fe.mIns.Size();
  178. for (int insIdx = 0; insIdx < NumIns; ++insIdx)
  179. std::cout << " (In) " << fe.mIns[insIdx].str() << std::endl;
  180. const size_t NumParams = fe.mParams.Size();
  181. for (int paramsIdx = 0; paramsIdx < NumParams; ++paramsIdx)
  182. std::cout << " (Param) " << fe.mParams[paramsIdx].str() << std::endl;
  183. }
  184. for (auto feBad : mForEachesBad) {
  185. std::cout << " (ForEachBad) ordinal=" << feBad->getOrdinal()
  186. << " name=\"" << feBad->getName() << "\""
  187. << std::endl;
  188. }
  189. const size_t NumInvokables = file.mInvokables.Size();
  190. for (int invIdx = 0; invIdx < NumInvokables; ++invIdx) {
  191. const auto &inv = file.mInvokables[invIdx];
  192. std::cout << " (Invokable) name=\"" << inv.mName << "\"" << std::endl;
  193. const size_t NumParams = inv.mParamCount;
  194. for (int paramsIdx = 0; paramsIdx < NumParams; ++paramsIdx)
  195. std::cout << " (Param) " << inv.mParams[paramsIdx].str() << std::endl;
  196. }
  197. const size_t NumReduces = file.mReduces.Size();
  198. for (int redIdx = 0; redIdx < NumReduces; ++redIdx) {
  199. const auto &red = file.mReduces[redIdx];
  200. std::cout << " (Reduce) name=\"" << red.mName
  201. << "\" result=\"" << red.mResult.str()
  202. << "\" exportable=" << red.mIsExportable
  203. << std::endl;
  204. const size_t NumIns = red.mAccumInCount;
  205. for (int insIdx = 0; insIdx < NumIns; ++insIdx)
  206. std::cout << " (In) " << red.mAccumIns[insIdx].str() << std::endl;
  207. }
  208. }
  209. }
  210. // ForEach /////////////////////////////////////////////////////////////////////////////////////
  211. void ReflectionState::beginForEaches(size_t Count) {
  212. slangAssert(!isClosed());
  213. if (!isActive())
  214. return;
  215. if (isCollecting()) {
  216. auto &file = mFiles.Current();
  217. file.mForEaches = new File::ForEach[Count];
  218. file.mForEachCount = Count;
  219. }
  220. if (isUsing()) {
  221. slangAssert(mForEachesBad.empty());
  222. mNumForEachesMatchedByOrdinal = 0;
  223. }
  224. }
  225. // Keep this in sync with RSReflectionJava::genExportForEach().
  226. void ReflectionState::beginForEach(const RSExportForEach *EF) {
  227. slangAssert(!isClosed() && (mForEachOpen < 0));
  228. if (!isActive())
  229. return;
  230. const bool IsKernel = EF->isKernelStyle();
  231. const std::string& Name = EF->getName();
  232. const unsigned Ordinal = EF->getOrdinal();
  233. const size_t InCount = EF->getInTypes().size();
  234. const size_t ParamCount = EF->params_count();
  235. const RSExportType *OET = EF->getOutType();
  236. if (OET && !IsKernel) {
  237. slangAssert(OET->getClass() == RSExportType::ExportClassPointer);
  238. OET = static_cast<const RSExportPointerType *>(OET)->getPointeeType();
  239. }
  240. const std::string OutType = (OET ? getUniqueTypeName(OET) : "");
  241. const bool HasOut = (EF->hasOut() || EF->hasReturn());
  242. mForEachOpen = Ordinal;
  243. mForEachFatal = true; // we'll set this to false if everything looks ok
  244. auto &file = mFiles.Current();
  245. auto &foreaches = file.mForEaches;
  246. if (isCollecting()) {
  247. slangAssert(Ordinal < file.mForEachCount);
  248. auto &foreach = foreaches[Ordinal];
  249. slangAssert(foreach.mState == File::ForEach::S_Initial);
  250. foreach.mState = File::ForEach::S_Collected;
  251. foreach.mName = Name;
  252. foreach.mIns.BeginCollecting(InCount);
  253. foreach.mParams.BeginCollecting(ParamCount);
  254. foreach.mOut = canon(OutType);
  255. foreach.mHasOut = HasOut;
  256. foreach.mSignatureMetadata = 0;
  257. foreach.mIsKernel = IsKernel;
  258. }
  259. if (isUsing()) {
  260. if (Ordinal >= file.mForEachCount) {
  261. mForEachesBad.push_back(EF);
  262. return;
  263. }
  264. auto &foreach = foreaches[Ordinal];
  265. slangAssert(foreach.mState == File::ForEach::S_Collected);
  266. foreach.mState = File::ForEach::S_UseMatched;
  267. ++mNumForEachesMatchedByOrdinal;
  268. if (foreach.mName != Name) {
  269. // Order matters because it determines slot number
  270. mForEachesBad.push_back(EF);
  271. return;
  272. }
  273. // At this point, we have matching ordinal and matching name.
  274. if (foreach.mIsKernel != IsKernel) {
  275. mRSC->ReportError(EF->getLocation(),
  276. "foreach kernel '%0' has __attribute__((kernel)) for %select{32|64}1-bit targets "
  277. "but not for %select{64|32}1-bit targets")
  278. << Name << IsKernel;
  279. return;
  280. }
  281. if ((foreach.mHasOut != HasOut) || !foreach.mOut.equals(OutType)) {
  282. // There are several different patterns we need to handle:
  283. // (1) Two different non-void* output types
  284. // (2) One non-void* output type, one void* output type
  285. // (3) One non-void* output type, one no-output
  286. // (4) One void* output type, one no-output
  287. if (foreach.mHasOut && HasOut) {
  288. if (foreach.mOut.size() && OutType.size()) {
  289. // (1) Two different non-void* output types
  290. mRSC->ReportError(EF->getLocation(),
  291. "foreach kernel '%0' has output type '%1' for 32-bit targets "
  292. "but output type '%2' for 64-bit targets")
  293. << Name << foreach.mOut.str() << OutType;
  294. } else {
  295. // (2) One non-void* return type, one void* output type
  296. const bool hasTyped64 = OutType.size();
  297. mRSC->ReportError(EF->getLocation(),
  298. "foreach kernel '%0' has output type '%1' for %select{32|64}2-bit targets "
  299. "but has untyped output for %select{64|32}2-bit targets")
  300. << Name << (foreach.mOut.str() + OutType) << hasTyped64;
  301. }
  302. } else {
  303. const std::string CombinedOutType = (foreach.mOut.str() + OutType);
  304. if (CombinedOutType.size()) {
  305. // (3) One non-void* output type, one no-output
  306. mRSC->ReportError(EF->getLocation(),
  307. "foreach kernel '%0' has output type '%1' for %select{32|64}2-bit targets "
  308. "but no output for %select{64|32}2-bit targets")
  309. << Name << CombinedOutType << HasOut;
  310. } else {
  311. // (4) One void* output type, one no-output
  312. mRSC->ReportError(EF->getLocation(),
  313. "foreach kernel '%0' has untyped output for %select{32|64}1-bit targets "
  314. "but no output for %select{64|32}1-bit targets")
  315. << Name << HasOut;
  316. }
  317. }
  318. }
  319. bool BadCount = false;
  320. if (foreach.mIns.Size() != InCount) {
  321. mRSC->ReportError(EF->getLocation(),
  322. "foreach kernel '%0' has %1 input%s1 for 32-bit targets "
  323. "but %2 input%s2 for 64-bit targets")
  324. << Name << unsigned(foreach.mIns.Size()) << unsigned(InCount);
  325. BadCount = true;
  326. }
  327. if (foreach.mParams.Size() != ParamCount) {
  328. mRSC->ReportError(EF->getLocation(),
  329. "foreach kernel '%0' has %1 usrData parameter%s1 for 32-bit targets "
  330. "but %2 usrData parameter%s2 for 64-bit targets")
  331. << Name << unsigned(foreach.mParams.Size()) << unsigned(ParamCount);
  332. BadCount = true;
  333. }
  334. if (BadCount)
  335. return;
  336. foreach.mIns.BeginUsing();
  337. foreach.mParams.BeginUsing();
  338. }
  339. mForEachFatal = false;
  340. }
  341. void ReflectionState::addForEachIn(const RSExportForEach *EF, const RSExportType *Type) {
  342. slangAssert(!isClosed());
  343. if (!isActive())
  344. return;
  345. slangAssert(mForEachOpen == EF->getOrdinal());
  346. // Type may be nullptr in the case of void*. See RSExportForEach::Create().
  347. if (Type && !EF->isKernelStyle()) {
  348. slangAssert(Type->getClass() == RSExportType::ExportClassPointer);
  349. Type = static_cast<const RSExportPointerType *>(Type)->getPointeeType();
  350. }
  351. const std::string TypeName = (Type ? getUniqueTypeName(Type) : std::string());
  352. auto &ins = mFiles.Current().mForEaches[EF->getOrdinal()].mIns;
  353. if (isCollecting()) {
  354. ins.CollectNext() = canon(TypeName);
  355. }
  356. if (isUsing()) {
  357. if (mForEachFatal)
  358. return;
  359. if (!ins.UseNext().equals(TypeName)) {
  360. if (ins.Current().size() && TypeName.size()) {
  361. mRSC->ReportError(EF->getLocation(),
  362. "%ordinal0 input of foreach kernel '%1' "
  363. "has type '%2' for 32-bit targets "
  364. "but type '%3' for 64-bit targets")
  365. << unsigned(ins.CurrentIdx() + 1)
  366. << EF->getName()
  367. << ins.Current().str()
  368. << TypeName;
  369. } else {
  370. const bool hasType64 = TypeName.size();
  371. mRSC->ReportError(EF->getLocation(),
  372. "%ordinal0 input of foreach kernel '%1' "
  373. "has type '%2' for %select{32|64}3-bit targets "
  374. "but is untyped for %select{64|32}3-bit targets")
  375. << unsigned(ins.CurrentIdx() + 1)
  376. << EF->getName()
  377. << (ins.Current().str() + TypeName)
  378. << hasType64;
  379. }
  380. }
  381. }
  382. }
  383. void ReflectionState::addForEachParam(const RSExportForEach *EF, const RSExportType *Type) {
  384. slangAssert(!isClosed());
  385. if (!isActive())
  386. return;
  387. slangAssert(mForEachOpen == EF->getOrdinal());
  388. const std::string TypeName = getUniqueTypeName(Type);
  389. auto &params = mFiles.Current().mForEaches[EF->getOrdinal()].mParams;
  390. if (isCollecting()) {
  391. params.CollectNext() = canon(TypeName);
  392. }
  393. if (isUsing()) {
  394. if (mForEachFatal)
  395. return;
  396. if (!params.UseNext().equals(TypeName)) {
  397. mRSC->ReportError(EF->getLocation(),
  398. "%ordinal0 usrData parameter of foreach kernel '%1' "
  399. "has type '%2' for 32-bit targets "
  400. "but type '%3' for 64-bit targets")
  401. << unsigned(params.CurrentIdx() + 1)
  402. << EF->getName()
  403. << params.Current().str()
  404. << TypeName;
  405. }
  406. }
  407. }
  408. void ReflectionState::addForEachSignatureMetadata(const RSExportForEach *EF, unsigned Metadata) {
  409. slangAssert(!isClosed());
  410. if (!isActive())
  411. return;
  412. slangAssert(mForEachOpen == EF->getOrdinal());
  413. // These are properties in the metadata that we need to check.
  414. const unsigned SpecialParameterBits = bcinfo::MD_SIG_X|bcinfo::MD_SIG_Y|bcinfo::MD_SIG_Z|bcinfo::MD_SIG_Ctxt;
  415. #ifndef __DISABLE_ASSERTS
  416. {
  417. // These are properties in the metadata that we already check in
  418. // some other way.
  419. const unsigned BoringBits = bcinfo::MD_SIG_In|bcinfo::MD_SIG_Out|bcinfo::MD_SIG_Usr|bcinfo::MD_SIG_Kernel;
  420. slangAssert((Metadata & ~(SpecialParameterBits | BoringBits)) == 0);
  421. }
  422. #endif
  423. auto &mSignatureMetadata = mFiles.Current().mForEaches[EF->getOrdinal()].mSignatureMetadata;
  424. if (isCollecting()) {
  425. mSignatureMetadata = Metadata;
  426. }
  427. if (isUsing()) {
  428. if (mForEachFatal)
  429. return;
  430. if ((mSignatureMetadata & SpecialParameterBits) != (Metadata & SpecialParameterBits)) {
  431. mRSC->ReportError(EF->getLocation(),
  432. "foreach kernel '%0' has different special parameters "
  433. "for 32-bit targets than for 64-bit targets")
  434. << EF->getName();
  435. }
  436. }
  437. }
  438. void ReflectionState::endForEach() {
  439. slangAssert(!isClosed());
  440. if (!isActive())
  441. return;
  442. slangAssert(mForEachOpen >= 0);
  443. if (isUsing() && !mForEachFatal) {
  444. slangAssert(mFiles.Current().mForEaches[mForEachOpen].mIns.isFinished());
  445. slangAssert(mFiles.Current().mForEaches[mForEachOpen].mParams.isFinished());
  446. }
  447. mForEachOpen = -1;
  448. }
  449. void ReflectionState::endForEaches() {
  450. slangAssert(mForEachOpen < 0);
  451. if (!isUsing())
  452. return;
  453. const auto &file = mFiles.Current();
  454. if (!mForEachesBad.empty()) {
  455. std::sort(mForEachesBad.begin(), mForEachesBad.end(),
  456. [](const RSExportForEach *a, const RSExportForEach *b) { return a->getOrdinal() < b->getOrdinal(); });
  457. // Note that after the sort, all kernels that are bad because of
  458. // name mismatch precede all kernels that are bad because of
  459. // too-high ordinal.
  460. // 32-bit and 64-bit compiles need to see foreach kernels in the
  461. // same order, because of slot number assignment. Once we see the
  462. // first name mismatch in the sequence of foreach kernels, it
  463. // doesn't make sense to issue further diagnostics regarding
  464. // foreach kernels except those that still happen to match by name
  465. // and ordinal (we already handled those diagnostics between
  466. // beginForEach() and endForEach()).
  467. bool ForEachesOrderFatal = false;
  468. for (const RSExportForEach *EF : mForEachesBad) {
  469. if (EF->getOrdinal() >= file.mForEachCount) {
  470. mRSC->ReportError(EF->getLocation(),
  471. "foreach kernel '%0' is only present for 64-bit targets")
  472. << EF->getName();
  473. } else {
  474. mRSC->ReportError(EF->getLocation(),
  475. "%ordinal0 foreach kernel is '%1' for 32-bit targets "
  476. "but '%2' for 64-bit targets")
  477. << (EF->getOrdinal() + 1)
  478. << mFiles.Current().mForEaches[EF->getOrdinal()].mName
  479. << EF->getName();
  480. ForEachesOrderFatal = true;
  481. break;
  482. }
  483. }
  484. mForEachesBad.clear();
  485. if (ForEachesOrderFatal)
  486. return;
  487. }
  488. if (mNumForEachesMatchedByOrdinal == file.mForEachCount)
  489. return;
  490. for (unsigned ord = 0; ord < file.mForEachCount; ord++) {
  491. const auto &fe = file.mForEaches[ord];
  492. if (fe.mState == File::ForEach::S_Collected) {
  493. mRSC->ReportError("in file '%0' foreach kernel '%1' is only present for 32-bit targets")
  494. << file.mRSSourceFileName << fe.mName;
  495. }
  496. }
  497. }
  498. // Invokable ///////////////////////////////////////////////////////////////////////////////////
  499. // Keep this in sync with RSReflectionJava::genExportFunction().
  500. void ReflectionState::declareInvokable(const RSExportFunc *EF) {
  501. slangAssert(!isClosed());
  502. if (!isActive())
  503. return;
  504. const std::string& Name = EF->getName(/*Mangle=*/false);
  505. const size_t ParamCount = EF->getNumParameters();
  506. auto &invokables = mFiles.Current().mInvokables;
  507. if (isCollecting()) {
  508. auto &invokable = invokables.CollectNext();
  509. invokable.mName = Name;
  510. invokable.mParamCount = ParamCount;
  511. if (EF->hasParam()) {
  512. unsigned FieldIdx = 0;
  513. invokable.mParams = new llvm::StringRef[ParamCount];
  514. for (RSExportFunc::const_param_iterator I = EF->params_begin(),
  515. E = EF->params_end();
  516. I != E; I++, FieldIdx++) {
  517. invokable.mParams[FieldIdx] = canon(getUniqueTypeName((*I)->getType()));
  518. }
  519. }
  520. }
  521. if (isUsing()) {
  522. if (mInvokablesOrderFatal)
  523. return;
  524. if (invokables.isFinished()) {
  525. // This doesn't actually break reflection, but that's a
  526. // coincidence of the fact that we reflect during the 64-bit
  527. // compilation pass rather than the 32-bit compilation pass, and
  528. // of the fact that the "extra" invokable(s) are at the end.
  529. mRSC->ReportError(EF->getLocation(),
  530. "invokable function '%0' is only present for 64-bit targets")
  531. << Name;
  532. return;
  533. }
  534. auto &invokable = invokables.UseNext();
  535. if (invokable.mName != Name) {
  536. // Order matters because it determines slot number
  537. mRSC->ReportError(EF->getLocation(),
  538. "%ordinal0 invokable function is '%1' for 32-bit targets "
  539. "but '%2' for 64-bit targets")
  540. << unsigned(invokables.CurrentIdx() + 1)
  541. << invokable.mName
  542. << Name;
  543. mInvokablesOrderFatal = true;
  544. return;
  545. }
  546. if (invokable.mParamCount != ParamCount) {
  547. mRSC->ReportError(EF->getLocation(),
  548. "invokable function '%0' has %1 parameter%s1 for 32-bit targets "
  549. "but %2 parameter%s2 for 64-bit targets")
  550. << Name << unsigned(invokable.mParamCount) << unsigned(ParamCount);
  551. return;
  552. }
  553. if (EF->hasParam()) {
  554. unsigned FieldIdx = 0;
  555. for (RSExportFunc::const_param_iterator I = EF->params_begin(),
  556. E = EF->params_end();
  557. I != E; I++, FieldIdx++) {
  558. const std::string Type = getUniqueTypeName((*I)->getType());
  559. if (!invokable.mParams[FieldIdx].equals(Type)) {
  560. mRSC->ReportError(EF->getLocation(),
  561. "%ordinal0 parameter of invokable function '%1' "
  562. "has type '%2' for 32-bit targets "
  563. "but type '%3' for 64-bit targets")
  564. << (FieldIdx + 1)
  565. << Name
  566. << invokable.mParams[FieldIdx].str()
  567. << Type;
  568. }
  569. }
  570. }
  571. }
  572. }
  573. void ReflectionState::endInvokables() {
  574. if (!isUsing() || mInvokablesOrderFatal)
  575. return;
  576. auto &invokables = mFiles.Current().mInvokables;
  577. while (!invokables.isFinished()) {
  578. const auto &invokable = invokables.UseNext();
  579. mRSC->ReportError("in file '%0' invokable function '%1' is only present for 32-bit targets")
  580. << mFiles.Current().mRSSourceFileName << invokable.mName;
  581. }
  582. }
  583. // Record //////////////////////////////////////////////////////////////////////////////////////
  584. void ReflectionState::beginRecords() {
  585. slangAssert(!isClosed());
  586. if (!isActive())
  587. return;
  588. slangAssert(mRecordsState != RS_Open);
  589. mRecordsState = RS_Open;
  590. mNumRecordsMatchedByName = 0;
  591. }
  592. void ReflectionState::endRecords() {
  593. slangAssert(!isClosed());
  594. if (!isActive())
  595. return;
  596. slangAssert(mRecordsState == RS_Open);
  597. mRecordsState = RS_Closed;
  598. if (isUsing()) {
  599. const File &file = mFiles.Current();
  600. if (mNumRecordsMatchedByName == file.mRecords.size())
  601. return;
  602. // NOTE: "StringMap iteration order, however, is not guaranteed to
  603. // be deterministic". So sort by name before reporting.
  604. // Alternatively, if we record additional information, we could
  605. // sort by source location or by order in which we discovered the
  606. // need to export.
  607. std::vector<llvm::StringRef> Non64RecordNames;
  608. for (auto I = file.mRecords.begin(), E = file.mRecords.end(); I != E; I++)
  609. if (!I->getValue().mMatchedByName && I->getValue().mOrdinary)
  610. Non64RecordNames.push_back(I->getKey());
  611. std::sort(Non64RecordNames.begin(), Non64RecordNames.end(),
  612. [](llvm::StringRef a, llvm::StringRef b) { return a.compare(b)==-1; });
  613. for (auto N : Non64RecordNames)
  614. mRSC->ReportError("in file '%0' structure '%1' is exported only for 32-bit targets")
  615. << file.mRSSourceFileName << N.str();
  616. }
  617. }
  618. void ReflectionState::declareRecord(const RSExportRecordType *ERT, bool Ordinary) {
  619. slangAssert(!isClosed());
  620. if (!isActive())
  621. return;
  622. slangAssert(mRecordsState == RS_Open);
  623. auto &records = mFiles.Current().mRecords;
  624. if (isCollecting()) {
  625. // Keep struct/field layout in sync with
  626. // RSReflectionJava::genPackVarOfType() and
  627. // RSReflectionJavaElementBuilder::genAddElement()
  628. // Save properties of record
  629. const size_t FieldCount = ERT->fields_size();
  630. File::Record::Field *Fields = new File::Record::Field[FieldCount];
  631. size_t Pos = 0; // Relative position of field within record
  632. unsigned FieldIdx = 0;
  633. for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), E = ERT->fields_end();
  634. I != E; I++, FieldIdx++) {
  635. const RSExportRecordType::Field *FieldExport = *I;
  636. size_t FieldOffset = FieldExport->getOffsetInParent();
  637. const RSExportType *T = FieldExport->getType();
  638. size_t FieldStoreSize = T->getStoreSize();
  639. size_t FieldAllocSize = T->getAllocSize();
  640. slangAssert(FieldOffset >= Pos);
  641. slangAssert(FieldAllocSize >= FieldStoreSize);
  642. auto &FieldState = Fields[FieldIdx];
  643. FieldState.mName = FieldExport->getName();
  644. FieldState.mType = canon(getUniqueTypeName(T));
  645. FieldState.mPrePadding = FieldOffset - Pos;
  646. FieldState.mPostPadding = FieldAllocSize - FieldStoreSize;
  647. FieldState.mOffset = FieldOffset;
  648. FieldState.mStoreSize = FieldStoreSize;
  649. Pos = FieldOffset + FieldAllocSize;
  650. }
  651. slangAssert(ERT->getAllocSize() >= Pos);
  652. // Insert record into map
  653. slangAssert(records.find(ERT->getName()) == records.end());
  654. File::Record &record = records[ERT->getName()];
  655. record.mFields = Fields;
  656. record.mFieldCount = FieldCount;
  657. record.mPostPadding = ERT->getAllocSize() - Pos;
  658. record.mAllocSize = ERT->getAllocSize();
  659. record.mOrdinary = Ordinary;
  660. record.mMatchedByName = false;
  661. }
  662. if (isUsing()) {
  663. if (!Ordinary)
  664. return;
  665. const auto RIT = records.find(ERT->getName());
  666. if (RIT == records.end()) {
  667. // This doesn't actually break reflection, but that's a
  668. // coincidence of the fact that we reflect during the 64-bit
  669. // compilation pass rather than the 32-bit compilation pass, so
  670. // a record that's only classified as exported during the 64-bit
  671. // compilation pass doesn't cause any problems.
  672. mRSC->ReportError(ERT->getLocation(), "structure '%0' is exported only for 64-bit targets")
  673. << ERT->getName();
  674. return;
  675. }
  676. File::Record &record = RIT->getValue();
  677. record.mMatchedByName = true;
  678. ++mNumRecordsMatchedByName;
  679. slangAssert(record.mOrdinary);
  680. if (ERT->fields_size() != record.mFieldCount) {
  681. mRSC->ReportError(ERT->getLocation(),
  682. "exported structure '%0' has %1 field%s1 for 32-bit targets "
  683. "but %2 field%s2 for 64-bit targets")
  684. << ERT->getName() << unsigned(record.mFieldCount) << unsigned(ERT->fields_size());
  685. return;
  686. }
  687. // Note that we are deliberately NOT comparing layout properties
  688. // (such as Field offsets and sizes, or Record allocation size);
  689. // we need to tolerate layout differences between 32-bit
  690. // compilation and 64-bit compilation.
  691. unsigned FieldIdx = 0;
  692. for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), E = ERT->fields_end();
  693. I != E; I++, FieldIdx++) {
  694. const RSExportRecordType::Field &FieldExport = **I;
  695. const File::Record::Field &FieldState = record.mFields[FieldIdx];
  696. if (FieldState.mName != FieldExport.getName()) {
  697. mRSC->ReportError(ERT->getLocation(),
  698. "%ordinal0 field of exported structure '%1' "
  699. "is '%2' for 32-bit targets "
  700. "but '%3' for 64-bit targets")
  701. << (FieldIdx + 1) << ERT->getName() << FieldState.mName << FieldExport.getName();
  702. return;
  703. }
  704. const std::string FieldExportType = getUniqueTypeName(FieldExport.getType());
  705. if (!FieldState.mType.equals(FieldExportType)) {
  706. mRSC->ReportError(ERT->getLocation(),
  707. "field '%0' of exported structure '%1' "
  708. "has type '%2' for 32-bit targets "
  709. "but type '%3' for 64-bit targets")
  710. << FieldState.mName << ERT->getName() << FieldState.mType.str() << FieldExportType;
  711. }
  712. }
  713. }
  714. }
  715. ReflectionState::Record32
  716. ReflectionState::getRecord32(const RSExportRecordType *ERT) {
  717. if (isUsing()) {
  718. const auto &Records = mFiles.Current().mRecords;
  719. const auto RIT = Records.find(ERT->getName());
  720. if (RIT != Records.end())
  721. return Record32(&RIT->getValue());
  722. }
  723. return Record32();
  724. }
  725. // Reduce //////////////////////////////////////////////////////////////////////////////////////
  726. void ReflectionState::declareReduce(const RSExportReduce *ER, bool IsExportable) {
  727. slangAssert(!isClosed());
  728. if (!isActive())
  729. return;
  730. auto &reduces = mFiles.Current().mReduces;
  731. if (isCollecting()) {
  732. auto &reduce = reduces.CollectNext();
  733. reduce.mName = ER->getNameReduce();
  734. const auto &InTypes = ER->getAccumulatorInTypes();
  735. const size_t InTypesSize = InTypes.size();
  736. reduce.mAccumInCount = InTypesSize;
  737. reduce.mAccumIns = new llvm::StringRef[InTypesSize];
  738. unsigned InTypesIdx = 0;
  739. for (const auto &InType : InTypes)
  740. reduce.mAccumIns[InTypesIdx++] = canon(getUniqueTypeName(InType));
  741. reduce.mResult = canon(getUniqueTypeName(ER->getResultType()));
  742. reduce.mIsExportable = IsExportable;
  743. }
  744. if (isUsing()) {
  745. if (mReducesOrderFatal)
  746. return;
  747. const std::string& Name = ER->getNameReduce();
  748. if (reduces.isFinished()) {
  749. // This doesn't actually break reflection, but that's a
  750. // coincidence of the fact that we reflect during the 64-bit
  751. // compilation pass rather than the 32-bit compilation pass, and
  752. // of the fact that the "extra" reduction kernel(s) are at the
  753. // end.
  754. mRSC->ReportError(ER->getLocation(),
  755. "reduction kernel '%0' is only present for 64-bit targets")
  756. << Name;
  757. return;
  758. }
  759. auto &reduce = reduces.UseNext();
  760. if (reduce.mName != Name) {
  761. // Order matters because it determines slot number. We might be
  762. // able to tolerate certain cases if we ignore non-exportable
  763. // kernels in the two sequences (32-bit and 64-bit) -- non-exportable
  764. // kernels do not take up slot numbers.
  765. mRSC->ReportError(ER->getLocation(),
  766. "%ordinal0 reduction kernel is '%1' for 32-bit targets "
  767. "but '%2' for 64-bit targets")
  768. << unsigned(reduces.CurrentIdx() + 1)
  769. << reduce.mName
  770. << Name;
  771. mReducesOrderFatal = true;
  772. return;
  773. }
  774. // If at least one of the two kernels (32-bit or 64-bit) is not
  775. // exporable, then there will be no reflection for that kernel,
  776. // and so any mismatch in result type or in inputs is irrelevant.
  777. // However, we may make more kernels exportable in the future.
  778. // Therefore, we'll forbid mismatches anyway.
  779. if (reduce.mIsExportable != IsExportable) {
  780. mRSC->ReportError(ER->getLocation(),
  781. "reduction kernel '%0' is reflected in Java only for %select{32|64}1-bit targets")
  782. << reduce.mName
  783. << IsExportable;
  784. }
  785. const std::string ResultType = getUniqueTypeName(ER->getResultType());
  786. if (!reduce.mResult.equals(ResultType)) {
  787. mRSC->ReportError(ER->getLocation(),
  788. "reduction kernel '%0' has result type '%1' for 32-bit targets "
  789. "but result type '%2' for 64-bit targets")
  790. << reduce.mName << reduce.mResult.str() << ResultType;
  791. }
  792. const auto &InTypes = ER->getAccumulatorInTypes();
  793. if (reduce.mAccumInCount != InTypes.size()) {
  794. mRSC->ReportError(ER->getLocation(),
  795. "reduction kernel '%0' has %1 input%s1 for 32-bit targets "
  796. "but %2 input%s2 for 64-bit targets")
  797. << Name << unsigned(reduce.mAccumInCount) << unsigned(InTypes.size());
  798. return;
  799. }
  800. unsigned FieldIdx = 0;
  801. for (const auto &InType : InTypes) {
  802. const std::string InTypeName = getUniqueTypeName(InType);
  803. const llvm::StringRef StateInTypeName = reduce.mAccumIns[FieldIdx++];
  804. if (!StateInTypeName.equals(InTypeName)) {
  805. mRSC->ReportError(ER->getLocation(),
  806. "%ordinal0 input of reduction kernel '%1' "
  807. "has type '%2' for 32-bit targets "
  808. "but type '%3' for 64-bit targets")
  809. << FieldIdx
  810. << Name
  811. << StateInTypeName.str()
  812. << InTypeName;
  813. }
  814. }
  815. }
  816. }
  817. void ReflectionState::endReduces() {
  818. if (!isUsing() || mReducesOrderFatal)
  819. return;
  820. auto &reduces = mFiles.Current().mReduces;
  821. while (!reduces.isFinished()) {
  822. const auto &reduce = reduces.UseNext();
  823. mRSC->ReportError("in file '%0' reduction kernel '%1' is only present for 32-bit targets")
  824. << mFiles.Current().mRSSourceFileName << reduce.mName;
  825. }
  826. }
  827. // Variable ////////////////////////////////////////////////////////////////////////////////////
  828. // Keep this in sync with initialization handling in
  829. // RSReflectionJava::genScriptClassConstructor().
  830. ReflectionState::Val32 ReflectionState::declareVariable(const RSExportVar *EV) {
  831. slangAssert(!isClosed());
  832. if (!isActive())
  833. return NoVal32();
  834. auto &variables = mFiles.Current().mVariables;
  835. if (isCollecting()) {
  836. auto &variable = variables.CollectNext();
  837. variable.mName = EV->getName();
  838. variable.mType = canon(getUniqueTypeName(EV->getType()));
  839. variable.mAllocSize = EV->getType()->getAllocSize();
  840. variable.mIsConst = EV->isConst();
  841. if (!EV->getInit().isUninit()) {
  842. variable.mInitializerCount = 1;
  843. variable.mInitializers = new clang::APValue[1];
  844. variable.mInitializers[0] = EV->getInit();
  845. } else if (EV->getArraySize()) {
  846. variable.mInitializerCount = EV->getNumInits();
  847. variable.mInitializers = new clang::APValue[variable.mInitializerCount];
  848. for (size_t i = 0; i < variable.mInitializerCount; ++i)
  849. variable.mInitializers[i] = EV->getInitArray(i);
  850. } else {
  851. variable.mInitializerCount = 0;
  852. }
  853. return NoVal32();
  854. }
  855. /*-- isUsing() -----------------------------------------------------------*/
  856. slangAssert(isUsing());
  857. if (mVariablesOrderFatal)
  858. return NoVal32();
  859. if (variables.isFinished()) {
  860. // This doesn't actually break reflection, but that's a
  861. // coincidence of the fact that we reflect during the 64-bit
  862. // compilation pass rather than the 32-bit compilation pass, and
  863. // of the fact that the "extra" variable(s) are at the end.
  864. mRSC->ReportError(EV->getLocation(), "global variable '%0' is only present for 64-bit targets")
  865. << EV->getName();
  866. return NoVal32();
  867. }
  868. const auto &variable = variables.UseNext();
  869. if (variable.mName != EV->getName()) {
  870. // Order matters because it determines slot number
  871. mRSC->ReportError(EV->getLocation(),
  872. "%ordinal0 global variable is '%1' for 32-bit targets "
  873. "but '%2' for 64-bit targets")
  874. << unsigned(variables.CurrentIdx() + 1)
  875. << variable.mName
  876. << EV->getName();
  877. mVariablesOrderFatal = true;
  878. return NoVal32();
  879. }
  880. const std::string TypeName = getUniqueTypeName(EV->getType());
  881. if (!variable.mType.equals(TypeName)) {
  882. mRSC->ReportError(EV->getLocation(),
  883. "global variable '%0' has type '%1' for 32-bit targets "
  884. "but type '%2' for 64-bit targets")
  885. << EV->getName()
  886. << variable.mType.str()
  887. << TypeName;
  888. return NoVal32();
  889. }
  890. if (variable.mIsConst != EV->isConst()) {
  891. mRSC->ReportError(EV->getLocation(),
  892. "global variable '%0' has inconsistent 'const' qualification "
  893. "between 32-bit targets and 64-bit targets")
  894. << EV->getName();
  895. return NoVal32();
  896. }
  897. // NOTE: Certain syntactically different but semantically
  898. // equivalent initialization patterns are unnecessarily rejected
  899. // as errors.
  900. //
  901. // Background:
  902. //
  903. // . A vector initialized with a scalar value is treated
  904. // by reflection as if all elements of the vector are
  905. // initialized with the scalar value.
  906. // . A vector may be initialized with a vector of greater
  907. // length; reflection ignores the extra initializers.
  908. // . If only the beginning of a vector is explicitly
  909. // initialized, reflection treats it as if trailing elements are
  910. // initialized to zero (by issuing explicit assignments to those
  911. // trailing elements).
  912. // . If only the beginning of an array is explicitly initialized,
  913. // reflection treats it as if trailing elements are initialized
  914. // to zero (by Java rules for newly-created arrays).
  915. //
  916. // Unnecessarily rejected as errors:
  917. //
  918. // . One compile initializes a vector with a scalar, and
  919. // another initializes it with a vector whose elements
  920. // are the scalar, as in
  921. //
  922. // int2 x =
  923. // #ifdef __LP64__
  924. // 1
  925. // #else
  926. // { 1, 1 }
  927. // #endif
  928. //
  929. // . Compiles initialize a vector with vectors of different
  930. // lengths, but the initializers agree up to the length
  931. // of the variable being initialized, as in
  932. //
  933. // int2 x = { 1, 2
  934. // #ifdef __LP64__
  935. // 3
  936. // #else
  937. // 4
  938. // #endif
  939. // };
  940. //
  941. // . Two compiles agree with the initializer for a vector or
  942. // array, except that one has some number of explicit trailing
  943. // zeroes, as in
  944. //
  945. // int x[4] = { 3, 2, 1
  946. // #ifdef __LP64__
  947. // , 0
  948. // #endif
  949. // };
  950. bool MismatchedInitializers = false;
  951. if (!EV->getInit().isUninit()) {
  952. // Use phase has a scalar initializer.
  953. // Make sure that Collect phase had a matching scalar initializer.
  954. if ((variable.mInitializerCount != 1) ||
  955. !equal(variable.mInitializers[0], EV->getInit()))
  956. MismatchedInitializers = true;
  957. } else if (EV->getArraySize()) {
  958. const size_t UseSize = EV->getNumInits();
  959. if (variable.mInitializerCount != UseSize)
  960. MismatchedInitializers = true;
  961. else {
  962. for (int i = 0; i < UseSize; ++i)
  963. if (!equal(variable.mInitializers[i], EV->getInitArray(i))) {
  964. MismatchedInitializers = true;
  965. break;
  966. }
  967. }
  968. } else if (variable.mInitializerCount != 0) {
  969. // Use phase does not have a scalar initializer, variable is not
  970. // an array, and Collect phase has an initializer. This is an error.
  971. MismatchedInitializers = true;
  972. }
  973. if (MismatchedInitializers) {
  974. mRSC->ReportError(EV->getLocation(),
  975. "global variable '%0' is initialized differently for 32-bit targets "
  976. "than for 64-bit targets")
  977. << EV->getName();
  978. return NoVal32();
  979. }
  980. return Val32(true, variable.mAllocSize);
  981. }
  982. void ReflectionState::endVariables() {
  983. if (!isUsing() || mVariablesOrderFatal)
  984. return;
  985. auto &variables = mFiles.Current().mVariables;
  986. while (!variables.isFinished()) {
  987. const auto &variable = variables.UseNext();
  988. mRSC->ReportError("in file '%0' global variable '%1' is only present for 32-bit targets")
  989. << mFiles.Current().mRSSourceFileName << variable.mName;
  990. }
  991. }
  992. } // namespace slang