mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-13 22:24:07 +00:00
Rearrange and comment code better. No functionality changes
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10808 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -11,6 +11,11 @@
|
|||||||
// (internal) ConstantFolding.h interface, which is used by the
|
// (internal) ConstantFolding.h interface, which is used by the
|
||||||
// ConstantExpr::get* methods to automatically fold constants when possible.
|
// ConstantExpr::get* methods to automatically fold constants when possible.
|
||||||
//
|
//
|
||||||
|
// The current constant folding implementation is implemented in two pieces: the
|
||||||
|
// template-based folder for simple primitive constants like ConstantInt, and
|
||||||
|
// the special case hackery that we use to symbolically evaluate expressions
|
||||||
|
// that use ConstantExprs.
|
||||||
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ConstantFolding.h"
|
#include "ConstantFolding.h"
|
||||||
@ -22,11 +27,6 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
static unsigned getSize(const Type *Ty) {
|
|
||||||
unsigned S = Ty->getPrimitiveSize();
|
|
||||||
return S ? S : 8; // Treat pointers at 8 bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct ConstRules {
|
struct ConstRules {
|
||||||
ConstRules() {}
|
ConstRules() {}
|
||||||
@ -71,158 +71,6 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Constant *llvm::ConstantFoldCastInstruction(const Constant *V,
|
|
||||||
const Type *DestTy) {
|
|
||||||
if (V->getType() == DestTy) return (Constant*)V;
|
|
||||||
|
|
||||||
if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
|
|
||||||
if (CE->getOpcode() == Instruction::Cast) {
|
|
||||||
Constant *Op = const_cast<Constant*>(CE->getOperand(0));
|
|
||||||
// Try to not produce a cast of a cast, which is almost always redundant.
|
|
||||||
if (!Op->getType()->isFloatingPoint() &&
|
|
||||||
!CE->getType()->isFloatingPoint() &&
|
|
||||||
!DestTy->getType()->isFloatingPoint()) {
|
|
||||||
unsigned S1 = getSize(Op->getType()), S2 = getSize(CE->getType());
|
|
||||||
unsigned S3 = getSize(DestTy);
|
|
||||||
if (Op->getType() == DestTy && S3 >= S2)
|
|
||||||
return Op;
|
|
||||||
if (S1 >= S2 && S2 >= S3)
|
|
||||||
return ConstantExpr::getCast(Op, DestTy);
|
|
||||||
if (S1 <= S2 && S2 >= S3 && S1 <= S3)
|
|
||||||
return ConstantExpr::getCast(Op, DestTy);
|
|
||||||
}
|
|
||||||
} else if (CE->getOpcode() == Instruction::GetElementPtr) {
|
|
||||||
// If all of the indexes in the GEP are null values, there is no pointer
|
|
||||||
// adjustment going on. We might as well cast the source pointer.
|
|
||||||
bool isAllNull = true;
|
|
||||||
for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
|
|
||||||
if (!CE->getOperand(i)->isNullValue()) {
|
|
||||||
isAllNull = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isAllNull)
|
|
||||||
return ConstantExpr::getCast(CE->getOperand(0), DestTy);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstRules &Rules = ConstRules::get(V, V);
|
|
||||||
|
|
||||||
switch (DestTy->getPrimitiveID()) {
|
|
||||||
case Type::BoolTyID: return Rules.castToBool(V);
|
|
||||||
case Type::UByteTyID: return Rules.castToUByte(V);
|
|
||||||
case Type::SByteTyID: return Rules.castToSByte(V);
|
|
||||||
case Type::UShortTyID: return Rules.castToUShort(V);
|
|
||||||
case Type::ShortTyID: return Rules.castToShort(V);
|
|
||||||
case Type::UIntTyID: return Rules.castToUInt(V);
|
|
||||||
case Type::IntTyID: return Rules.castToInt(V);
|
|
||||||
case Type::ULongTyID: return Rules.castToULong(V);
|
|
||||||
case Type::LongTyID: return Rules.castToLong(V);
|
|
||||||
case Type::FloatTyID: return Rules.castToFloat(V);
|
|
||||||
case Type::DoubleTyID: return Rules.castToDouble(V);
|
|
||||||
case Type::PointerTyID:
|
|
||||||
return Rules.castToPointer(V, cast<PointerType>(DestTy));
|
|
||||||
default: return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
|
|
||||||
const Constant *V1,
|
|
||||||
const Constant *V2) {
|
|
||||||
Constant *C;
|
|
||||||
switch (Opcode) {
|
|
||||||
default: return 0;
|
|
||||||
case Instruction::Add: return ConstRules::get(V1, V2).add(V1, V2);
|
|
||||||
case Instruction::Sub: return ConstRules::get(V1, V2).sub(V1, V2);
|
|
||||||
case Instruction::Mul: return ConstRules::get(V1, V2).mul(V1, V2);
|
|
||||||
case Instruction::Div: return ConstRules::get(V1, V2).div(V1, V2);
|
|
||||||
case Instruction::Rem: return ConstRules::get(V1, V2).rem(V1, V2);
|
|
||||||
case Instruction::And: return ConstRules::get(V1, V2).op_and(V1, V2);
|
|
||||||
case Instruction::Or: return ConstRules::get(V1, V2).op_or (V1, V2);
|
|
||||||
case Instruction::Xor: return ConstRules::get(V1, V2).op_xor(V1, V2);
|
|
||||||
|
|
||||||
case Instruction::Shl: return ConstRules::get(V1, V2).shl(V1, V2);
|
|
||||||
case Instruction::Shr: return ConstRules::get(V1, V2).shr(V1, V2);
|
|
||||||
|
|
||||||
case Instruction::SetEQ: return ConstRules::get(V1, V2).equalto(V1, V2);
|
|
||||||
case Instruction::SetLT: return ConstRules::get(V1, V2).lessthan(V1, V2);
|
|
||||||
case Instruction::SetGT: return ConstRules::get(V1, V2).lessthan(V2, V1);
|
|
||||||
case Instruction::SetNE: // V1 != V2 === !(V1 == V2)
|
|
||||||
C = ConstRules::get(V1, V2).equalto(V1, V2);
|
|
||||||
break;
|
|
||||||
case Instruction::SetLE: // V1 <= V2 === !(V2 < V1)
|
|
||||||
C = ConstRules::get(V1, V2).lessthan(V2, V1);
|
|
||||||
break;
|
|
||||||
case Instruction::SetGE: // V1 >= V2 === !(V1 < V2)
|
|
||||||
C = ConstRules::get(V1, V2).lessthan(V1, V2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the folder broke out of the switch statement, invert the boolean
|
|
||||||
// constant value, if it exists, and return it.
|
|
||||||
if (!C) return 0;
|
|
||||||
return ConstantExpr::get(Instruction::Xor, ConstantBool::True, C);
|
|
||||||
}
|
|
||||||
|
|
||||||
Constant *llvm::ConstantFoldGetElementPtr(const Constant *C,
|
|
||||||
const std::vector<Constant*> &IdxList) {
|
|
||||||
if (IdxList.size() == 0 ||
|
|
||||||
(IdxList.size() == 1 && IdxList[0]->isNullValue()))
|
|
||||||
return const_cast<Constant*>(C);
|
|
||||||
|
|
||||||
// TODO If C is null and all idx's are null, return null of the right type.
|
|
||||||
|
|
||||||
|
|
||||||
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(const_cast<Constant*>(C))) {
|
|
||||||
// Combine Indices - If the source pointer to this getelementptr instruction
|
|
||||||
// is a getelementptr instruction, combine the indices of the two
|
|
||||||
// getelementptr instructions into a single instruction.
|
|
||||||
//
|
|
||||||
if (CE->getOpcode() == Instruction::GetElementPtr) {
|
|
||||||
const Type *LastTy = 0;
|
|
||||||
for (gep_type_iterator I = gep_type_begin(CE), E = gep_type_end(CE);
|
|
||||||
I != E; ++I)
|
|
||||||
LastTy = *I;
|
|
||||||
|
|
||||||
if ((LastTy && isa<ArrayType>(LastTy)) || IdxList[0]->isNullValue()) {
|
|
||||||
std::vector<Constant*> NewIndices;
|
|
||||||
NewIndices.reserve(IdxList.size() + CE->getNumOperands());
|
|
||||||
for (unsigned i = 1, e = CE->getNumOperands()-1; i != e; ++i)
|
|
||||||
NewIndices.push_back(cast<Constant>(CE->getOperand(i)));
|
|
||||||
|
|
||||||
// Add the last index of the source with the first index of the new GEP.
|
|
||||||
// Make sure to handle the case when they are actually different types.
|
|
||||||
Constant *Combined = CE->getOperand(CE->getNumOperands()-1);
|
|
||||||
if (!IdxList[0]->isNullValue()) // Otherwise it must be an array
|
|
||||||
Combined =
|
|
||||||
ConstantExpr::get(Instruction::Add,
|
|
||||||
ConstantExpr::getCast(IdxList[0], Type::LongTy),
|
|
||||||
ConstantExpr::getCast(Combined, Type::LongTy));
|
|
||||||
|
|
||||||
NewIndices.push_back(Combined);
|
|
||||||
NewIndices.insert(NewIndices.end(), IdxList.begin()+1, IdxList.end());
|
|
||||||
return ConstantExpr::getGetElementPtr(CE->getOperand(0), NewIndices);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement folding of:
|
|
||||||
// int* getelementptr ([2 x int]* cast ([3 x int]* %X to [2 x int]*),
|
|
||||||
// long 0, long 0)
|
|
||||||
// To: int* getelementptr ([3 x int]* %X, long 0, long 0)
|
|
||||||
//
|
|
||||||
if (CE->getOpcode() == Instruction::Cast && IdxList.size() > 1 &&
|
|
||||||
IdxList[0]->isNullValue())
|
|
||||||
if (const PointerType *SPT =
|
|
||||||
dyn_cast<PointerType>(CE->getOperand(0)->getType()))
|
|
||||||
if (const ArrayType *SAT = dyn_cast<ArrayType>(SPT->getElementType()))
|
|
||||||
if (const ArrayType *CAT =
|
|
||||||
dyn_cast<ArrayType>(cast<PointerType>(C->getType())->getElementType()))
|
|
||||||
if (CAT->getElementType() == SAT->getElementType())
|
|
||||||
return ConstantExpr::getGetElementPtr(
|
|
||||||
(Constant*)CE->getOperand(0), IdxList);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// TemplateRules Class
|
// TemplateRules Class
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -604,9 +452,9 @@ struct DirectIntRules
|
|||||||
// DirectFPRules Class
|
// DirectFPRules Class
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// DirectFPRules provides implementations of functions that are valid on
|
/// DirectFPRules provides implementations of functions that are valid on
|
||||||
// floating point types, but not all types in general.
|
/// floating point types, but not all types in general.
|
||||||
//
|
///
|
||||||
template <class ConstantClass, class BuiltinType, Type **Ty>
|
template <class ConstantClass, class BuiltinType, Type **Ty>
|
||||||
struct DirectFPRules
|
struct DirectFPRules
|
||||||
: public DirectRules<ConstantClass, BuiltinType, Ty,
|
: public DirectRules<ConstantClass, BuiltinType, Ty,
|
||||||
@ -619,6 +467,9 @@ struct DirectFPRules
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// ConstRules::get - This method returns the constant rules implementation that
|
||||||
|
/// implements the semantics of the two specified constants.
|
||||||
ConstRules &ConstRules::get(const Constant *V1, const Constant *V2) {
|
ConstRules &ConstRules::get(const Constant *V1, const Constant *V2) {
|
||||||
static EmptyRules EmptyR;
|
static EmptyRules EmptyR;
|
||||||
static BoolRules BoolR;
|
static BoolRules BoolR;
|
||||||
@ -654,3 +505,169 @@ ConstRules &ConstRules::get(const Constant *V1, const Constant *V2) {
|
|||||||
case Type::DoubleTyID: return DoubleR;
|
case Type::DoubleTyID: return DoubleR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// ConstantFold*Instruction Implementations
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// These methods contain the special case hackery required to symbolically
|
||||||
|
// evaluate some constant expression cases, and use the ConstantRules class to
|
||||||
|
// evaluate normal constants.
|
||||||
|
//
|
||||||
|
static unsigned getSize(const Type *Ty) {
|
||||||
|
unsigned S = Ty->getPrimitiveSize();
|
||||||
|
return S ? S : 8; // Treat pointers at 8 bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
Constant *llvm::ConstantFoldCastInstruction(const Constant *V,
|
||||||
|
const Type *DestTy) {
|
||||||
|
if (V->getType() == DestTy) return (Constant*)V;
|
||||||
|
|
||||||
|
if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
|
||||||
|
if (CE->getOpcode() == Instruction::Cast) {
|
||||||
|
Constant *Op = const_cast<Constant*>(CE->getOperand(0));
|
||||||
|
// Try to not produce a cast of a cast, which is almost always redundant.
|
||||||
|
if (!Op->getType()->isFloatingPoint() &&
|
||||||
|
!CE->getType()->isFloatingPoint() &&
|
||||||
|
!DestTy->getType()->isFloatingPoint()) {
|
||||||
|
unsigned S1 = getSize(Op->getType()), S2 = getSize(CE->getType());
|
||||||
|
unsigned S3 = getSize(DestTy);
|
||||||
|
if (Op->getType() == DestTy && S3 >= S2)
|
||||||
|
return Op;
|
||||||
|
if (S1 >= S2 && S2 >= S3)
|
||||||
|
return ConstantExpr::getCast(Op, DestTy);
|
||||||
|
if (S1 <= S2 && S2 >= S3 && S1 <= S3)
|
||||||
|
return ConstantExpr::getCast(Op, DestTy);
|
||||||
|
}
|
||||||
|
} else if (CE->getOpcode() == Instruction::GetElementPtr) {
|
||||||
|
// If all of the indexes in the GEP are null values, there is no pointer
|
||||||
|
// adjustment going on. We might as well cast the source pointer.
|
||||||
|
bool isAllNull = true;
|
||||||
|
for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
|
||||||
|
if (!CE->getOperand(i)->isNullValue()) {
|
||||||
|
isAllNull = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isAllNull)
|
||||||
|
return ConstantExpr::getCast(CE->getOperand(0), DestTy);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstRules &Rules = ConstRules::get(V, V);
|
||||||
|
|
||||||
|
switch (DestTy->getPrimitiveID()) {
|
||||||
|
case Type::BoolTyID: return Rules.castToBool(V);
|
||||||
|
case Type::UByteTyID: return Rules.castToUByte(V);
|
||||||
|
case Type::SByteTyID: return Rules.castToSByte(V);
|
||||||
|
case Type::UShortTyID: return Rules.castToUShort(V);
|
||||||
|
case Type::ShortTyID: return Rules.castToShort(V);
|
||||||
|
case Type::UIntTyID: return Rules.castToUInt(V);
|
||||||
|
case Type::IntTyID: return Rules.castToInt(V);
|
||||||
|
case Type::ULongTyID: return Rules.castToULong(V);
|
||||||
|
case Type::LongTyID: return Rules.castToLong(V);
|
||||||
|
case Type::FloatTyID: return Rules.castToFloat(V);
|
||||||
|
case Type::DoubleTyID: return Rules.castToDouble(V);
|
||||||
|
case Type::PointerTyID:
|
||||||
|
return Rules.castToPointer(V, cast<PointerType>(DestTy));
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
|
||||||
|
const Constant *V1,
|
||||||
|
const Constant *V2) {
|
||||||
|
Constant *C;
|
||||||
|
switch (Opcode) {
|
||||||
|
default: return 0;
|
||||||
|
case Instruction::Add: return ConstRules::get(V1, V2).add(V1, V2);
|
||||||
|
case Instruction::Sub: return ConstRules::get(V1, V2).sub(V1, V2);
|
||||||
|
case Instruction::Mul: return ConstRules::get(V1, V2).mul(V1, V2);
|
||||||
|
case Instruction::Div: return ConstRules::get(V1, V2).div(V1, V2);
|
||||||
|
case Instruction::Rem: return ConstRules::get(V1, V2).rem(V1, V2);
|
||||||
|
case Instruction::And: return ConstRules::get(V1, V2).op_and(V1, V2);
|
||||||
|
case Instruction::Or: return ConstRules::get(V1, V2).op_or (V1, V2);
|
||||||
|
case Instruction::Xor: return ConstRules::get(V1, V2).op_xor(V1, V2);
|
||||||
|
|
||||||
|
case Instruction::Shl: return ConstRules::get(V1, V2).shl(V1, V2);
|
||||||
|
case Instruction::Shr: return ConstRules::get(V1, V2).shr(V1, V2);
|
||||||
|
|
||||||
|
case Instruction::SetEQ: return ConstRules::get(V1, V2).equalto(V1, V2);
|
||||||
|
case Instruction::SetLT: return ConstRules::get(V1, V2).lessthan(V1, V2);
|
||||||
|
case Instruction::SetGT: return ConstRules::get(V1, V2).lessthan(V2, V1);
|
||||||
|
case Instruction::SetNE: // V1 != V2 === !(V1 == V2)
|
||||||
|
C = ConstRules::get(V1, V2).equalto(V1, V2);
|
||||||
|
break;
|
||||||
|
case Instruction::SetLE: // V1 <= V2 === !(V2 < V1)
|
||||||
|
C = ConstRules::get(V1, V2).lessthan(V2, V1);
|
||||||
|
break;
|
||||||
|
case Instruction::SetGE: // V1 >= V2 === !(V1 < V2)
|
||||||
|
C = ConstRules::get(V1, V2).lessthan(V1, V2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the folder broke out of the switch statement, invert the boolean
|
||||||
|
// constant value, if it exists, and return it.
|
||||||
|
if (!C) return 0;
|
||||||
|
return ConstantExpr::get(Instruction::Xor, ConstantBool::True, C);
|
||||||
|
}
|
||||||
|
|
||||||
|
Constant *llvm::ConstantFoldGetElementPtr(const Constant *C,
|
||||||
|
const std::vector<Constant*> &IdxList) {
|
||||||
|
if (IdxList.size() == 0 ||
|
||||||
|
(IdxList.size() == 1 && IdxList[0]->isNullValue()))
|
||||||
|
return const_cast<Constant*>(C);
|
||||||
|
|
||||||
|
// TODO If C is null and all idx's are null, return null of the right type.
|
||||||
|
|
||||||
|
|
||||||
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(const_cast<Constant*>(C))) {
|
||||||
|
// Combine Indices - If the source pointer to this getelementptr instruction
|
||||||
|
// is a getelementptr instruction, combine the indices of the two
|
||||||
|
// getelementptr instructions into a single instruction.
|
||||||
|
//
|
||||||
|
if (CE->getOpcode() == Instruction::GetElementPtr) {
|
||||||
|
const Type *LastTy = 0;
|
||||||
|
for (gep_type_iterator I = gep_type_begin(CE), E = gep_type_end(CE);
|
||||||
|
I != E; ++I)
|
||||||
|
LastTy = *I;
|
||||||
|
|
||||||
|
if ((LastTy && isa<ArrayType>(LastTy)) || IdxList[0]->isNullValue()) {
|
||||||
|
std::vector<Constant*> NewIndices;
|
||||||
|
NewIndices.reserve(IdxList.size() + CE->getNumOperands());
|
||||||
|
for (unsigned i = 1, e = CE->getNumOperands()-1; i != e; ++i)
|
||||||
|
NewIndices.push_back(cast<Constant>(CE->getOperand(i)));
|
||||||
|
|
||||||
|
// Add the last index of the source with the first index of the new GEP.
|
||||||
|
// Make sure to handle the case when they are actually different types.
|
||||||
|
Constant *Combined = CE->getOperand(CE->getNumOperands()-1);
|
||||||
|
if (!IdxList[0]->isNullValue()) // Otherwise it must be an array
|
||||||
|
Combined =
|
||||||
|
ConstantExpr::get(Instruction::Add,
|
||||||
|
ConstantExpr::getCast(IdxList[0], Type::LongTy),
|
||||||
|
ConstantExpr::getCast(Combined, Type::LongTy));
|
||||||
|
|
||||||
|
NewIndices.push_back(Combined);
|
||||||
|
NewIndices.insert(NewIndices.end(), IdxList.begin()+1, IdxList.end());
|
||||||
|
return ConstantExpr::getGetElementPtr(CE->getOperand(0), NewIndices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement folding of:
|
||||||
|
// int* getelementptr ([2 x int]* cast ([3 x int]* %X to [2 x int]*),
|
||||||
|
// long 0, long 0)
|
||||||
|
// To: int* getelementptr ([3 x int]* %X, long 0, long 0)
|
||||||
|
//
|
||||||
|
if (CE->getOpcode() == Instruction::Cast && IdxList.size() > 1 &&
|
||||||
|
IdxList[0]->isNullValue())
|
||||||
|
if (const PointerType *SPT =
|
||||||
|
dyn_cast<PointerType>(CE->getOperand(0)->getType()))
|
||||||
|
if (const ArrayType *SAT = dyn_cast<ArrayType>(SPT->getElementType()))
|
||||||
|
if (const ArrayType *CAT =
|
||||||
|
dyn_cast<ArrayType>(cast<PointerType>(C->getType())->getElementType()))
|
||||||
|
if (CAT->getElementType() == SAT->getElementType())
|
||||||
|
return ConstantExpr::getGetElementPtr(
|
||||||
|
(Constant*)CE->getOperand(0), IdxList);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user