[CodeGenPrepare] Refine the cost model provided by the promotion helper.

- Use TargetLowering to check for the actual cost of each extension.
- Provide a factorized method to check for the cost of an extension:
  TargetLowering::isExtFree.
- Provide a virtual method TargetLowering::isExtFreeImpl for targets to be able
  to tune the cost of non-free extensions.

This refactoring offers a better granularity to model what really happens on
different targets.

No performance changes and very few code differences.

Part of <rdar://problem/19267165> 

llvm-svn: 231855
This commit is contained in:
Quentin Colombet 2015-03-10 21:48:15 +00:00
parent 4bb90a71de
commit 1b274f99ad
4 changed files with 141 additions and 64 deletions

View File

@ -1484,6 +1484,33 @@ public:
virtual bool isProfitableToHoist(Instruction *I) const { return true; } virtual bool isProfitableToHoist(Instruction *I) const { return true; }
/// Return true if the extension represented by \p I is free.
/// Unlikely the is[Z|FP]ExtFree family which is based on types,
/// this method can use the context provided by \p I to decide
/// whether or not \p I is free.
/// This method extends the behavior of the is[Z|FP]ExtFree family.
/// In other words, if is[Z|FP]Free returns true, then this method
/// returns true as well. The converse is not true.
/// The target can perform the adequate checks by overriding isExtFreeImpl.
/// \pre \p I must be a sign, zero, or fp extension.
bool isExtFree(const Instruction *I) const {
switch (I->getOpcode()) {
case Instruction::FPExt:
if (isFPExtFree(EVT::getEVT(I->getType())))
return true;
break;
case Instruction::ZExt:
if (isZExtFree(I->getOperand(0)->getType(), I->getType()))
return true;
break;
case Instruction::SExt:
break;
default:
llvm_unreachable("Instruction is not an extension");
}
return isExtFreeImpl(I);
}
/// Return true if any actual instruction that defines a value of type Ty1 /// Return true if any actual instruction that defines a value of type Ty1
/// implicitly zero-extends the value to Ty2 in the result register. /// implicitly zero-extends the value to Ty2 in the result register.
/// ///
@ -1847,6 +1874,11 @@ private:
CallingConv::ID LibcallCallingConvs[RTLIB::UNKNOWN_LIBCALL]; CallingConv::ID LibcallCallingConvs[RTLIB::UNKNOWN_LIBCALL];
protected: protected:
/// Return true if the extension represented by \p I is free.
/// \pre \p I is a sign, zero, or fp extension and
/// is[Z|FP]ExtFree of the related types is not true.
virtual bool isExtFreeImpl(const Instruction *I) const { return false; }
/// \brief Specify maximum number of store instructions per memset call. /// \brief Specify maximum number of store instructions per memset call.
/// ///
/// When lowering \@llvm.memset this field specifies the maximum number of /// When lowering \@llvm.memset this field specifies the maximum number of

View File

@ -186,7 +186,7 @@ class TypePromotionTransaction;
bool ExtLdPromotion(TypePromotionTransaction &TPT, LoadInst *&LI, bool ExtLdPromotion(TypePromotionTransaction &TPT, LoadInst *&LI,
Instruction *&Inst, Instruction *&Inst,
const SmallVectorImpl<Instruction *> &Exts, const SmallVectorImpl<Instruction *> &Exts,
unsigned CreatedInst); unsigned CreatedInstCost);
bool splitBranchCondition(Function &F); bool splitBranchCondition(Function &F);
bool simplifyOffsetableRelocate(Instruction &I); bool simplifyOffsetableRelocate(Instruction &I);
}; };
@ -2023,7 +2023,7 @@ private:
ExtAddrMode &AMBefore, ExtAddrMode &AMBefore,
ExtAddrMode &AMAfter); ExtAddrMode &AMAfter);
bool ValueAlreadyLiveAtInst(Value *Val, Value *KnownLive1, Value *KnownLive2); bool ValueAlreadyLiveAtInst(Value *Val, Value *KnownLive1, Value *KnownLive2);
bool IsPromotionProfitable(unsigned MatchedSize, unsigned SizeWithPromotion, bool IsPromotionProfitable(unsigned NewCost, unsigned OldCost,
Value *PromotedOperand) const; Value *PromotedOperand) const;
}; };
@ -2157,7 +2157,7 @@ class TypePromotionHelper {
/// \brief Utility function to promote the operand of \p Ext when this /// \brief Utility function to promote the operand of \p Ext when this
/// operand is a promotable trunc or sext or zext. /// operand is a promotable trunc or sext or zext.
/// \p PromotedInsts maps the instructions to their type before promotion. /// \p PromotedInsts maps the instructions to their type before promotion.
/// \p CreatedInsts[out] contains how many non-free instructions have been /// \p CreatedInstsCost[out] contains the cost of all instructions
/// created to promote the operand of Ext. /// created to promote the operand of Ext.
/// Newly added extensions are inserted in \p Exts. /// Newly added extensions are inserted in \p Exts.
/// Newly added truncates are inserted in \p Truncs. /// Newly added truncates are inserted in \p Truncs.
@ -2165,53 +2165,55 @@ class TypePromotionHelper {
/// \return The promoted value which is used instead of Ext. /// \return The promoted value which is used instead of Ext.
static Value *promoteOperandForTruncAndAnyExt( static Value *promoteOperandForTruncAndAnyExt(
Instruction *Ext, TypePromotionTransaction &TPT, Instruction *Ext, TypePromotionTransaction &TPT,
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
SmallVectorImpl<Instruction *> *Exts, SmallVectorImpl<Instruction *> *Exts,
SmallVectorImpl<Instruction *> *Truncs); SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI);
/// \brief Utility function to promote the operand of \p Ext when this /// \brief Utility function to promote the operand of \p Ext when this
/// operand is promotable and is not a supported trunc or sext. /// operand is promotable and is not a supported trunc or sext.
/// \p PromotedInsts maps the instructions to their type before promotion. /// \p PromotedInsts maps the instructions to their type before promotion.
/// \p CreatedInsts[out] contains how many non-free instructions have been /// \p CreatedInstsCost[out] contains the cost of all the instructions
/// created to promote the operand of Ext. /// created to promote the operand of Ext.
/// Newly added extensions are inserted in \p Exts. /// Newly added extensions are inserted in \p Exts.
/// Newly added truncates are inserted in \p Truncs. /// Newly added truncates are inserted in \p Truncs.
/// Should never be called directly. /// Should never be called directly.
/// \return The promoted value which is used instead of Ext. /// \return The promoted value which is used instead of Ext.
static Value * static Value *promoteOperandForOther(Instruction *Ext,
promoteOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT, TypePromotionTransaction &TPT,
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, InstrToOrigTy &PromotedInsts,
unsigned &CreatedInstsCost,
SmallVectorImpl<Instruction *> *Exts, SmallVectorImpl<Instruction *> *Exts,
SmallVectorImpl<Instruction *> *Truncs, bool IsSExt); SmallVectorImpl<Instruction *> *Truncs,
const TargetLowering &TLI, bool IsSExt);
/// \see promoteOperandForOther. /// \see promoteOperandForOther.
static Value * static Value *signExtendOperandForOther(
signExtendOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT, Instruction *Ext, TypePromotionTransaction &TPT,
InstrToOrigTy &PromotedInsts, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
unsigned &CreatedInsts,
SmallVectorImpl<Instruction *> *Exts, SmallVectorImpl<Instruction *> *Exts,
SmallVectorImpl<Instruction *> *Truncs) { SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI) {
return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInsts, Exts, return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInstsCost,
Truncs, true); Exts, Truncs, TLI, true);
} }
/// \see promoteOperandForOther. /// \see promoteOperandForOther.
static Value * static Value *zeroExtendOperandForOther(
zeroExtendOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT, Instruction *Ext, TypePromotionTransaction &TPT,
InstrToOrigTy &PromotedInsts, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
unsigned &CreatedInsts,
SmallVectorImpl<Instruction *> *Exts, SmallVectorImpl<Instruction *> *Exts,
SmallVectorImpl<Instruction *> *Truncs) { SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI) {
return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInsts, Exts, return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInstsCost,
Truncs, false); Exts, Truncs, TLI, false);
} }
public: public:
/// Type for the utility function that promotes the operand of Ext. /// Type for the utility function that promotes the operand of Ext.
typedef Value *(*Action)(Instruction *Ext, TypePromotionTransaction &TPT, typedef Value *(*Action)(Instruction *Ext, TypePromotionTransaction &TPT,
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, InstrToOrigTy &PromotedInsts,
unsigned &CreatedInstsCost,
SmallVectorImpl<Instruction *> *Exts, SmallVectorImpl<Instruction *> *Exts,
SmallVectorImpl<Instruction *> *Truncs); SmallVectorImpl<Instruction *> *Truncs,
const TargetLowering &TLI);
/// \brief Given a sign/zero extend instruction \p Ext, return the approriate /// \brief Given a sign/zero extend instruction \p Ext, return the approriate
/// action to promote the operand of \p Ext instead of using Ext. /// action to promote the operand of \p Ext instead of using Ext.
/// \return NULL if no promotable action is possible with the current /// \return NULL if no promotable action is possible with the current
@ -2328,16 +2330,18 @@ TypePromotionHelper::Action TypePromotionHelper::getAction(
Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt( Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt(
llvm::Instruction *SExt, TypePromotionTransaction &TPT, llvm::Instruction *SExt, TypePromotionTransaction &TPT,
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
SmallVectorImpl<Instruction *> *Exts, SmallVectorImpl<Instruction *> *Exts,
SmallVectorImpl<Instruction *> *Truncs) { SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI) {
// By construction, the operand of SExt is an instruction. Otherwise we cannot // By construction, the operand of SExt is an instruction. Otherwise we cannot
// get through it and this method should not be called. // get through it and this method should not be called.
Instruction *SExtOpnd = cast<Instruction>(SExt->getOperand(0)); Instruction *SExtOpnd = cast<Instruction>(SExt->getOperand(0));
Value *ExtVal = SExt; Value *ExtVal = SExt;
bool HasMergedNonFreeExt = false;
if (isa<ZExtInst>(SExtOpnd)) { if (isa<ZExtInst>(SExtOpnd)) {
// Replace s|zext(zext(opnd)) // Replace s|zext(zext(opnd))
// => zext(opnd). // => zext(opnd).
HasMergedNonFreeExt = !TLI.isExtFree(SExtOpnd);
Value *ZExt = Value *ZExt =
TPT.createZExt(SExt, SExtOpnd->getOperand(0), SExt->getType()); TPT.createZExt(SExt, SExtOpnd->getOperand(0), SExt->getType());
TPT.replaceAllUsesWith(SExt, ZExt); TPT.replaceAllUsesWith(SExt, ZExt);
@ -2348,7 +2352,7 @@ Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt(
// => z|sext(opnd). // => z|sext(opnd).
TPT.setOperand(SExt, 0, SExtOpnd->getOperand(0)); TPT.setOperand(SExt, 0, SExtOpnd->getOperand(0));
} }
CreatedInsts = 0; CreatedInstsCost = 0;
// Remove dead code. // Remove dead code.
if (SExtOpnd->use_empty()) if (SExtOpnd->use_empty())
@ -2357,8 +2361,11 @@ Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt(
// Check if the extension is still needed. // Check if the extension is still needed.
Instruction *ExtInst = dyn_cast<Instruction>(ExtVal); Instruction *ExtInst = dyn_cast<Instruction>(ExtVal);
if (!ExtInst || ExtInst->getType() != ExtInst->getOperand(0)->getType()) { if (!ExtInst || ExtInst->getType() != ExtInst->getOperand(0)->getType()) {
if (ExtInst && Exts) if (ExtInst) {
if (Exts)
Exts->push_back(ExtInst); Exts->push_back(ExtInst);
CreatedInstsCost = !TLI.isExtFree(ExtInst) && !HasMergedNonFreeExt;
}
return ExtVal; return ExtVal;
} }
@ -2371,13 +2378,14 @@ Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt(
Value *TypePromotionHelper::promoteOperandForOther( Value *TypePromotionHelper::promoteOperandForOther(
Instruction *Ext, TypePromotionTransaction &TPT, Instruction *Ext, TypePromotionTransaction &TPT,
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
SmallVectorImpl<Instruction *> *Exts, SmallVectorImpl<Instruction *> *Exts,
SmallVectorImpl<Instruction *> *Truncs, bool IsSExt) { SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI,
bool IsSExt) {
// By construction, the operand of Ext is an instruction. Otherwise we cannot // By construction, the operand of Ext is an instruction. Otherwise we cannot
// get through it and this method should not be called. // get through it and this method should not be called.
Instruction *ExtOpnd = cast<Instruction>(Ext->getOperand(0)); Instruction *ExtOpnd = cast<Instruction>(Ext->getOperand(0));
CreatedInsts = 0; CreatedInstsCost = 0;
if (!ExtOpnd->hasOneUse()) { if (!ExtOpnd->hasOneUse()) {
// ExtOpnd will be promoted. // ExtOpnd will be promoted.
// All its uses, but Ext, will need to use a truncated value of the // All its uses, but Ext, will need to use a truncated value of the
@ -2452,7 +2460,6 @@ Value *TypePromotionHelper::promoteOperandForOther(
continue; continue;
} }
ExtForOpnd = cast<Instruction>(ValForExtOpnd); ExtForOpnd = cast<Instruction>(ValForExtOpnd);
++CreatedInsts;
} }
if (Exts) if (Exts)
Exts->push_back(ExtForOpnd); Exts->push_back(ExtForOpnd);
@ -2461,6 +2468,7 @@ Value *TypePromotionHelper::promoteOperandForOther(
// Move the sign extension before the insertion point. // Move the sign extension before the insertion point.
TPT.moveBefore(ExtForOpnd, ExtOpnd); TPT.moveBefore(ExtForOpnd, ExtOpnd);
TPT.setOperand(ExtOpnd, OpIdx, ExtForOpnd); TPT.setOperand(ExtOpnd, OpIdx, ExtForOpnd);
CreatedInstsCost += !TLI.isExtFree(ExtForOpnd);
// If more sext are required, new instructions will have to be created. // If more sext are required, new instructions will have to be created.
ExtForOpnd = nullptr; ExtForOpnd = nullptr;
} }
@ -2473,22 +2481,22 @@ Value *TypePromotionHelper::promoteOperandForOther(
/// IsPromotionProfitable - Check whether or not promoting an instruction /// IsPromotionProfitable - Check whether or not promoting an instruction
/// to a wider type was profitable. /// to a wider type was profitable.
/// \p MatchedSize gives the number of instructions that have been matched /// \p NewCost gives the cost of extension instructions created by the
/// in the addressing mode after the promotion was applied. /// promotion.
/// \p SizeWithPromotion gives the number of created instructions for /// \p OldCost gives the cost of extension instructions before the promotion
/// the promotion plus the number of instructions that have been /// plus the number of instructions that have been
/// matched in the addressing mode before the promotion. /// matched in the addressing mode the promotion.
/// \p PromotedOperand is the value that has been promoted. /// \p PromotedOperand is the value that has been promoted.
/// \return True if the promotion is profitable, false otherwise. /// \return True if the promotion is profitable, false otherwise.
bool bool AddressingModeMatcher::IsPromotionProfitable(
AddressingModeMatcher::IsPromotionProfitable(unsigned MatchedSize, unsigned NewCost, unsigned OldCost, Value *PromotedOperand) const {
unsigned SizeWithPromotion, DEBUG(dbgs() << "OldCost: " << OldCost << "\tNewCost: " << NewCost << '\n');
Value *PromotedOperand) const { // The cost of the new extensions is greater than the cost of the
// We folded less instructions than what we created to promote the operand. // old extension plus what we folded.
// This is not profitable. // This is not profitable.
if (MatchedSize < SizeWithPromotion) if (NewCost > OldCost)
return false; return false;
if (MatchedSize > SizeWithPromotion) if (NewCost < OldCost)
return true; return true;
// The promotion is neutral but it may help folding the sign extension in // The promotion is neutral but it may help folding the sign extension in
// loads for instance. // loads for instance.
@ -2686,9 +2694,10 @@ bool AddressingModeMatcher::MatchOperationAddr(User *AddrInst, unsigned Opcode,
TypePromotionTransaction::ConstRestorationPt LastKnownGood = TypePromotionTransaction::ConstRestorationPt LastKnownGood =
TPT.getRestorationPoint(); TPT.getRestorationPoint();
unsigned CreatedInsts = 0; unsigned CreatedInstsCost = 0;
unsigned ExtCost = !TLI.isExtFree(Ext);
Value *PromotedOperand = Value *PromotedOperand =
TPH(Ext, TPT, PromotedInsts, CreatedInsts, nullptr, nullptr); TPH(Ext, TPT, PromotedInsts, CreatedInstsCost, nullptr, nullptr, TLI);
// SExt has been moved away. // SExt has been moved away.
// Thus either it will be rematched later in the recursive calls or it is // Thus either it will be rematched later in the recursive calls or it is
// gone. Anyway, we must not fold it into the addressing mode at this point. // gone. Anyway, we must not fold it into the addressing mode at this point.
@ -2710,7 +2719,12 @@ bool AddressingModeMatcher::MatchOperationAddr(User *AddrInst, unsigned Opcode,
unsigned OldSize = AddrModeInsts.size(); unsigned OldSize = AddrModeInsts.size();
if (!MatchAddr(PromotedOperand, Depth) || if (!MatchAddr(PromotedOperand, Depth) ||
!IsPromotionProfitable(AddrModeInsts.size(), OldSize + CreatedInsts, // The total of the new cost is equals to the cost of the created
// instructions.
// The total of the old cost is equals to the cost of the extension plus
// what we have saved in the addressing mode.
!IsPromotionProfitable(CreatedInstsCost,
ExtCost + (AddrModeInsts.size() - OldSize),
PromotedOperand)) { PromotedOperand)) {
AddrMode = BackupAddrMode; AddrMode = BackupAddrMode;
AddrModeInsts.resize(OldSize); AddrModeInsts.resize(OldSize);
@ -3470,7 +3484,7 @@ static bool hasSameExtUse(Instruction *Inst, const TargetLowering &TLI) {
bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT, bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT,
LoadInst *&LI, Instruction *&Inst, LoadInst *&LI, Instruction *&Inst,
const SmallVectorImpl<Instruction *> &Exts, const SmallVectorImpl<Instruction *> &Exts,
unsigned CreatedInsts = 0) { unsigned CreatedInstsCost = 0) {
// Iterate over all the extensions to see if one form an ext(load). // Iterate over all the extensions to see if one form an ext(load).
for (auto I : Exts) { for (auto I : Exts) {
// Check if we directly have ext(load). // Check if we directly have ext(load).
@ -3492,10 +3506,11 @@ bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT,
TypePromotionTransaction::ConstRestorationPt LastKnownGood = TypePromotionTransaction::ConstRestorationPt LastKnownGood =
TPT.getRestorationPoint(); TPT.getRestorationPoint();
SmallVector<Instruction *, 4> NewExts; SmallVector<Instruction *, 4> NewExts;
unsigned NewCreatedInsts = 0; unsigned NewCreatedInstsCost = 0;
unsigned ExtCost = !TLI->isExtFree(I);
// Promote. // Promote.
Value *PromotedVal = Value *PromotedVal = TPH(I, TPT, PromotedInsts, NewCreatedInstsCost,
TPH(I, TPT, PromotedInsts, NewCreatedInsts, &NewExts, nullptr); &NewExts, nullptr, *TLI);
assert(PromotedVal && assert(PromotedVal &&
"TypePromotionHelper should have filtered out those cases"); "TypePromotionHelper should have filtered out those cases");
@ -3505,9 +3520,10 @@ bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT,
// With exactly 2, the transformation is neutral, because we will merge // With exactly 2, the transformation is neutral, because we will merge
// one extension but leave one. However, we optimistically keep going, // one extension but leave one. However, we optimistically keep going,
// because the new extension may be removed too. // because the new extension may be removed too.
unsigned TotalCreatedInsts = CreatedInsts + NewCreatedInsts; long long TotalCreatedInstsCost = CreatedInstsCost + NewCreatedInstsCost;
TotalCreatedInstsCost -= ExtCost;
if (!StressExtLdPromotion && if (!StressExtLdPromotion &&
(TotalCreatedInsts > 1 || (TotalCreatedInstsCost > 1 ||
!isPromotedInstructionLegal(*TLI, PromotedVal))) { !isPromotedInstructionLegal(*TLI, PromotedVal))) {
// The promotion is not profitable, rollback to the previous state. // The promotion is not profitable, rollback to the previous state.
TPT.rollback(LastKnownGood); TPT.rollback(LastKnownGood);
@ -3515,8 +3531,8 @@ bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT,
} }
// The promotion is profitable. // The promotion is profitable.
// Check if it exposes an ext(load). // Check if it exposes an ext(load).
(void)ExtLdPromotion(TPT, LI, Inst, NewExts, TotalCreatedInsts); (void)ExtLdPromotion(TPT, LI, Inst, NewExts, TotalCreatedInstsCost);
if (LI && (StressExtLdPromotion || NewCreatedInsts == 0 || if (LI && (StressExtLdPromotion || NewCreatedInstsCost <= ExtCost ||
// If we have created a new extension, i.e., now we have two // If we have created a new extension, i.e., now we have two
// extensions. We must make sure one of them is merged with // extensions. We must make sure one of them is merged with
// the load, otherwise we may degrade the code quality. // the load, otherwise we may degrade the code quality.

View File

@ -90,9 +90,7 @@ define i8 @oneArgPromotionZExt(i8 %arg1, i8* %base) {
; rolled back. ; rolled back.
; Still, this test case exercises the desired code path. ; Still, this test case exercises the desired code path.
; CHECK-LABEL: @oneArgPromotionCstZExt ; CHECK-LABEL: @oneArgPromotionCstZExt
; CHECK: [[ZEXT:%[a-zA-Z_0-9-]+]] = zext i16 undef to i32 ; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 0, 1
; CHECK: [[SEXT:%[a-zA-Z_0-9-]+]] = sext i32 [[ZEXT]] to i64
; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[SEXT]], 1
; CHECK: getelementptr inbounds i8, i8* %base, i64 [[PROMOTED]] ; CHECK: getelementptr inbounds i8, i8* %base, i64 [[PROMOTED]]
; CHECK: ret ; CHECK: ret
define i8 @oneArgPromotionCstZExt(i8* %base) { define i8 @oneArgPromotionCstZExt(i8* %base) {

View File

@ -361,3 +361,34 @@ entry:
%conv3 = sext i16 %add to i32 %conv3 = sext i16 %add to i32
ret i32 %conv3 ret i32 %conv3
} }
; Check that we see that one zext can be derived from the other for free.
; OPTALL-LABEL: @promoteTwoArgZextWithSourceExtendedTwice
; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8, i8* %p
; OPT-NEXT: [[ZEXT64:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i64
; OPT-NEXT: [[ZEXT32:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i32
; OPT-NEXT: [[RES32:%[a-zA-Z_0-9-]+]] = add nuw i32 [[ZEXT32]], %b
; OPT-NEXT: [[RES64:%[a-zA-Z_0-9-]+]] = add nuw i64 [[ZEXT64]], 12
; OPT-NEXT: store i32 [[RES32]], i32* %addr
; OPT-NEXT: store i64 [[RES64]], i64* %q
;
; DISABLE-NEXT: [[ZEXT32:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i32
; DISABLE-NEXT: [[RES32:%[a-zA-Z_0-9-]+]] = add nuw i32 [[ZEXT32]], %b
; DISABLE-NEXT: [[RES2_32:%[a-zA-Z_0-9-]+]] = add nuw i32 [[ZEXT32]], 12
; DISABLE-NEXT: store i32 [[RES32]], i32* %addr
; DISABLE-NEXT: [[ZEXT64:%[a-zA-Z_0-9-]+]] = zext i32 [[RES2_32]] to i64
; DISABLE-NEXT: store i64 [[ZEXT64]], i64* %q
;
; OPTALL-NEXT: ret void
define void @promoteTwoArgZextWithSourceExtendedTwice(i8* %p, i64* %q, i32 %b, i32* %addr) {
entry:
%t = load i8, i8* %p
%zextt = zext i8 %t to i32
%add = add nuw i32 %zextt, %b
%add2 = add nuw i32 %zextt, 12
store i32 %add, i32 *%addr
%s = zext i32 %add2 to i64
store i64 %s, i64* %q
ret void
}