[llvm-commits] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp
Chris Lattner
lattner at cs.uiuc.edu
Fri May 12 19:06:16 PDT 2006
Changes in directory llvm/lib/Transforms/Scalar:
InstructionCombining.cpp updated: 1.479 -> 1.480
---
Log message:
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.
---
Diffs of the changes: (+119 -0)
InstructionCombining.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 119 insertions(+)
Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp
diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.479 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.480
--- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.479 Thu May 11 12:11:52 2006
+++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Fri May 12 21:06:03 2006
@@ -256,6 +256,8 @@
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 @@
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 @@
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();
More information about the llvm-commits
mailing list