mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-18 12:29:21 +00:00
* Cleaned up addressing mode matching code.
* Cleaned up and tweaked LEA cost analysis code. Removed some hacks. * Handle ADD $X, c to MOV32ri $X+c. These patterns cannot be autogen'd and they need to be matched before LEA. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26376 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
53f280a30e
commit
51a9ed9b41
@ -46,7 +46,6 @@ namespace {
|
|||||||
enum {
|
enum {
|
||||||
RegBase,
|
RegBase,
|
||||||
FrameIndexBase,
|
FrameIndexBase,
|
||||||
ConstantPoolBase
|
|
||||||
} BaseType;
|
} BaseType;
|
||||||
|
|
||||||
struct { // This is really a union, discriminated by BaseType!
|
struct { // This is really a union, discriminated by BaseType!
|
||||||
@ -58,9 +57,12 @@ namespace {
|
|||||||
SDOperand IndexReg;
|
SDOperand IndexReg;
|
||||||
unsigned Disp;
|
unsigned Disp;
|
||||||
GlobalValue *GV;
|
GlobalValue *GV;
|
||||||
|
Constant *CP;
|
||||||
|
unsigned Align; // CP alignment.
|
||||||
|
|
||||||
X86ISelAddressMode()
|
X86ISelAddressMode()
|
||||||
: BaseType(RegBase), Scale(1), IndexReg(), Disp(0), GV(0) {
|
: BaseType(RegBase), Scale(1), IndexReg(), Disp(0), GV(0),
|
||||||
|
CP(0), Align(0) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -132,7 +134,9 @@ namespace {
|
|||||||
Scale = getI8Imm(AM.Scale);
|
Scale = getI8Imm(AM.Scale);
|
||||||
Index = AM.IndexReg;
|
Index = AM.IndexReg;
|
||||||
Disp = AM.GV ? CurDAG->getTargetGlobalAddress(AM.GV, MVT::i32, AM.Disp)
|
Disp = AM.GV ? CurDAG->getTargetGlobalAddress(AM.GV, MVT::i32, AM.Disp)
|
||||||
: getI32Imm(AM.Disp);
|
: (AM.CP ?
|
||||||
|
CurDAG->getTargetConstantPool(AM.CP, MVT::i32, AM.Align, AM.Disp)
|
||||||
|
: getI32Imm(AM.Disp));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getI8Imm - Return a target constant with the specified value, of type
|
/// getI8Imm - Return a target constant with the specified value, of type
|
||||||
@ -266,26 +270,44 @@ void X86DAGToDAGISel::EmitFunctionEntryCode(Function &Fn, MachineFunction &MF) {
|
|||||||
/// addressing mode
|
/// addressing mode
|
||||||
bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
|
bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
|
||||||
bool isRoot) {
|
bool isRoot) {
|
||||||
bool StopHere = false;
|
bool Available = false;
|
||||||
// If N has already been selected, we may or may not want to fold its
|
// If N has already been selected, reuse the result unless in some very
|
||||||
// operands into the addressing mode. It will result in code duplication!
|
// specific cases.
|
||||||
// FIXME: Right now we do. That is, as long as the selected target node
|
|
||||||
// does not produce a chain. This may require a more sophisticated heuristics.
|
|
||||||
std::map<SDOperand, SDOperand>::iterator CGMI= CodeGenMap.find(N.getValue(0));
|
std::map<SDOperand, SDOperand>::iterator CGMI= CodeGenMap.find(N.getValue(0));
|
||||||
if (CGMI != CodeGenMap.end()) {
|
if (CGMI != CodeGenMap.end()) {
|
||||||
if (isRoot)
|
Available = true;
|
||||||
// Stop here if it is a root. It's probably not profitable to go deeper.
|
|
||||||
StopHere = true;
|
|
||||||
else {
|
|
||||||
for (unsigned i = 0, e = CGMI->second.Val->getNumValues(); i != e; ++i) {
|
|
||||||
if (CGMI->second.Val->getValueType(i) == MVT::Other)
|
|
||||||
StopHere = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (N.getOpcode()) {
|
switch (N.getOpcode()) {
|
||||||
default: break;
|
default: break;
|
||||||
|
case ISD::Constant:
|
||||||
|
AM.Disp += cast<ConstantSDNode>(N)->getValue();
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case X86ISD::Wrapper:
|
||||||
|
// If both base and index components have been picked, we can't fit
|
||||||
|
// the result available in the register in the addressing mode. Duplicate
|
||||||
|
// GlobalAddress or ConstantPool as displacement.
|
||||||
|
if (!Available || (AM.Base.Reg.Val && AM.IndexReg.Val)) {
|
||||||
|
if (ConstantPoolSDNode *CP =
|
||||||
|
dyn_cast<ConstantPoolSDNode>(N.getOperand(0))) {
|
||||||
|
if (AM.CP == 0) {
|
||||||
|
AM.CP = CP->get();
|
||||||
|
AM.Align = CP->getAlignment();
|
||||||
|
AM.Disp += CP->getOffset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (GlobalAddressSDNode *G =
|
||||||
|
dyn_cast<GlobalAddressSDNode>(N.getOperand(0))) {
|
||||||
|
if (AM.GV == 0) {
|
||||||
|
AM.GV = G->getGlobal();
|
||||||
|
AM.Disp += G->getOffset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case ISD::FrameIndex:
|
case ISD::FrameIndex:
|
||||||
if (AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0) {
|
if (AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0) {
|
||||||
AM.BaseType = X86ISelAddressMode::FrameIndexBase;
|
AM.BaseType = X86ISelAddressMode::FrameIndexBase;
|
||||||
@ -294,48 +316,8 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ISD::ConstantPool:
|
|
||||||
if (AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0) {
|
|
||||||
if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N)) {
|
|
||||||
AM.BaseType = X86ISelAddressMode::ConstantPoolBase;
|
|
||||||
AM.Base.Reg = CurDAG->getTargetConstantPool(CP->get(), MVT::i32,
|
|
||||||
CP->getAlignment());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ISD::GlobalAddress:
|
|
||||||
if (AM.GV == 0) {
|
|
||||||
AM.GV = cast<GlobalAddressSDNode>(N)->getGlobal();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case X86ISD::Wrapper:
|
|
||||||
if (ConstantPoolSDNode *CP =
|
|
||||||
dyn_cast<ConstantPoolSDNode>(N.getOperand(0))) {
|
|
||||||
if (AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0) {
|
|
||||||
AM.BaseType = X86ISelAddressMode::ConstantPoolBase;
|
|
||||||
AM.Base.Reg = CurDAG->getTargetConstantPool(CP->get(), MVT::i32,
|
|
||||||
CP->getAlignment());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (GlobalAddressSDNode *G =
|
|
||||||
dyn_cast<GlobalAddressSDNode>(N.getOperand(0))) {
|
|
||||||
if (AM.GV == 0) {
|
|
||||||
AM.GV = cast<GlobalAddressSDNode>(N.getOperand(0))->getGlobal();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ISD::Constant:
|
|
||||||
AM.Disp += cast<ConstantSDNode>(N)->getValue();
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case ISD::SHL:
|
case ISD::SHL:
|
||||||
if (!StopHere && AM.IndexReg.Val == 0 && AM.Scale == 1)
|
if (!Available && AM.IndexReg.Val == 0 && AM.Scale == 1)
|
||||||
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1))) {
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1))) {
|
||||||
unsigned Val = CN->getValue();
|
unsigned Val = CN->getValue();
|
||||||
if (Val == 1 || Val == 2 || Val == 3) {
|
if (Val == 1 || Val == 2 || Val == 3) {
|
||||||
@ -361,8 +343,10 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
|
|||||||
|
|
||||||
case ISD::MUL:
|
case ISD::MUL:
|
||||||
// X*[3,5,9] -> X+X*[2,4,8]
|
// X*[3,5,9] -> X+X*[2,4,8]
|
||||||
if (!StopHere && AM.IndexReg.Val == 0 && AM.BaseType == X86ISelAddressMode::RegBase &&
|
if (!Available &&
|
||||||
AM.Base.Reg.Val == 0)
|
AM.BaseType == X86ISelAddressMode::RegBase &&
|
||||||
|
AM.Base.Reg.Val == 0 &&
|
||||||
|
AM.IndexReg.Val == 0)
|
||||||
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1)))
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1)))
|
||||||
if (CN->getValue() == 3 || CN->getValue() == 5 || CN->getValue() == 9) {
|
if (CN->getValue() == 3 || CN->getValue() == 5 || CN->getValue() == 9) {
|
||||||
AM.Scale = unsigned(CN->getValue())-1;
|
AM.Scale = unsigned(CN->getValue())-1;
|
||||||
@ -389,7 +373,7 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ISD::ADD: {
|
case ISD::ADD: {
|
||||||
if (!StopHere) {
|
if (!Available) {
|
||||||
X86ISelAddressMode Backup = AM;
|
X86ISelAddressMode Backup = AM;
|
||||||
if (!MatchAddress(N.Val->getOperand(0), AM, false) &&
|
if (!MatchAddress(N.Val->getOperand(0), AM, false) &&
|
||||||
!MatchAddress(N.Val->getOperand(1), AM, false))
|
!MatchAddress(N.Val->getOperand(1), AM, false))
|
||||||
@ -406,10 +390,6 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM,
|
|||||||
|
|
||||||
// Is the base register already occupied?
|
// Is the base register already occupied?
|
||||||
if (AM.BaseType != X86ISelAddressMode::RegBase || AM.Base.Reg.Val) {
|
if (AM.BaseType != X86ISelAddressMode::RegBase || AM.Base.Reg.Val) {
|
||||||
// TargetConstantPool cannot be anything but the base.
|
|
||||||
if (N.getOpcode() == ISD::TargetConstantPool)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// If so, check to see if the scale index register is set.
|
// If so, check to see if the scale index register is set.
|
||||||
if (AM.IndexReg.Val == 0) {
|
if (AM.IndexReg.Val == 0) {
|
||||||
AM.IndexReg = N;
|
AM.IndexReg = N;
|
||||||
@ -445,9 +425,56 @@ bool X86DAGToDAGISel::SelectAddr(SDOperand N, SDOperand &Base, SDOperand &Scale,
|
|||||||
AM.IndexReg = CurDAG->getRegister(0, MVT::i32);
|
AM.IndexReg = CurDAG->getRegister(0, MVT::i32);
|
||||||
|
|
||||||
getAddressOperands(AM, Base, Scale, Index, Disp);
|
getAddressOperands(AM, Base, Scale, Index, Disp);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SelectLEAAddr - it calls SelectAddr and determines if the maximal addressing
|
||||||
|
/// mode it matches can be cost effectively emitted as an LEA instruction.
|
||||||
|
/// For X86, it always is unless it's just a (Reg + const).
|
||||||
|
bool X86DAGToDAGISel::SelectLEAAddr(SDOperand N, SDOperand &Base,
|
||||||
|
SDOperand &Scale,
|
||||||
|
SDOperand &Index, SDOperand &Disp) {
|
||||||
|
X86ISelAddressMode AM;
|
||||||
|
if (MatchAddress(N, AM))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned Complexity = 0;
|
||||||
|
if (AM.BaseType == X86ISelAddressMode::RegBase)
|
||||||
|
if (AM.Base.Reg.Val)
|
||||||
|
Complexity = 1;
|
||||||
|
else
|
||||||
|
AM.Base.Reg = CurDAG->getRegister(0, MVT::i32);
|
||||||
|
else if (AM.BaseType == X86ISelAddressMode::FrameIndexBase)
|
||||||
|
Complexity = 4;
|
||||||
|
|
||||||
|
if (AM.IndexReg.Val)
|
||||||
|
Complexity++;
|
||||||
|
else
|
||||||
|
AM.IndexReg = CurDAG->getRegister(0, MVT::i32);
|
||||||
|
|
||||||
|
if (AM.Scale > 1)
|
||||||
|
Complexity += 2;
|
||||||
|
|
||||||
|
// FIXME: We are artificially lowering the criteria to turn ADD %reg, $GA
|
||||||
|
// to a LEA. This is determined with some expermentation but is by no means
|
||||||
|
// optimal (especially for code size consideration). LEA is nice because of
|
||||||
|
// its three-address nature. Tweak the cost function again when we can run
|
||||||
|
// convertToThreeAddress() at register allocation time.
|
||||||
|
if (AM.GV || AM.CP)
|
||||||
|
Complexity += 2;
|
||||||
|
|
||||||
|
if (AM.Disp && (AM.Base.Reg.Val || AM.IndexReg.Val))
|
||||||
|
Complexity++;
|
||||||
|
|
||||||
|
if (Complexity > 2) {
|
||||||
|
getAddressOperands(AM, Base, Scale, Index, Disp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool X86DAGToDAGISel::TryFoldLoad(SDOperand P, SDOperand N,
|
bool X86DAGToDAGISel::TryFoldLoad(SDOperand P, SDOperand N,
|
||||||
SDOperand &Base, SDOperand &Scale,
|
SDOperand &Base, SDOperand &Scale,
|
||||||
SDOperand &Index, SDOperand &Disp) {
|
SDOperand &Index, SDOperand &Disp) {
|
||||||
@ -465,67 +492,6 @@ static bool isRegister0(SDOperand Op) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SelectLEAAddr - it calls SelectAddr and determines if the maximal addressing
|
|
||||||
/// mode it matches can be cost effectively emitted as an LEA instruction.
|
|
||||||
/// For X86, it always is unless it's just a (Reg + const).
|
|
||||||
bool X86DAGToDAGISel::SelectLEAAddr(SDOperand N, SDOperand &Base,
|
|
||||||
SDOperand &Scale,
|
|
||||||
SDOperand &Index, SDOperand &Disp) {
|
|
||||||
X86ISelAddressMode AM;
|
|
||||||
if (!MatchAddress(N, AM)) {
|
|
||||||
bool SelectIndex = false;
|
|
||||||
bool Check = false;
|
|
||||||
if (AM.BaseType == X86ISelAddressMode::RegBase) {
|
|
||||||
if (AM.Base.Reg.Val)
|
|
||||||
Check = true;
|
|
||||||
else
|
|
||||||
AM.Base.Reg = CurDAG->getRegister(0, MVT::i32);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AM.IndexReg.Val)
|
|
||||||
SelectIndex = true;
|
|
||||||
else
|
|
||||||
AM.IndexReg = CurDAG->getRegister(0, MVT::i32);
|
|
||||||
|
|
||||||
if (Check) {
|
|
||||||
unsigned Complexity = 0;
|
|
||||||
if (AM.Scale > 1)
|
|
||||||
Complexity++;
|
|
||||||
if (SelectIndex)
|
|
||||||
Complexity++;
|
|
||||||
if (AM.GV) {
|
|
||||||
Complexity++;
|
|
||||||
if (AM.Disp)
|
|
||||||
Complexity++;
|
|
||||||
} else if (AM.Disp > 1)
|
|
||||||
Complexity++;
|
|
||||||
// Suppose base == %eax and it has multiple uses, then instead of
|
|
||||||
// movl %eax, %ecx
|
|
||||||
// addl $8, %ecx
|
|
||||||
// use
|
|
||||||
// leal 8(%eax), %ecx.
|
|
||||||
// FIXME: If the other uses ended up being scheduled ahead of the leal
|
|
||||||
// then it would have been better to use the addl. The proper way to
|
|
||||||
// handle this is with using X86InstrInfo::convertToThreeAddress hook.
|
|
||||||
// From an email:
|
|
||||||
// BTW, this problem is the one that inspired the
|
|
||||||
// "X86InstrInfo::convertToThreeAddress" hook (which would handle this
|
|
||||||
// the "right" way). Unfortunately the X86 implementation of this is
|
|
||||||
// disabled, because we don't currently have enough information handy to
|
|
||||||
// know that the flags from the add is dead when the hook is called (from
|
|
||||||
// the register allocator).
|
|
||||||
if (AM.Base.Reg.Val->use_size() > 1)
|
|
||||||
Complexity++;
|
|
||||||
if (Complexity <= 1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAddressOperands(AM, Base, Scale, Index, Disp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// getGlobalBaseReg - Output the instructions required to put the
|
/// getGlobalBaseReg - Output the instructions required to put the
|
||||||
/// base address to use for accessing globals into a register.
|
/// base address to use for accessing globals into a register.
|
||||||
///
|
///
|
||||||
@ -589,37 +555,42 @@ void X86DAGToDAGISel::Select(SDOperand &Result, SDOperand N) {
|
|||||||
Result = getGlobalBaseReg();
|
Result = getGlobalBaseReg();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case X86ISD::Wrapper: {
|
case ISD::ADD: {
|
||||||
// It's beneficial to manully select the wrapper nodes here rather
|
// Turn ADD X, c to MOV32ri X+c. This cannot be done with tblgen'd
|
||||||
// then using tablgen'd code to match this. We do not want to mutate the
|
// code and is matched first so to prevent it from being turned into
|
||||||
// node to MOV32ri and we do not want to record this in CodeGenMap.
|
// LEA32r X+c.
|
||||||
// We want to allow the wrapped leaf nodes be duplicated so they can
|
SDOperand N0 = N.getOperand(0);
|
||||||
// be used in addressing modes.
|
SDOperand N1 = N.getOperand(1);
|
||||||
// e.g.
|
if (N.Val->getValueType(0) == MVT::i32 &&
|
||||||
// 0xa59e4a0: i32 = TargetGlobalAddress <xxx> 0
|
N0.getOpcode() == X86ISD::Wrapper &&
|
||||||
// 0xa59e740: i32 = X86ISD::Wrapper 0xa59e4a0
|
N1.getOpcode() == ISD::Constant) {
|
||||||
// ...
|
unsigned Offset = (unsigned)cast<ConstantSDNode>(N1)->getValue();
|
||||||
// 0xa59e880: i32 = add 0xa59e740, 0xa59e800
|
SDOperand C(0, 0);
|
||||||
// ...
|
// TODO: handle ExternalSymbolSDNode.
|
||||||
// 0xa59e880: <multiple use>
|
if (GlobalAddressSDNode *G =
|
||||||
// 0xa59e970: i32 = add 0xa59e880, 0xa59e910
|
dyn_cast<GlobalAddressSDNode>(N0.getOperand(0))) {
|
||||||
// ...
|
C = CurDAG->getTargetGlobalAddress(G->getGlobal(), MVT::i32,
|
||||||
// 0xa59ea60: i32,ch = load 0xa589780, 0xa59e970, 0xa59ea00
|
G->getOffset() + Offset);
|
||||||
// ...
|
} else if (ConstantPoolSDNode *CP =
|
||||||
// 0xa59e880: <multiple use>
|
dyn_cast<ConstantPoolSDNode>(N0.getOperand(0))) {
|
||||||
// 0xa59eb60: ch = CopyToReg 0xa59ea60:1, 0xa59eaf0, 0xa59e880
|
C = CurDAG->getTargetConstantPool(CP->get(), MVT::i32,
|
||||||
// By allowing the TargetGlobalAddress to be duplicated, it can appear
|
CP->getAlignment(),
|
||||||
// in the load address as well as an operand of the add.
|
CP->getOffset()+Offset);
|
||||||
Result = SDOperand(CurDAG->getTargetNode(X86::MOV32ri, MVT::i32,
|
}
|
||||||
N.getOperand(0)), 0);
|
|
||||||
#ifndef NDEBUG
|
if (C.Val) {
|
||||||
DEBUG(std::cerr << std::string(Indent-2, ' '));
|
if (N.Val->hasOneUse()) {
|
||||||
DEBUG(std::cerr << "== ");
|
Result = CurDAG->SelectNodeTo(N.Val, X86::MOV32ri, MVT::i32, C);
|
||||||
DEBUG(Result.Val->dump(CurDAG));
|
} else {
|
||||||
DEBUG(std::cerr << "\n");
|
SDNode *ResNode = CurDAG->getTargetNode(X86::MOV32ri, MVT::i32, C);
|
||||||
Indent -= 2;
|
Result = CodeGenMap[N] = SDOperand(ResNode, 0);
|
||||||
#endif
|
}
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other cases are handled by auto-generated code.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ISD::MULHU:
|
case ISD::MULHU:
|
||||||
|
Loading…
Reference in New Issue
Block a user