47 #define DEBUG_TYPE "aarch64-type-promotion"
51 cl::desc(
"Enable merging of redundant sexts when one is dominating"
55 #define AARCH64_TYPE_PROMO_NAME "AArch64 Address Type Promotion"
62 class AArch64AddressTypePromotion :
public FunctionPass {
66 AArch64AddressTypePromotion()
82 Type *ConsideredSExtType;
112 bool propagateSignExtension(Instructions &SExtInsts);
117 bool shouldConsiderSExt(
const Instruction *SExt)
const;
126 void analyzeSExtension(Instructions &SExtInsts);
129 void mergeSExts(ValueToInsts &ValToSExtendedUses,
130 SetOfInstructions &ToRemove);
143 return new AArch64AddressTypePromotion();
146 bool AArch64AddressTypePromotion::canGetThrough(
const Instruction *Inst) {
147 if (isa<SExtInst>(Inst))
151 if (BinOp && isa<OverflowingBinaryOperator>(BinOp) &&
156 if (isa<TruncInst>(Inst) && isa<SExtInst>(Inst->
getOperand(0))) {
162 ConsideredSExtType->getIntegerBitWidth())
169 bool AArch64AddressTypePromotion::shouldGetThrough(
const Instruction *Inst) {
174 if (isa<SExtInst>(Inst) &&
185 if (isa<TruncInst>(Inst))
192 if (isa<BinaryOperator>(Inst) && isa<ConstantInt>(Inst->
getOperand(1)))
199 return !(isa<SelectInst>(Inst) && OpIdx == 0);
203 AArch64AddressTypePromotion::shouldConsiderSExt(
const Instruction *SExt)
const {
204 if (SExt->
getType() != ConsideredSExtType)
208 if (isa<GetElementPtrInst>(U))
241 AArch64AddressTypePromotion::propagateSignExtension(Instructions &SExtInsts) {
242 DEBUG(
dbgs() <<
"*** Propagate Sign Extension ***\n");
244 bool LocalChange =
false;
245 SetOfInstructions ToRemove;
246 ValueToInsts ValToSExtendedUses;
247 while (!SExtInsts.empty()) {
251 DEBUG(
dbgs() <<
"Consider:\n" << *SExt <<
'\n');
254 if (SExt->
use_empty() && ToRemove.count(SExt)) {
255 DEBUG(
dbgs() <<
"No uses => marked as delete\n");
260 while (
auto *Inst = dyn_cast<Instruction>(SExt->
getOperand(0))) {
261 DEBUG(
dbgs() <<
"Try to get through:\n" << *Inst <<
'\n');
262 if (!canGetThrough(Inst) || !shouldGetThrough(Inst)) {
271 if (isa<SExtInst>(Inst) || isa<TruncInst>(Inst)) {
272 DEBUG(
dbgs() <<
"SExt or trunc, mark it as to remove\n");
279 assert(User &&
"User of sext is not an Instruction!");
282 ToRemove.insert(Inst);
300 DEBUG(
dbgs() <<
"Propagate SExt to operands\n");
301 for (
int OpIdx = 0, EndOpIdx = Inst->
getNumOperands(); OpIdx != EndOpIdx;
306 DEBUG(
dbgs() <<
"No need to propagate\n");
311 if (
const ConstantInt *Cst = dyn_cast<ConstantInt>(Opnd)) {
312 DEBUG(
dbgs() <<
"Statically sign extend\n");
314 Cst->getSExtValue()));
318 if (isa<UndefValue>(Opnd)) {
319 DEBUG(
dbgs() <<
"Statically sign extend\n");
326 "Only one operand should have been sign extended");
330 DEBUG(
dbgs() <<
"Move before:\n" << *Inst <<
"\nSign extend\n");
335 SExtForOpnd =
nullptr;
337 if (SExtForOpnd == SExt) {
338 DEBUG(
dbgs() <<
"Sign extension is useless now\n");
339 ToRemove.insert(SExt);
347 if (!ToRemove.count(SExt) &&
349 DEBUG(
dbgs() <<
"Sign extension is useless, attach its use to "
352 ToRemove.insert(SExt);
354 ValToSExtendedUses[SExt->
getOperand(0)].push_back(SExt);
358 mergeSExts(ValToSExtendedUses, ToRemove);
362 I->eraseFromParent();
366 void AArch64AddressTypePromotion::mergeSExts(ValueToInsts &ValToSExtendedUses,
367 SetOfInstructions &ToRemove) {
368 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
370 for (
auto &Entry : ValToSExtendedUses) {
371 Instructions &Insts = Entry.second;
374 if (ToRemove.count(Inst))
376 bool inserted =
false;
377 for (
auto &Pt : CurPts) {
379 DEBUG(
dbgs() <<
"Replace all uses of:\n" << *Pt <<
"\nwith:\n"
381 Pt->replaceAllUsesWith(Inst);
392 DEBUG(
dbgs() <<
"Replace all uses of:\n" << *Inst <<
"\nwith:\n"
395 ToRemove.insert(Inst);
400 CurPts.push_back(Inst);
405 void AArch64AddressTypePromotion::analyzeSExtension(Instructions &SExtInsts) {
406 DEBUG(
dbgs() <<
"*** Analyze Sign Extensions ***\n");
410 for (
auto &BB : *
Func) {
411 for (
auto &II : BB) {
415 if (!isa<SExtInst>(SExt) || !shouldConsiderSExt(SExt))
418 DEBUG(
dbgs() <<
"Found:\n" << (*SExt) <<
'\n');
428 for (
const User *U : SExt->
users()) {
431 DEBUG(
dbgs() <<
"Interesting use in GetElementPtrInst\n" << *Inst
445 if (BinOp && isa<ConstantInt>(BinOp->
getOperand(0)))
449 }
while (Inst && canGetThrough(Inst) && shouldGetThrough(Inst));
451 DEBUG(
dbgs() <<
"Head of the chain:\n" << *Last <<
'\n');
453 SeenChains.
find(Last);
454 if (insert || AlreadySeen != SeenChains.
end()) {
456 SExtInsts.push_back(SExt);
457 if (AlreadySeen != SeenChains.
end() && AlreadySeen->second !=
nullptr) {
458 DEBUG(
dbgs() <<
"Insert chain member\n");
459 SExtInsts.push_back(AlreadySeen->second);
460 SeenChains[Last] =
nullptr;
463 DEBUG(
dbgs() <<
"Record its chain membership\n");
464 SeenChains[Last] = SExt;
470 bool AArch64AddressTypePromotion::runOnFunction(
Function &
F) {
479 DEBUG(
dbgs() <<
"*** " << getPassName() <<
": " << Func->getName() <<
'\n');
481 Instructions SExtInsts;
482 analyzeSExtension(SExtInsts);
483 return propagateSignExtension(SExtInsts);
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
unsigned getNumOperands() const
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
static IntegerType * getInt64Ty(LLVMContext &C)
FunctionPass * createAArch64AddressTypePromotionPass()
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
A Use represents the edge between a Value definition and its users.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
an instruction for type-safe pointer arithmetic to access elements of arrays and structs ...
initializer< Ty > init(const Ty &Val)
unsigned getOperandNo() const
Return the operand # of this use in its User.
The instances of the Type class are immutable: once they are created, they are never changed...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
bool hasNoSignedWrap() const
Determine whether the no signed wrap flag is set.
Represent the analysis usage information of a pass.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,"Assign register bank of generic virtual registers", false, false) RegBankSelect
User * getUser() const
Returns the User that contains this Use.
FunctionPass class - This class is used to implement most global optimizations.
Value * getOperand(unsigned i) const
unsigned getIntegerBitWidth() const
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
bool dominates(const Instruction *Def, const Use &U) const
Return true if Def dominates a use in User.
void initializeAArch64AddressTypePromotionPass(PassRegistry &)
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
This is the shared class of boolean and integer constants.
bool hasNoUnsignedWrap() const
Determine whether the no unsigned wrap flag is set.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
Type * getType() const
All values are typed, get the type of this value.
static ConstantInt * getSigned(IntegerType *Ty, int64_t V)
Return a ConstantInt with the specified value for the specified type.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
void setOperand(unsigned i, Value *Val)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
iterator_range< user_iterator > users()
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasOneUse() const
Return true if there is exactly one user of this value.
iterator find(const KeyT &Val)
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Value Representation.
void moveBefore(Instruction *MovePos)
Unlink this instruction from its current basic block and insert it into the basic block that MovePos ...
StringRef - Represent a constant reference to a string, i.e.
Legacy analysis pass which computes a DominatorTree.