HLOperations.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  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. #include "dxc/HLSL/HLOperations.h"
  12. #include "dxc/HlslIntrinsicOp.h"
  13. #include "llvm/IR/Function.h"
  14. #include "llvm/IR/Instructions.h"
  15. #include "llvm/IR/Module.h"
  16. #include "llvm/Support/raw_ostream.h"
  17. using namespace hlsl;
  18. using namespace llvm;
  19. namespace hlsl {
  20. const char HLPrefixStr [] = "dx.hl";
  21. const char * const HLPrefix = HLPrefixStr;
  22. static const char HLLowerStrategyStr[] = "dx.hlls";
  23. static const char * const HLLowerStrategy = HLLowerStrategyStr;
  24. static const char HLWaveSensitiveStr[] = "dx.wave-sensitive";
  25. static const char * const HLWaveSensitive = HLWaveSensitiveStr;
  26. static StringRef HLOpcodeGroupNames[]{
  27. "notHLDXIL", // NotHL,
  28. "<ext>", // HLExtIntrinsic - should always refer through extension
  29. "op", // HLIntrinsic,
  30. "cast", // HLCast,
  31. "init", // HLInit,
  32. "binop", // HLBinOp,
  33. "unop", // HLUnOp,
  34. "subscript", // HLSubscript,
  35. "matldst", // HLMatLoadStore,
  36. "select", // HLSelect,
  37. "createhandle",// HLCreateHandle,
  38. "annotatehandle" // HLAnnotateHandle,
  39. "numOfHLDXIL", // NumOfHLOps
  40. };
  41. static StringRef HLOpcodeGroupFullNames[]{
  42. "notHLDXIL", // NotHL,
  43. "<ext>", // HLExtIntrinsic - should aways refer through extension
  44. "dx.hl.op", // HLIntrinsic,
  45. "dx.hl.cast", // HLCast,
  46. "dx.hl.init", // HLInit,
  47. "dx.hl.binop", // HLBinOp,
  48. "dx.hl.unop", // HLUnOp,
  49. "dx.hl.subscript", // HLSubscript,
  50. "dx.hl.matldst", // HLMatLoadStore,
  51. "dx.hl.select", // HLSelect,
  52. "dx.hl.createhandle", // HLCreateHandle,
  53. "dx.hl.annotatehandle", // HLAnnotateHandle,
  54. "numOfHLDXIL", // NumOfHLOps
  55. };
  56. static HLOpcodeGroup GetHLOpcodeGroupInternal(StringRef group) {
  57. if (!group.empty()) {
  58. switch (group[0]) {
  59. case 'o': // op
  60. return HLOpcodeGroup::HLIntrinsic;
  61. case 'c': // cast
  62. switch (group[1]) {
  63. case 'a': // cast
  64. return HLOpcodeGroup::HLCast;
  65. case 'r': // createhandle
  66. return HLOpcodeGroup::HLCreateHandle;
  67. }
  68. case 'i': // init
  69. return HLOpcodeGroup::HLInit;
  70. case 'b': // binaryOp
  71. return HLOpcodeGroup::HLBinOp;
  72. case 'u': // unaryOp
  73. return HLOpcodeGroup::HLUnOp;
  74. case 's': // subscript
  75. switch (group[1]) {
  76. case 'u':
  77. return HLOpcodeGroup::HLSubscript;
  78. case 'e':
  79. return HLOpcodeGroup::HLSelect;
  80. }
  81. case 'm': // matldst
  82. return HLOpcodeGroup::HLMatLoadStore;
  83. case 'a': // annotatehandle
  84. return HLOpcodeGroup::HLAnnotateHandle;
  85. }
  86. }
  87. return HLOpcodeGroup::NotHL;
  88. }
  89. // GetHLOpGroup by function name.
  90. HLOpcodeGroup GetHLOpcodeGroupByName(const Function *F) {
  91. StringRef name = F->getName();
  92. if (!name.startswith(HLPrefix)) {
  93. // This could be an external intrinsic, but this function
  94. // won't recognize those as such. Use GetHLOpcodeGroupByName
  95. // to make that distinction.
  96. return HLOpcodeGroup::NotHL;
  97. }
  98. const unsigned prefixSize = sizeof(HLPrefixStr);
  99. StringRef group = name.substr(prefixSize);
  100. return GetHLOpcodeGroupInternal(group);
  101. }
  102. HLOpcodeGroup GetHLOpcodeGroup(llvm::Function *F) {
  103. llvm::StringRef name = GetHLOpcodeGroupNameByAttr(F);
  104. HLOpcodeGroup result = GetHLOpcodeGroupInternal(name);
  105. if (result == HLOpcodeGroup::NotHL) {
  106. result = name.empty() ? result : HLOpcodeGroup::HLExtIntrinsic;
  107. }
  108. if (result == HLOpcodeGroup::NotHL) {
  109. result = GetHLOpcodeGroupByName(F);
  110. }
  111. return result;
  112. }
  113. llvm::StringRef GetHLOpcodeGroupNameByAttr(llvm::Function *F) {
  114. Attribute groupAttr = F->getFnAttribute(hlsl::HLPrefix);
  115. StringRef group = groupAttr.getValueAsString();
  116. return group;
  117. }
  118. StringRef GetHLOpcodeGroupName(HLOpcodeGroup op) {
  119. switch (op) {
  120. case HLOpcodeGroup::HLCast:
  121. case HLOpcodeGroup::HLInit:
  122. case HLOpcodeGroup::HLBinOp:
  123. case HLOpcodeGroup::HLUnOp:
  124. case HLOpcodeGroup::HLIntrinsic:
  125. case HLOpcodeGroup::HLSubscript:
  126. case HLOpcodeGroup::HLMatLoadStore:
  127. case HLOpcodeGroup::HLSelect:
  128. case HLOpcodeGroup::HLCreateHandle:
  129. case HLOpcodeGroup::HLAnnotateHandle:
  130. return HLOpcodeGroupNames[static_cast<unsigned>(op)];
  131. default:
  132. llvm_unreachable("invalid op");
  133. return "";
  134. }
  135. }
  136. StringRef GetHLOpcodeGroupFullName(HLOpcodeGroup op) {
  137. switch (op) {
  138. case HLOpcodeGroup::HLCast:
  139. case HLOpcodeGroup::HLInit:
  140. case HLOpcodeGroup::HLBinOp:
  141. case HLOpcodeGroup::HLUnOp:
  142. case HLOpcodeGroup::HLIntrinsic:
  143. case HLOpcodeGroup::HLSubscript:
  144. case HLOpcodeGroup::HLMatLoadStore:
  145. case HLOpcodeGroup::HLSelect:
  146. case HLOpcodeGroup::HLCreateHandle:
  147. case HLOpcodeGroup::HLAnnotateHandle:
  148. return HLOpcodeGroupFullNames[static_cast<unsigned>(op)];
  149. default:
  150. llvm_unreachable("invalid op");
  151. return "";
  152. }
  153. }
  154. llvm::StringRef GetHLOpcodeName(HLUnaryOpcode Op) {
  155. switch (Op) {
  156. case HLUnaryOpcode::PostInc: return "++";
  157. case HLUnaryOpcode::PostDec: return "--";
  158. case HLUnaryOpcode::PreInc: return "++";
  159. case HLUnaryOpcode::PreDec: return "--";
  160. case HLUnaryOpcode::Plus: return "+";
  161. case HLUnaryOpcode::Minus: return "-";
  162. case HLUnaryOpcode::Not: return "~";
  163. case HLUnaryOpcode::LNot: return "!";
  164. case HLUnaryOpcode::Invalid:
  165. case HLUnaryOpcode::NumOfUO:
  166. // Invalid Unary Ops
  167. break;
  168. }
  169. llvm_unreachable("Unknown unary operator");
  170. }
  171. llvm::StringRef GetHLOpcodeName(HLBinaryOpcode Op) {
  172. switch (Op) {
  173. case HLBinaryOpcode::Mul: return "*";
  174. case HLBinaryOpcode::UDiv:
  175. case HLBinaryOpcode::Div: return "/";
  176. case HLBinaryOpcode::URem:
  177. case HLBinaryOpcode::Rem: return "%";
  178. case HLBinaryOpcode::Add: return "+";
  179. case HLBinaryOpcode::Sub: return "-";
  180. case HLBinaryOpcode::Shl: return "<<";
  181. case HLBinaryOpcode::UShr:
  182. case HLBinaryOpcode::Shr: return ">>";
  183. case HLBinaryOpcode::ULT:
  184. case HLBinaryOpcode::LT: return "<";
  185. case HLBinaryOpcode::UGT:
  186. case HLBinaryOpcode::GT: return ">";
  187. case HLBinaryOpcode::ULE:
  188. case HLBinaryOpcode::LE: return "<=";
  189. case HLBinaryOpcode::UGE:
  190. case HLBinaryOpcode::GE: return ">=";
  191. case HLBinaryOpcode::EQ: return "==";
  192. case HLBinaryOpcode::NE: return "!=";
  193. case HLBinaryOpcode::And: return "&";
  194. case HLBinaryOpcode::Xor: return "^";
  195. case HLBinaryOpcode::Or: return "|";
  196. case HLBinaryOpcode::LAnd: return "&&";
  197. case HLBinaryOpcode::LOr: return "||";
  198. case HLBinaryOpcode::Invalid:
  199. case HLBinaryOpcode::NumOfBO:
  200. // Invalid Binary Ops
  201. break;
  202. }
  203. llvm_unreachable("Invalid OpCode!");
  204. }
  205. llvm::StringRef GetHLOpcodeName(HLSubscriptOpcode Op) {
  206. switch (Op) {
  207. case HLSubscriptOpcode::DefaultSubscript:
  208. return "[]";
  209. case HLSubscriptOpcode::ColMatSubscript:
  210. return "colMajor[]";
  211. case HLSubscriptOpcode::RowMatSubscript:
  212. return "rowMajor[]";
  213. case HLSubscriptOpcode::ColMatElement:
  214. return "colMajor_m";
  215. case HLSubscriptOpcode::RowMatElement:
  216. return "rowMajor_m";
  217. case HLSubscriptOpcode::DoubleSubscript:
  218. return "[][]";
  219. case HLSubscriptOpcode::CBufferSubscript:
  220. return "cb";
  221. case HLSubscriptOpcode::VectorSubscript:
  222. return "vector[]";
  223. }
  224. return "";
  225. }
  226. llvm::StringRef GetHLOpcodeName(HLCastOpcode Op) {
  227. switch (Op) {
  228. case HLCastOpcode::DefaultCast:
  229. return "default";
  230. case HLCastOpcode::ToUnsignedCast:
  231. return "toUnsigned";
  232. case HLCastOpcode::FromUnsignedCast:
  233. return "fromUnsigned";
  234. case HLCastOpcode::UnsignedUnsignedCast:
  235. return "unsignedUnsigned";
  236. case HLCastOpcode::ColMatrixToVecCast:
  237. return "colMatToVec";
  238. case HLCastOpcode::RowMatrixToVecCast:
  239. return "rowMatToVec";
  240. case HLCastOpcode::ColMatrixToRowMatrix:
  241. return "colMatToRowMat";
  242. case HLCastOpcode::RowMatrixToColMatrix:
  243. return "rowMatToColMat";
  244. case HLCastOpcode::HandleToResCast:
  245. return "handleToRes";
  246. }
  247. return "";
  248. }
  249. llvm::StringRef GetHLOpcodeName(HLMatLoadStoreOpcode Op) {
  250. switch (Op) {
  251. case HLMatLoadStoreOpcode::ColMatLoad:
  252. return "colLoad";
  253. case HLMatLoadStoreOpcode::ColMatStore:
  254. return "colStore";
  255. case HLMatLoadStoreOpcode::RowMatLoad:
  256. return "rowLoad";
  257. case HLMatLoadStoreOpcode::RowMatStore:
  258. return "rowStore";
  259. }
  260. llvm_unreachable("invalid matrix load store operator");
  261. }
  262. StringRef GetHLLowerStrategy(Function *F) {
  263. llvm::Attribute A = F->getFnAttribute(HLLowerStrategy);
  264. llvm::StringRef LowerStrategy = A.getValueAsString();
  265. return LowerStrategy;
  266. }
  267. void SetHLLowerStrategy(Function *F, StringRef S) {
  268. F->addFnAttr(HLLowerStrategy, S);
  269. }
  270. // Set function attribute indicating wave-sensitivity
  271. void SetHLWaveSensitive(Function *F) {
  272. F->addFnAttr(HLWaveSensitive, "y");
  273. }
  274. // Return if this Function is dependent on other wave members indicated by attribute
  275. bool IsHLWaveSensitive(Function *F) {
  276. AttributeSet attrSet = F->getAttributes();
  277. return attrSet.hasAttribute(AttributeSet::FunctionIndex, HLWaveSensitive);
  278. }
  279. std::string GetHLFullName(HLOpcodeGroup op, unsigned opcode) {
  280. assert(op != HLOpcodeGroup::HLExtIntrinsic && "else table name should be used");
  281. std::string opName = GetHLOpcodeGroupFullName(op).str() + ".";
  282. switch (op) {
  283. case HLOpcodeGroup::HLBinOp: {
  284. HLBinaryOpcode binOp = static_cast<HLBinaryOpcode>(opcode);
  285. return opName + GetHLOpcodeName(binOp).str();
  286. }
  287. case HLOpcodeGroup::HLUnOp: {
  288. HLUnaryOpcode unOp = static_cast<HLUnaryOpcode>(opcode);
  289. return opName + GetHLOpcodeName(unOp).str();
  290. }
  291. case HLOpcodeGroup::HLIntrinsic: {
  292. // intrinsic with same signature will share the funciton now
  293. // The opcode is in arg0.
  294. return opName;
  295. }
  296. case HLOpcodeGroup::HLMatLoadStore: {
  297. HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
  298. return opName + GetHLOpcodeName(matOp).str();
  299. }
  300. case HLOpcodeGroup::HLSubscript: {
  301. HLSubscriptOpcode subOp = static_cast<HLSubscriptOpcode>(opcode);
  302. return opName + GetHLOpcodeName(subOp).str();
  303. }
  304. case HLOpcodeGroup::HLCast: {
  305. HLCastOpcode castOp = static_cast<HLCastOpcode>(opcode);
  306. return opName + GetHLOpcodeName(castOp).str();
  307. }
  308. default:
  309. return opName;
  310. }
  311. }
  312. // Get opcode from arg0 of function call.
  313. unsigned GetHLOpcode(const CallInst *CI) {
  314. Value *idArg = CI->getArgOperand(HLOperandIndex::kOpcodeIdx);
  315. Constant *idConst = cast<Constant>(idArg);
  316. return idConst->getUniqueInteger().getLimitedValue();
  317. }
  318. unsigned GetRowMajorOpcode(HLOpcodeGroup group, unsigned opcode) {
  319. switch (group) {
  320. case HLOpcodeGroup::HLMatLoadStore: {
  321. HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
  322. switch (matOp) {
  323. case HLMatLoadStoreOpcode::ColMatLoad:
  324. return static_cast<unsigned>(HLMatLoadStoreOpcode::RowMatLoad);
  325. case HLMatLoadStoreOpcode::ColMatStore:
  326. return static_cast<unsigned>(HLMatLoadStoreOpcode::RowMatStore);
  327. default:
  328. return opcode;
  329. }
  330. } break;
  331. case HLOpcodeGroup::HLSubscript: {
  332. HLSubscriptOpcode subOp = static_cast<HLSubscriptOpcode>(opcode);
  333. switch (subOp) {
  334. case HLSubscriptOpcode::ColMatElement:
  335. return static_cast<unsigned>(HLSubscriptOpcode::RowMatElement);
  336. case HLSubscriptOpcode::ColMatSubscript:
  337. return static_cast<unsigned>(HLSubscriptOpcode::RowMatSubscript);
  338. default:
  339. return opcode;
  340. }
  341. } break;
  342. default:
  343. return opcode;
  344. }
  345. }
  346. bool HasUnsignedOpcode(unsigned opcode) {
  347. return HasUnsignedIntrinsicOpcode(static_cast<IntrinsicOp>(opcode));
  348. }
  349. unsigned GetUnsignedOpcode(unsigned opcode) {
  350. return GetUnsignedIntrinsicOpcode(static_cast<IntrinsicOp>(opcode));
  351. }
  352. // For HLBinaryOpcode
  353. bool HasUnsignedOpcode(HLBinaryOpcode opcode) {
  354. switch (opcode) {
  355. case HLBinaryOpcode::Div:
  356. case HLBinaryOpcode::Rem:
  357. case HLBinaryOpcode::Shr:
  358. case HLBinaryOpcode::LT:
  359. case HLBinaryOpcode::GT:
  360. case HLBinaryOpcode::LE:
  361. case HLBinaryOpcode::GE:
  362. return true;
  363. default:
  364. return false;
  365. }
  366. }
  367. HLBinaryOpcode GetUnsignedOpcode(HLBinaryOpcode opcode) {
  368. switch (opcode) {
  369. case HLBinaryOpcode::Div:
  370. return HLBinaryOpcode::UDiv;
  371. case HLBinaryOpcode::Rem:
  372. return HLBinaryOpcode::URem;
  373. case HLBinaryOpcode::Shr:
  374. return HLBinaryOpcode::UShr;
  375. case HLBinaryOpcode::LT:
  376. return HLBinaryOpcode::ULT;
  377. case HLBinaryOpcode::GT:
  378. return HLBinaryOpcode::UGT;
  379. case HLBinaryOpcode::LE:
  380. return HLBinaryOpcode::ULE;
  381. case HLBinaryOpcode::GE:
  382. return HLBinaryOpcode::UGE;
  383. default:
  384. return opcode;
  385. }
  386. }
  387. static void SetHLFunctionAttribute(Function *F, HLOpcodeGroup group,
  388. unsigned opcode) {
  389. switch (group) {
  390. case HLOpcodeGroup::HLUnOp:
  391. case HLOpcodeGroup::HLBinOp:
  392. case HLOpcodeGroup::HLCast:
  393. case HLOpcodeGroup::HLSubscript:
  394. if (!F->hasFnAttribute(Attribute::ReadNone)) {
  395. F->addFnAttr(Attribute::ReadNone);
  396. F->addFnAttr(Attribute::NoUnwind);
  397. }
  398. break;
  399. case HLOpcodeGroup::HLInit:
  400. if (!F->hasFnAttribute(Attribute::ReadNone))
  401. if (!F->getReturnType()->isVoidTy()) {
  402. F->addFnAttr(Attribute::ReadNone);
  403. F->addFnAttr(Attribute::NoUnwind);
  404. }
  405. break;
  406. case HLOpcodeGroup::HLMatLoadStore: {
  407. HLMatLoadStoreOpcode matOp = static_cast<HLMatLoadStoreOpcode>(opcode);
  408. if (matOp == HLMatLoadStoreOpcode::ColMatLoad ||
  409. matOp == HLMatLoadStoreOpcode::RowMatLoad)
  410. if (!F->hasFnAttribute(Attribute::ReadOnly)) {
  411. F->addFnAttr(Attribute::ReadOnly);
  412. F->addFnAttr(Attribute::NoUnwind);
  413. }
  414. } break;
  415. case HLOpcodeGroup::HLCreateHandle: {
  416. F->addFnAttr(Attribute::ReadNone);
  417. F->addFnAttr(Attribute::NoUnwind);
  418. } break;
  419. case HLOpcodeGroup::HLAnnotateHandle: {
  420. F->addFnAttr(Attribute::ReadNone);
  421. F->addFnAttr(Attribute::NoUnwind);
  422. } break;
  423. case HLOpcodeGroup::HLIntrinsic: {
  424. IntrinsicOp intrinsicOp = static_cast<IntrinsicOp>(opcode);
  425. switch (intrinsicOp) {
  426. default:
  427. break;
  428. case IntrinsicOp::IOP_DeviceMemoryBarrierWithGroupSync:
  429. case IntrinsicOp::IOP_DeviceMemoryBarrier:
  430. case IntrinsicOp::IOP_GroupMemoryBarrierWithGroupSync:
  431. case IntrinsicOp::IOP_GroupMemoryBarrier:
  432. case IntrinsicOp::IOP_AllMemoryBarrierWithGroupSync:
  433. case IntrinsicOp::IOP_AllMemoryBarrier:
  434. F->addFnAttr(Attribute::NoDuplicate);
  435. break;
  436. }
  437. } break;
  438. case HLOpcodeGroup::NotHL:
  439. case HLOpcodeGroup::HLExtIntrinsic:
  440. case HLOpcodeGroup::HLSelect:
  441. case HLOpcodeGroup::NumOfHLOps:
  442. // No default attributes for these opcodes.
  443. break;
  444. }
  445. }
  446. Function *GetOrCreateHLFunction(Module &M, FunctionType *funcTy,
  447. HLOpcodeGroup group, unsigned opcode) {
  448. AttributeSet attribs;
  449. return GetOrCreateHLFunction(M, funcTy, group, nullptr, nullptr, opcode, attribs);
  450. }
  451. Function *GetOrCreateHLFunction(Module &M, FunctionType *funcTy,
  452. HLOpcodeGroup group, StringRef *groupName,
  453. StringRef *fnName, unsigned opcode) {
  454. AttributeSet attribs;
  455. return GetOrCreateHLFunction(M, funcTy, group, groupName, fnName, opcode, attribs);
  456. }
  457. Function *GetOrCreateHLFunction(Module &M, FunctionType *funcTy,
  458. HLOpcodeGroup group, unsigned opcode,
  459. const AttributeSet &attribs) {
  460. return GetOrCreateHLFunction(M, funcTy, group, nullptr, nullptr, opcode, attribs);
  461. }
  462. Function *GetOrCreateHLFunction(Module &M, FunctionType *funcTy,
  463. HLOpcodeGroup group, StringRef *groupName,
  464. StringRef *fnName, unsigned opcode,
  465. const AttributeSet &attribs) {
  466. std::string mangledName;
  467. raw_string_ostream mangledNameStr(mangledName);
  468. if (group == HLOpcodeGroup::HLExtIntrinsic) {
  469. assert(groupName && "else intrinsic should have been rejected");
  470. assert(fnName && "else intrinsic should have been rejected");
  471. mangledNameStr << *groupName;
  472. mangledNameStr << '.';
  473. mangledNameStr << *fnName;
  474. }
  475. else {
  476. mangledNameStr << GetHLFullName(group, opcode);
  477. // Need to add wave sensitivity to name to prevent clashes with non-wave intrinsic
  478. if(attribs.hasAttribute(AttributeSet::FunctionIndex, HLWaveSensitive))
  479. mangledNameStr << "wave";
  480. mangledNameStr << '.';
  481. funcTy->print(mangledNameStr);
  482. }
  483. mangledNameStr.flush();
  484. Function *F = cast<Function>(M.getOrInsertFunction(mangledName, funcTy));
  485. if (group == HLOpcodeGroup::HLExtIntrinsic) {
  486. F->addFnAttr(hlsl::HLPrefix, *groupName);
  487. }
  488. SetHLFunctionAttribute(F, group, opcode);
  489. // Copy attributes
  490. if (attribs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone))
  491. F->addFnAttr(Attribute::ReadNone);
  492. if (attribs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly))
  493. F->addFnAttr(Attribute::ReadOnly);
  494. if (attribs.hasAttribute(AttributeSet::FunctionIndex, HLWaveSensitive))
  495. F->addFnAttr(HLWaveSensitive, "y");
  496. return F;
  497. }
  498. // HLFunction with body cannot share with HLFunction without body.
  499. // So need add name.
  500. Function *GetOrCreateHLFunctionWithBody(Module &M, FunctionType *funcTy,
  501. HLOpcodeGroup group, unsigned opcode,
  502. StringRef name) {
  503. std::string operatorName = GetHLFullName(group, opcode);
  504. std::string mangledName = operatorName + "." + name.str();
  505. raw_string_ostream mangledNameStr(mangledName);
  506. funcTy->print(mangledNameStr);
  507. mangledNameStr.flush();
  508. Function *F = cast<Function>(M.getOrInsertFunction(mangledName, funcTy));
  509. SetHLFunctionAttribute(F, group, opcode);
  510. F->setLinkage(llvm::GlobalValue::LinkageTypes::InternalLinkage);
  511. return F;
  512. }
  513. Value *callHLFunction(Module &Module, HLOpcodeGroup OpcodeGroup, unsigned Opcode,
  514. Type *RetTy, ArrayRef<Value*> Args, IRBuilder<> &Builder) {
  515. AttributeSet attribs;
  516. return callHLFunction(Module, OpcodeGroup, Opcode, RetTy, Args, attribs, Builder);
  517. }
  518. Value *callHLFunction(Module &Module, HLOpcodeGroup OpcodeGroup, unsigned Opcode,
  519. Type *RetTy, ArrayRef<Value*> Args, const AttributeSet &attribs, IRBuilder<> &Builder) {
  520. SmallVector<Type*, 4> ArgTys;
  521. ArgTys.reserve(Args.size());
  522. for (Value *Arg : Args)
  523. ArgTys.emplace_back(Arg->getType());
  524. FunctionType *FuncTy = FunctionType::get(RetTy, ArgTys, /* isVarArg */ false);
  525. Function *Func = GetOrCreateHLFunction(Module, FuncTy, OpcodeGroup, Opcode, attribs);
  526. return Builder.CreateCall(Func, Args);
  527. }
  528. } // namespace hlsl