summaryrefslogtreecommitdiff
path: root/lib/Transforms
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2006-05-13 02:06:03 +0000
committerChris Lattner <sabre@nondot.org>2006-05-13 02:06:03 +0000
commit70074e00a2342c2db7bb675a53750db9f4ac59e5 (patch)
treecba230bd23f133d74b3015bbeba8e18750698ab1 /lib/Transforms
parent5250bae5eed2aa1989f6a710d56fe6eac5bd9e8e (diff)
downloadllvm-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.cpp119
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();