forked from OSchip/llvm-project
[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:
parent
4bb90a71de
commit
1b274f99ad
|
@ -1484,6 +1484,33 @@ public:
|
|||
|
||||
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
|
||||
/// implicitly zero-extends the value to Ty2 in the result register.
|
||||
///
|
||||
|
@ -1847,6 +1874,11 @@ private:
|
|||
CallingConv::ID LibcallCallingConvs[RTLIB::UNKNOWN_LIBCALL];
|
||||
|
||||
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.
|
||||
///
|
||||
/// When lowering \@llvm.memset this field specifies the maximum number of
|
||||
|
|
|
@ -186,7 +186,7 @@ class TypePromotionTransaction;
|
|||
bool ExtLdPromotion(TypePromotionTransaction &TPT, LoadInst *&LI,
|
||||
Instruction *&Inst,
|
||||
const SmallVectorImpl<Instruction *> &Exts,
|
||||
unsigned CreatedInst);
|
||||
unsigned CreatedInstCost);
|
||||
bool splitBranchCondition(Function &F);
|
||||
bool simplifyOffsetableRelocate(Instruction &I);
|
||||
};
|
||||
|
@ -2023,7 +2023,7 @@ private:
|
|||
ExtAddrMode &AMBefore,
|
||||
ExtAddrMode &AMAfter);
|
||||
bool ValueAlreadyLiveAtInst(Value *Val, Value *KnownLive1, Value *KnownLive2);
|
||||
bool IsPromotionProfitable(unsigned MatchedSize, unsigned SizeWithPromotion,
|
||||
bool IsPromotionProfitable(unsigned NewCost, unsigned OldCost,
|
||||
Value *PromotedOperand) const;
|
||||
};
|
||||
|
||||
|
@ -2157,7 +2157,7 @@ class TypePromotionHelper {
|
|||
/// \brief Utility function to promote the operand of \p Ext when this
|
||||
/// operand is a promotable trunc or sext or zext.
|
||||
/// \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.
|
||||
/// Newly added extensions are inserted in \p Exts.
|
||||
/// Newly added truncates are inserted in \p Truncs.
|
||||
|
@ -2165,53 +2165,55 @@ class TypePromotionHelper {
|
|||
/// \return The promoted value which is used instead of Ext.
|
||||
static Value *promoteOperandForTruncAndAnyExt(
|
||||
Instruction *Ext, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
|
||||
SmallVectorImpl<Instruction *> *Exts,
|
||||
SmallVectorImpl<Instruction *> *Truncs);
|
||||
SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI);
|
||||
|
||||
/// \brief Utility function to promote the operand of \p Ext when this
|
||||
/// operand is promotable and is not a supported trunc or sext.
|
||||
/// \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.
|
||||
/// Newly added extensions are inserted in \p Exts.
|
||||
/// Newly added truncates are inserted in \p Truncs.
|
||||
/// Should never be called directly.
|
||||
/// \return The promoted value which is used instead of Ext.
|
||||
static Value *
|
||||
promoteOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts,
|
||||
static Value *promoteOperandForOther(Instruction *Ext,
|
||||
TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts,
|
||||
unsigned &CreatedInstsCost,
|
||||
SmallVectorImpl<Instruction *> *Exts,
|
||||
SmallVectorImpl<Instruction *> *Truncs, bool IsSExt);
|
||||
SmallVectorImpl<Instruction *> *Truncs,
|
||||
const TargetLowering &TLI, bool IsSExt);
|
||||
|
||||
/// \see promoteOperandForOther.
|
||||
static Value *
|
||||
signExtendOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts,
|
||||
unsigned &CreatedInsts,
|
||||
static Value *signExtendOperandForOther(
|
||||
Instruction *Ext, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
|
||||
SmallVectorImpl<Instruction *> *Exts,
|
||||
SmallVectorImpl<Instruction *> *Truncs) {
|
||||
return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInsts, Exts,
|
||||
Truncs, true);
|
||||
SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI) {
|
||||
return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInstsCost,
|
||||
Exts, Truncs, TLI, true);
|
||||
}
|
||||
|
||||
/// \see promoteOperandForOther.
|
||||
static Value *
|
||||
zeroExtendOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts,
|
||||
unsigned &CreatedInsts,
|
||||
static Value *zeroExtendOperandForOther(
|
||||
Instruction *Ext, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
|
||||
SmallVectorImpl<Instruction *> *Exts,
|
||||
SmallVectorImpl<Instruction *> *Truncs) {
|
||||
return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInsts, Exts,
|
||||
Truncs, false);
|
||||
SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI) {
|
||||
return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInstsCost,
|
||||
Exts, Truncs, TLI, false);
|
||||
}
|
||||
|
||||
public:
|
||||
/// Type for the utility function that promotes the operand of Ext.
|
||||
typedef Value *(*Action)(Instruction *Ext, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts,
|
||||
InstrToOrigTy &PromotedInsts,
|
||||
unsigned &CreatedInstsCost,
|
||||
SmallVectorImpl<Instruction *> *Exts,
|
||||
SmallVectorImpl<Instruction *> *Truncs);
|
||||
SmallVectorImpl<Instruction *> *Truncs,
|
||||
const TargetLowering &TLI);
|
||||
/// \brief Given a sign/zero extend instruction \p Ext, return the approriate
|
||||
/// action to promote the operand of \p Ext instead of using Ext.
|
||||
/// \return NULL if no promotable action is possible with the current
|
||||
|
@ -2328,16 +2330,18 @@ TypePromotionHelper::Action TypePromotionHelper::getAction(
|
|||
|
||||
Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt(
|
||||
llvm::Instruction *SExt, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
|
||||
SmallVectorImpl<Instruction *> *Exts,
|
||||
SmallVectorImpl<Instruction *> *Truncs) {
|
||||
SmallVectorImpl<Instruction *> *Truncs, const TargetLowering &TLI) {
|
||||
// By construction, the operand of SExt is an instruction. Otherwise we cannot
|
||||
// get through it and this method should not be called.
|
||||
Instruction *SExtOpnd = cast<Instruction>(SExt->getOperand(0));
|
||||
Value *ExtVal = SExt;
|
||||
bool HasMergedNonFreeExt = false;
|
||||
if (isa<ZExtInst>(SExtOpnd)) {
|
||||
// Replace s|zext(zext(opnd))
|
||||
// => zext(opnd).
|
||||
HasMergedNonFreeExt = !TLI.isExtFree(SExtOpnd);
|
||||
Value *ZExt =
|
||||
TPT.createZExt(SExt, SExtOpnd->getOperand(0), SExt->getType());
|
||||
TPT.replaceAllUsesWith(SExt, ZExt);
|
||||
|
@ -2348,7 +2352,7 @@ Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt(
|
|||
// => z|sext(opnd).
|
||||
TPT.setOperand(SExt, 0, SExtOpnd->getOperand(0));
|
||||
}
|
||||
CreatedInsts = 0;
|
||||
CreatedInstsCost = 0;
|
||||
|
||||
// Remove dead code.
|
||||
if (SExtOpnd->use_empty())
|
||||
|
@ -2357,8 +2361,11 @@ Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt(
|
|||
// Check if the extension is still needed.
|
||||
Instruction *ExtInst = dyn_cast<Instruction>(ExtVal);
|
||||
if (!ExtInst || ExtInst->getType() != ExtInst->getOperand(0)->getType()) {
|
||||
if (ExtInst && Exts)
|
||||
if (ExtInst) {
|
||||
if (Exts)
|
||||
Exts->push_back(ExtInst);
|
||||
CreatedInstsCost = !TLI.isExtFree(ExtInst) && !HasMergedNonFreeExt;
|
||||
}
|
||||
return ExtVal;
|
||||
}
|
||||
|
||||
|
@ -2371,13 +2378,14 @@ Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt(
|
|||
|
||||
Value *TypePromotionHelper::promoteOperandForOther(
|
||||
Instruction *Ext, TypePromotionTransaction &TPT,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts,
|
||||
InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost,
|
||||
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
|
||||
// get through it and this method should not be called.
|
||||
Instruction *ExtOpnd = cast<Instruction>(Ext->getOperand(0));
|
||||
CreatedInsts = 0;
|
||||
CreatedInstsCost = 0;
|
||||
if (!ExtOpnd->hasOneUse()) {
|
||||
// ExtOpnd will be promoted.
|
||||
// All its uses, but Ext, will need to use a truncated value of the
|
||||
|
@ -2452,7 +2460,6 @@ Value *TypePromotionHelper::promoteOperandForOther(
|
|||
continue;
|
||||
}
|
||||
ExtForOpnd = cast<Instruction>(ValForExtOpnd);
|
||||
++CreatedInsts;
|
||||
}
|
||||
if (Exts)
|
||||
Exts->push_back(ExtForOpnd);
|
||||
|
@ -2461,6 +2468,7 @@ Value *TypePromotionHelper::promoteOperandForOther(
|
|||
// Move the sign extension before the insertion point.
|
||||
TPT.moveBefore(ExtForOpnd, ExtOpnd);
|
||||
TPT.setOperand(ExtOpnd, OpIdx, ExtForOpnd);
|
||||
CreatedInstsCost += !TLI.isExtFree(ExtForOpnd);
|
||||
// If more sext are required, new instructions will have to be created.
|
||||
ExtForOpnd = nullptr;
|
||||
}
|
||||
|
@ -2473,22 +2481,22 @@ Value *TypePromotionHelper::promoteOperandForOther(
|
|||
|
||||
/// IsPromotionProfitable - Check whether or not promoting an instruction
|
||||
/// to a wider type was profitable.
|
||||
/// \p MatchedSize gives the number of instructions that have been matched
|
||||
/// in the addressing mode after the promotion was applied.
|
||||
/// \p SizeWithPromotion gives the number of created instructions for
|
||||
/// the promotion plus the number of instructions that have been
|
||||
/// matched in the addressing mode before the promotion.
|
||||
/// \p NewCost gives the cost of extension instructions created by the
|
||||
/// promotion.
|
||||
/// \p OldCost gives the cost of extension instructions before the promotion
|
||||
/// plus the number of instructions that have been
|
||||
/// matched in the addressing mode the promotion.
|
||||
/// \p PromotedOperand is the value that has been promoted.
|
||||
/// \return True if the promotion is profitable, false otherwise.
|
||||
bool
|
||||
AddressingModeMatcher::IsPromotionProfitable(unsigned MatchedSize,
|
||||
unsigned SizeWithPromotion,
|
||||
Value *PromotedOperand) const {
|
||||
// We folded less instructions than what we created to promote the operand.
|
||||
bool AddressingModeMatcher::IsPromotionProfitable(
|
||||
unsigned NewCost, unsigned OldCost, Value *PromotedOperand) const {
|
||||
DEBUG(dbgs() << "OldCost: " << OldCost << "\tNewCost: " << NewCost << '\n');
|
||||
// The cost of the new extensions is greater than the cost of the
|
||||
// old extension plus what we folded.
|
||||
// This is not profitable.
|
||||
if (MatchedSize < SizeWithPromotion)
|
||||
if (NewCost > OldCost)
|
||||
return false;
|
||||
if (MatchedSize > SizeWithPromotion)
|
||||
if (NewCost < OldCost)
|
||||
return true;
|
||||
// The promotion is neutral but it may help folding the sign extension in
|
||||
// loads for instance.
|
||||
|
@ -2686,9 +2694,10 @@ bool AddressingModeMatcher::MatchOperationAddr(User *AddrInst, unsigned Opcode,
|
|||
|
||||
TypePromotionTransaction::ConstRestorationPt LastKnownGood =
|
||||
TPT.getRestorationPoint();
|
||||
unsigned CreatedInsts = 0;
|
||||
unsigned CreatedInstsCost = 0;
|
||||
unsigned ExtCost = !TLI.isExtFree(Ext);
|
||||
Value *PromotedOperand =
|
||||
TPH(Ext, TPT, PromotedInsts, CreatedInsts, nullptr, nullptr);
|
||||
TPH(Ext, TPT, PromotedInsts, CreatedInstsCost, nullptr, nullptr, TLI);
|
||||
// SExt has been moved away.
|
||||
// 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.
|
||||
|
@ -2710,7 +2719,12 @@ bool AddressingModeMatcher::MatchOperationAddr(User *AddrInst, unsigned Opcode,
|
|||
unsigned OldSize = AddrModeInsts.size();
|
||||
|
||||
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)) {
|
||||
AddrMode = BackupAddrMode;
|
||||
AddrModeInsts.resize(OldSize);
|
||||
|
@ -3470,7 +3484,7 @@ static bool hasSameExtUse(Instruction *Inst, const TargetLowering &TLI) {
|
|||
bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT,
|
||||
LoadInst *&LI, Instruction *&Inst,
|
||||
const SmallVectorImpl<Instruction *> &Exts,
|
||||
unsigned CreatedInsts = 0) {
|
||||
unsigned CreatedInstsCost = 0) {
|
||||
// Iterate over all the extensions to see if one form an ext(load).
|
||||
for (auto I : Exts) {
|
||||
// Check if we directly have ext(load).
|
||||
|
@ -3492,10 +3506,11 @@ bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT,
|
|||
TypePromotionTransaction::ConstRestorationPt LastKnownGood =
|
||||
TPT.getRestorationPoint();
|
||||
SmallVector<Instruction *, 4> NewExts;
|
||||
unsigned NewCreatedInsts = 0;
|
||||
unsigned NewCreatedInstsCost = 0;
|
||||
unsigned ExtCost = !TLI->isExtFree(I);
|
||||
// Promote.
|
||||
Value *PromotedVal =
|
||||
TPH(I, TPT, PromotedInsts, NewCreatedInsts, &NewExts, nullptr);
|
||||
Value *PromotedVal = TPH(I, TPT, PromotedInsts, NewCreatedInstsCost,
|
||||
&NewExts, nullptr, *TLI);
|
||||
assert(PromotedVal &&
|
||||
"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
|
||||
// one extension but leave one. However, we optimistically keep going,
|
||||
// because the new extension may be removed too.
|
||||
unsigned TotalCreatedInsts = CreatedInsts + NewCreatedInsts;
|
||||
long long TotalCreatedInstsCost = CreatedInstsCost + NewCreatedInstsCost;
|
||||
TotalCreatedInstsCost -= ExtCost;
|
||||
if (!StressExtLdPromotion &&
|
||||
(TotalCreatedInsts > 1 ||
|
||||
(TotalCreatedInstsCost > 1 ||
|
||||
!isPromotedInstructionLegal(*TLI, PromotedVal))) {
|
||||
// The promotion is not profitable, rollback to the previous state.
|
||||
TPT.rollback(LastKnownGood);
|
||||
|
@ -3515,8 +3531,8 @@ bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT,
|
|||
}
|
||||
// The promotion is profitable.
|
||||
// Check if it exposes an ext(load).
|
||||
(void)ExtLdPromotion(TPT, LI, Inst, NewExts, TotalCreatedInsts);
|
||||
if (LI && (StressExtLdPromotion || NewCreatedInsts == 0 ||
|
||||
(void)ExtLdPromotion(TPT, LI, Inst, NewExts, TotalCreatedInstsCost);
|
||||
if (LI && (StressExtLdPromotion || NewCreatedInstsCost <= ExtCost ||
|
||||
// If we have created a new extension, i.e., now we have two
|
||||
// extensions. We must make sure one of them is merged with
|
||||
// the load, otherwise we may degrade the code quality.
|
||||
|
|
|
@ -90,9 +90,7 @@ define i8 @oneArgPromotionZExt(i8 %arg1, i8* %base) {
|
|||
; rolled back.
|
||||
; Still, this test case exercises the desired code path.
|
||||
; CHECK-LABEL: @oneArgPromotionCstZExt
|
||||
; CHECK: [[ZEXT:%[a-zA-Z_0-9-]+]] = zext i16 undef to i32
|
||||
; 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: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 0, 1
|
||||
; CHECK: getelementptr inbounds i8, i8* %base, i64 [[PROMOTED]]
|
||||
; CHECK: ret
|
||||
define i8 @oneArgPromotionCstZExt(i8* %base) {
|
||||
|
|
|
@ -361,3 +361,34 @@ entry:
|
|||
%conv3 = sext i16 %add to i32
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue