25#include "llvm/IR/IntrinsicsAMDGPU.h"
29#define DEBUG_TYPE "amdgpu-late-codegenprepare"
35class AMDGPULateCodeGenPrepare
36 :
public InstVisitor<AMDGPULateCodeGenPrepare, bool> {
49 :
F(
F),
DL(
F.getDataLayout()), ST(ST), AC(AC), UA(UA) {}
51 bool visitInstruction(
Instruction &) {
return false; }
60 APInt(
DL.getIndexTypeSizeInBits(
Base->getType()), AccessSize),
64 bool canWidenScalarExtLoad(
LoadInst &LI)
const;
70class LiveRegOptimizer {
77 Type *
const ConvertToScalar;
86 Type *calculateConvertType(
Type *OriginalType);
104 bool shouldReplace(
Type *ITy) {
109 const auto *
TLI = ST.getTargetLowering();
135 unsigned EB =
IT->getBitWidth();
136 unsigned EC = VT->getNumElements();
138 if ((EB == 8 || EB == 16) && ST.hasSDWA() && EC * EB <= 32) {
139 switch (BO->getOpcode()) {
140 case Instruction::Add:
141 case Instruction::Sub:
142 case Instruction::And:
143 case Instruction::Or:
144 case Instruction::Xor:
169 return Intr->getIntrinsicID() == Intrinsic::amdgcn_perm;
174 while (!UserList.
empty()) {
176 if (!CVisited.
insert(CII).second)
181 if (CII->getParent() ==
II->getParent() && !IsLookThru(CII) &&
189 for (
User *
V : CII->users())
203bool AMDGPULateCodeGenPrepare::run() {
211 LiveRegOptimizer LRO(*
F.getParent(), ST);
220 Changed |= LRO.optimizeLiveType(&
I, DeadInsts);
227Type *LiveRegOptimizer::calculateConvertType(
Type *OriginalType) {
233 TypeSize OriginalSize =
DL.getTypeSizeInBits(VTy);
234 TypeSize ConvertScalarSize =
DL.getTypeSizeInBits(ConvertToScalar);
235 unsigned ConvertEltCount =
236 (OriginalSize + ConvertScalarSize - 1) / ConvertScalarSize;
238 if (OriginalSize <= ConvertScalarSize)
241 return VectorType::get(Type::getIntNTy(
Mod.getContext(), ConvertScalarSize),
242 ConvertEltCount,
false);
245Value *LiveRegOptimizer::convertToOptType(Instruction *
V,
248 Type *NewTy = calculateConvertType(
V->getType());
250 TypeSize OriginalSize =
DL.getTypeSizeInBits(VTy);
251 TypeSize NewSize =
DL.getTypeSizeInBits(NewTy);
256 if (OriginalSize == NewSize)
257 return Builder.CreateBitCast(
V, NewTy,
V->getName() +
".bc");
260 assert(NewSize > OriginalSize);
263 SmallVector<int, 8> ShuffleMask;
265 for (
unsigned I = 0;
I < OriginalElementCount;
I++)
268 for (
uint64_t I = OriginalElementCount;
I < ExpandedVecElementCount;
I++)
269 ShuffleMask.
push_back(OriginalElementCount);
271 Value *ExpandedVec = Builder.CreateShuffleVector(
V, ShuffleMask);
272 return Builder.CreateBitCast(ExpandedVec, NewTy,
V->getName() +
".bc");
275Value *LiveRegOptimizer::convertFromOptType(
Type *ConvertType, Instruction *
V,
277 BasicBlock *InsertBB) {
280 TypeSize OriginalSize =
DL.getTypeSizeInBits(
V->getType());
281 TypeSize NewSize =
DL.getTypeSizeInBits(NewVTy);
285 if (OriginalSize == NewSize)
286 return Builder.CreateBitCast(
V, NewVTy,
V->getName() +
".bc");
290 assert(OriginalSize > NewSize);
292 if (!
V->getType()->isVectorTy()) {
307 SmallVector<int, 8> ShuffleMask(NarrowElementCount);
308 std::iota(ShuffleMask.
begin(), ShuffleMask.
end(), 0);
310 return Builder.CreateShuffleVector(Converted, ShuffleMask);
313bool LiveRegOptimizer::optimizeLiveType(
314 Instruction *
I, SmallVectorImpl<WeakTrackingVH> &DeadInsts) {
315 SmallVector<Instruction *, 4> Worklist;
316 SmallPtrSet<PHINode *, 4> PhiNodes;
317 SmallPtrSet<Instruction *, 4> Defs;
318 SmallPtrSet<Instruction *, 4>
Uses;
319 SmallPtrSet<Instruction *, 4> Visited;
322 while (!Worklist.
empty()) {
328 if (!shouldReplace(
II->getType()))
331 if (!isCoercionProfitable(
II))
337 for (
Value *
V :
Phi->incoming_values()) {
340 if (!PhiNodes.
count(OpPhi) && !Visited.
count(OpPhi))
357 for (User *
V :
II->users()) {
360 if (!PhiNodes.
count(OpPhi) && !Visited.
count(OpPhi))
368 Uses.insert(UseInst);
376 for (Instruction *
D : Defs) {
379 Value *ConvertVal = convertToOptType(
D, InsertPt);
381 ValMap[
D] = ConvertVal;
386 for (PHINode *Phi : PhiNodes) {
388 Phi->getNumIncomingValues(),
389 Phi->getName() +
".tc",
Phi->getIterator());
393 for (PHINode *Phi : PhiNodes) {
395 bool MissingIncVal =
false;
396 for (
int I = 0,
E =
Phi->getNumIncomingValues();
I <
E;
I++) {
397 Value *IncVal =
Phi->getIncomingValue(
I);
399 Type *NewType = calculateConvertType(
Phi->getType());
400 NewPhi->
addIncoming(ConstantInt::get(NewType, 0,
false),
401 Phi->getIncomingBlock(
I));
405 MissingIncVal =
true;
411 SmallVector<Value *, 4> PHIWorklist;
412 SmallPtrSet<Value *, 4> VisitedPhis;
414 while (!PHIWorklist.
empty()) {
416 VisitedPhis.
insert(NextDeadValue);
418 llvm::find_if(PhiNodes, [
this, &NextDeadValue](PHINode *CandPhi) {
419 return ValMap[CandPhi] == NextDeadValue;
423 if (OriginalPhi != PhiNodes.end())
424 ValMap.
erase(*OriginalPhi);
426 for (User *U : NextDeadValue->
users()) {
440 for (Instruction *U :
Uses) {
444 Value *NewVal =
nullptr;
445 if (BBUseValMap.contains(
U->getParent()) &&
446 BBUseValMap[
U->getParent()].contains(Val))
447 NewVal = BBUseValMap[
U->getParent()][Val];
460 InsertPt,
U->getParent());
461 BBUseValMap[
U->getParent()][ValMap[
Op]] = NewVal;
465 U->setOperand(OpIdx, NewVal);
473bool AMDGPULateCodeGenPrepare::canWidenScalarExtLoad(LoadInst &LI)
const {
486 unsigned TySize =
DL.getTypeStoreSize(Ty);
497bool AMDGPULateCodeGenPrepare::visitLoadInst(LoadInst &LI) {
498 if (!ST.
getCLOpts().late_codegenprepare_widen_constant_loads)
506 if (!canWidenScalarExtLoad(LI))
513 int64_t Adjust =
Offset & 0x3;
514 int64_t AccessOffset =
Offset - Adjust;
515 if (AccessOffset < 0 || !isSafeToWidenLoad(
Base, AccessOffset + 4, &LI))
521 unsigned LdBits =
DL.getTypeStoreSizeInBits(LI.
getType());
522 auto *IntNTy = Type::getIntNTy(LI.
getContext(), LdBits);
524 auto *NewPtr = IRB.CreateConstGEP1_64(
529 LoadInst *NewLd = IRB.CreateAlignedLoad(IRB.getInt32Ty(), NewPtr,
Align(4));
532 unsigned ShAmt = Adjust * 8;
533 Value *Shifted = ShAmt ? IRB.CreateLShr(NewLd, ShAmt) : NewLd;
534 Value *NewVal = IRB.CreateBitCast(
535 IRB.CreateTrunc(Shifted,
DL.typeSizeEqualsStoreSize(LI.
getType())
551 bool Changed = AMDGPULateCodeGenPrepare(
F, ST, &AC, UI).run();
567 return "AMDGPU IR late optimizations";
594 return AMDGPULateCodeGenPrepare(
F, ST, &AC, UI).run();
598 "AMDGPU IR late optimizations",
false,
false)
const TargetLowering & TLI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static cl::opt< ITMode > IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), cl::values(clEnumValN(DefaultIT, "arm-default-it", "Generate any type of IT block"), clEnumValN(RestrictedIT, "arm-restrict-it", "Disallow complex IT blocks")))
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static bool runOnFunction(Function &F, bool PostInlining)
uint64_t IntrinsicInst * II
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Remove Loads Into Fake Uses
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
Target-Independent Code Generator Pass Configuration Options pass.
bool runOnFunction(Function &F) override
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
AMDGPULateCodeGenPrepareLegacy()
StringRef getPassName() const override
getPassName - Return a nice clean name for a pass.
PreservedAnalyses run(Function &, FunctionAnalysisManager &)
const AMDGPUOptions & getCLOpts() const
Class for arbitrary precision integers.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
A function analysis which provides an AssumptionCache.
An immutable pass that tracks lazily created AssumptionCache objects.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
InstListType::iterator iterator
Instruction iterators...
Represents analyses that only rely on functions' control flow.
This is the base class for all instructions that perform data casts.
A parsed version of the target data layout string in and methods for querying it.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
bool erase(const KeyT &Val)
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
Class to represent fixed width SIMD vectors.
FunctionPass class - This class is used to implement most global optimizations.
bool skipFunction(const Function &F) const
Optional passes call this function to check whether the pass should be skipped.
bool hasScalarSubwordLoads() const
This instruction inserts a single (scalar) element into a VectorType value.
Base class for instruction visitors.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
bool isTerminator() const
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
An instruction for reading from memory.
unsigned getPointerAddressSpace() const
Returns the address space of the pointer operand.
Value * getPointerOperand()
Align getAlign() const
Return the alignment of the access that is being performed.
A Module instance is used to store all the information related to an LLVM module.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
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 none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
This instruction constructs a fixed permutation of two input vectors.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
std::pair< LegalizeTypeAction, EVT > LegalizeKind
LegalizeKind holds the legalization kind that needs to happen to EVT in order to type-legalize it.
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.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isAggregateType() const
Return true if the type is an aggregate type.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
ElementCount getElementCount() const
Return an ElementCount instance to represent the (possibly scalable) number of elements in the vector...
Type * getElementType() const
constexpr ScalarTy getFixedValue() const
const ParentTy * getParent() const
@ CONSTANT_ADDRESS_32BIT
Address space for 32-bit constant memory.
@ CONSTANT_ADDRESS
Address space for constant memory (VTX2).
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
void copyMetadataForWidenedLoad(LoadInst &Dest, const LoadInst &Source)
NodeAddr< PhiNode * > Phi
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
GenericUniformityInfo< SSAContext > UniformityInfo
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Value * GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL, bool AllowNonInbounds=true)
Analyze the specified pointer to see if it can be expressed as a base pointer plus a constant offset.
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...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto reverse(ContainerTy &&C)
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
@ Mod
The access may modify the value stored in memory.
DWARFExpression::Operation Op
LLVM_ABI bool isDereferenceableAndAlignedPointer(const Value *V, Type *Ty, Align Alignment, const SimplifyQuery &Q, bool IgnoreFree=false)
Returns true if V is always a dereferenceable pointer with alignment greater or equal than requested.
LLVM_ABI bool RecursivelyDeleteTriviallyDeadInstructionsPermissive(SmallVectorImpl< WeakTrackingVH > &DeadInsts, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
Same functionality as RecursivelyDeleteTriviallyDeadInstructions, but allow instructions that are not...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
FunctionPass * createAMDGPULateCodeGenPrepareLegacyPass()
DenseMap< const Value *, Value * > ValueToValueMap
This struct is a compact representation of a valid (non-zero power of two) alignment.
static LLVM_ABI EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.