diff options
author | Chris Lattner <sabre@nondot.org> | 2006-05-13 02:06:03 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2006-05-13 02:06:03 +0000 |
commit | 70074e00a2342c2db7bb675a53750db9f4ac59e5 (patch) | |
tree | cba230bd23f133d74b3015bbeba8e18750698ab1 /lib/Transforms | |
parent | 5250bae5eed2aa1989f6a710d56fe6eac5bd9e8e (diff) | |
download | llvm-70074e00a2342c2db7bb675a53750db9f4ac59e5.tar.gz llvm-70074e00a2342c2db7bb675a53750db9f4ac59e5.tar.bz2 llvm-70074e00a2342c2db7bb675a53750db9f4ac59e5.tar.xz |
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
Diffstat (limited to 'lib/Transforms')
-rw-r--r-- | lib/Transforms/Scalar/InstructionCombining.cpp | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index 3f5f2cd9de..f25ac97ef5 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<InstCombiner> 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<Constant>(V)) return true; + + Instruction *I = dyn_cast<Instruction>(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<Constant>(V)) + return ConstantExpr::getCast(C, Ty); + + // Otherwise, it must be an instruction. + Instruction *I = cast<Instruction>(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<Instruction>(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(); |