HLOperations.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // HLOperations.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Implementation of DXIL operations. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #pragma once
  12. #include "dxc/HLSL/HLOperations.h"
  13. #include "dxc/HlslIntrinsicOp.h"
  14. #include "llvm/IR/Function.h"
  15. #include "llvm/IR/Instructions.h"
  16. #include "llvm/IR/Module.h"
  17. #include "llvm/Support/raw_ostream.h"
  18. using namespace hlsl;
  19. using namespace llvm;
  20. namespace hlsl {
  21. const char HLPrefixStr [] = "dx.hl";
  22. const char * const HLPrefix = HLPrefixStr;
  23. static const char HLLowerStrategyStr[] = "dx.hlls";
  24. static const char * const HLLowerStrategy = HLLowerStrategyStr;
  25. static StringRef HLOpcodeGroupNames[]{
  26. "notHLDXIL", // NotHL,
  27. "<ext>", // HLExtIntrinsic - should always refer through extension
  28. "op", // HLIntrinsic,
  29. "cast", // HLCast,
  30. "init", // HLInit,
  31. "binop", // HLBinOp,
  32. "unop", // HLUnOp,
  33. "subscript", // HLSubscript,
  34. "matldst", // HLMatLoadStore,
  35. "select", // HLSelect,
  36. "createhandle",// HLCreateHandle,
  37. "numOfHLDXIL", // NumOfHLOps
  38. };
  39. static StringRef HLOpcodeGroupFullNames[]{
  40. "notHLDXIL", // NotHL,
  41. "<ext>", // HLExtIntrinsic - should aways refer through extension
  42. "dx.hl.op", // HLIntrinsic,
  43. "dx.hl.cast", // HLCast,
  44. "dx.hl.init", // HLInit,
  45. "dx.hl.binop", // HLBinOp,
  46. "dx.hl.unop", // HLUnOp,
  47. "dx.hl.subscript", // HLSubscript,
  48. "dx.hl.matldst", // HLMatLoadStore,
  49. "dx.hl.select", // HLSelect,
  50. "dx.hl.createhandle", // HLCreateHandle,
  51. "numOfHLDXIL", // NumOfHLOps
  52. };
  53. static HLOpcodeGroup GetHLOpcodeGroupInternal(StringRef group) {
  54. if (!group.empty()) {
  55. switch (group[0]) {
  56. case 'o': // op
  57. return HLOpcodeGroup::HLIntrinsic;
  58. case 'c': // cast
  59. switch (group[1]) {
  60. case 'a': // cast
  61. return HLOpcodeGroup::HLCast;
  62. case 'r': // createhandle
  63. return HLOpcodeGroup::HLCreateHandle;
  64. }
  65. case 'i': // init
  66. return HLOpcodeGroup::HLInit;
  67. case 'b': // binaryOp
  68. return HLOpcodeGroup::HLBinOp;
  69. case 'u': // unaryOp
  70. return HLOpcodeGroup::HLUnOp;
  71. case 's': // subscript
  72. switch (group[1]) {
  73. case 'u':
  74. return HLOpcodeGroup::HLSubscript;
  75. case 'e':
  76. return HLOpcodeGroup::HLSelect;
  77. }
  78. case 'm': // matldst
  79. return HLOpcodeGroup::HLMatLoadStore;
  80. }
  81. }
  82. return HLOpcodeGroup::NotHL;
  83. }
  84. // GetHLOpGroup by function name.
  85. HLOpcodeGroup GetHLOpcodeGroupByName(const Function *F) {
  86. StringRef name = F->getName();
  87. if (!name.startswith(HLPrefix)) {
  88. // This could be an external intrinsic, but this function
  89. // won't recognize those as such. Use GetHLOpcodeGroupByName
  90. // to make that distinction.
  91. return HLOpcodeGroup::NotHL;
  92. }
  93. const unsigned prefixSize = sizeof(HLPrefixStr);
  94. StringRef group = name.substr(prefixSize);
  95. return GetHLOpcodeGroupInternal(group);
  96. }
  97. HLOpcodeGroup GetHLOpcodeGroup(llvm::Function *F) {
  98. llvm::StringRef name = GetHLOpcodeGroupNameByAttr(F);
  99. HLOpcodeGroup result = GetHLOpcodeGroupInternal(name);
  100. if (result == HLOpcodeGroup::NotHL) {
  101. result = name.empty() ? result : HLOpcodeGroup::HLExtIntrinsic;
  102. }
  103. if (result == HLOpcodeGroup::NotHL) {
  104. result = GetHLOpcodeGroupByName(F);
  105. }
  106. return result;
  107. }
  108. llvm::StringRef GetHLOpcodeGroupNameByAttr(llvm::Function *F) {
  109. Attribute groupAttr = F->getFnAttribute(hlsl::HLPrefix);
  110. StringRef group = groupAttr.getValueAsString();
  111. return group;
  112. }
  113. StringRef GetHLOpcodeGroupName(HLOpcodeGroup op) {
  114. switch (op) {
  115. case HLOpcodeGroup::HLCast:
  116. case HLOpcodeGroup::HLInit:
  117. case HLOpcodeGroup::HLBinOp:
  118. case HLOpcodeGroup::HLUnOp:
  119. case HLOpcodeGroup::HLIntrinsic:
  120. case HLOpcodeGroup::HLSubscript:
  121. case HLOpcodeGroup::HLMatLoadStore:
  122. case HLOpcodeGroup::HLSelect:
  123. case HLOpcodeGroup::HLCreateHandle:
  124. return HLOpcodeGroupNames[static_cast<unsigned>(op)];
  125. default:
  126. llvm_unreachable("invalid op");
  127. return "";
  128. }
  129. }
  130. StringRef GetHLOpcodeGroupFullName(HLOpcodeGroup op) {
  131. switch (op) {
  132. case HLOpcodeGroup::HLCast:
  133. case HLOpcodeGroup::HLInit:
  134. case HLOpcodeGroup::HLBinOp:
  135. case HLOpcodeGroup::HLUnOp:
  136. case HLOpcodeGroup::HLIntrinsic:
  137. case HLOpcodeGroup::HLSubscript:
  138. case HLOpcodeGroup::HLMatLoadStore:
  139. case HLOpcodeGroup::HLSelect:
  140. case HLOpcodeGroup::HLCreateHandle:
  141. return HLOpcodeGroupFullNames[static_cast<unsigned>(op)];
  142. default:
  143. llvm_unreachable("invalid op");
  144. return "";
  145. }
  146. }
  147. llvm::StringRef GetHLOpcodeName(HLUnaryOpcode Op) {
  148. switch (Op) {
  149. case HLUnaryOpcode::PostInc: return "++";
  150. case HLUnaryOpcode::PostDec: return "--";
  151. case HLUnaryOpcode::PreInc: return "++";
  152. case HLUnaryOpcode::PreDec: return "--";
  153. case HLUnaryOpcode::Plus: return "+";
  154. case HLUnaryOpcode::Minus: return "-";
  155. case HLUnaryOpcode::Not: return "~";
  156. case HLUnaryOpcode::LNot: return "!";
  157. }
  158. llvm_unreachable("Unknown unary operator");
  159. }
  160. llvm::StringRef GetHLOpcodeName(HLBinaryOpcode Op) {
  161. switch (Op) {
  162. case HLBinaryOpcode::Mul: return "*";
  163. case HLBinaryOpcode::UDiv:
  164. case HLBinaryOpcode::Div: return "/";
  165. case HLBinaryOpcode::URem:
  166. case HLBinaryOpcode::Rem: return "%";
  167. case HLBinaryOpcode::Add: return "+";
  168. case HLBinaryOpcode::Sub: return "-";
  169. case HLBinaryOpcode::Shl: return "<<";
  170. case HLBinaryOpcode::UShr:
  171. case HLBinaryOpcode::Shr: return ">>";
  172. case HLBinaryOpcode::ULT:
  173. case HLBinaryOpcode::LT: return "<";
  174. case HLBinaryOpcode::UGT:
  175. case HLBinaryOpcode::GT: return ">";
  176. case HLBinaryOpcode::ULE:
  177. case HLBinaryOpcode::LE: return "<=";
  178. case HLBinaryOpcode::UGE:
  179. case HLBinaryOpcode::GE: return ">=";
  180. case HLBinaryOpcode::EQ: return "==";
  181. case HLBinaryOpcode::NE: return "!=";
  182. case HLBinaryOpcode::And: return "&";
  183. case HLBinaryOpcode::Xor: return "^";
  184. case HLBinaryOpcode::Or: return "|";
  185. case HLBinaryOpcode::LAnd: return "&&";
  186. case HLBinaryOpcode::LOr: return "||";
  187. }
  188. llvm_unreachable("Invalid OpCode!");
  189. }
  190. llvm::StringRef GetHLOpcodeName(HLSubscriptOpcode Op) {
  191. switch (Op) {
  192. case HLSubscriptOpcode::DefaultSubscript:
  193. return "[]";
  194. case HLSubscriptOpcode::ColMatSubscript:
  195. return "colMajor[]";
  196. case HLSubscriptOpcode::RowMatSubscript:
  197. return "rowMajor[]";
  198. case HLSubscriptOpcode::ColMatElement:
  199. return "colMajor_m";
  200. case HLSubscriptOpcode::RowMatElement:
  201. return "rowMajor_m";
  202. case HLSubscriptOpcode::DoubleSubscript:
  203. return "[][]";
  204. case HLSubscriptOpcode::CBufferSubscript:
  205. return "cb";
  206. case HLSubscriptOpcode::VectorSubscript:
  207. return "vector[]";
  208. }
  209. return "";
  210. }
  211. llvm::StringRef GetHLOpcodeName(HLCastOpcode Op) {
  212. switch (Op) {
  213. case HLCastOpcode::DefaultCast:
  214. return "default";
  215. case HLCastOpcode::ToUnsignedCast:
  216. return "toUnsigned";
  217. case HLCastOpcode::FromUnsignedCast:
  218. return "fromUnsigned";
  219. case HLCastOpcode::UnsignedUnsignedCast:
  220. return "unsignedUnsigned";
  221. case HLCastOpcode::ColMatrixToVecCast:
  222. return "colMatToVec";
  223. case HLCastOpcode::RowMatrixToVecCast:
  224. return "rowMatToVec";
  225. case HLCastOpcode::ColMatrixToRowMatrix:
  226. return "colMatToRowMat";
  227. case HLCastOpcode::RowMatrixToColMatrix:
  228. return "rowMatToColMat";
  229. case HLCastOpcode::HandleToResCast:
  230. return "handleToRes";
  231. }
  232. return "";
  233. }
  234. llvm::StringRef GetHLOpcodeName(HLMatLoadStoreOpcode Op) {
  235. switch (Op) {
  236. case HLMatLoadStoreOpcode::ColMatLoad:
  237. return "colLoad";
  238. case HLMatLoadStoreOpcode::ColMatStore:
  239. return "colStore";
  240. case HLMatLoadStoreOpcode::RowMatLoad:
  241. return "rowLoad";
  242. case HLMatLoadStoreOpcode::RowMatStore:
  243. return "rowStore";
  244. }
  245. llvm_unreachable("invalid matrix load store operator");
  246. }
  247. StringRef GetHLLowerStrategy(Function *F) {
  248. llvm::Attribute A = F->getFnAttribute(HLLowerStrategy);
  249. llvm::StringRef LowerStrategy = A.getValueAsString();
  250. return LowerStrategy;
  251. }
  252. void SetHLLowerStrategy(Function *F, StringRef S) {
  253. F->addFnAttr(HLLowerStrategy, S);
  254. }
  255. std::string GetHLFullName(HLOpcodeGroup op, unsigned opcode) {
  256. assert(op != HLOpcodeGroup::HLExtIntrinsic && "else table name should be used");
  257. std::string opName = GetHLOpcodeGroupFullName(op).str() + ".";
  258. switch (op) {
  259. case HLOpcodeGroup::HLBinOp: {
  260. HLBinaryOpcode binOp = static_cast<HLBinaryOpcode>(opcode);
  261. return opName + GetHLOpcodeName(binOp).str();
  262. }
  263. case HLOpcodeGroup::HLUnOp: {
  264. HLUnaryOpcode unOp = static_cast<HLUnaryOpcode>(opcode);
  265. return opName + GetHLOpcodeName(unOp).str();
  266. }
  267. case HLOpcodeGroup::HLIntrinsic: {
  268. // intrinsic with same signature will share the funciton now
  269. // The opcode is in arg0.
  270. return opName;
  271. }
  272. case HLOpcodeGroup::HLMatLoadStore: {
  273. HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
  274. return opName + GetHLOpcodeName(matOp).str();
  275. }
  276. case HLOpcodeGroup::HLSubscript: {
  277. HLSubscriptOpcode subOp = static_cast<HLSubscriptOpcode>(opcode);
  278. return opName + GetHLOpcodeName(subOp).str();
  279. }
  280. case HLOpcodeGroup::HLCast: {
  281. HLCastOpcode castOp = static_cast<HLCastOpcode>(opcode);
  282. return opName + GetHLOpcodeName(castOp).str();
  283. }
  284. default:
  285. return opName;
  286. }
  287. }
  288. // Get opcode from arg0 of function call.
  289. unsigned GetHLOpcode(const CallInst *CI) {
  290. Value *idArg = CI->getArgOperand(HLOperandIndex::kOpcodeIdx);
  291. Constant *idConst = cast<Constant>(idArg);
  292. return idConst->getUniqueInteger().getLimitedValue();
  293. }
  294. unsigned GetRowMajorOpcode(HLOpcodeGroup group, unsigned opcode) {
  295. switch (group) {
  296. case HLOpcodeGroup::HLMatLoadStore: {
  297. HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
  298. switch (matOp) {
  299. case HLMatLoadStoreOpcode::ColMatLoad:
  300. return static_cast<unsigned>(HLMatLoadStoreOpcode::RowMatLoad);
  301. case HLMatLoadStoreOpcode::ColMatStore:
  302. return static_cast<unsigned>(HLMatLoadStoreOpcode::RowMatStore);
  303. default:
  304. return opcode;
  305. }
  306. } break;
  307. case HLOpcodeGroup::HLSubscript: {
  308. HLSubscriptOpcode subOp = static_cast<HLSubscriptOpcode>(opcode);
  309. switch (subOp) {
  310. case HLSubscriptOpcode::ColMatElement:
  311. return static_cast<unsigned>(HLSubscriptOpcode::RowMatElement);
  312. case HLSubscriptOpcode::ColMatSubscript:
  313. return static_cast<unsigned>(HLSubscriptOpcode::RowMatSubscript);
  314. default:
  315. return opcode;
  316. }
  317. } break;
  318. default:
  319. return opcode;
  320. }
  321. }
  322. bool HasUnsignedOpcode(unsigned opcode) {
  323. return HasUnsignedIntrinsicOpcode(static_cast<IntrinsicOp>(opcode));
  324. }
  325. unsigned GetUnsignedOpcode(unsigned opcode) {
  326. return GetUnsignedIntrinsicOpcode(static_cast<IntrinsicOp>(opcode));
  327. }
  328. // For HLBinaryOpcode
  329. bool HasUnsignedOpcode(HLBinaryOpcode opcode) {
  330. switch (opcode) {
  331. case HLBinaryOpcode::Div:
  332. case HLBinaryOpcode::Rem:
  333. case HLBinaryOpcode::Shr:
  334. case HLBinaryOpcode::LT:
  335. case HLBinaryOpcode::GT:
  336. case HLBinaryOpcode::LE:
  337. case HLBinaryOpcode::GE:
  338. return true;
  339. default:
  340. return false;
  341. }
  342. }
  343. HLBinaryOpcode GetUnsignedOpcode(HLBinaryOpcode opcode) {
  344. switch (opcode) {
  345. case HLBinaryOpcode::Div:
  346. return HLBinaryOpcode::UDiv;
  347. case HLBinaryOpcode::Rem:
  348. return HLBinaryOpcode::URem;
  349. case HLBinaryOpcode::Shr:
  350. return HLBinaryOpcode::UShr;
  351. case HLBinaryOpcode::LT:
  352. return HLBinaryOpcode::ULT;
  353. case HLBinaryOpcode::GT:
  354. return HLBinaryOpcode::UGT;
  355. case HLBinaryOpcode::LE:
  356. return HLBinaryOpcode::ULE;
  357. case HLBinaryOpcode::GE:
  358. return HLBinaryOpcode::UGE;
  359. default:
  360. return opcode;
  361. }
  362. }
  363. static void SetHLFunctionAttribute(Function *F, HLOpcodeGroup group,
  364. unsigned opcode) {
  365. switch (group) {
  366. case HLOpcodeGroup::HLUnOp:
  367. case HLOpcodeGroup::HLBinOp:
  368. case HLOpcodeGroup::HLCast:
  369. case HLOpcodeGroup::HLSubscript:
  370. if (!F->hasFnAttribute(Attribute::ReadNone)) {
  371. F->addFnAttr(Attribute::ReadNone);
  372. F->addFnAttr(Attribute::NoUnwind);
  373. }
  374. break;
  375. case HLOpcodeGroup::HLInit:
  376. if (!F->hasFnAttribute(Attribute::ReadNone))
  377. if (!F->getReturnType()->isVoidTy()) {
  378. F->addFnAttr(Attribute::ReadNone);
  379. F->addFnAttr(Attribute::NoUnwind);
  380. }
  381. break;
  382. case HLOpcodeGroup::HLMatLoadStore: {
  383. HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
  384. if (matOp == HLMatLoadStoreOpcode::ColMatLoad ||
  385. matOp == HLMatLoadStoreOpcode::RowMatLoad)
  386. if (!F->hasFnAttribute(Attribute::ReadOnly)) {
  387. F->addFnAttr(Attribute::ReadOnly);
  388. F->addFnAttr(Attribute::NoUnwind);
  389. }
  390. } break;
  391. case HLOpcodeGroup::HLCreateHandle: {
  392. F->addFnAttr(Attribute::ReadNone);
  393. F->addFnAttr(Attribute::NoUnwind);
  394. F->addFnAttr(Attribute::NoInline);
  395. F->setLinkage(llvm::GlobalValue::LinkageTypes::InternalLinkage);
  396. } break;
  397. }
  398. }
  399. Function *GetOrCreateHLFunction(Module &M, FunctionType *funcTy,
  400. HLOpcodeGroup group, unsigned opcode) {
  401. return GetOrCreateHLFunction(M, funcTy, group, nullptr, nullptr, opcode);
  402. }
  403. Function *GetOrCreateHLFunction(Module &M, FunctionType *funcTy,
  404. HLOpcodeGroup group, llvm::StringRef *groupName,
  405. llvm::StringRef *fnName, unsigned opcode) {
  406. std::string mangledName;
  407. raw_string_ostream mangledNameStr(mangledName);
  408. if (group == HLOpcodeGroup::HLExtIntrinsic) {
  409. assert(groupName && "else intrinsic should have been rejected");
  410. assert(fnName && "else intrinsic should have been rejected");
  411. mangledNameStr << *groupName;
  412. mangledNameStr << '.';
  413. mangledNameStr << *fnName;
  414. }
  415. else {
  416. mangledNameStr << GetHLFullName(group, opcode);
  417. mangledNameStr << '.';
  418. funcTy->print(mangledNameStr);
  419. }
  420. mangledNameStr.flush();
  421. Function *F = cast<Function>(M.getOrInsertFunction(mangledName, funcTy));
  422. if (group == HLOpcodeGroup::HLExtIntrinsic) {
  423. F->addFnAttr(hlsl::HLPrefix, *groupName);
  424. }
  425. SetHLFunctionAttribute(F, group, opcode);
  426. return F;
  427. }
  428. // HLFunction with body cannot share with HLFunction without body.
  429. // So need add name.
  430. Function *GetOrCreateHLFunctionWithBody(Module &M, FunctionType *funcTy,
  431. HLOpcodeGroup group, unsigned opcode,
  432. StringRef name) {
  433. std::string operatorName = GetHLFullName(group, opcode);
  434. std::string mangledName = operatorName + "." + name.str();
  435. raw_string_ostream mangledNameStr(mangledName);
  436. funcTy->print(mangledNameStr);
  437. mangledNameStr.flush();
  438. Function *F = cast<Function>(M.getOrInsertFunction(mangledName, funcTy));
  439. SetHLFunctionAttribute(F, group, opcode);
  440. return F;
  441. }
  442. } // namespace hlsl