Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -241,6 +241,7 @@ bool tryToPromoteExts(TypePromotionTransaction &TPT, const SmallVectorImpl &Exts, SmallVectorImpl &ProfitablyMovedExts, + bool *hasMultiUserOperand = nullptr, unsigned CreatedInstsCost = 0); bool mergeSExts(Function &F); bool performAddressTypePromotion( @@ -3254,9 +3255,12 @@ /// because we do not want to promote these instructions as CodeGenPrepare /// will reinsert them later. Thus creating an infinite loop: create/remove. /// \p PromotedInsts maps the instructions to their type before promotion. + /// \p hasMultiUserOperand Set true if we encounter an operand which has + /// multiple users. static Action getAction(Instruction *Ext, const SetOfInstrs &InsertedInsts, const TargetLowering &TLI, - const InstrToOrigTy &PromotedInsts); + const InstrToOrigTy &PromotedInsts, + bool *hasMultiUserOperand = nullptr); }; bool TypePromotionHelper::canGetThrough(const Instruction *Inst, @@ -3325,7 +3329,8 @@ TypePromotionHelper::Action TypePromotionHelper::getAction( Instruction *Ext, const SetOfInstrs &InsertedInsts, - const TargetLowering &TLI, const InstrToOrigTy &PromotedInsts) { + const TargetLowering &TLI, const InstrToOrigTy &PromotedInsts, + bool *hasMultiUserOperand) { assert((isa(Ext) || isa(Ext)) && "Unexpected instruction type"); Instruction *ExtOpnd = dyn_cast(Ext->getOperand(0)); @@ -3351,8 +3356,14 @@ // Regular instruction. // Abort early if we will have to insert non-free instructions. - if (!ExtOpnd->hasOneUse() && !TLI.isTruncateFree(ExtTy, ExtOpnd->getType())) - return nullptr; + + if (!ExtOpnd->hasOneUse()) { + if (hasMultiUserOperand) + *hasMultiUserOperand = true; + if (!TLI.isTruncateFree(ExtTy, ExtOpnd->getType())) + return nullptr; + } + return IsSExt ? signExtendOperandForOther : zeroExtendOperandForOther; } @@ -4539,7 +4550,7 @@ bool CodeGenPrepare::tryToPromoteExts( TypePromotionTransaction &TPT, const SmallVectorImpl &Exts, SmallVectorImpl &ProfitablyMovedExts, - unsigned CreatedInstsCost) { + bool *hasMultiUserOperand, unsigned CreatedInstsCost) { bool Promoted = false; // Iterate over all the extensions to try to promote them. @@ -4558,8 +4569,8 @@ return false; // Get the action to perform the promotion. - TypePromotionHelper::Action TPH = - TypePromotionHelper::getAction(I, InsertedInsts, *TLI, PromotedInsts); + TypePromotionHelper::Action TPH = TypePromotionHelper::getAction( + I, InsertedInsts, *TLI, PromotedInsts, hasMultiUserOperand); // Check if we can promote. if (!TPH) { // Save the current extension as we cannot move up through its operand. @@ -4602,7 +4613,8 @@ } // Continue promoting NewExts as far as doing so is profitable. SmallVector NewlyMovedExts; - (void)tryToPromoteExts(TPT, NewExts, NewlyMovedExts, TotalCreatedInstsCost); + (void)tryToPromoteExts(TPT, NewExts, NewlyMovedExts, hasMultiUserOperand, + TotalCreatedInstsCost); bool NewPromoted = false; for (auto ExtInst : NewlyMovedExts) { Instruction *MovedExt = cast(ExtInst); @@ -4767,8 +4779,9 @@ SmallVector Exts; SmallVector SpeculativelyMovedExts; Exts.push_back(Inst); - - bool HasPromoted = tryToPromoteExts(TPT, Exts, SpeculativelyMovedExts); + bool hasMultiUserOperand = false; + bool HasPromoted = + tryToPromoteExts(TPT, Exts, SpeculativelyMovedExts, &hasMultiUserOperand); // Look for a load being extended. LoadInst *LI = nullptr; @@ -4795,8 +4808,11 @@ return true; } - // Continue promoting SExts if known as considerable depending on targets. - if (ATPConsiderable && + // Continue promoting SExts if known as considerable depending on targets. We + // do not allow address type promtion if detecting an instruction which has + // multiple users in the middle of promotion. In such case, ISel could lose + // opportunities to fold the extension as part of address modes. + if (ATPConsiderable && !hasMultiUserOperand && performAddressTypePromotion(Inst, AllowPromotionWithoutCommonHeader, HasPromoted, TPT, SpeculativelyMovedExts)) return true; Index: test/CodeGen/AArch64/arm64-addr-type-promotion.ll =================================================================== --- test/CodeGen/AArch64/arm64-addr-type-promotion.ll +++ test/CodeGen/AArch64/arm64-addr-type-promotion.ll @@ -83,3 +83,25 @@ %retval.0 = phi i8 [ %conv9, %if.then ], [ %conv24, %if.then19 ], [ %conv41, %if.then36 ], [ 0, %if.end25 ] ret i8 %retval.0 } + +%struct.GlobalData = type { [32000 x float], [3 x i32]} +@global_data = common global %struct.GlobalData zeroinitializer, align 16 +define i32 @multipleUser(i8 %c, i32 %j, float %s) { +; CHECK: multipleUser +; CHECK-NOT: sxtw x{{[0-9]+}}, w{{[0-9]+}} +; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}, w{{[0-9]+}}, sxtw #2] +entry: + %c1 = icmp eq i8 %c, 0 + br i1 %c1, label %if.then, label %end + +if.then: + %add = add nsw i32 %j, 1 + %sext1 = sext i32 %add to i64 + %arrayidx = getelementptr inbounds %struct.GlobalData, %struct.GlobalData* @global_data, i64 0, i32 0, i64 %sext1 + store float %s, float* %arrayidx, align 4 + br label %end + +end: + %j.1 = phi i32 [ %add, %if.then ], [ %j, %entry ] + ret i32 %j.1 +}