From 70074e00a2342c2db7bb675a53750db9f4ac59e5 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 13 May 2006 02:06:03 +0000 Subject: [PATCH] Implement simple promotion for cast elimination in instcombine. This is currently very limited, but can be extended in the future. For example, we now compile: uint %test30(uint %c1) { %c2 = cast uint %c1 to ubyte %c3 = xor ubyte %c2, 1 %c4 = cast ubyte %c3 to uint ret uint %c4 } to: _xor: movzbl 4(%esp), %eax xorl $1, %eax ret instead of: _xor: movb $1, %al xorb 4(%esp), %al movzbl %al, %eax ret More impressively, we now compile: struct B { unsigned bit : 1; }; void xor(struct B *b) { b->bit = b->bit ^ 1; } To (X86/PPC): _xor: movl 4(%esp), %eax xorl $-2147483648, (%eax) ret _xor: lwz r2, 0(r3) xoris r2, r2, 32768 stw r2, 0(r3) blr instead of (X86/PPC): _xor: movl 4(%esp), %eax movl (%eax), %ecx movl %ecx, %edx shrl $31, %edx # TRUNCATE movb %dl, %dl xorb $1, %dl movzbl %dl, %edx andl $2147483647, %ecx shll $31, %edx orl %ecx, %edx movl %edx, (%eax) ret _xor: lwz r2, 0(r3) srwi r4, r2, 31 xori r4, r4, 1 rlwimi r2, r4, 31, 0, 0 stw r2, 0(r3) blr This implements InstCombine/cast.ll:test30. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@28273 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Scalar/InstructionCombining.cpp | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index 3f5f2cd9de6..f25ac97ef5c 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -256,6 +256,8 @@ namespace { Instruction *InsertRangeTest(Value *V, Constant *Lo, Constant *Hi, bool Inside, Instruction &IB); Instruction *PromoteCastOfAllocation(CastInst &CI, AllocationInst &AI); + + Value *EvaluateInDifferentType(Value *V, const Type *Ty); }; RegisterOpt X("instcombine", "Combine redundant instructions"); @@ -4779,6 +4781,71 @@ Instruction *InstCombiner::PromoteCastOfAllocation(CastInst &CI, return ReplaceInstUsesWith(CI, New); } +/// CanEvaluateInDifferentType - Return true if we can take the specified value +/// and return it without inserting any new casts. This is used by code that +/// tries to decide whether promoting or shrinking integer operations to wider +/// or smaller types will allow us to eliminate a truncate or extend. +static bool CanEvaluateInDifferentType(Value *V, const Type *Ty, + int &NumCastsRemoved) { + if (isa(V)) return true; + + Instruction *I = dyn_cast(V); + if (!I || !I->hasOneUse()) return false; + + switch (I->getOpcode()) { + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + // These operators can all arbitrarily be extended or truncated. + return CanEvaluateInDifferentType(I->getOperand(0), Ty, NumCastsRemoved) && + CanEvaluateInDifferentType(I->getOperand(1), Ty, NumCastsRemoved); + case Instruction::Cast: + // If this is a cast from the destination type, we can trivially eliminate + // it, and this will remove a cast overall. + if (I->getOperand(0)->getType() == Ty) { + ++NumCastsRemoved; + return true; + } + // TODO: Can handle more cases here. + break; + } + + return false; +} + +/// EvaluateInDifferentType - Given an expression that +/// CanEvaluateInDifferentType returns true for, actually insert the code to +/// evaluate the expression. +Value *InstCombiner::EvaluateInDifferentType(Value *V, const Type *Ty) { + if (Constant *C = dyn_cast(V)) + return ConstantExpr::getCast(C, Ty); + + // Otherwise, it must be an instruction. + Instruction *I = cast(V); + Instruction *Res; + switch (I->getOpcode()) { + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: { + Value *LHS = EvaluateInDifferentType(I->getOperand(0), Ty); + Value *RHS = EvaluateInDifferentType(I->getOperand(1), Ty); + Res = BinaryOperator::create((Instruction::BinaryOps)I->getOpcode(), + LHS, RHS, I->getName()); + break; + } + case Instruction::Cast: + // If this is a cast from the destination type, return the input. + if (I->getOperand(0)->getType() == Ty) + return I->getOperand(0); + + // TODO: Can handle more cases here. + assert(0 && "Unreachable!"); + break; + } + + return InsertNewInstBefore(Res, *I); +} + // CastInst simplification // @@ -4906,6 +4973,58 @@ Instruction *InstCombiner::visitCastInst(CastInst &CI) { if (Instruction *SrcI = dyn_cast(Src)) if (SrcI->hasOneUse() && Src->getType()->isIntegral() && CI.getType()->isInteger()) { // Don't mess with casts to bool here + + int NumCastsRemoved = 0; + if (CanEvaluateInDifferentType(SrcI, CI.getType(), NumCastsRemoved)) { + // If this cast is a truncate, evaluting in a different type always + // eliminates the cast, so it is always a win. If this is a noop-cast + // this just removes a noop cast which isn't pointful, but simplifies + // the code. If this is a zero-extension, we need to do an AND to + // maintain the clear top-part of the computation, so we require that + // the input have eliminated at least one cast. If this is a sign + // extension, we insert two new casts (to do the extension) so we + // require that two casts have been eliminated. + bool DoXForm; + switch (getCastType(Src->getType(), CI.getType())) { + default: assert(0 && "Unknown cast type!"); + case Noop: + case Truncate: + DoXForm = true; + break; + case Zeroext: + DoXForm = NumCastsRemoved >= 1; + break; + case Signext: + DoXForm = NumCastsRemoved >= 2; + break; + } + + if (DoXForm) { + Value *Res = EvaluateInDifferentType(SrcI, CI.getType()); + assert(Res->getType() == CI.getType()); + switch (getCastType(Src->getType(), CI.getType())) { + default: assert(0 && "Unknown cast type!"); + case Noop: + case Truncate: + // Just replace this cast with the result. + return ReplaceInstUsesWith(CI, Res); + case Zeroext: { + // We need to emit an AND to clear the high bits. + unsigned SrcBitSize = Src->getType()->getPrimitiveSizeInBits(); + unsigned DestBitSize = CI.getType()->getPrimitiveSizeInBits(); + assert(SrcBitSize < DestBitSize && "Not a zext?"); + Constant *C = ConstantUInt::get(Type::ULongTy, (1 << SrcBitSize)-1); + C = ConstantExpr::getCast(C, CI.getType()); + return BinaryOperator::createAnd(Res, C); + } + case Signext: + // We need to emit a cast to truncate, then a cast to sext. + return new CastInst(InsertCastBefore(Res, Src->getType(), CI), + CI.getType()); + } + } + } + const Type *DestTy = CI.getType(); unsigned SrcBitSize = Src->getType()->getPrimitiveSizeInBits(); unsigned DestBitSize = DestTy->getPrimitiveSizeInBits();