31#include "llvm/IR/IntrinsicsAMDGPU.h"
36#define DEBUG_TYPE "amdgpu-atomic-optimizer"
43struct ReplacementInfo {
67class AMDGPUAtomicOptimizerImpl
80 Value *
const Identity)
const;
83 std::pair<Value *, Value *>
89 bool ValDivergent,
bool IsLDS)
const;
92 AMDGPUAtomicOptimizerImpl() =
delete;
97 :
F(
F), UA(UA),
DL(
F.getDataLayout()), DTU(DTU), ST(ST),
109char AMDGPUAtomicOptimizer::ID = 0;
113bool AMDGPUAtomicOptimizer::runOnFunction(
Function &
F) {
114 if (skipFunction(
F)) {
119 getAnalysis<UniformityInfoWrapperPass>().getUniformityInfo();
122 getAnalysisIfAvailable<DominatorTreeWrapperPass>();
124 DomTreeUpdater::UpdateStrategy::Lazy);
130 return AMDGPUAtomicOptimizerImpl(
F, UA, DTU, ST, ScanImpl).run();
138 DomTreeUpdater::UpdateStrategy::Lazy);
141 bool IsChanged = AMDGPUAtomicOptimizerImpl(
F, UA, DTU, ST, ScanImpl).run();
152bool AMDGPUAtomicOptimizerImpl::run() {
160 if (ToReplace.empty())
163 for (
auto &[
I,
Op, ValIdx, ValDivergent, IsLDS] : ToReplace)
164 optimizeAtomic(*
I,
Op, ValIdx, ValDivergent, IsLDS);
170 switch (Ty->getTypeID()) {
175 unsigned Size = Ty->getIntegerBitWidth();
183void AMDGPUAtomicOptimizerImpl::visitAtomicRMWInst(AtomicRMWInst &
I) {
184 if (
I.getType()->isVectorTy() ||
I.isVolatile())
188 switch (
I.getPointerAddressSpace()) {
219 !(
I.getType()->isFloatTy() ||
I.getType()->isDoubleTy())) {
223 const unsigned PtrIdx = 0;
224 const unsigned ValIdx = 1;
239 if (ScanImpl == ScanOptions::DPP && !ST.hasDPP())
250 if (IsLDS && ValDivergent && ScanImpl == ScanOptions::Iterative &&
252 TargetLowering::AtomicExpansionKind::None)
258 ToReplace.push_back({&
I,
Op, ValIdx, ValDivergent, IsLDS});
261void AMDGPUAtomicOptimizerImpl::visitIntrinsicInst(IntrinsicInst &
I) {
262 if (
I.getType()->isVectorTy())
267 switch (
I.getIntrinsicID()) {
270 case Intrinsic::amdgcn_struct_buffer_atomic_add:
271 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_add:
272 case Intrinsic::amdgcn_raw_buffer_atomic_add:
273 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_add:
276 case Intrinsic::amdgcn_struct_buffer_atomic_sub:
277 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub:
278 case Intrinsic::amdgcn_raw_buffer_atomic_sub:
279 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub:
282 case Intrinsic::amdgcn_struct_buffer_atomic_and:
283 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_and:
284 case Intrinsic::amdgcn_raw_buffer_atomic_and:
285 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_and:
288 case Intrinsic::amdgcn_struct_buffer_atomic_or:
289 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_or:
290 case Intrinsic::amdgcn_raw_buffer_atomic_or:
291 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_or:
294 case Intrinsic::amdgcn_struct_buffer_atomic_xor:
295 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_xor:
296 case Intrinsic::amdgcn_raw_buffer_atomic_xor:
297 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor:
300 case Intrinsic::amdgcn_struct_buffer_atomic_smin:
301 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smin:
302 case Intrinsic::amdgcn_raw_buffer_atomic_smin:
303 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin:
306 case Intrinsic::amdgcn_struct_buffer_atomic_umin:
307 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umin:
308 case Intrinsic::amdgcn_raw_buffer_atomic_umin:
309 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin:
312 case Intrinsic::amdgcn_struct_buffer_atomic_smax:
313 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smax:
314 case Intrinsic::amdgcn_raw_buffer_atomic_smax:
315 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax:
318 case Intrinsic::amdgcn_struct_buffer_atomic_umax:
319 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umax:
320 case Intrinsic::amdgcn_raw_buffer_atomic_umax:
321 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax:
330 const unsigned ValIdx = 0;
339 if (ScanImpl == ScanOptions::DPP && !ST.hasDPP())
348 for (
unsigned Idx = 1;
Idx <
I.getNumOperands();
Idx++) {
357 ToReplace.push_back({&
I,
Op, ValIdx, ValDivergent,
false});
370 return B.CreateBinOp(Instruction::Add,
LHS,
RHS);
374 return B.CreateBinOp(Instruction::Sub,
LHS,
RHS);
378 return B.CreateBinOp(Instruction::And,
LHS,
RHS);
380 return B.CreateBinOp(Instruction::Or,
LHS,
RHS);
382 return B.CreateBinOp(Instruction::Xor,
LHS,
RHS);
397 return B.CreateMaxNum(
LHS,
RHS);
399 return B.CreateMinNum(
LHS,
RHS);
409 Value *Identity)
const {
410 Type *AtomicTy =
V->getType();
413 M, Intrinsic::amdgcn_update_dpp, AtomicTy);
418 B.CreateCall(UpdateDPP,
419 {Identity, V, B.getInt32(DPP::ROW_SHR0 | 1 << Idx),
420 B.getInt32(0xf), B.getInt32(0xf), B.getFalse()}));
422 if (ST.hasDPPBroadcasts()) {
426 B.CreateCall(UpdateDPP,
427 {Identity, V, B.getInt32(DPP::BCAST15), B.getInt32(0xa),
428 B.getInt32(0xf), B.getFalse()}));
431 B.CreateCall(UpdateDPP,
432 {Identity, V, B.getInt32(DPP::BCAST31), B.getInt32(0xc),
433 B.getInt32(0xf), B.getFalse()}));
440 assert(ST.hasPermlane16Insts());
442 B.CreateIntrinsic(AtomicTy, Intrinsic::amdgcn_permlanex16,
444 B.getInt32(-1),
B.getFalse(),
B.getFalse()});
446 Value *UpdateDPPCall =
B.CreateCall(
448 B.getInt32(0xa),
B.getInt32(0xf),
B.getFalse()});
453 Value *
const Lane31 =
B.CreateIntrinsic(
454 AtomicTy, Intrinsic::amdgcn_readlane, {
V,
B.getInt32(31)});
456 Value *UpdateDPPCall =
B.CreateCall(
458 B.getInt32(0xc),
B.getInt32(0xf),
B.getFalse()});
469 Value *Identity)
const {
470 Type *AtomicTy =
V->getType();
473 M, Intrinsic::amdgcn_update_dpp, AtomicTy);
474 if (ST.hasDPPWavefrontShifts()) {
476 V =
B.CreateCall(UpdateDPP,
478 B.getInt32(0xf),
B.getFalse()});
481 M, Intrinsic::amdgcn_readlane, AtomicTy);
483 M, Intrinsic::amdgcn_writelane, AtomicTy);
488 V =
B.CreateCall(UpdateDPP,
490 B.getInt32(0xf),
B.getInt32(0xf),
B.getFalse()});
493 V =
B.CreateCall(WriteLane, {
B.CreateCall(ReadLane, {Old,
B.getInt32(15)}),
500 {
B.CreateCall(ReadLane, {Old,
B.getInt32(31)}),
B.getInt32(32),
V});
505 {
B.CreateCall(ReadLane, {Old,
B.getInt32(47)}),
B.getInt32(48),
V});
517std::pair<Value *, Value *> AMDGPUAtomicOptimizerImpl::buildScanIteratively(
519 Instruction &
I, BasicBlock *ComputeLoop, BasicBlock *ComputeEnd)
const {
520 auto *Ty =
I.getType();
522 auto *EntryBB =
I.getParent();
525 B.CreateIntrinsic(Intrinsic::amdgcn_ballot, WaveTy,
B.getTrue());
528 B.SetInsertPoint(ComputeLoop);
532 auto *OldValuePhi =
B.CreatePHI(Ty, 2,
"OldValuePhi");
534 auto *ActiveBits =
B.CreatePHI(WaveTy, 2,
"ActiveBits");
535 ActiveBits->addIncoming(Ballot, EntryBB);
539 B.CreateIntrinsic(Intrinsic::cttz, WaveTy, {ActiveBits,
B.getTrue()});
541 auto *LaneIdxInt =
B.CreateTrunc(FF1,
B.getInt32Ty());
544 Value *LaneValue =
B.CreateIntrinsic(
V->getType(), Intrinsic::amdgcn_readlane,
549 Value *OldValue =
B.CreateIntrinsic(
V->getType(), Intrinsic::amdgcn_writelane,
550 {Accumulator, LaneIdxInt, OldValuePhi});
551 OldValuePhi->addIncoming(OldValue, ComputeLoop);
555 Accumulator->addIncoming(NewAccumulator, ComputeLoop);
559 auto *
Mask =
B.CreateShl(ConstantInt::get(WaveTy, 1), FF1);
561 auto *InverseMask =
B.CreateXor(Mask, ConstantInt::getAllOnesValue(WaveTy));
562 auto *NewActiveBits =
B.CreateAnd(ActiveBits, InverseMask);
563 ActiveBits->addIncoming(NewActiveBits, ComputeLoop);
566 auto *IsEnd =
B.CreateICmpEQ(NewActiveBits, ConstantInt::get(WaveTy, 0));
567 B.CreateCondBr(IsEnd, ComputeEnd, ComputeLoop);
569 B.SetInsertPoint(ComputeEnd);
571 return {OldValue, NewAccumulator};
577 const unsigned BitWidth = Ty->getPrimitiveSizeInBits();
612 "Atomic Op yet to be ported to use Wave Reduction intrinsics.");
615 return Intrinsic::amdgcn_wave_reduce_add;
618 return Intrinsic::amdgcn_wave_reduce_fadd;
620 return Intrinsic::amdgcn_wave_reduce_and;
622 return Intrinsic::amdgcn_wave_reduce_or;
624 return Intrinsic::amdgcn_wave_reduce_xor;
626 return Intrinsic::amdgcn_wave_reduce_umax;
628 return Intrinsic::amdgcn_wave_reduce_max;
630 return Intrinsic::amdgcn_wave_reduce_fmax;
632 return Intrinsic::amdgcn_wave_reduce_umin;
634 return Intrinsic::amdgcn_wave_reduce_min;
636 return Intrinsic::amdgcn_wave_reduce_fmin;
645void AMDGPUAtomicOptimizerImpl::optimizeAtomic(Instruction &
I,
656 if (IsLDS && ValDivergent && ScanImpl == ScanOptions::DPP) {
657 if (MDNode *MD =
I.getMetadata(
"amdgpu.expected.active.lanes")) {
659 constexpr unsigned ActiveLanesThreshold = 5;
660 if (CI->getValue().ule(ActiveLanesThreshold))
669 B.setIsFPConstrained(
I.getFunction()->hasFnAttribute(Attribute::StrictFP));
686 Value *
const Cond =
B.CreateIntrinsic(Intrinsic::amdgcn_ps_live, {});
694 B.SetInsertPoint(&
I);
697 Type *
const Ty =
I.getType();
698 Type *Int32Ty =
B.getInt32Ty();
700 [[maybe_unused]]
const unsigned TyBitWidth =
DL.getTypeSizeInBits(Ty);
704 Value *
V =
I.getOperand(ValIdx);
709 CallInst *
const Ballot =
B.CreateIntrinsicWithoutFolding(
710 Intrinsic::amdgcn_ballot, WaveTy,
B.getTrue());
719 B.CreateIntrinsic(Intrinsic::amdgcn_mbcnt_lo, {Ballot,
B.getInt32(0)});
721 Value *
const ExtractLo =
B.CreateTrunc(Ballot, Int32Ty);
722 Value *
const ExtractHi =
B.CreateTrunc(
B.CreateLShr(Ballot, 32), Int32Ty);
723 Mbcnt =
B.CreateIntrinsic(Intrinsic::amdgcn_mbcnt_lo,
724 {ExtractLo,
B.getInt32(0)});
725 Mbcnt =
B.CreateIntrinsic(Intrinsic::amdgcn_mbcnt_hi, {ExtractHi, Mbcnt});
729 LLVMContext &
C =
F->getContext();
730 const bool NeedResult = !
I.use_empty();
731 const bool UseWaveReductionIntrinsic = !ValDivergent || !NeedResult;
743 Value *ExclScan =
nullptr;
744 Value *NewV =
nullptr;
748 if (UseWaveReductionIntrinsic) {
750 unsigned Strategy = ScanImpl == ScanOptions::DPP ? 2 : 1;
752 NewV =
B.CreateIntrinsic(WaveRedIntrinsic, Ty, {
V,
B.getInt32(Strategy)});
756 assert(ValDivergent && NeedResult);
757 if (ScanImpl == ScanOptions::DPP) {
761 B.CreateIntrinsic(Intrinsic::amdgcn_set_inactive, Ty, {
V, Identity});
762 NewV = buildScan(
B, ScanOp, NewV, Identity);
763 ExclScan = buildShiftRight(
B, NewV, Identity);
768 NewV =
B.CreateIntrinsic(Ty, Intrinsic::amdgcn_readlane,
769 {NewV, LastLaneIdx});
771 NewV =
B.CreateIntrinsic(Intrinsic::amdgcn_strict_wwm, Ty, NewV);
772 }
else if (ScanImpl == ScanOptions::Iterative) {
776 std::tie(ExclScan, NewV) = buildScanIteratively(
B, ScanOp, Identity,
V,
I,
777 ComputeLoop, ComputeEnd);
786 Value *
const Cond =
B.CreateICmpEQ(Mbcnt,
B.getInt32(0));
808 if (!UseWaveReductionIntrinsic && ScanImpl == ScanOptions::Iterative) {
814 B.SetInsertPoint(ComputeEnd);
816 B.Insert(Terminator);
820 B.SetInsertPoint(OriginalBB);
821 B.CreateBr(ComputeLoop);
825 {{DominatorTree::Insert, OriginalBB, ComputeLoop},
826 {DominatorTree::Insert, ComputeLoop, ComputeEnd}});
831 DomTreeUpdates.push_back({DominatorTree::Insert, ComputeEnd, Succ});
832 DomTreeUpdates.push_back({DominatorTree::Delete, OriginalBB, Succ});
837 Predecessor = ComputeEnd;
839 Predecessor = OriginalBB;
842 B.SetInsertPoint(SingleLaneTerminator);
852 B.SetInsertPoint(&
I);
856 PHINode *
const PHI =
B.CreatePHI(Ty, 2);
858 PHI->addIncoming(NewI, SingleLaneTerminator->
getParent());
865 ReadlaneVal =
B.CreateZExt(
PHI,
B.getInt32Ty());
867 Value *BroadcastI =
B.CreateIntrinsic(
868 ReadlaneVal->
getType(), Intrinsic::amdgcn_readfirstlane, ReadlaneVal);
870 BroadcastI =
B.CreateTrunc(BroadcastI, Ty);
876 Value *LaneOffset =
nullptr;
878 if (ScanImpl == ScanOptions::DPP) {
880 B.CreateIntrinsic(Intrinsic::amdgcn_strict_wwm, Ty, ExclScan);
881 }
else if (ScanImpl == ScanOptions::Iterative) {
882 LaneOffset = ExclScan;
887 Mbcnt = isAtomicFloatingPointTy ?
B.CreateUIToFP(Mbcnt, Ty)
888 :
B.CreateIntCast(Mbcnt, Ty,
false);
904 LaneOffset =
B.CreateSelect(
Cond, Identity,
V);
907 LaneOffset =
buildMul(
B,
V,
B.CreateAnd(Mbcnt, 1));
911 LaneOffset =
B.CreateFMul(
V, Mbcnt);
917 if (isAtomicFloatingPointTy) {
935 PHINode *
const PHI =
B.CreatePHI(Ty, 2);
937 PHI->addIncoming(Result,
I.getParent());
938 I.replaceAllUsesWith(
PHI);
941 I.replaceAllUsesWith(Result);
950 "AMDGPU atomic optimizations",
false,
false)
957 return new AMDGPUAtomicOptimizer(ScanStrategy);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static Constant * getIdentityValueForAtomicOp(Type *const Ty, AtomicRMWInst::BinOp Op)
static bool isLegalCrossLaneType(Type *Ty)
static Value * buildMul(IRBuilder<> &B, Value *LHS, Value *RHS)
static Value * buildNonAtomicBinOp(IRBuilder<> &B, AtomicRMWInst::BinOp Op, Value *LHS, Value *RHS)
static Intrinsic::ID getWaveReductionIntrinsic(AtomicRMWInst::BinOp Op)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool runOnFunction(Function &F, bool PostInlining)
AMD GCN specific subclass of TargetSubtarget.
Machine Check Debug Module
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
SmallVector< MachineOperand, 4 > Cond
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
Target-Independent Code Generator Pass Configuration Options pass.
bool isSingleLaneExecution(const Function &Kernel) const
Return true if only a single workitem can be active in a wave.
unsigned getWavefrontSize() const
static APFloat getNaN(const fltSemantics &Sem, bool Negative=false, uint64_t payload=0)
Factory for NaN values.
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
static APInt getMinValue(unsigned numBits)
Gets minimum unsigned value of APInt for a specific bit width.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
an instruction that atomically reads a memory location, combines it with another value,...
static bool isFPOperation(BinOp Op)
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Min
*p = old <signed v ? old : v
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ FMin
*p = minnum(old, v) minnum matches the behavior of llvm.minnum.
@ UMax
*p = old >unsigned v ? old : v
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
LLVM_ABI InstListType::const_iterator getFirstNonPHIIt() const
Returns an iterator to the first instruction in this block that is not a PHINode instruction.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ ICMP_SLT
signed less than
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ ICMP_ULT
unsigned less than
This is the shared class of boolean and integer constants.
bool isOne() const
This is just a convenience method to make client code smaller for a common case.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
DominatorTree & getDomTree()
FunctionPass class - This class is used to implement most global optimizations.
const SITargetLowering * getTargetLowering() const override
void applyUpdates(ArrayRef< UpdateT > Updates)
Submit updates to all available trees.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Base class for instruction visitors.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Primary interface to the complete machine description for the target machine.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
Target-Independent Code Generator Pass Configuration Options.
TMC & getTM() const
Get the right type of TargetMachine for this target.
The instances of the Type class are immutable: once they are created, they are never changed.
@ FloatTyID
32-bit floating point type
@ IntegerTyID
Arbitrary bit width integers.
@ DoubleTyID
64-bit floating point type
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
void setOperand(unsigned i, Value *Val)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
const ParentTy * getParent() const
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ LOCAL_ADDRESS
Address space for local memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ AMDGPU_PS
Used for Mesa/AMDPAL pixel shaders.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
GenericUniformityInfo< SSAContext > UniformityInfo
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
FunctionPass * createAMDGPUAtomicOptimizerPass(ScanOptions ScanStrategy)
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DWARFExpression::Operation Op
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
char & AMDGPUAtomicOptimizerID
LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)