From 0c7f4e46b6fcfdaa113b3c529886e41f8dac36b1 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 17 Dec 2014 00:29:23 +0000 Subject: [PATCH] Revert "[CodeGenPrepare] Move sign/zero extensions near loads using type promotion." This reverts commit r224351. It causes assertion failures when building ICU. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@224397 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Target/TargetLowering.h | 8 - lib/CodeGen/CodeGenPrepare.cpp | 298 +++---------------- lib/CodeGen/TargetLoweringBase.cpp | 1 - lib/Target/X86/X86ISelLowering.cpp | 2 +- test/CodeGen/X86/codegen-prepare-extload.ll | 310 +------------------- 5 files changed, 48 insertions(+), 571 deletions(-) diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 1f5c1fd7157..17cfe9d913b 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -264,11 +264,6 @@ public: return MaskAndBranchFoldingIsLegal; } - /// \brief Return true if the target wants to use the optimization that - /// turns ext(promotableInst1(...(promotableInstN(load)))) into - /// promotedInst1(...(promotedInstN(ext(load)))). - bool enableExtLdPromotion() const { return EnableExtLdPromotion; } - /// Return true if the target can combine store(extractelement VectorTy, /// Idx). /// \p Cost[out] gives the cost of that transformation when this is true. @@ -1959,9 +1954,6 @@ protected: /// a mask of a single bit, a compare, and a branch into a single instruction. bool MaskAndBranchFoldingIsLegal; - /// \see enableExtLdPromotion. - bool EnableExtLdPromotion; - protected: /// Return true if the value types that can be represented by the specified /// register class are all legal. diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp index a2d724272b8..577c048ba60 100644 --- a/lib/CodeGen/CodeGenPrepare.cpp +++ b/lib/CodeGen/CodeGenPrepare.cpp @@ -91,16 +91,6 @@ static cl::opt StressStoreExtract( "stress-cgp-store-extract", cl::Hidden, cl::init(false), cl::desc("Stress test store(extract) optimizations in CodeGenPrepare")); -static cl::opt DisableExtLdPromotion( - "disable-cgp-ext-ld-promotion", cl::Hidden, cl::init(false), - cl::desc("Disable ext(promotable(ld)) -> promoted(ext(ld)) optimization in " - "CodeGenPrepare")); - -static cl::opt StressExtLdPromotion( - "stress-cgp-ext-ld-promotion", cl::Hidden, cl::init(false), - cl::desc("Stress test ext(promotable(ld)) -> promoted(ext(ld)) " - "optimization in CodeGenPrepare")); - namespace { typedef SmallPtrSet SetOfInstrs; struct TypeIsSExt { @@ -109,7 +99,6 @@ struct TypeIsSExt { TypeIsSExt(Type *Ty, bool IsSExt) : Ty(Ty), IsSExt(IsSExt) {} }; typedef DenseMap InstrToOrigTy; -class TypePromotionTransaction; class CodeGenPrepare : public FunctionPass { /// TLI - Keep a pointer of a TargetLowering to consult for determining @@ -169,7 +158,7 @@ class TypePromotionTransaction; bool OptimizeMemoryInst(Instruction *I, Value *Addr, Type *AccessTy); bool OptimizeInlineAsmInst(CallInst *CS); bool OptimizeCallInst(CallInst *CI); - bool MoveExtToFormExtLoad(Instruction *&I); + bool MoveExtToFormExtLoad(Instruction *I); bool OptimizeExtUses(Instruction *I); bool OptimizeSelectInst(SelectInst *SI); bool OptimizeShuffleVectorInst(ShuffleVectorInst *SI); @@ -177,10 +166,6 @@ class TypePromotionTransaction; bool DupRetToEnableTailCallOpts(BasicBlock *BB); bool PlaceDbgValues(Function &F); bool sinkAndCmp(Function &F); - bool ExtLdPromotion(TypePromotionTransaction &TPT, LoadInst *&LI, - Instruction *&Inst, - const SmallVectorImpl &Exts, - unsigned CreatedInst); bool splitBranchCondition(Function &F); }; } @@ -1737,23 +1722,6 @@ static bool MightBeFoldableInst(Instruction *I) { } } -/// \brief Check whether or not \p Val is a legal instruction for \p TLI. -/// \note \p Val is assumed to be the product of some type promotion. -/// Therefore if \p Val has an undefined state in \p TLI, this is assumed -/// to be legal, as the non-promoted value would have had the same state. -static bool isPromotedInstructionLegal(const TargetLowering &TLI, Value *Val) { - Instruction *PromotedInst = dyn_cast(Val); - if (!PromotedInst) - return false; - int ISDOpcode = TLI.InstructionOpcodeToISD(PromotedInst->getOpcode()); - // If the ISDOpcode is undefined, it was undefined before the promotion. - if (!ISDOpcode) - return true; - // Otherwise, check if the promoted instruction is legal or not. - return TLI.isOperationLegalOrCustom( - ISDOpcode, TLI.getValueType(PromotedInst->getType())); -} - /// \brief Hepler class to perform type promotion. class TypePromotionHelper { /// \brief Utility function to check whether or not a sign or zero extension @@ -1783,59 +1751,46 @@ class TypePromotionHelper { /// \p PromotedInsts maps the instructions to their type before promotion. /// \p CreatedInsts[out] contains how many non-free instructions have been /// 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 *promoteOperandForTruncAndAnyExt( - Instruction *Ext, TypePromotionTransaction &TPT, - InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, - SmallVectorImpl *Exts, - SmallVectorImpl *Truncs); + static Value *promoteOperandForTruncAndAnyExt(Instruction *Ext, + TypePromotionTransaction &TPT, + InstrToOrigTy &PromotedInsts, + unsigned &CreatedInsts); /// \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 /// 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, - SmallVectorImpl *Exts, - SmallVectorImpl *Truncs, bool IsSExt); + static Value *promoteOperandForOther(Instruction *Ext, + TypePromotionTransaction &TPT, + InstrToOrigTy &PromotedInsts, + unsigned &CreatedInsts, bool IsSExt); /// \see promoteOperandForOther. - static Value * - signExtendOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT, - InstrToOrigTy &PromotedInsts, - unsigned &CreatedInsts, - SmallVectorImpl *Exts, - SmallVectorImpl *Truncs) { - return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInsts, Exts, - Truncs, true); + static Value *signExtendOperandForOther(Instruction *Ext, + TypePromotionTransaction &TPT, + InstrToOrigTy &PromotedInsts, + unsigned &CreatedInsts) { + return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInsts, true); } /// \see promoteOperandForOther. - static Value * - zeroExtendOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT, - InstrToOrigTy &PromotedInsts, - unsigned &CreatedInsts, - SmallVectorImpl *Exts, - SmallVectorImpl *Truncs) { - return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInsts, Exts, - Truncs, false); + static Value *zeroExtendOperandForOther(Instruction *Ext, + TypePromotionTransaction &TPT, + InstrToOrigTy &PromotedInsts, + unsigned &CreatedInsts) { + return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInsts, false); } public: /// Type for the utility function that promotes the operand of Ext. typedef Value *(*Action)(Instruction *Ext, TypePromotionTransaction &TPT, - InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, - SmallVectorImpl *Exts, - SmallVectorImpl *Truncs); + InstrToOrigTy &PromotedInsts, + unsigned &CreatedInsts); /// \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 @@ -1879,9 +1834,8 @@ bool TypePromotionHelper::canGetThrough(const Instruction *Inst, // Check if we can use this operand in the extension. // If the type is larger than the result type of the extension, // we cannot. - if (!OpndVal->getType()->isIntegerTy() || - OpndVal->getType()->getIntegerBitWidth() > - ConsideredExtType->getIntegerBitWidth()) + if (OpndVal->getType()->getIntegerBitWidth() > + ConsideredExtType->getIntegerBitWidth()) return false; // If the operand of the truncate is not an instruction, we will not have @@ -1946,9 +1900,7 @@ TypePromotionHelper::Action TypePromotionHelper::getAction( Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt( llvm::Instruction *SExt, TypePromotionTransaction &TPT, - InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, - SmallVectorImpl *Exts, - SmallVectorImpl *Truncs) { + InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts) { // 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(SExt->getOperand(0)); @@ -1974,11 +1926,8 @@ Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt( // Check if the extension is still needed. Instruction *ExtInst = dyn_cast(ExtVal); - if (!ExtInst || ExtInst->getType() != ExtInst->getOperand(0)->getType()) { - if (ExtInst && Exts) - Exts->push_back(ExtInst); + if (!ExtInst || ExtInst->getType() != ExtInst->getOperand(0)->getType()) return ExtVal; - } // At this point we have: ext ty opnd to ty. // Reassign the uses of ExtInst to the opnd and remove ExtInst. @@ -1989,9 +1938,7 @@ Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt( Value *TypePromotionHelper::promoteOperandForOther( Instruction *Ext, TypePromotionTransaction &TPT, - InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, - SmallVectorImpl *Exts, - SmallVectorImpl *Truncs, bool IsSExt) { + InstrToOrigTy &PromotedInsts, unsigned &CreatedInsts, 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(Ext->getOperand(0)); @@ -2006,8 +1953,6 @@ Value *TypePromotionHelper::promoteOperandForOther( ITrunc->removeFromParent(); // Insert it just after the definition. ITrunc->insertAfter(ExtOpnd); - if (Truncs) - Truncs->push_back(ITrunc); } TPT.replaceAllUsesWith(ExtOpnd, Trunc); @@ -2068,8 +2013,7 @@ Value *TypePromotionHelper::promoteOperandForOther( : TPT.createZExt(Ext, Opnd, Ext->getType())); ++CreatedInsts; } - if (Exts) - Exts->push_back(ExtForOpnd); + TPT.setOperand(ExtForOpnd, 0, Opnd); // Move the sign extension before the insertion point. @@ -2107,7 +2051,16 @@ AddressingModeMatcher::IsPromotionProfitable(unsigned MatchedSize, // The promotion is neutral but it may help folding the sign extension in // loads for instance. // Check that we did not create an illegal instruction. - return isPromotedInstructionLegal(TLI, PromotedOperand); + Instruction *PromotedInst = dyn_cast(PromotedOperand); + if (!PromotedInst) + return false; + int ISDOpcode = TLI.InstructionOpcodeToISD(PromotedInst->getOpcode()); + // If the ISDOpcode is undefined, it was undefined before the promotion. + if (!ISDOpcode) + return true; + // Otherwise, check if the promoted instruction is legal or not. + return TLI.isOperationLegalOrCustom( + ISDOpcode, TLI.getValueType(PromotedInst->getType())); } /// MatchOperationAddr - Given an instruction or constant expr, see if we can @@ -2301,8 +2254,7 @@ bool AddressingModeMatcher::MatchOperationAddr(User *AddrInst, unsigned Opcode, TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); unsigned CreatedInsts = 0; - Value *PromotedOperand = - TPH(Ext, TPT, PromotedInsts, CreatedInsts, nullptr, nullptr); + Value *PromotedOperand = TPH(Ext, TPT, PromotedInsts, CreatedInsts); // 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. @@ -3001,172 +2953,17 @@ bool CodeGenPrepare::OptimizeInlineAsmInst(CallInst *CS) { return MadeChange; } -/// \brief Check if all the uses of \p Inst are equivalent (or free) zero or -/// sign extensions. -static bool hasSameExtUse(Instruction *Inst, const TargetLowering &TLI) { - assert(!Inst->use_empty() && "Input must have at least one use"); - const Instruction *FirstUser = cast(*Inst->user_begin()); - bool IsSExt = isa(FirstUser); - Type *ExtTy = FirstUser->getType(); - for (const User *U : Inst->users()) { - const Instruction *UI = cast(U); - if ((IsSExt && !isa(UI)) || (!IsSExt && !isa(UI))) - return false; - Type *CurTy = UI->getType(); - // Same input and output types: Same instruction after CSE. - if (CurTy == ExtTy) - continue; - - // If IsSExt is true, we are in this situation: - // a = Inst - // b = sext ty1 a to ty2 - // c = sext ty1 a to ty3 - // Assuming ty2 is shorter than ty3, this could be turned into: - // a = Inst - // b = sext ty1 a to ty2 - // c = sext ty2 b to ty3 - // However, the last sext is not free. - if (IsSExt) - return false; - - // This is a ZExt, maybe this is free to extend from one type to another. - // In that case, we would not account for a different use. - Type *NarrowTy; - Type *LargeTy; - if (ExtTy->getScalarType()->getIntegerBitWidth() > - CurTy->getScalarType()->getIntegerBitWidth()) { - NarrowTy = CurTy; - LargeTy = ExtTy; - } else { - NarrowTy = ExtTy; - LargeTy = CurTy; - } - - if (!TLI.isZExtFree(NarrowTy, LargeTy)) - return false; - } - // All uses are the same or can be derived from one another for free. - return true; -} - -/// \brief Try to form ExtLd by promoting \p Exts until they reach a -/// load instruction. -/// If an ext(load) can be formed, it is returned via \p LI for the load -/// and \p Inst for the extension. -/// Otherwise LI == nullptr and Inst == nullptr. -/// When some promotion happened, \p TPT contains the proper state to -/// revert them. -/// -/// \return true when promoting was necessary to expose the ext(load) -/// opportunity, false otherwise. -/// -/// Example: -/// \code -/// %ld = load i32* %addr -/// %add = add nuw i32 %ld, 4 -/// %zext = zext i32 %add to i64 -/// \endcode -/// => -/// \code -/// %ld = load i32* %addr -/// %zext = zext i32 %ld to i64 -/// %add = add nuw i64 %zext, 4 -/// \encode -/// Thanks to the promotion, we can match zext(load i32*) to i64. -bool CodeGenPrepare::ExtLdPromotion(TypePromotionTransaction &TPT, - LoadInst *&LI, Instruction *&Inst, - const SmallVectorImpl &Exts, - unsigned CreatedInsts = 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). - if ((LI = dyn_cast(I->getOperand(0)))) { - Inst = I; - // No promotion happened here. - return false; - } - // Check whether or not we want to do any promotion. - if (!TLI || !TLI->enableExtLdPromotion() || DisableExtLdPromotion) - continue; - // Get the action to perform the promotion. - TypePromotionHelper::Action TPH = TypePromotionHelper::getAction( - I, InsertedTruncsSet, *TLI, PromotedInsts); - // Check if we can promote. - if (!TPH) - continue; - // Save the current state. - TypePromotionTransaction::ConstRestorationPt LastKnownGood = - TPT.getRestorationPoint(); - SmallVector NewExts; - unsigned NewCreatedInsts = 0; - // Promote. - Value *PromotedVal = - TPH(I, TPT, PromotedInsts, NewCreatedInsts, &NewExts, nullptr); - assert(PromotedVal && - "TypePromotionHelper should have filtered out those cases"); - - // We would be able to merge only one extension in a load. - // Therefore, if we have more than 1 new extension we heuristically - // cut this search path, because it means we degrade the code quality. - // 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; - if (!StressExtLdPromotion && - (TotalCreatedInsts > 1 || - !isPromotedInstructionLegal(*TLI, PromotedVal))) { - // The promotion is not profitable, rollback to the previous state. - TPT.rollback(LastKnownGood); - continue; - } - // The promotion is profitable. - // Check if it exposes an ext(load). - (void)ExtLdPromotion(TPT, LI, Inst, NewExts, TotalCreatedInsts); - if (LI && (StressExtLdPromotion || NewCreatedInsts == 0 || - // 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. - (LI->hasOneUse() || hasSameExtUse(LI, *TLI)))) - // Promotion happened. - return true; - // If this does not help to expose an ext(load) then, rollback. - TPT.rollback(LastKnownGood); - } - // None of the extension can form an ext(load). - LI = nullptr; - Inst = nullptr; - return false; -} - /// MoveExtToFormExtLoad - Move a zext or sext fed by a load into the same /// basic block as the load, unless conditions are unfavorable. This allows /// SelectionDAG to fold the extend into the load. -/// \p I[in/out] the extension may be modified during the process if some -/// promotions apply. /// -bool CodeGenPrepare::MoveExtToFormExtLoad(Instruction *&I) { - // Try to promote a chain of computation if it allows to form - // an extended load. - TypePromotionTransaction TPT; - TypePromotionTransaction::ConstRestorationPt LastKnownGood = - TPT.getRestorationPoint(); - SmallVector Exts; - Exts.push_back(I); +bool CodeGenPrepare::MoveExtToFormExtLoad(Instruction *I) { // Look for a load being extended. - LoadInst *LI = nullptr; - Instruction *OldExt = I; - bool HasPromoted = ExtLdPromotion(TPT, LI, I, Exts); - if (!LI || !I) { - assert(!HasPromoted && !LI && "If we did not match any load instruction " - "the code must remain the same"); - I = OldExt; - return false; - } + LoadInst *LI = dyn_cast(I->getOperand(0)); + if (!LI) return false; // If they're already in the same block, there's nothing to do. - // Make the cheap checks first if we did not promote. - // If we promoted, we need to check if it is indeed profitable. - if (!HasPromoted && LI->getParent() == I->getParent()) + if (LI->getParent() == I->getParent()) return false; EVT VT = TLI->getValueType(I->getType()); @@ -3176,11 +2973,8 @@ bool CodeGenPrepare::MoveExtToFormExtLoad(Instruction *&I) { // isn't worthwhile. if (!LI->hasOneUse() && TLI && (TLI->isTypeLegal(LoadVT) || !TLI->isTypeLegal(VT)) && - !TLI->isTruncateFree(I->getType(), LI->getType())) { - I = OldExt; - TPT.rollback(LastKnownGood); + !TLI->isTruncateFree(I->getType(), LI->getType())) return false; - } // Check whether the target supports casts folded into loads. unsigned LType; @@ -3190,15 +2984,11 @@ bool CodeGenPrepare::MoveExtToFormExtLoad(Instruction *&I) { assert(isa(I) && "Unexpected ext type!"); LType = ISD::SEXTLOAD; } - if (TLI && !TLI->isLoadExtLegal(LType, LoadVT)) { - I = OldExt; - TPT.rollback(LastKnownGood); + if (TLI && !TLI->isLoadExtLegal(LType, LoadVT)) return false; - } // Move the extend into the same block as the load, so that SelectionDAG // can fold it. - TPT.commit(); I->removeFromParent(); I->insertAfter(LI); ++NumExtsMoved; diff --git a/lib/CodeGen/TargetLoweringBase.cpp b/lib/CodeGen/TargetLoweringBase.cpp index 1c0dceb50be..8805104689e 100644 --- a/lib/CodeGen/TargetLoweringBase.cpp +++ b/lib/CodeGen/TargetLoweringBase.cpp @@ -714,7 +714,6 @@ TargetLoweringBase::TargetLoweringBase(const TargetMachine &tm) JumpIsExpensive = false; PredictableSelectIsExpensive = false; MaskAndBranchFoldingIsLegal = false; - EnableExtLdPromotion = false; HasFloatingPointExceptions = true; StackPointerRegisterToSaveRestore = 0; ExceptionPointerRegister = 0; diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 2678ca645fd..2cd1d12ac7d 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1689,7 +1689,7 @@ void X86TargetLowering::resetOperationActions() { // Predictable cmov don't hurt on atom because it's in-order. PredictableSelectIsExpensive = !Subtarget->isAtom(); - EnableExtLdPromotion = true; + setPrefFunctionAlignment(4); // 2^4 bytes. verifyIntrinsicTables(); diff --git a/test/CodeGen/X86/codegen-prepare-extload.ll b/test/CodeGen/X86/codegen-prepare-extload.ll index 18fcff0e23d..9320706d972 100644 --- a/test/CodeGen/X86/codegen-prepare-extload.ll +++ b/test/CodeGen/X86/codegen-prepare-extload.ll @@ -1,21 +1,12 @@ ; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s ; RUN: llc < %s -mtriple=x86_64-win64 | FileCheck %s -; RUN: opt -codegenprepare < %s -mtriple=x86_64-apple-macosx -S | FileCheck %s --check-prefix=OPTALL --check-prefix=OPT --check-prefix=NONSTRESS -; RUN: opt -codegenprepare < %s -mtriple=x86_64-apple-macosx -S -stress-cgp-ext-ld-promotion | FileCheck %s --check-prefix=OPTALL --check-prefix=OPT --check-prefix=STRESS -; RUN: opt -codegenprepare < %s -mtriple=x86_64-apple-macosx -S -disable-cgp-ext-ld-promotion | FileCheck %s --check-prefix=OPTALL --check-prefix=DISABLE - ; rdar://7304838 + ; CodeGenPrepare should move the zext into the block with the load ; so that SelectionDAG can select it with the load. -; -; CHECK-LABEL: foo: + ; CHECK: movsbl ({{%rdi|%rcx}}), %eax -; -; OPTALL-LABEL: @foo -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %p -; OPTALL-NEXT: [[ZEXT:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i32 -; OPTALL: store i32 [[ZEXT]], i32* %q -; OPTALL: ret + define void @foo(i8* %p, i32* %q) { entry: %t = load i8* %p @@ -28,298 +19,3 @@ true: false: ret void } - -; Check that we manage to form a zextload is an operation with only one -; argument to explicitly extend is in the the way. -; OPTALL-LABEL: @promoteOneArg -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %p -; OPT-NEXT: [[ZEXT:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i32 -; OPT-NEXT: [[RES:%[a-zA-Z_0-9-]+]] = add nuw i32 [[ZEXT]], 2 -; Make sure the operation is not promoted when the promotion pass is disabled. -; DISABLE: [[ADD:%[a-zA-Z_0-9-]+]] = add nuw i8 [[LD]], 2 -; DISABLE: [[RES:%[a-zA-Z_0-9-]+]] = zext i8 [[ADD]] to i32 -; OPTALL: store i32 [[RES]], i32* %q -; OPTALL: ret -define void @promoteOneArg(i8* %p, i32* %q) { -entry: - %t = load i8* %p - %add = add nuw i8 %t, 2 - %a = icmp slt i8 %t, 20 - br i1 %a, label %true, label %false -true: - %s = zext i8 %add to i32 - store i32 %s, i32* %q - ret void -false: - ret void -} - -; Check that we manage to form a sextload is an operation with only one -; argument to explicitly extend is in the the way. -; Version with sext. -; OPTALL-LABEL: @promoteOneArgSExt -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %p -; OPT-NEXT: [[SEXT:%[a-zA-Z_0-9-]+]] = sext i8 [[LD]] to i32 -; OPT-NEXT: [[RES:%[a-zA-Z_0-9-]+]] = add nsw i32 [[SEXT]], 2 -; DISABLE: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i8 [[LD]], 2 -; DISABLE: [[RES:%[a-zA-Z_0-9-]+]] = sext i8 [[ADD]] to i32 -; OPTALL: store i32 [[RES]], i32* %q -; OPTALL: ret -define void @promoteOneArgSExt(i8* %p, i32* %q) { -entry: - %t = load i8* %p - %add = add nsw i8 %t, 2 - %a = icmp slt i8 %t, 20 - br i1 %a, label %true, label %false -true: - %s = sext i8 %add to i32 - store i32 %s, i32* %q - ret void -false: - ret void -} - -; Check that we manage to form a zextload is an operation with two -; arguments to explicitly extend is in the the way. -; Extending %add will create two extensions: -; 1. One for %b. -; 2. One for %t. -; #1 will not be removed as we do not know anything about %b. -; #2 may not be merged with the load because %t is used in a comparison. -; Since two extensions may be emitted in the end instead of one before the -; transformation, the regular heuristic does not apply the optimization. -; -; OPTALL-LABEL: @promoteTwoArgZext -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %p -; -; STRESS-NEXT: [[ZEXTLD:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i32 -; STRESS-NEXT: [[ZEXTB:%[a-zA-Z_0-9-]+]] = zext i8 %b to i32 -; STRESS-NEXT: [[RES:%[a-zA-Z_0-9-]+]] = add nuw i32 [[ZEXTLD]], [[ZEXTB]] -; -; NONSTRESS: [[ADD:%[a-zA-Z_0-9-]+]] = add nuw i8 [[LD]], %b -; NONSTRESS: [[RES:%[a-zA-Z_0-9-]+]] = zext i8 [[ADD]] to i32 -; -; DISABLE: [[ADD:%[a-zA-Z_0-9-]+]] = add nuw i8 [[LD]], %b -; DISABLE: [[RES:%[a-zA-Z_0-9-]+]] = zext i8 [[ADD]] to i32 -; -; OPTALL: store i32 [[RES]], i32* %q -; OPTALL: ret -define void @promoteTwoArgZext(i8* %p, i32* %q, i8 %b) { -entry: - %t = load i8* %p - %add = add nuw i8 %t, %b - %a = icmp slt i8 %t, 20 - br i1 %a, label %true, label %false -true: - %s = zext i8 %add to i32 - store i32 %s, i32* %q - ret void -false: - ret void -} - -; Check that we manage to form a sextload is an operation with two -; arguments to explicitly extend is in the the way. -; Version with sext. -; OPTALL-LABEL: @promoteTwoArgSExt -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %p -; -; STRESS-NEXT: [[SEXTLD:%[a-zA-Z_0-9-]+]] = sext i8 [[LD]] to i32 -; STRESS-NEXT: [[SEXTB:%[a-zA-Z_0-9-]+]] = sext i8 %b to i32 -; STRESS-NEXT: [[RES:%[a-zA-Z_0-9-]+]] = add nsw i32 [[SEXTLD]], [[SEXTB]] -; -; NONSTRESS: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i8 [[LD]], %b -; NONSTRESS: [[RES:%[a-zA-Z_0-9-]+]] = sext i8 [[ADD]] to i32 -; -; DISABLE: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i8 [[LD]], %b -; DISABLE: [[RES:%[a-zA-Z_0-9-]+]] = sext i8 [[ADD]] to i32 -; OPTALL: store i32 [[RES]], i32* %q -; OPTALL: ret -define void @promoteTwoArgSExt(i8* %p, i32* %q, i8 %b) { -entry: - %t = load i8* %p - %add = add nsw i8 %t, %b - %a = icmp slt i8 %t, 20 - br i1 %a, label %true, label %false -true: - %s = sext i8 %add to i32 - store i32 %s, i32* %q - ret void -false: - ret void -} - -; Check that we do not a zextload if we need to introduce more than -; one additional extension. -; OPTALL-LABEL: @promoteThreeArgZext -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %p -; -; STRESS-NEXT: [[ZEXTLD:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i32 -; STRESS-NEXT: [[ZEXTB:%[a-zA-Z_0-9-]+]] = zext i8 %b to i32 -; STRESS-NEXT: [[TMP:%[a-zA-Z_0-9-]+]] = add nuw i32 [[ZEXTLD]], [[ZEXTB]] -; STRESS-NEXT: [[ZEXTC:%[a-zA-Z_0-9-]+]] = zext i8 %c to i32 -; STRESS-NEXT: [[RES:%[a-zA-Z_0-9-]+]] = add nuw i32 [[TMP]], [[ZEXTC]] -; -; NONSTRESS-NEXT: [[TMP:%[a-zA-Z_0-9-]+]] = add nuw i8 [[LD]], %b -; NONSTRESS-NEXT: [[ADD:%[a-zA-Z_0-9-]+]] = add nuw i8 [[TMP]], %c -; NONSTRESS: [[RES:%[a-zA-Z_0-9-]+]] = zext i8 [[ADD]] to i32 -; -; DISABLE: add nuw i8 -; DISABLE: [[ADD:%[a-zA-Z_0-9-]+]] = add nuw i8 -; DISABLE: [[RES:%[a-zA-Z_0-9-]+]] = zext i8 [[ADD]] to i32 -; -; OPTALL: store i32 [[RES]], i32* %q -; OPTALL: ret -define void @promoteThreeArgZext(i8* %p, i32* %q, i8 %b, i8 %c) { -entry: - %t = load i8* %p - %tmp = add nuw i8 %t, %b - %add = add nuw i8 %tmp, %c - %a = icmp slt i8 %t, 20 - br i1 %a, label %true, label %false -true: - %s = zext i8 %add to i32 - store i32 %s, i32* %q - ret void -false: - ret void -} - -; Check that we manage to form a zextload after promoting and merging -; two extensions. -; OPTALL-LABEL: @promoteMergeExtArgZExt -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %p -; -; STRESS-NEXT: [[ZEXTLD:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i32 -; STRESS-NEXT: [[ZEXTB:%[a-zA-Z_0-9-]+]] = zext i16 %b to i32 -; STRESS-NEXT: [[RES:%[a-zA-Z_0-9-]+]] = add nuw i32 [[ZEXTLD]], [[ZEXTB]] -; -; NONSTRESS: [[ZEXTLD:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i16 -; NONSTRESS: [[ADD:%[a-zA-Z_0-9-]+]] = add nuw i16 [[ZEXTLD]], %b -; NONSTRESS: [[RES:%[a-zA-Z_0-9-]+]] = zext i16 [[ADD]] to i32 -; -; DISABLE: [[ZEXTLD:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i16 -; DISABLE: [[ADD:%[a-zA-Z_0-9-]+]] = add nuw i16 [[ZEXTLD]], %b -; DISABLE: [[RES:%[a-zA-Z_0-9-]+]] = zext i16 [[ADD]] to i32 -; -; OPTALL: store i32 [[RES]], i32* %q -; OPTALL: ret -define void @promoteMergeExtArgZExt(i8* %p, i32* %q, i16 %b) { -entry: - %t = load i8* %p - %ext = zext i8 %t to i16 - %add = add nuw i16 %ext, %b - %a = icmp slt i8 %t, 20 - br i1 %a, label %true, label %false -true: - %s = zext i16 %add to i32 - store i32 %s, i32* %q - ret void -false: - ret void -} - -; Check that we manage to form a sextload after promoting and merging -; two extensions. -; Version with sext. -; OPTALL-LABEL: @promoteMergeExtArgSExt -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %p -; -; STRESS-NEXT: [[ZEXTLD:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i32 -; STRESS-NEXT: [[ZEXTB:%[a-zA-Z_0-9-]+]] = sext i16 %b to i32 -; STRESS-NEXT: [[RES:%[a-zA-Z_0-9-]+]] = add nsw i32 [[ZEXTLD]], [[ZEXTB]] -; -; NONSTRESS: [[ZEXTLD:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i16 -; NONSTRESS: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i16 [[ZEXTLD]], %b -; NONSTRESS: [[RES:%[a-zA-Z_0-9-]+]] = sext i16 [[ADD]] to i32 -; -; DISABLE: [[ZEXTLD:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i16 -; DISABLE: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i16 [[ZEXTLD]], %b -; DISABLE: [[RES:%[a-zA-Z_0-9-]+]] = sext i16 [[ADD]] to i32 -; OPTALL: store i32 [[RES]], i32* %q -; OPTALL: ret -define void @promoteMergeExtArgSExt(i8* %p, i32* %q, i16 %b) { -entry: - %t = load i8* %p - %ext = zext i8 %t to i16 - %add = add nsw i16 %ext, %b - %a = icmp slt i8 %t, 20 - br i1 %a, label %true, label %false -true: - %s = sext i16 %add to i32 - store i32 %s, i32* %q - ret void -false: - ret void -} - -; Check that we manage to catch all the extload opportunities that are exposed -; by the different iterations of codegen prepare. -; Moreover, check that we do not promote more than we need to. -; Here is what is happening in this test (not necessarly in this order): -; 1. We try to promote the operand of %sextadd. -; a. This creates one sext of %ld2 and one of %zextld -; b. The sext of %ld2 can be combine with %ld2, so we remove one sext but -; introduced one. This is fine with the current heuristic: neutral. -; => We have one zext of %zextld left and we created one sext of %ld2. -; 2. We try to promote the operand of %sextaddza. -; a. This creates one sext of %zexta and one of %zextld -; b. The sext of %zexta does not lead to any load, it stays here, even if it -; could have been combine with the zext of %a. -; c. The sext of %zextld leads to %ld and can be combined with it. This is -; done by promoting %zextld. This is fine with the current heuristic: -; neutral. -; => We have created a new zext of %ld and we created one sext of %zexta. -; 3. We try to promote the operand of %sextaddb. -; a. This creates one sext of %b and one of %zextld -; b. The sext of %b is a dead-end, nothing to be done. -; c. Same thing as 2.c. happens. -; => We have created a new zext of %ld and we created one sext of %b. -; 4. We try to promote the operand of the zext of %zextld introduced in #1. -; a. Same thing as 2.c. happens. -; b. %zextld does not have any other uses. It is dead coded. -; => We have created a new zext of %ld and we removed a zext of %zextld and -; a zext of %ld. -; Currently we do not try to reuse existing extensions, so in the end we have -; 3 identical zext of %ld. The extensions will be CSE'ed by SDag. -; -; OPTALL-LABEL: @severalPromotions -; OPTALL: [[LD:%[a-zA-Z_0-9-]+]] = load i8* %addr1 -; OPT-NEXT: [[ZEXTLD1_1:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i64 -; OPT-NEXT: [[ZEXTLD1_2:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i64 -; OPT-NEXT: [[ZEXTLD1_3:%[a-zA-Z_0-9-]+]] = zext i8 [[LD]] to i64 -; OPT-NEXT: [[LD2:%[a-zA-Z_0-9-]+]] = load i32* %addr2 -; OPT-NEXT: [[SEXTLD2:%[a-zA-Z_0-9-]+]] = sext i32 [[LD2]] to i64 -; OPT-NEXT: [[RES:%[a-zA-Z_0-9-]+]] = add nsw i64 [[SEXTLD2]], [[ZEXTLD1_1]] -; We do not combine this one: see 2.b. -; OPT-NEXT: [[ZEXTA:%[a-zA-Z_0-9-]+]] = zext i8 %a to i32 -; OPT-NEXT: [[SEXTZEXTA:%[a-zA-Z_0-9-]+]] = sext i32 [[ZEXTA]] to i64 -; OPT-NEXT: [[RESZA:%[a-zA-Z_0-9-]+]] = add nsw i64 [[SEXTZEXTA]], [[ZEXTLD1_3]] -; OPT-NEXT: [[SEXTB:%[a-zA-Z_0-9-]+]] = sext i32 %b to i64 -; OPT-NEXT: [[RESB:%[a-zA-Z_0-9-]+]] = add nsw i64 [[SEXTB]], [[ZEXTLD1_2]] -; -; DISABLE: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i32 -; DISABLE: [[RES:%[a-zA-Z_0-9-]+]] = sext i32 [[ADD]] to i64 -; DISABLE: [[ADDZA:%[a-zA-Z_0-9-]+]] = add nsw i32 -; DISABLE: [[RESZA:%[a-zA-Z_0-9-]+]] = sext i32 [[ADDZA]] to i64 -; DISABLE: [[ADDB:%[a-zA-Z_0-9-]+]] = add nsw i32 -; DISABLE: [[RESB:%[a-zA-Z_0-9-]+]] = sext i32 [[ADDB]] to i64 -; -; OPTALL: call void @dummy(i64 [[RES]], i64 [[RESZA]], i64 [[RESB]]) -; OPTALL: ret -define void @severalPromotions(i8* %addr1, i32* %addr2, i8 %a, i32 %b) { - %ld = load i8* %addr1 - %zextld = zext i8 %ld to i32 - %ld2 = load i32* %addr2 - %add = add nsw i32 %ld2, %zextld - %sextadd = sext i32 %add to i64 - %zexta = zext i8 %a to i32 - %addza = add nsw i32 %zexta, %zextld - %sextaddza = sext i32 %addza to i64 - %addb = add nsw i32 %b, %zextld - %sextaddb = sext i32 %addb to i64 - call void @dummy(i64 %sextadd, i64 %sextaddza, i64 %sextaddb) - ret void -} - -declare void @dummy(i64, i64, i64)