LLVM: lib/Target/DirectX/DXILIntrinsicExpansion.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

23#include "llvm/IR/IntrinsicsDirectX.h"

30

31#define DEBUG_TYPE "dxil-intrinsic-expansion"

32

33using namespace llvm;

34

36

37public:

40

41 static char ID;

42};

43

45 switch (F.getIntrinsicID()) {

46 case Intrinsic::abs:

47 case Intrinsic::atan2:

48 case Intrinsic::exp:

49 case Intrinsic:🪵

50 case Intrinsic::log10:

51 case Intrinsic::pow:

52 case Intrinsic::dx_all:

53 case Intrinsic::dx_any:

54 case Intrinsic::dx_cross:

55 case Intrinsic::dx_uclamp:

56 case Intrinsic::dx_sclamp:

57 case Intrinsic::dx_nclamp:

58 case Intrinsic::dx_degrees:

59 case Intrinsic::dx_lerp:

60 case Intrinsic::dx_normalize:

61 case Intrinsic::dx_fdot:

62 case Intrinsic::dx_sdot:

63 case Intrinsic::dx_udot:

64 case Intrinsic::dx_sign:

65 case Intrinsic::dx_step:

66 case Intrinsic::dx_radians:

67 case Intrinsic::vector_reduce_add:

68 case Intrinsic::vector_reduce_fadd:

69 return true;

70 }

71 return false;

72}

74 assert(IntrinsicId == Intrinsic::vector_reduce_add ||

75 IntrinsicId == Intrinsic::vector_reduce_fadd);

76

78 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);

79

81 Type *Ty = X->getType();

82 auto *XVec = dyn_cast(Ty);

83 unsigned XVecSize = XVec->getNumElements();

85

86

87 if (IsFAdd) {

89 if (StartValue && !StartValue->isZeroValue())

90 Sum = Builder.CreateFAdd(Sum, StartValue);

91 }

92

93

94 for (unsigned I = 1; I < XVecSize; I++) {

96 if (IsFAdd)

98 else

99 Sum = Builder.CreateAdd(Sum, Elt);

100 }

101

102 return Sum;

103}

104

108 Type *Ty = X->getType();

114 ConstantInt::get(EltTy, 0))

115 : ConstantInt::get(EltTy, 0);

116 auto *V = Builder.CreateSub(Zero, X);

117 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {X, V}, nullptr,

118 "dx.max");

119}

120

122

124 if (cast(VT)->getNumElements() != 3)

126 false);

127

131

135

139

144 };

145

146 Value *yz_zy = MulSub(op0_y, op0_z, op1_y, op1_z);

147 Value *zx_xz = MulSub(op0_z, op0_x, op1_z, op1_x);

148 Value *xy_yx = MulSub(op0_x, op0_y, op1_x, op1_y);

149

154 return cross;

155}

156

157

158

159

161 Type *ATy = A->getType();

162 [[maybe_unused]] Type *BTy = B->getType();

164

166

167 auto *AVec = dyn_cast(ATy);

168

170

172 switch (AVec->getNumElements()) {

173 case 2:

174 DotIntrinsic = Intrinsic::dx_dot2;

175 break;

176 case 3:

177 DotIntrinsic = Intrinsic::dx_dot3;

178 break;

179 case 4:

180 DotIntrinsic = Intrinsic::dx_dot4;

181 break;

182 default:

184 Twine("Invalid dot product input vector: length is outside 2-4"),

185 false);

186 return nullptr;

187 }

190}

191

192

193

194

198}

199

200

203 assert(DotIntrinsic == Intrinsic::dx_sdot ||

204 DotIntrinsic == Intrinsic::dx_udot);

207 Type *ATy = A->getType();

208 [[maybe_unused]] Type *BTy = B->getType();

210

212

213 auto *AVec = dyn_cast(ATy);

214

216

218 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot

219 ? Intrinsic::dx_imad

220 : Intrinsic::dx_umad;

223 Result = Builder.CreateMul(Elt0, Elt1);

224 for (unsigned I = 1; I < AVec->getNumElements(); I++) {

227 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,

229 nullptr, "dx.mad");

230 }

231 return Result;

232}

233

237 Type *Ty = X->getType();

246 auto *Exp2Call =

247 Builder.CreateIntrinsic(Ty, Intrinsic::exp2, {NewX}, nullptr, "dx.exp2");

250 return Exp2Call;

251}

252

257 Type *Ty = X->getType();

259

262 if (IntrinsicId == Intrinsic::dx_any)

263 return Builder.CreateOr(Result, Elt);

264 assert(IntrinsicId == Intrinsic::dx_all);

265 return Builder.CreateAnd(Result, Elt);

266 };

267

268 Value *Result = nullptr;

271 ? Builder.CreateFCmpUNE(X, ConstantFP::get(EltTy, 0))

272 : Builder.CreateICmpNE(X, ConstantInt::get(EltTy, 0));

273 } else {

274 auto *XVec = dyn_cast(Ty);

280 ConstantFP::get(EltTy, 0)))

284 ConstantInt::get(EltTy, 0)));

286 for (unsigned I = 1; I < XVec->getNumElements(); I++) {

288 Result = ApplyOp(intrinsicId, Result, Elt);

289 }

290 }

291 return Result;

292}

293

301 return Builder.CreateFAdd(X, V, "dx.lerp");

302}

303

308 Type *Ty = X->getType();

314 ConstantFP::get(EltTy, LogConstVal))

315 : ConstantFP::get(EltTy, LogConstVal);

316 auto *Log2Call =

317 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {X}, nullptr, "elt.log2");

320 return Builder.CreateFMul(Ln2Const, Log2Call);

321}

324}

325

326

327

333

334 auto *XVec = dyn_cast(Ty);

335 if (!XVec) {

336 if (auto *constantFP = dyn_cast(X)) {

337 const APFloat &fpVal = constantFP->getValueAPF();

340 false);

341 }

343 }

344

346

347

348

349 if (auto *constantFP = dyn_cast(DotProduct)) {

350 const APFloat &fpVal = constantFP->getValueAPF();

353 false);

354 }

355

358 nullptr, "dx.rsqrt");

359

360 Value *MultiplicandVec =

362 return Builder.CreateFMul(X, MultiplicandVec);

363}

364

368 Type *Ty = X->getType();

371

373

375 Builder.CreateIntrinsic(Ty, Intrinsic::atan, {Tan}, nullptr, "Elt.Atan");

378

379

383 Constant *Zero = ConstantFP::get(Ty, 0);

386

387

388 Value *Result = Atan;

393

394

396 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);

397

398

400 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);

401

402

404 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);

405

406

408 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);

409

410 return Result;

411}

412

414

417 Type *Ty = X->getType();

419

420 auto *Log2Call =

421 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {X}, nullptr, "elt.log2");

423 auto *Exp2Call =

424 Builder.CreateIntrinsic(Ty, Intrinsic::exp2, {Mul}, nullptr, "elt.exp2");

427 return Exp2Call;

428}

429

431

434 Type *Ty = X->getType();

436

440

442 auto *XVec = dyn_cast(Ty);

447 }

448

450}

451

454 Type *Ty = X->getType();

458}

459

461 if (ClampIntrinsic == Intrinsic::dx_uclamp)

462 return Intrinsic::umax;

463 if (ClampIntrinsic == Intrinsic::dx_sclamp)

464 return Intrinsic::smax;

465 assert(ClampIntrinsic == Intrinsic::dx_nclamp);

466 return Intrinsic::maxnum;

467}

468

470 if (ClampIntrinsic == Intrinsic::dx_uclamp)

471 return Intrinsic::umin;

472 if (ClampIntrinsic == Intrinsic::dx_sclamp)

473 return Intrinsic::smin;

474 assert(ClampIntrinsic == Intrinsic::dx_nclamp);

475 return Intrinsic::minnum;

476}

477

483 Type *Ty = X->getType();

486 {X, Min}, nullptr, "dx.max");

488 {MaxCall, Max}, nullptr, "dx.min");

489}

490

493 Type *Ty = X->getType();

496 return Builder.CreateFMul(X, DegreesRatio);

497}

498

501 Type *Ty = X->getType();

505

507

513 } else {

517 }

518

521

522 return Builder.CreateSub(ZextGT, ZextLT);

523}

524

526 Value *Result = nullptr;

528 switch (IntrinsicId) {

529 case Intrinsic::abs:

531 break;

532 case Intrinsic::atan2:

534 break;

535 case Intrinsic::exp:

537 break;

538 case Intrinsic:🪵

540 break;

541 case Intrinsic::log10:

543 break;

544 case Intrinsic::pow:

546 break;

547 case Intrinsic::dx_all:

548 case Intrinsic::dx_any:

550 break;

551 case Intrinsic::dx_cross:

553 break;

554 case Intrinsic::dx_uclamp:

555 case Intrinsic::dx_sclamp:

556 case Intrinsic::dx_nclamp:

558 break;

559 case Intrinsic::dx_degrees:

561 break;

562 case Intrinsic::dx_lerp:

564 break;

565 case Intrinsic::dx_normalize:

567 break;

568 case Intrinsic::dx_fdot:

570 break;

571 case Intrinsic::dx_sdot:

572 case Intrinsic::dx_udot:

574 break;

575 case Intrinsic::dx_sign:

577 break;

578 case Intrinsic::dx_step:

580 break;

581 case Intrinsic::dx_radians:

583 break;

584 case Intrinsic::vector_reduce_add:

585 case Intrinsic::vector_reduce_fadd:

587 break;

588 }

589 if (Result) {

592 return true;

593 }

594 return false;

595}

596

600 continue;

601 bool IntrinsicExpanded = false;

603 auto *IntrinsicCall = dyn_cast(U);

604 if (!IntrinsicCall)

605 continue;

607 }

608 if (F.user_empty() && IntrinsicExpanded)

609 F.eraseFromParent();

610 }

611 return true;

612}

613

619}

620

623}

624

626

628 "DXIL Intrinsic Expansion", false, false)

631

634}

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static Value * expandNormalizeIntrinsic(CallInst *Orig)

static bool expandIntrinsic(Function &F, CallInst *Orig)

static Value * expandClampIntrinsic(CallInst *Orig, Intrinsic::ID ClampIntrinsic)

static bool expansionIntrinsics(Module &M)

static Value * expandLerpIntrinsic(CallInst *Orig)

static Value * expandCrossIntrinsic(CallInst *Orig)

static Value * expandVecReduceAdd(CallInst *Orig, Intrinsic::ID IntrinsicId)

static Value * expandAtan2Intrinsic(CallInst *Orig)

static Value * expandLog10Intrinsic(CallInst *Orig)

static Intrinsic::ID getMinForClamp(Intrinsic::ID ClampIntrinsic)

static Value * expandStepIntrinsic(CallInst *Orig)

static Value * expandIntegerDotIntrinsic(CallInst *Orig, Intrinsic::ID DotIntrinsic)

static Value * expandPowIntrinsic(CallInst *Orig)

static Value * expandLogIntrinsic(CallInst *Orig, float LogConstVal=numbers::ln2f)

static Value * expandDegreesIntrinsic(CallInst *Orig)

static Value * expandExpIntrinsic(CallInst *Orig)

static Value * expandSignIntrinsic(CallInst *Orig)

static Intrinsic::ID getMaxForClamp(Intrinsic::ID ClampIntrinsic)

static Value * expandAnyOrAllIntrinsic(CallInst *Orig, Intrinsic::ID intrinsicId)

static Value * expandAbs(CallInst *Orig)

static Value * expandFloatDotIntrinsic(CallInst *Orig, Value *A, Value *B)

static Value * expandRadiansIntrinsic(CallInst *Orig)

static bool isIntrinsicExpansion(Function &F)

static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")

Module.h This file contains the declarations for the Module class.

This header defines various interfaces for pass management in LLVM.

static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")

#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)

#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)

const SmallVectorImpl< MachineOperand > & Cond

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

static unsigned getNumElements(Type *Ty)

This file defines the SmallVector class.

bool runOnModule(Module &M) override

runOnModule - Virtual method overriden by subclasses to process the module being operated on.

DXILIntrinsicExpansionLegacy()

A container for analyses that lazily runs them and caches their results.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

void setAttributes(AttributeList A)

Set the attributes for this call.

AttributeList getAttributes() const

Return the attributes for this call.

This class represents a function call, abstracting a target machine's calling convention.

void setTailCall(bool IsTc=true)

static Constant * getSplat(ElementCount EC, Constant *Elt)

Return a ConstantVector with the specified constant in each element.

This is an important base class in LLVM.

static Constant * getNullValue(Type *Ty)

Constructor to create a '0' constant of arbitrary type.

bool isZeroValue() const

Return true if the value is negative zero or null value.

PreservedAnalyses run(Module &M, ModuleAnalysisManager &)

static constexpr ElementCount getFixed(ScalarTy MinVal)

Value * CreateFSub(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)

Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")

Value * CreateFDiv(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)

Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")

Value * CreateFAdd(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)

Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")

Return a vector value that contains.

Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)

Value * CreateFCmpUNE(Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)

void setFastMathFlags(FastMathFlags NewFMF)

Set the fast-math flags to be used with generated fp-math operators.

Value * CreateFCmpOLT(Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)

Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")

CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")

Create a call to intrinsic ID with Args, mangled using Types.

Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)

Value * CreateFCmpOEQ(Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)

Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")

Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="")

Value * CreateICmpSLT(Value *LHS, Value *RHS, const Twine &Name="")

Value * CreateFMul(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)

Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateFCmpOGE(Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

InstListType::iterator eraseFromParent()

This method unlinks 'this' from the containing basic block and deletes it.

FastMathFlags getFastMathFlags() const LLVM_READONLY

Convenience function for getting all the fast-math flags, which must be an operator which supports th...

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

A Module instance is used to store all the information related to an LLVM module.

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses none()

Convenience factory function for the empty preserved set.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

The instances of the Type class are immutable: once they are created, they are never changed.

bool isVectorTy() const

True if this is an instance of VectorType.

bool isFloatingPointTy() const

Return true if this is one of the floating-point types.

bool isIntegerTy() const

True if this is an instance of IntegerType.

Type * getScalarType() const

If this is a vector type, return the element type, otherwise return 'this'.

static UndefValue * get(Type *T)

Static factory methods - Return an 'undef' object of the specified type.

Value * getOperand(unsigned i) const

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

StringRef getName() const

Return a constant reference to the value's name.

This is an optimization pass for GlobalISel generic memory operations.

iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)

Make a range that does early increment to allow mutation of the underlying range without disrupting i...

void report_fatal_error(Error Err, bool gen_crash_diag=true)

Report a serious error, calling any installed error handler.

ModulePass * createDXILIntrinsicExpansionLegacyPass()

Pass to expand intrinsic operations that lack DXIL opCodes.