48 #define DEBUG_TYPE "aarch64-type-promotion"
52 cl::desc(
"Enable the type promotion pass"),
56 cl::desc(
"Enable merging of redundant sexts when one is dominating"
69 class AArch64AddressTypePromotion :
public FunctionPass {
73 AArch64AddressTypePromotion()
78 const char *getPassName()
const override {
79 return "AArch64 Address Type Promotion";
91 Type *ConsideredSExtType;
121 bool propagateSignExtension(Instructions &SExtInsts);
126 bool shouldConsiderSExt(
const Instruction *SExt)
const;
135 void analyzeSExtension(Instructions &SExtInsts);
138 void mergeSExts(ValueToInsts &ValToSExtendedUses,
139 SetOfInstructions &ToRemove);
146 "AArch64 Type Promotion Pass",
false,
false)
152 return new AArch64AddressTypePromotion();
155 bool AArch64AddressTypePromotion::canGetThrough(
const Instruction *Inst) {
156 if (isa<SExtInst>(Inst))
160 if (BinOp && isa<OverflowingBinaryOperator>(BinOp) &&
165 if (isa<TruncInst>(Inst) && isa<SExtInst>(Inst->
getOperand(0))) {
171 ConsideredSExtType->getIntegerBitWidth())
178 bool AArch64AddressTypePromotion::shouldGetThrough(
const Instruction *Inst) {
183 if (isa<SExtInst>(Inst) &&
194 if (isa<TruncInst>(Inst))
201 if (isa<BinaryOperator>(Inst) && isa<ConstantInt>(Inst->
getOperand(1)))
208 if (isa<SelectInst>(Inst) && OpIdx == 0)
214 AArch64AddressTypePromotion::shouldConsiderSExt(
const Instruction *SExt)
const {
215 if (SExt->
getType() != ConsideredSExtType)
219 if (isa<GetElementPtrInst>(U))
252 AArch64AddressTypePromotion::propagateSignExtension(Instructions &SExtInsts) {
253 DEBUG(
dbgs() <<
"*** Propagate Sign Extension ***\n");
255 bool LocalChange =
false;
256 SetOfInstructions ToRemove;
257 ValueToInsts ValToSExtendedUses;
258 while (!SExtInsts.empty()) {
262 DEBUG(
dbgs() <<
"Consider:\n" << *SExt <<
'\n');
265 if (SExt->
use_empty() && ToRemove.count(SExt)) {
266 DEBUG(
dbgs() <<
"No uses => marked as delete\n");
271 while (
auto *Inst = dyn_cast<Instruction>(SExt->
getOperand(0))) {
272 DEBUG(
dbgs() <<
"Try to get through:\n" << *Inst <<
'\n');
273 if (!canGetThrough(Inst) || !shouldGetThrough(Inst)) {
282 if (isa<SExtInst>(Inst) || isa<TruncInst>(Inst)) {
283 DEBUG(
dbgs() <<
"SExt or trunc, mark it as to remove\n");
290 assert(User &&
"User of sext is not an Instruction!");
293 ToRemove.insert(Inst);
311 DEBUG(
dbgs() <<
"Propagate SExt to operands\n");
312 for (
int OpIdx = 0, EndOpIdx = Inst->
getNumOperands(); OpIdx != EndOpIdx;
317 DEBUG(
dbgs() <<
"No need to propagate\n");
322 if (
const ConstantInt *Cst = dyn_cast<ConstantInt>(Opnd)) {
323 DEBUG(
dbgs() <<
"Statically sign extend\n");
325 Cst->getSExtValue()));
329 if (isa<UndefValue>(Opnd)) {
330 DEBUG(
dbgs() <<
"Statically sign extend\n");
336 assert(SExtForOpnd &&
337 "Only one operand should have been sign extended");
341 DEBUG(
dbgs() <<
"Move before:\n" << *Inst <<
"\nSign extend\n");
346 SExtForOpnd =
nullptr;
348 if (SExtForOpnd == SExt) {
349 DEBUG(
dbgs() <<
"Sign extension is useless now\n");
350 ToRemove.insert(SExt);
358 if (!ToRemove.count(SExt) &&
360 DEBUG(
dbgs() <<
"Sign extension is useless, attach its use to "
363 ToRemove.insert(SExt);
365 ValToSExtendedUses[SExt->
getOperand(0)].push_back(SExt);
369 mergeSExts(ValToSExtendedUses, ToRemove);
373 I->eraseFromParent();
377 void AArch64AddressTypePromotion::mergeSExts(ValueToInsts &ValToSExtendedUses,
378 SetOfInstructions &ToRemove) {
379 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
381 for (
auto &Entry : ValToSExtendedUses) {
382 Instructions &Insts = Entry.second;
385 if (ToRemove.count(Inst))
387 bool inserted =
false;
388 for (
auto &Pt : CurPts) {
390 DEBUG(
dbgs() <<
"Replace all uses of:\n" << *Pt <<
"\nwith:\n"
392 Pt->replaceAllUsesWith(Inst);
403 DEBUG(
dbgs() <<
"Replace all uses of:\n" << *Inst <<
"\nwith:\n"
406 ToRemove.insert(Inst);
411 CurPts.push_back(Inst);
416 void AArch64AddressTypePromotion::analyzeSExtension(Instructions &SExtInsts) {
417 DEBUG(
dbgs() <<
"*** Analyze Sign Extensions ***\n");
421 for (
auto &BB : *
Func) {
422 for (
auto &II : BB) {
426 if (!isa<SExtInst>(SExt) || !shouldConsiderSExt(SExt))
429 DEBUG(
dbgs() <<
"Found:\n" << (*SExt) <<
'\n');
439 for (
const User *U : SExt->
users()) {
442 DEBUG(
dbgs() <<
"Interesting use in GetElementPtrInst\n" << *Inst
456 if (BinOp && isa<ConstantInt>(BinOp->
getOperand(0)))
460 }
while (Inst && canGetThrough(Inst) && shouldGetThrough(Inst));
462 DEBUG(
dbgs() <<
"Head of the chain:\n" << *Last <<
'\n');
464 SeenChains.
find(Last);
465 if (insert || AlreadySeen != SeenChains.
end()) {
467 SExtInsts.push_back(SExt);
468 if (AlreadySeen != SeenChains.
end() && AlreadySeen->second !=
nullptr) {
469 DEBUG(
dbgs() <<
"Insert chain member\n");
470 SExtInsts.push_back(AlreadySeen->second);
471 SeenChains[Last] =
nullptr;
474 DEBUG(
dbgs() <<
"Record its chain membership\n");
475 SeenChains[Last] = SExt;
481 bool AArch64AddressTypePromotion::runOnFunction(
Function &
F) {
487 DEBUG(
dbgs() <<
"*** " << getPassName() <<
": " << Func->getName() <<
'\n');
489 Instructions SExtInsts;
490 analyzeSExtension(SExtInsts);
491 return propagateSignExtension(SExtInsts);
Pass interface - Implemented by all 'passes'.
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)
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
A Use represents the edge between a Value definition and its users.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
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...
GetElementPtrInst - an instruction for type-safe pointer arithmetic to access elements of arrays and ...
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...
Represent the analysis usage information of a pass.
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
static UndefValue * get(Type *T)
get() - Static factory methods - Return an 'undef' object of the specified type.
FunctionPass * createAArch64AddressTypePromotionPass()
bool hasNoSignedWrap() const
Determine whether the no signed wrap flag is set.
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...
unsigned getIntegerBitWidth() const
This is the shared class of boolean and integer constants.
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()
LLVM_ATTRIBUTE_UNUSED_RESULT std::enable_if< !is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
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)
void mutateType(Type *Ty)
Mutate the type of this Value to be of the specified type.
LLVM Value Representation.
bool hasNoUnsignedWrap() const
Determine whether the no unsigned wrap flag is set.
void moveBefore(Instruction *MovePos)
moveBefore - Unlink this instruction from its current basic block and insert it into the basic block ...
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
Legacy analysis pass which computes a DominatorTree.