aboutsummaryrefslogtreecommitdiff
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
parent5250bae5eed2aa1989f6a710d56fe6eac5bd9e8e (diff)
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
-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();