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
This commit is contained in:
Chris Lattner 2006-05-13 02:06:03 +00:00
parent 5250bae5ee
commit 70074e00a2

View File

@ -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();