DxilExpandTrigIntrinsics.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilExpandTrigIntrinsics.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. // Expand trigonmetric intrinsics to a sequence of dxil instructions. //
  9. // ========================================================================= //
  10. //
  11. // We provide expansions to approximate several trigonmetric functions that
  12. // typically do not have native instructions in hardware. The details of each
  13. // expansion is given below, but typically the exansion occurs in three steps
  14. //
  15. // 1. Perform range reduction (if necessary) to reduce input range
  16. // to a value that works with the approximation.
  17. // 2. Compute an approximation to the function (typically by evaluating
  18. // a polynomial).
  19. // 3. Perform range expansion (if necessary) to map the result back to
  20. // the original range.
  21. //
  22. // For example, say we are expanding f(x) using an approximation to f, call it
  23. // f*(x). And assume that f* only works for positive inputs, but we know that
  24. // f(-x) = -f(x).Then the expansion would be
  25. //
  26. // 1. a = abs(x)
  27. // 2. v = f*(a)
  28. // 3. e = x < 0 ? -v : v
  29. //
  30. // where e contains the final expanded result.
  31. //
  32. // References
  33. // ---------------------------------------------------------------------------
  34. // [HMF] Handbook of Mathematical Formulas by Abramowitz and Stegun, 1964
  35. // [ADC] Approximations for Digital Computers by Hastings, 1955
  36. // [WIK] Wikipedia, 2017
  37. //
  38. // The approximation functions mostly come from [ADC]. The approximations
  39. // are also referenced in [HMF], but they give original credit to [ADC].
  40. //
  41. ///////////////////////////////////////////////////////////////////////////////
  42. #include "dxc/HLSL/DxilGenerationPass.h"
  43. #include "dxc/DXIL/DxilOperations.h"
  44. #include "dxc/DXIL/DxilSignatureElement.h"
  45. #include "dxc/DXIL/DxilModule.h"
  46. #include "dxc/Support/Global.h"
  47. #include "dxc/DXIL/DxilInstructions.h"
  48. #include "llvm/IR/Module.h"
  49. #include "llvm/Pass.h"
  50. #include "llvm/IR/IRBuilder.h"
  51. #include "llvm/IR/InstIterator.h"
  52. #include "llvm/ADT/MapVector.h"
  53. #include <cmath>
  54. #include <utility>
  55. using namespace llvm;
  56. using namespace hlsl;
  57. namespace {
  58. class DxilExpandTrigIntrinsics : public FunctionPass {
  59. private:
  60. public:
  61. static char ID; // Pass identification, replacement for typeid
  62. explicit DxilExpandTrigIntrinsics() : FunctionPass(ID) {}
  63. const char *getPassName() const override {
  64. return "DXIL expand trig intrinsics";
  65. }
  66. bool runOnFunction(Function &F) override;
  67. private:
  68. typedef std::vector<CallInst *> IntrinsicList;
  69. IntrinsicList findTrigFunctionsToExpand(Function &F);
  70. CallInst *isExpandableTrigIntrinsicCall(Instruction *I);
  71. bool expandTrigIntrinsics(DxilModule &DM, const IntrinsicList &worklist);
  72. FastMathFlags getFastMathFlagsForIntrinsic(CallInst *intrinsic);
  73. void prepareBuilderToExpandIntrinsic(IRBuilder<> &builder, CallInst *intrinsic);
  74. // Expansion implementations.
  75. Value *expandACos(IRBuilder<> &builder, DxilInst_Acos acos, DxilModule &DM);
  76. Value *expandASin(IRBuilder<> &builder, DxilInst_Asin asin, DxilModule &DM);
  77. Value *expandATan(IRBuilder<> &builder, DxilInst_Atan atan, DxilModule &DM);
  78. Value *expandHCos(IRBuilder<> &builder, DxilInst_Hcos hcos, DxilModule &DM);
  79. Value *expandHSin(IRBuilder<> &builder, DxilInst_Hsin hsin, DxilModule &DM);
  80. Value *expandHTan(IRBuilder<> &builder, DxilInst_Htan htan, DxilModule &DM);
  81. Value *expandTan(IRBuilder<> &builder, DxilInst_Tan tan, DxilModule &DM);
  82. };
  83. // Math constants.
  84. // Values taken from https://msdn.microsoft.com/en-us/library/4hwaceh6.aspx.
  85. // Replicated here because they are not part of standard C++.
  86. namespace math {
  87. constexpr double PI = 3.14159265358979323846;
  88. constexpr double PI_2 = 1.57079632679489661923;
  89. constexpr double LOG2E = 1.44269504088896340736;
  90. }
  91. }
  92. bool DxilExpandTrigIntrinsics::runOnFunction(Function &F) {
  93. DxilModule &DM = F.getParent()->GetOrCreateDxilModule();
  94. IntrinsicList intrinsics = findTrigFunctionsToExpand(F);
  95. const bool changed = expandTrigIntrinsics(DM, intrinsics);
  96. return changed;
  97. }
  98. CallInst *DxilExpandTrigIntrinsics::isExpandableTrigIntrinsicCall(Instruction *I) {
  99. if (OP::IsDxilOpFuncCallInst(I)) {
  100. switch (OP::GetDxilOpFuncCallInst(I)) {
  101. case OP::OpCode::Acos:
  102. case OP::OpCode::Asin:
  103. case OP::OpCode::Atan:
  104. case OP::OpCode::Hcos:
  105. case OP::OpCode::Hsin:
  106. case OP::OpCode::Htan:
  107. case OP::OpCode::Tan:
  108. return cast<CallInst>(I);
  109. default: break;
  110. }
  111. }
  112. return nullptr;
  113. }
  114. DxilExpandTrigIntrinsics::IntrinsicList DxilExpandTrigIntrinsics::findTrigFunctionsToExpand(Function &F) {
  115. IntrinsicList worklist;
  116. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
  117. if (CallInst *call = isExpandableTrigIntrinsicCall(&*I))
  118. worklist.push_back(call);
  119. return worklist;
  120. }
  121. static bool isPreciseBuilder(IRBuilder<> &builder) {
  122. return !builder.getFastMathFlags().any();
  123. }
  124. static void setPreciseBuilder(IRBuilder<> &builder, bool precise) {
  125. FastMathFlags flags;
  126. if (precise)
  127. flags.clear();
  128. else
  129. flags.setUnsafeAlgebra();
  130. builder.SetFastMathFlags(flags);
  131. }
  132. void DxilExpandTrigIntrinsics::prepareBuilderToExpandIntrinsic(IRBuilder<> &builder, CallInst *intrinsic) {
  133. DxilModule &DM = intrinsic->getModule()->GetOrCreateDxilModule();
  134. builder.SetInsertPoint(intrinsic);
  135. setPreciseBuilder(builder, DM.IsPrecise(intrinsic));
  136. }
  137. bool DxilExpandTrigIntrinsics::expandTrigIntrinsics(DxilModule &DM, const IntrinsicList &worklist) {
  138. IRBuilder<> builder(DM.GetCtx());
  139. for (CallInst *intrinsic: worklist) {
  140. Value *expansion = nullptr;
  141. prepareBuilderToExpandIntrinsic(builder, intrinsic);
  142. OP::OpCode opcode = OP::GetDxilOpFuncCallInst(intrinsic);
  143. switch (opcode) {
  144. case OP::OpCode::Acos: expansion = expandACos(builder, intrinsic, DM); break;
  145. case OP::OpCode::Asin: expansion = expandASin(builder, intrinsic, DM); break;
  146. case OP::OpCode::Atan: expansion = expandATan(builder, intrinsic, DM); break;
  147. case OP::OpCode::Hcos: expansion = expandHCos(builder, intrinsic, DM); break;
  148. case OP::OpCode::Hsin: expansion = expandHSin(builder, intrinsic, DM); break;
  149. case OP::OpCode::Htan: expansion = expandHTan(builder, intrinsic, DM); break;
  150. case OP::OpCode::Tan: expansion = expandTan(builder, intrinsic, DM); break;
  151. default:
  152. assert(false && "unexpected intrinsic");
  153. break;
  154. }
  155. assert(expansion);
  156. intrinsic->replaceAllUsesWith(expansion);
  157. intrinsic->eraseFromParent();
  158. }
  159. return !worklist.empty();
  160. }
  161. // Helper
  162. // return dx.op.UnaryFloat(X)
  163. //
  164. static Value *emitUnaryFloat(IRBuilder<> &builder, Value *X, OP *dxOp, OP::OpCode opcode, StringRef name) {
  165. Function *F = dxOp->GetOpFunc(opcode, X->getType());
  166. Value *Args[] = { dxOp->GetI32Const(static_cast<int>(opcode)), X };
  167. CallInst *Call = builder.CreateCall(F, Args, name);
  168. if (isPreciseBuilder(builder))
  169. DxilMDHelper::MarkPrecise(Call);
  170. return Call;
  171. }
  172. // Helper
  173. // return dx.op.Fabs(X)
  174. //
  175. static Value *emitFAbs(IRBuilder<> &builder, Value *X, OP *dxOp, StringRef name) {
  176. return emitUnaryFloat(builder, X, dxOp, OP::OpCode::FAbs, name);
  177. }
  178. // Helper
  179. // return dx.op.Sqrt(X)
  180. //
  181. static Value *emitSqrt(IRBuilder<> &builder, Value *X, OP *dxOp, StringRef name) {
  182. return emitUnaryFloat(builder, X, dxOp, OP::OpCode::Sqrt, name);
  183. }
  184. // Helper
  185. // return sqrt(1 - X) * psi*(X)
  186. //
  187. // We compute the polynomial using Horners method to evaluate it efficently.
  188. //
  189. // psi*(X) = a0 + a1x + a2x^2 + a3x^3
  190. // = a0 + x(a1 + a2x + a3x^2)
  191. // = a0 + x(a1 + x(a2 + a3x))
  192. //
  193. static Value *emitSqrt1mXtimesPsiX(IRBuilder<> &builder, Value *X, OP *dxOp, StringRef name) {
  194. Value *One = ConstantFP::get(X->getType(), 1.0);
  195. Value *a0 = ConstantFP::get(X->getType(), 1.5707288);
  196. Value *a1 = ConstantFP::get(X->getType(), -0.2121144);
  197. Value *a2 = ConstantFP::get(X->getType(), 0.0742610);
  198. Value *a3 = ConstantFP::get(X->getType(), -0.0187293);
  199. // sqrt(1-x)
  200. Value *r1 = builder.CreateFSub(One, X, name);
  201. Value *r2 = emitSqrt(builder, r1, dxOp, name);
  202. // psi*(x)
  203. Value *r3 = builder.CreateFMul(X, a3, name);
  204. r3 = builder.CreateFAdd(r3, a2, name);
  205. r3 = builder.CreateFMul(X, r3, name);
  206. r3 = builder.CreateFAdd(r3, a1, name);
  207. r3 = builder.CreateFMul(X, r3, name);
  208. r3 = builder.CreateFAdd(r3, a0, name);
  209. // sqrt(1-x) * psi*(x)
  210. Value *r4 = builder.CreateFMul(r2, r3, name);
  211. return r4;
  212. }
  213. // Helper
  214. // return e^x, e^-x
  215. //
  216. // We can use the dxil Exp function to compute the exponential. The only slight
  217. // wrinkle is that in dxil Exp(x) = 2^x and we need e^x. Luckily we can easily
  218. // change the base of the exponent using the following identity [HFM(p69)]
  219. //
  220. // e^x = 2^{x * log_2(e)}
  221. //
  222. static std::pair<Value *, Value *> emitExEmx(IRBuilder<> &builder, Value *X, OP *dxOp, StringRef name) {
  223. Value *Zero = ConstantFP::get(X->getType(), 0.0);
  224. Value *Log2e = ConstantFP::get(X->getType(), math::LOG2E);
  225. Value *r0 = builder.CreateFMul(X, Log2e, name);
  226. Value *r1 = emitUnaryFloat(builder, r0, dxOp, OP::OpCode::Exp, name);
  227. Value *r2 = builder.CreateFSub(Zero, r0, name);
  228. Value *r3 = emitUnaryFloat(builder, r2, dxOp, OP::OpCode::Exp, name);
  229. return std::make_pair(r1, r3);
  230. }
  231. // Asin
  232. // ----------------------------------------------------------------------------
  233. // Function
  234. // arcsin X = pi/2 - sqrt(1 - X) * psi(X)
  235. //
  236. // Range
  237. // 0 <= X <= 1
  238. //
  239. // Approximation
  240. // Psi*(X) = a0 + a1x + a2x^2 + a3x^3
  241. // a0 = 1.5707288
  242. // a1 = -0.2121144
  243. // a2 = 0.0742610
  244. // a3 = -0.0187293
  245. //
  246. // The domain of the approximation is 0 <=x <= 1, but the domain of asin is
  247. // -1 <= x <= 1. So we need to perform a range reduction to [0,1] before
  248. // computing the approximation.
  249. //
  250. // We use the following identity from [HMF(p80),WIK] for range reduction
  251. //
  252. // asin(-x) = -asin(x)
  253. //
  254. // We take the absolute value of x, compute asin(x) using the approximation
  255. // and then negate the value if x < 0.
  256. //
  257. // In [HMF] the authors claim an error, e, of |e| <= 5e-5, but the error graph
  258. // in [ADC] looks like the error can be larger that that for some inputs.
  259. //
  260. Value *DxilExpandTrigIntrinsics::expandASin(IRBuilder<> &builder, DxilInst_Asin asin, DxilModule &DM) {
  261. assert(asin);
  262. StringRef name = "asin.x";
  263. Value *X = asin.get_value();
  264. Value *PI_2 = ConstantFP::get(X->getType(), math::PI_2);
  265. Value *Zero = ConstantFP::get(X->getType(), 0.0);
  266. // Range reduction to [0, 1]
  267. Value *absX = emitFAbs(builder, X, DM.GetOP(), name);
  268. // Approximation
  269. Value *psiX = emitSqrt1mXtimesPsiX(builder, absX, DM.GetOP(), name);
  270. Value *asinX = builder.CreateFSub(PI_2, psiX, name);
  271. Value *asinmX = builder.CreateFSub(Zero, asinX, name);
  272. // Range expansion to [-1, 1]
  273. Value *lt0 = builder.CreateFCmp(CmpInst::FCMP_ULT, X, Zero, name);
  274. Value *r = builder.CreateSelect(lt0, asinmX, asinX, name);
  275. return r;
  276. }
  277. // Acos
  278. // ----------------------------------------------------------------------------
  279. // The acos expansion uses the following identity [WIK]. So that we can use the
  280. // same approximation psi*(x) that we use for asin.
  281. //
  282. // acos(x) = pi/2 - asin(x)
  283. //
  284. // Substituting the equation for asin(x) we get
  285. //
  286. // acos(x) = pi/2 - asin(x)
  287. // = pi/2 - (pi/2 - sqrt(1-x)*psi(x))
  288. // = sqrt(1-x)*psi(x)
  289. //
  290. // We use the following identity from [HMF(p80),WIK] for range reduction
  291. //
  292. // acos(-x) = pi - acos(x)
  293. // = pi - sqrt(1-x)*psi(x)
  294. //
  295. // We take the absolute value of x, compute acos(x) using the approximation
  296. // and then subtract from pi if x < 0.
  297. //
  298. Value *DxilExpandTrigIntrinsics::expandACos(IRBuilder<> &builder, DxilInst_Acos acos, DxilModule &DM) {
  299. assert(acos);
  300. StringRef name = "acos.x";
  301. Value *X = acos.get_value();
  302. Value *PI = ConstantFP::get(X->getType(), math::PI);
  303. Value *Zero = ConstantFP::get(X->getType(), 0.0);
  304. // Range reduction to [0, 1]
  305. Value *absX = emitFAbs(builder, X, DM.GetOP(), name);
  306. // Approximation
  307. Value *acosX = emitSqrt1mXtimesPsiX(builder, absX, DM.GetOP(), name);
  308. Value *acosmX = builder.CreateFSub(PI, acosX, name);
  309. // Range expansion to [-1, 1]
  310. Value *lt0 = builder.CreateFCmp(CmpInst::FCMP_ULT, X, Zero, name);
  311. Value *r = builder.CreateSelect(lt0, acosmX, acosX, name);
  312. return r;
  313. }
  314. // Atan
  315. // ----------------------------------------------------------------------------
  316. // Function
  317. // arctan X
  318. //
  319. // Range
  320. // -1 <= X <= 1
  321. //
  322. // Approximation
  323. // arctan*(x) = c1x + c3x^3 + c5x^5 + c7x^7 + c9x^9
  324. // c1 = 0.9998660
  325. // c3 = -0.3302995
  326. // c5 = 0.1801410
  327. // c7 = -0.0851330
  328. // c9 = 0.0208351
  329. //
  330. // The polynomial is evaluated using Horner's method to efficiently compute the
  331. // value
  332. //
  333. // c1x + c3x^3 + c5x^5 + c7x^7 + c9x^9
  334. // = x(c1 + c3x^2 + c5x^4 + c7x^6 + c9x^8)
  335. // = x(c1 + x^2(c3 + c5x^2 + c7x^4 + c9x^6))
  336. // = x(c1 + x^2(c3 + x^2(c5 + c7x^2 + c9x^4)))
  337. // = x(c1 + x^2(c3 + x^2(c5 + x^2(c7 + c9x^2))))
  338. //
  339. // The range reduction is a little more compilicated for atan because the
  340. // domain of atan is [-inf, inf], but the domain of the approximation is only
  341. // [-1, 1]. We use the following identities for range reduction from
  342. // [HMF(p80),WIK]
  343. //
  344. // arctan(-x) = -arctan(x)
  345. // arctan(x) = pi/2 - arctan(1/x) if x > 0
  346. //
  347. // The first identity allows us to only work with positive numbers. The second
  348. // identity allows us to reduce the range to [0,1]. We first convert the value
  349. // to positive by taking abs(x). Then if x > 1 we compute arctan(1/x).
  350. //
  351. // To expand the range we check if x > 1 then subtracted the computed value from
  352. // pi/2 and if x is negative then negate the final value.
  353. //
  354. Value *DxilExpandTrigIntrinsics::expandATan(IRBuilder<> &builder, DxilInst_Atan atan, DxilModule &DM) {
  355. assert(atan);
  356. StringRef name = "atan.x";
  357. Value *X = atan.get_value();
  358. Value *PI_2 = ConstantFP::get(X->getType(), math::PI_2);
  359. Value *One = ConstantFP::get(X->getType(), 1.0);
  360. Value *Zero = ConstantFP::get(X->getType(), 0.0);
  361. Value *c1 = ConstantFP::get(X->getType(), 0.9998660);
  362. Value *c3 = ConstantFP::get(X->getType(), -0.3302995);
  363. Value *c5 = ConstantFP::get(X->getType(), 0.1801410);
  364. Value *c7 = ConstantFP::get(X->getType(), -0.0851330);
  365. Value *c9 = ConstantFP::get(X->getType(), 0.0208351);
  366. // Range reduction to [0, inf]
  367. Value *absX = emitFAbs(builder, X, DM.GetOP(), name);
  368. // Range reduction to [0, 1]
  369. Value *gt1 = builder.CreateFCmp(CmpInst::FCMP_UGT, absX, One, name);
  370. Value *r1 = builder.CreateFDiv(One, absX, name);
  371. Value *r2 = builder.CreateSelect(gt1, r1, absX, name);
  372. // Approximate
  373. Value *r3 = builder.CreateFMul(r2, r2, name);
  374. Value *r4 = builder.CreateFMul(r3, c9, name);
  375. r4 = builder.CreateFAdd(r4, c7, name);
  376. r4 = builder.CreateFMul(r4, r3, name);
  377. r4 = builder.CreateFAdd(r4, c5, name);
  378. r4 = builder.CreateFMul(r4, r3, name);
  379. r4 = builder.CreateFAdd(r4, c3, name);
  380. r4 = builder.CreateFMul(r4, r3, name);
  381. r4 = builder.CreateFAdd(r4, c1, name);
  382. r4 = builder.CreateFMul(r2, r4, name);
  383. // Range Expansion to [0, inf]
  384. Value *r5 = builder.CreateFSub(PI_2, r4, name);
  385. Value *r6 = builder.CreateSelect(gt1, r5, r4, name);
  386. // Range Expansion to [-inf, inf]
  387. Value *r7 = builder.CreateFSub(Zero, r6, name);
  388. Value *lt0 = builder.CreateFCmp(CmpInst::FCMP_ULT, X, Zero, name);
  389. Value *r = builder.CreateSelect(lt0, r7, r6, name);
  390. return r;
  391. }
  392. // Hcos
  393. // ----------------------------------------------------------------------------
  394. // We use the following identity for computing hcos(x) from [HMF(p83)]
  395. //
  396. // cosh(x) = (e^x + e^-x) / 2
  397. //
  398. // No range reduction is needed.
  399. //
  400. Value *DxilExpandTrigIntrinsics::expandHCos(IRBuilder<> &builder, DxilInst_Hcos hcos, DxilModule &DM) {
  401. assert(hcos);
  402. StringRef name = "hcos.x";
  403. Value *eX, *emX;
  404. Value *X = hcos.get_value();
  405. Value *Two = ConstantFP::get(X->getType(), 2.0);
  406. std::tie(eX, emX) = emitExEmx(builder, X, DM.GetOP(), name);
  407. Value *r4 = builder.CreateFAdd(eX, emX, name);
  408. Value *r = builder.CreateFDiv(r4, Two, name);
  409. return r;
  410. }
  411. // Hsin
  412. // ----------------------------------------------------------------------------
  413. // We use the following identity for computing hsin(x) from[HMF(p83)]
  414. //
  415. // sinh(x) = (e^x - e^-x) / 2
  416. //
  417. // No range reduction is needed.
  418. //
  419. Value *DxilExpandTrigIntrinsics::expandHSin(IRBuilder<> &builder, DxilInst_Hsin hsin, DxilModule &DM) {
  420. assert(hsin);
  421. StringRef name = "hsin.x";
  422. Value *eX, *emX;
  423. Value *X = hsin.get_value();
  424. Value *Two = ConstantFP::get(X->getType(), 2.0);
  425. std::tie(eX, emX) = emitExEmx(builder, X, DM.GetOP(), name);
  426. Value *r4 = builder.CreateFSub(eX, emX, name);
  427. Value *r = builder.CreateFDiv(r4, Two, name);
  428. return r;
  429. }
  430. // Htan
  431. // ----------------------------------------------------------------------------
  432. // We use the following identity for computing hsin(x) from[HMF(p83)]
  433. //
  434. // tanh(x) = (e^x - e^-x) / (e^x + e^-x)
  435. //
  436. // No range reduction is needed.
  437. //
  438. Value *DxilExpandTrigIntrinsics::expandHTan(IRBuilder<> &builder, DxilInst_Htan htan, DxilModule &DM) {
  439. assert(htan);
  440. StringRef name = "htan.x";
  441. Value *eX, *emX;
  442. Value *X = htan.get_value();
  443. std::tie(eX, emX) = emitExEmx(builder, X, DM.GetOP(), name);
  444. Value *r4 = builder.CreateFSub(eX, emX, name);
  445. Value *r5 = builder.CreateFAdd(eX, emX, name);
  446. Value *r = builder.CreateFDiv(r4, r5, name);
  447. return r;
  448. }
  449. // Tan
  450. // ----------------------------------------------------------------------------
  451. // We use the following identity for computing tan(x)
  452. //
  453. // tan(x) = sin(x) / cos(x)
  454. //
  455. // No range reduction is needed.
  456. //
  457. Value *DxilExpandTrigIntrinsics::expandTan(IRBuilder<> &builder,
  458. DxilInst_Tan tan, DxilModule &DM) {
  459. assert(tan);
  460. StringRef name = "tan.x";
  461. Value *X = tan.get_value();
  462. OP *dxOp = DM.GetOP();
  463. Value *sin = emitUnaryFloat(builder, X, dxOp, OP::OpCode::Sin, name);
  464. Value *cos = emitUnaryFloat(builder, X, dxOp, OP::OpCode::Cos, name);
  465. Value *r = builder.CreateFDiv(sin, cos, name);
  466. return r;
  467. }
  468. char DxilExpandTrigIntrinsics::ID = 0;
  469. FunctionPass *llvm::createDxilExpandTrigIntrinsicsPass() {
  470. return new DxilExpandTrigIntrinsics();
  471. }
  472. INITIALIZE_PASS(DxilExpandTrigIntrinsics,
  473. "hlsl-dxil-expand-trig-intrinsics",
  474. "DXIL expand trig intrinsics", false, false)