mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-20 12:31:40 +00:00
New functionality for instcombine:
* New ReplaceInstUsesWith function to factor out tons of common code This needs to be used more in the future still, but it's a good start * New InsertNewInstBefore to allow multi-instruction replacements * Change getMaxValue functions to isAllOnesValue function, which doesn't have to CREATE/lookup a new constant. Also the name is accurate * Add new isMaxValue, isMinValue, isMaxValueMinusOne, isMinValuePlusOne functions: This should be moved to Constant* classes eventually * Implement xor X, ALLONES -> not X * Fold ALL setcc's of booleans away * Handle various SetCC's for integers against values at the end of their ranges, possibly off by one. This implements the setcc-strength-reduce.ll testcase. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@3286 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
42dbd3044c
commit
8b170945ea
@ -77,6 +77,27 @@ namespace {
|
||||
|
||||
// visitInstruction - Specify what to return for unhandled instructions...
|
||||
Instruction *visitInstruction(Instruction &I) { return 0; }
|
||||
|
||||
// InsertNewInstBefore - insert an instruction New before instruction Old
|
||||
// in the program. Add the new instruction to the worklist.
|
||||
//
|
||||
void InsertNewInstBefore(Instruction *New, Instruction &Old) {
|
||||
BasicBlock *BB = Old.getParent();
|
||||
BB->getInstList().insert(&Old, New); // Insert inst
|
||||
WorkList.push_back(New); // Add to worklist
|
||||
}
|
||||
|
||||
// ReplaceInstUsesWith - This method is to be used when an instruction is
|
||||
// found to be dead, replacable with another preexisting expression. Here
|
||||
// we add all uses of I to the worklist, replace all uses of I with the new
|
||||
// value, then return I, so that the inst combiner will know that I was
|
||||
// modified.
|
||||
//
|
||||
Instruction *ReplaceInstUsesWith(Instruction &I, Value *V) {
|
||||
AddUsesToWorkList(I); // Add all modified instrs to worklist
|
||||
I.replaceAllUsesWith(V);
|
||||
return &I;
|
||||
}
|
||||
};
|
||||
|
||||
RegisterOpt<InstCombiner> X("instcombine", "Combine redundant instructions");
|
||||
@ -246,23 +267,96 @@ Instruction *InstCombiner::visitRem(BinaryOperator &I) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Constant *getMaxValue(const Type *Ty) {
|
||||
assert(Ty == Type::BoolTy || Ty->isIntegral());
|
||||
if (Ty == Type::BoolTy)
|
||||
return ConstantBool::True;
|
||||
// FIXME: These should be moved to Constants.h
|
||||
|
||||
if (Ty->isSigned())
|
||||
return ConstantSInt::get(Ty, -1);
|
||||
else if (Ty->isUnsigned()) {
|
||||
// isAllOnesValue - Return true if integral or boolean value is all ones.
|
||||
static bool isAllOnesValue(const Constant *C) {
|
||||
if (const ConstantBool *CB = dyn_cast<ConstantBool>(C))
|
||||
return CB == ConstantBool::True;
|
||||
else if (const ConstantSInt *CS = dyn_cast<ConstantSInt>(C))
|
||||
return CS->getValue() == -1;
|
||||
else if (const ConstantUInt *CU = dyn_cast<ConstantUInt>(C)) {
|
||||
// Calculate -1 casted to the right type...
|
||||
unsigned TypeBits = Ty->getPrimitiveSize()*8;
|
||||
uint64_t Val = (uint64_t)-1LL; // All ones
|
||||
unsigned TypeBits = C->getType()->getPrimitiveSize()*8;
|
||||
uint64_t Val = ~0ULL; // All ones
|
||||
Val >>= 64-TypeBits; // Shift out unwanted 1 bits...
|
||||
return ConstantUInt::get(Ty, Val);
|
||||
return CU->getValue() == Val;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// isMaxValue - Return true if this is the maximum value for this type.
|
||||
static bool isMaxValue(const Constant *C) {
|
||||
if (const ConstantBool *CB = dyn_cast<ConstantBool>(C))
|
||||
return CB == ConstantBool::True;
|
||||
else if (const ConstantUInt *CU = dyn_cast<ConstantUInt>(C))
|
||||
return isAllOnesValue(C);
|
||||
else if (const ConstantSInt *CS = dyn_cast<ConstantSInt>(C)) {
|
||||
// Calculate 011111111111111...
|
||||
unsigned TypeBits = C->getType()->getPrimitiveSize()*8;
|
||||
int64_t Val = INT64_MAX; // All ones
|
||||
Val >>= 64-TypeBits; // Shift out unwanted 1 bits...
|
||||
return CS->getValue() == Val;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// isMinValue - Return true if this is the minimum value for this type.
|
||||
static bool isMinValue(const Constant *C) {
|
||||
if (const ConstantBool *CB = dyn_cast<ConstantBool>(C))
|
||||
return CB == ConstantBool::False;
|
||||
else if (const ConstantUInt *CU = dyn_cast<ConstantUInt>(C))
|
||||
return CU->getValue() == 0;
|
||||
else if (const ConstantSInt *CS = dyn_cast<ConstantSInt>(C)) {
|
||||
// Calculate 1111111111000000000000
|
||||
unsigned TypeBits = C->getType()->getPrimitiveSize()*8;
|
||||
int64_t Val = -1; // All ones
|
||||
Val <<= TypeBits-1; // Shift over to the right spot
|
||||
return CS->getValue() == Val;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// isMaxValueMinusOne - return true if this is Max-1
|
||||
static bool isMaxValueMinusOne(const Constant *C) {
|
||||
if (!isa<ConstantInt>(C)) return false;
|
||||
|
||||
if (const ConstantUInt *CU = dyn_cast<ConstantUInt>(C)) {
|
||||
// Calculate -1 casted to the right type...
|
||||
unsigned TypeBits = C->getType()->getPrimitiveSize()*8;
|
||||
uint64_t Val = ~0ULL; // All ones
|
||||
Val >>= 64-TypeBits; // Shift out unwanted 1 bits...
|
||||
return CU->getValue() == Val-1;
|
||||
}
|
||||
|
||||
const ConstantSInt *CS = cast<ConstantSInt>(C);
|
||||
|
||||
// Calculate 0111111111..11111
|
||||
unsigned TypeBits = C->getType()->getPrimitiveSize()*8;
|
||||
int64_t Val = INT64_MAX; // All ones
|
||||
Val >>= 64-TypeBits; // Shift out unwanted 1 bits...
|
||||
return CS->getValue() == Val-1;
|
||||
}
|
||||
|
||||
// isMinValuePlusOne - return true if this is Min+1
|
||||
static bool isMinValuePlusOne(const Constant *C) {
|
||||
if (!isa<ConstantInt>(C)) return false;
|
||||
|
||||
if (const ConstantUInt *CU = dyn_cast<ConstantUInt>(C))
|
||||
return CU->getValue() == 1;
|
||||
|
||||
const ConstantSInt *CS = cast<ConstantSInt>(C);
|
||||
|
||||
// Calculate 1111111111000000000000
|
||||
unsigned TypeBits = C->getType()->getPrimitiveSize()*8;
|
||||
int64_t Val = -1; // All ones
|
||||
Val <<= TypeBits-1; // Shift over to the right spot
|
||||
return CS->getValue() == Val+1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
||||
bool Changed = SimplifyBinOp(I);
|
||||
@ -277,7 +371,7 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
||||
|
||||
// and X, -1 == X
|
||||
if (Constant *RHS = dyn_cast<Constant>(Op1))
|
||||
if (RHS == getMaxValue(I.getType())) {
|
||||
if (isAllOnesValue(RHS)) {
|
||||
AddUsesToWorkList(I); // Add all modified instrs to worklist
|
||||
I.replaceAllUsesWith(Op0);
|
||||
return &I;
|
||||
@ -301,7 +395,7 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
|
||||
|
||||
// or X, -1 == -1
|
||||
if (Constant *RHS = dyn_cast<Constant>(Op1))
|
||||
if (RHS == getMaxValue(I.getType())) {
|
||||
if (isAllOnesValue(RHS)) {
|
||||
AddUsesToWorkList(I); // Add all modified instrs to worklist
|
||||
I.replaceAllUsesWith(Op1);
|
||||
return &I;
|
||||
@ -323,16 +417,34 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) {
|
||||
return &I;
|
||||
}
|
||||
|
||||
// xor X, 0 == X
|
||||
if (Op1 == Constant::getNullValue(I.getType())) {
|
||||
AddUsesToWorkList(I); // Add all modified instrs to worklist
|
||||
I.replaceAllUsesWith(Op0);
|
||||
return &I;
|
||||
if (Constant *Op1C = dyn_cast<Constant>(Op1)) {
|
||||
// xor X, 0 == X
|
||||
if (Op1C->isNullValue()) {
|
||||
AddUsesToWorkList(I); // Add all modified instrs to worklist
|
||||
I.replaceAllUsesWith(Op0);
|
||||
return &I;
|
||||
}
|
||||
|
||||
// xor X, -1 = not X
|
||||
if (isAllOnesValue(Op1C))
|
||||
return UnaryOperator::create(Instruction::Not, Op0, I.getName());
|
||||
}
|
||||
|
||||
return Changed ? &I : 0;
|
||||
}
|
||||
|
||||
// AddOne, SubOne - Add or subtract a constant one from an integer constant...
|
||||
static Constant *AddOne(ConstantInt *C) {
|
||||
Constant *Result = *C + *ConstantInt::get(C->getType(), 1);
|
||||
assert(Result && "Constant folding integer addition failed!");
|
||||
return Result;
|
||||
}
|
||||
static Constant *SubOne(ConstantInt *C) {
|
||||
Constant *Result = *C - *ConstantInt::get(C->getType(), 1);
|
||||
assert(Result && "Constant folding integer addition failed!");
|
||||
return Result;
|
||||
}
|
||||
|
||||
// isTrueWhenEqual - Return true if the specified setcondinst instruction is
|
||||
// true when both operands are equal...
|
||||
//
|
||||
@ -344,20 +456,93 @@ static bool isTrueWhenEqual(Instruction &I) {
|
||||
|
||||
Instruction *InstCombiner::visitSetCondInst(BinaryOperator &I) {
|
||||
bool Changed = SimplifyBinOp(I);
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
const Type *Ty = Op0->getType();
|
||||
|
||||
// setcc X, X
|
||||
if (I.getOperand(0) == I.getOperand(1)) {
|
||||
AddUsesToWorkList(I); // Add all modified instrs to worklist
|
||||
I.replaceAllUsesWith(ConstantBool::get(isTrueWhenEqual(I)));
|
||||
return &I;
|
||||
}
|
||||
if (Op0 == Op1)
|
||||
return ReplaceInstUsesWith(I, ConstantBool::get(isTrueWhenEqual(I)));
|
||||
|
||||
// setcc <global*>, 0 - Global value addresses are never null!
|
||||
if (isa<GlobalValue>(I.getOperand(0)) &&
|
||||
isa<ConstantPointerNull>(I.getOperand(1))) {
|
||||
AddUsesToWorkList(I); // Add all modified instrs to worklist
|
||||
I.replaceAllUsesWith(ConstantBool::get(!isTrueWhenEqual(I)));
|
||||
return &I;
|
||||
if (isa<GlobalValue>(Op0) && isa<ConstantPointerNull>(Op1))
|
||||
return ReplaceInstUsesWith(I, ConstantBool::get(!isTrueWhenEqual(I)));
|
||||
|
||||
// setcc's with boolean values can always be turned into bitwise operations
|
||||
if (Ty == Type::BoolTy) {
|
||||
// If this is <, >, or !=, we can change this into a simple xor instruction
|
||||
if (!isTrueWhenEqual(I))
|
||||
return BinaryOperator::create(Instruction::Xor, Op0, Op1, I.getName());
|
||||
|
||||
// Otherwise we need to make a temporary intermediate instruction and insert
|
||||
// it into the instruction stream. This is what we are after:
|
||||
//
|
||||
// seteq bool %A, %B -> ~(A^B)
|
||||
// setle bool %A, %B -> ~A | B
|
||||
// setge bool %A, %B -> A | ~B
|
||||
//
|
||||
if (I.getOpcode() == Instruction::SetEQ) { // seteq case
|
||||
Instruction *Xor = BinaryOperator::create(Instruction::Xor, Op0, Op1,
|
||||
I.getName()+"tmp");
|
||||
InsertNewInstBefore(Xor, I);
|
||||
return UnaryOperator::create(Instruction::Not, Xor, I.getName());
|
||||
}
|
||||
|
||||
// Handle the setXe cases...
|
||||
assert(I.getOpcode() == Instruction::SetGE ||
|
||||
I.getOpcode() == Instruction::SetLE);
|
||||
|
||||
if (I.getOpcode() == Instruction::SetGE)
|
||||
std::swap(Op0, Op1); // Change setge -> setle
|
||||
|
||||
// Now we just have the SetLE case.
|
||||
Instruction *Not =
|
||||
UnaryOperator::create(Instruction::Not, Op0, I.getName()+"tmp");
|
||||
InsertNewInstBefore(Not, I);
|
||||
return BinaryOperator::create(Instruction::Or, Not, Op1, I.getName());
|
||||
}
|
||||
|
||||
// Check to see if we are doing one of many comparisons against constant
|
||||
// integers at the end of their ranges...
|
||||
//
|
||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1)) {
|
||||
// Check to see if we are comparing against the minimum or maximum value...
|
||||
if (isMinValue(CI)) {
|
||||
if (I.getOpcode() == Instruction::SetLT) // A < MIN -> FALSE
|
||||
return ReplaceInstUsesWith(I, ConstantBool::False);
|
||||
if (I.getOpcode() == Instruction::SetGE) // A >= MIN -> TRUE
|
||||
return ReplaceInstUsesWith(I, ConstantBool::True);
|
||||
if (I.getOpcode() == Instruction::SetLE) // A <= MIN -> A == MIN
|
||||
return BinaryOperator::create(Instruction::SetEQ, Op0,Op1, I.getName());
|
||||
if (I.getOpcode() == Instruction::SetGT) // A > MIN -> A != MIN
|
||||
return BinaryOperator::create(Instruction::SetNE, Op0,Op1, I.getName());
|
||||
|
||||
} else if (isMaxValue(CI)) {
|
||||
if (I.getOpcode() == Instruction::SetGT) // A > MAX -> FALSE
|
||||
return ReplaceInstUsesWith(I, ConstantBool::False);
|
||||
if (I.getOpcode() == Instruction::SetLE) // A <= MAX -> TRUE
|
||||
return ReplaceInstUsesWith(I, ConstantBool::True);
|
||||
if (I.getOpcode() == Instruction::SetGE) // A >= MAX -> A == MAX
|
||||
return BinaryOperator::create(Instruction::SetEQ, Op0,Op1, I.getName());
|
||||
if (I.getOpcode() == Instruction::SetLT) // A < MAX -> A != MAX
|
||||
return BinaryOperator::create(Instruction::SetNE, Op0,Op1, I.getName());
|
||||
|
||||
// Comparing against a value really close to min or max?
|
||||
} else if (isMinValuePlusOne(CI)) {
|
||||
if (I.getOpcode() == Instruction::SetLT) // A < MIN+1 -> A == MIN
|
||||
return BinaryOperator::create(Instruction::SetEQ, Op0,
|
||||
SubOne(CI), I.getName());
|
||||
if (I.getOpcode() == Instruction::SetGE) // A >= MIN-1 -> A != MIN
|
||||
return BinaryOperator::create(Instruction::SetNE, Op0,
|
||||
SubOne(CI), I.getName());
|
||||
|
||||
} else if (isMaxValueMinusOne(CI)) {
|
||||
if (I.getOpcode() == Instruction::SetGT) // A > MAX-1 -> A == MAX
|
||||
return BinaryOperator::create(Instruction::SetEQ, Op0,
|
||||
AddOne(CI), I.getName());
|
||||
if (I.getOpcode() == Instruction::SetLE) // A <= MAX-1 -> A != MAX
|
||||
return BinaryOperator::create(Instruction::SetNE, Op0,
|
||||
AddOne(CI), I.getName());
|
||||
}
|
||||
}
|
||||
|
||||
return Changed ? &I : 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user