From dcc0e7eaa12e0005a8eb8a92d1500129dced6153 Mon Sep 17 00:00:00 2001 From: Quentin Colombet Date: Thu, 11 Sep 2014 21:22:14 +0000 Subject: [PATCH] [CodeGenPrepare] Teach the addressing mode matcher how to promote zext. I.e., teach it about 'sext (zext a to ty) to ty2' => zext a to ty2. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217629 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CodeGenPrepare.cpp | 69 +++++++++++++++---- .../X86/codegen-prepare-addrmode-sext.ll | 15 ++++ 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp index 4c0345d921a..c8d203d9978 100644 --- a/lib/CodeGen/CodeGenPrepare.cpp +++ b/lib/CodeGen/CodeGenPrepare.cpp @@ -1297,6 +1297,29 @@ class TypePromotionTransaction { } }; + /// \brief Build a zero extension instruction. + class ZExtBuilder : public TypePromotionAction { + public: + /// \brief Build a zero extension instruction of \p Opnd producing a \p Ty + /// result. + /// zext Opnd to Ty. + ZExtBuilder(Instruction *InsertPt, Value *Opnd, Type *Ty) + : TypePromotionAction(Inst) { + IRBuilder<> Builder(InsertPt); + Inst = cast(Builder.CreateZExt(Opnd, Ty, "promoted")); + DEBUG(dbgs() << "Do: ZExtBuilder: " << *Inst << "\n"); + } + + /// \brief Get the built instruction. + Instruction *getBuiltInstruction() { return Inst; } + + /// \brief Remove the built instruction. + void undo() override { + DEBUG(dbgs() << "Undo: ZExtBuilder: " << *Inst << "\n"); + Inst->eraseFromParent(); + } + }; + /// \brief Mutate an instruction to another type. class TypeMutator : public TypePromotionAction { /// Record the original type. @@ -1425,6 +1448,8 @@ public: Instruction *createTrunc(Instruction *Opnd, Type *Ty); /// Same as IRBuilder::createSExt. Instruction *createSExt(Instruction *Inst, Value *Opnd, Type *Ty); + /// Same as IRBuilder::createZExt. + Instruction *createZExt(Instruction *Inst, Value *Opnd, Type *Ty); /// Same as Instruction::moveBefore. void moveBefore(Instruction *Inst, Instruction *Before); /// @} @@ -1472,6 +1497,14 @@ Instruction *TypePromotionTransaction::createSExt(Instruction *Inst, return I; } +Instruction *TypePromotionTransaction::createZExt(Instruction *Inst, + Value *Opnd, Type *Ty) { + std::unique_ptr Ptr(new ZExtBuilder(Inst, Opnd, Ty)); + Instruction *I = Ptr->getBuiltInstruction(); + Actions.push_back(std::move(Ptr)); + return I; +} + void TypePromotionTransaction::moveBefore(Instruction *Inst, Instruction *Before) { Actions.push_back( @@ -1684,16 +1717,16 @@ class TypePromotionHelper { } /// \brief Utility function to promote the operand of \p SExt when this - /// operand is a promotable trunc or sext. + /// 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 /// created to promote the operand of SExt. /// Should never be called directly. /// \return The promoted value which is used instead of SExt. - static Value *promoteOperandForTruncAndSExt(Instruction *SExt, - TypePromotionTransaction &TPT, - InstrToOrigTy &PromotedInsts, - unsigned &CreatedInsts); + static Value *promoteOperandForTruncAndAnyExt(Instruction *SExt, + TypePromotionTransaction &TPT, + InstrToOrigTy &PromotedInsts, + unsigned &CreatedInsts); /// \brief Utility function to promote the operand of \p SExt when this /// operand is promotable and is not a supported trunc or sext. @@ -1729,8 +1762,8 @@ public: bool TypePromotionHelper::canGetThrough(const Instruction *Inst, Type *ConsideredSExtType, const InstrToOrigTy &PromotedInsts) { - // We can always get through sext. - if (isa(Inst)) + // We can always get through sext or zext. + if (isa(Inst) || isa(Inst)) return true; // We can get through binary operator, if it is legal. In other words, the @@ -1798,8 +1831,9 @@ TypePromotionHelper::Action TypePromotionHelper::getAction( // SExt or Trunc instructions. // Return the related handler. - if (isa(SExtOpnd) || isa(SExtOpnd)) - return promoteOperandForTruncAndSExt; + if (isa(SExtOpnd) || isa(SExtOpnd) || + isa(SExtOpnd)) + return promoteOperandForTruncAndAnyExt; // Regular instruction. // Abort early if we will have to insert non-free instructions. @@ -1809,15 +1843,24 @@ TypePromotionHelper::Action TypePromotionHelper::getAction( return promoteOperandForOther; } -Value *TypePromotionHelper::promoteOperandForTruncAndSExt( +Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt( llvm::Instruction *SExt, TypePromotionTransaction &TPT, 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)); - // Replace sext(trunc(opnd)) or sext(sext(opnd)) - // => sext(opnd). - TPT.setOperand(SExt, 0, SExtOpnd->getOperand(0)); + if (isa(SExtOpnd)) { + // Replace sext(zext(opnd)) + // => zext(opnd). + Instruction *ZExt = + TPT.createZExt(SExt, SExtOpnd->getOperand(0), SExt->getType()); + TPT.replaceAllUsesWith(SExt, ZExt); + TPT.eraseInstruction(SExt); + } else { + // Replace sext(trunc(opnd)) or sext(sext(opnd)) + // => sext(opnd). + TPT.setOperand(SExt, 0, SExtOpnd->getOperand(0)); + } CreatedInsts = 0; // Remove dead code. diff --git a/test/CodeGen/X86/codegen-prepare-addrmode-sext.ll b/test/CodeGen/X86/codegen-prepare-addrmode-sext.ll index 78e1dd287f6..af2d1dbeebf 100644 --- a/test/CodeGen/X86/codegen-prepare-addrmode-sext.ll +++ b/test/CodeGen/X86/codegen-prepare-addrmode-sext.ll @@ -67,6 +67,21 @@ define i8 @oneArgPromotion(i32 %arg1, i8* %base) { ret i8 %res } +; Check that we are able to merge a sign extension with a zero extension. +; CHECK-LABEL: @oneArgPromotionZExt +; CHECK: [[ARG1ZEXT:%[a-zA-Z_0-9-]+]] = zext i8 %arg1 to i64 +; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1ZEXT]], 1 +; CHECK: getelementptr inbounds i8* %base, i64 [[PROMOTED]] +; CHECK: ret +define i8 @oneArgPromotionZExt(i8 %arg1, i8* %base) { + %zext = zext i8 %arg1 to i32 + %add = add nsw i32 %zext, 1 + %sextadd = sext i32 %add to i64 + %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd + %res = load i8* %arrayidx + ret i8 %res +} + ; Check that we do not promote truncate when we cannot determine the ; bits that are dropped. ; CHECK-LABEL: @oneArgPromotionBlockTrunc1