25#include "llvm/IR/IntrinsicsAMDGPU.h"
30#define DEBUG_TYPE "amdgpu-late-codegenprepare"
39 WidenLoads(
"amdgpu-late-codegenprepare-widen-constant-loads",
40 cl::desc(
"Widen sub-dword constant address space loads in "
41 "AMDGPULateCodeGenPrepare"),
46class AMDGPULateCodeGenPrepare
47 :
public InstVisitor<AMDGPULateCodeGenPrepare, bool> {
60 :
F(
F),
DL(
F.getDataLayout()), ST(ST), AC(AC), UA(UA) {}
62 bool visitInstruction(Instruction &) {
return false; }
67 bool isSafeToWidenLoad(
const Value *
Base, uint64_t AccessSize,
68 const Instruction *CxtI)
const {
71 APInt(DL.getIndexTypeSizeInBits(
Base->getType()), AccessSize),
72 SimplifyQuery(DL,
nullptr,
nullptr, AC, CxtI));
75 bool canWidenScalarExtLoad(LoadInst &LI)
const;
76 bool visitLoadInst(LoadInst &LI);
81class LiveRegOptimizer {
85 const GCNSubtarget &ST;
88 Type *
const ConvertToScalar;
92 DenseMap<BasicBlock *, ValueToValueMap> BBUseValMap;
97 Type *calculateConvertType(
Type *OriginalType);
104 Value *convertFromOptType(
Type *ConvertType, Instruction *V,
106 BasicBlock *InsertBlock);
110 bool optimizeLiveType(Instruction *
I,
111 SmallVectorImpl<WeakTrackingVH> &DeadInsts);
115 bool shouldReplace(
Type *ITy) {
120 const auto *TLI = ST.getTargetLowering();
135 bool isOpLegal(
const Instruction *
I) {
146 unsigned EB =
IT->getBitWidth();
147 unsigned EC = VT->getNumElements();
149 if ((EB == 8 || EB == 16) && ST.hasSDWA() && EC * EB <= 32) {
150 switch (BO->getOpcode()) {
151 case Instruction::Add:
152 case Instruction::Sub:
153 case Instruction::And:
154 case Instruction::Or:
155 case Instruction::Xor:
168 bool isCoercionProfitable(Instruction *
II) {
169 SmallPtrSet<Instruction *, 4> CVisited;
170 SmallVector<Instruction *, 4> UserList;
174 for (User *V :
II->users())
180 return Intr->getIntrinsicID() == Intrinsic::amdgcn_perm;
181 return isa<PHINode, ShuffleVectorInst, InsertElementInst,
182 ExtractElementInst, CastInst>(
II);
185 while (!UserList.
empty()) {
187 if (!CVisited.
insert(CII).second)
192 if (CII->getParent() ==
II->getParent() && !IsLookThru(CII) &&
200 for (User *V : CII->users())
207 LiveRegOptimizer(
Module &Mod,
const GCNSubtarget &ST)
208 : Mod(Mod), DL(Mod.getDataLayout()), ST(ST),
214bool AMDGPULateCodeGenPrepare::run() {
222 LiveRegOptimizer LRO(*
F.getParent(), ST);
226 bool HasScalarSubwordLoads =
ST.hasScalarSubwordLoads();
231 Changed |= LRO.optimizeLiveType(&
I, DeadInsts);
238Type *LiveRegOptimizer::calculateConvertType(
Type *OriginalType) {
244 TypeSize OriginalSize =
DL.getTypeSizeInBits(VTy);
245 TypeSize ConvertScalarSize =
DL.getTypeSizeInBits(ConvertToScalar);
246 unsigned ConvertEltCount =
247 (OriginalSize + ConvertScalarSize - 1) / ConvertScalarSize;
249 if (OriginalSize <= ConvertScalarSize)
252 return VectorType::get(Type::getIntNTy(
Mod.getContext(), ConvertScalarSize),
253 ConvertEltCount,
false);
256Value *LiveRegOptimizer::convertToOptType(Instruction *V,
259 Type *NewTy = calculateConvertType(
V->getType());
261 TypeSize OriginalSize =
DL.getTypeSizeInBits(VTy);
262 TypeSize NewSize =
DL.getTypeSizeInBits(NewTy);
267 if (OriginalSize == NewSize)
268 return Builder.CreateBitCast(V, NewTy,
V->getName() +
".bc");
271 assert(NewSize > OriginalSize);
274 SmallVector<int, 8> ShuffleMask;
276 for (
unsigned I = 0;
I < OriginalElementCount;
I++)
279 for (uint64_t
I = OriginalElementCount;
I < ExpandedVecElementCount;
I++)
280 ShuffleMask.
push_back(OriginalElementCount);
282 Value *ExpandedVec = Builder.CreateShuffleVector(V, ShuffleMask);
283 return Builder.CreateBitCast(ExpandedVec, NewTy,
V->getName() +
".bc");
286Value *LiveRegOptimizer::convertFromOptType(
Type *ConvertType, Instruction *V,
288 BasicBlock *InsertBB) {
291 TypeSize OriginalSize =
DL.getTypeSizeInBits(
V->getType());
292 TypeSize NewSize =
DL.getTypeSizeInBits(NewVTy);
296 if (OriginalSize == NewSize)
297 return Builder.CreateBitCast(V, NewVTy,
V->getName() +
".bc");
301 assert(OriginalSize > NewSize);
303 if (!
V->getType()->isVectorTy()) {
318 SmallVector<int, 8> ShuffleMask(NarrowElementCount);
319 std::iota(ShuffleMask.
begin(), ShuffleMask.
end(), 0);
321 return Builder.CreateShuffleVector(Converted, ShuffleMask);
324bool LiveRegOptimizer::optimizeLiveType(
325 Instruction *
I, SmallVectorImpl<WeakTrackingVH> &DeadInsts) {
326 SmallVector<Instruction *, 4> Worklist;
327 SmallPtrSet<PHINode *, 4> PhiNodes;
328 SmallPtrSet<Instruction *, 4> Defs;
329 SmallPtrSet<Instruction *, 4>
Uses;
330 SmallPtrSet<Instruction *, 4> Visited;
333 while (!Worklist.
empty()) {
339 if (!shouldReplace(
II->getType()))
342 if (!isCoercionProfitable(
II))
348 for (
Value *V :
Phi->incoming_values()) {
351 if (!PhiNodes.
count(OpPhi) && !Visited.
count(OpPhi))
368 for (User *V :
II->users()) {
371 if (!PhiNodes.
count(OpPhi) && !Visited.
count(OpPhi))
379 Uses.insert(UseInst);
387 for (Instruction *
D : Defs) {
390 Value *ConvertVal = convertToOptType(
D, InsertPt);
392 ValMap[
D] = ConvertVal;
397 for (PHINode *Phi : PhiNodes) {
399 Phi->getNumIncomingValues(),
400 Phi->getName() +
".tc",
Phi->getIterator());
404 for (PHINode *Phi : PhiNodes) {
406 bool MissingIncVal =
false;
407 for (
int I = 0,
E =
Phi->getNumIncomingValues();
I <
E;
I++) {
408 Value *IncVal =
Phi->getIncomingValue(
I);
410 Type *NewType = calculateConvertType(
Phi->getType());
411 NewPhi->
addIncoming(ConstantInt::get(NewType, 0,
false),
412 Phi->getIncomingBlock(
I));
416 MissingIncVal =
true;
422 SmallVector<Value *, 4> PHIWorklist;
423 SmallPtrSet<Value *, 4> VisitedPhis;
425 while (!PHIWorklist.
empty()) {
427 VisitedPhis.
insert(NextDeadValue);
429 llvm::find_if(PhiNodes, [
this, &NextDeadValue](PHINode *CandPhi) {
430 return ValMap[CandPhi] == NextDeadValue;
434 if (OriginalPhi != PhiNodes.end())
435 ValMap.
erase(*OriginalPhi);
439 for (User *U : NextDeadValue->
users()) {
449 for (Instruction *U :
Uses) {
453 Value *NewVal =
nullptr;
454 if (BBUseValMap.
contains(
U->getParent()) &&
455 BBUseValMap[
U->getParent()].contains(Val))
456 NewVal = BBUseValMap[
U->getParent()][Val];
468 InsertPt,
U->getParent());
469 BBUseValMap[
U->getParent()][ValMap[
Op]] = NewVal;
473 U->setOperand(
OpIdx, NewVal);
481bool AMDGPULateCodeGenPrepare::canWidenScalarExtLoad(LoadInst &LI)
const {
494 unsigned TySize =
DL.getTypeStoreSize(Ty);
505bool AMDGPULateCodeGenPrepare::visitLoadInst(LoadInst &LI) {
514 if (!canWidenScalarExtLoad(LI))
521 int64_t Adjust =
Offset & 0x3;
522 int64_t AccessOffset =
Offset - Adjust;
523 if (AccessOffset < 0 || !isSafeToWidenLoad(
Base, AccessOffset + 4, &LI))
529 unsigned LdBits =
DL.getTypeStoreSizeInBits(LI.
getType());
530 auto *IntNTy = Type::getIntNTy(LI.
getContext(), LdBits);
532 auto *NewPtr = IRB.CreateConstGEP1_64(
537 LoadInst *NewLd = IRB.CreateAlignedLoad(IRB.getInt32Ty(), NewPtr,
Align(4));
540 unsigned ShAmt = Adjust * 8;
541 Value *Shifted = ShAmt ? IRB.CreateLShr(NewLd, ShAmt) : NewLd;
542 Value *NewVal = IRB.CreateBitCast(
543 IRB.CreateTrunc(Shifted,
DL.typeSizeEqualsStoreSize(LI.
getType())
559 bool Changed = AMDGPULateCodeGenPrepare(
F, ST, &AC, UI).run();
575 return "AMDGPU IR late optimizations";
602 return AMDGPULateCodeGenPrepare(
F, ST, &AC, UI).run();
606 "AMDGPU IR late optimizations",
false,
false)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static cl::opt< bool > WidenLoads("amdgpu-late-codegenprepare-widen-constant-loads", cl::desc("Widen sub-dword constant address space loads in " "AMDGPULateCodeGenPrepare"), cl::ReallyHidden, cl::init(true))
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)
Machine Check Debug Module
MachineInstr unsigned OpIdx
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
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
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 &)
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.
InstListType::iterator iterator
Instruction iterators...
Represents analyses that only rely on functions' control flow.
A parsed version of the target data layout string in and methods for querying it.
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.
bool erase(const KeyT &Val)
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
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.
Base class for instruction visitors.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
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.
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 ...
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.
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
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.
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.
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)
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
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)
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...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
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
static LLVM_ABI EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.