[llvm-commits] CVS: llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
Chris Lattner
lattner at cs.uiuc.edu
Fri Nov 18 18:11:19 PST 2005
Changes in directory llvm/lib/Target/X86:
X86ISelDAGToDAG.cpp updated: 1.2 -> 1.3
---
Log message:
Add load and other support to the dag-dag isel. Patch contributed by Evan
Cheng!
---
Diffs of the changes: (+225 -2)
X86ISelDAGToDAG.cpp | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 225 insertions(+), 2 deletions(-)
Index: llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
diff -u llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.2 llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.3
--- llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.2 Wed Nov 16 16:59:19 2005
+++ llvm/lib/Target/X86/X86ISelDAGToDAG.cpp Fri Nov 18 20:11:08 2005
@@ -15,6 +15,8 @@
#include "X86.h"
#include "X86Subtarget.h"
#include "X86ISelLowering.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Target/TargetMachine.h"
@@ -27,6 +29,32 @@
//===----------------------------------------------------------------------===//
namespace {
+ /// X86ISelAddressMode - This corresponds to X86AddressMode, but uses
+ /// SDOperand's instead of register numbers for the leaves of the matched
+ /// tree.
+ struct X86ISelAddressMode {
+ enum {
+ RegBase,
+ FrameIndexBase,
+ } BaseType;
+
+ struct { // This is really a union, discriminated by BaseType!
+ SDOperand Reg;
+ int FrameIndex;
+ } Base;
+
+ unsigned Scale;
+ SDOperand IndexReg;
+ unsigned Disp;
+ GlobalValue *GV;
+
+ X86ISelAddressMode()
+ : BaseType(RegBase), Scale(1), IndexReg(), Disp(), GV(0) {
+ }
+ };
+}
+
+namespace {
Statistic<>
NumFPKill("x86-codegen", "Number of FP_REG_KILL instructions added");
@@ -66,6 +94,15 @@
private:
SDOperand Select(SDOperand N);
+ void SelectAddress(SDOperand N, X86ISelAddressMode &AM);
+ bool MatchAddress(SDOperand N, X86ISelAddressMode &AM);
+
+ /// getI8Imm - Return a target constant with the specified value, of type
+ /// i8.
+ inline SDOperand getI8Imm(unsigned Imm) {
+ return CurDAG->getTargetConstant(Imm, MVT::i8);
+ }
+
/// getI16Imm - Return a target constant with the specified value, of type
/// i16.
inline SDOperand getI16Imm(unsigned Imm) {
@@ -93,6 +130,141 @@
ScheduleAndEmitDAG(DAG);
}
+/// SelectAddress - Pattern match the maximal addressing mode for this node.
+void X86DAGToDAGISel::SelectAddress(SDOperand N, X86ISelAddressMode &AM) {
+ MatchAddress(N, AM);
+
+ if (AM.BaseType == X86ISelAddressMode::RegBase && !AM.Base.Reg.Val) {
+ AM.Base.Reg = CurDAG->getRegister(0, MVT::i32);
+ } else {
+ AM.Base.Reg = Select(AM.Base.Reg);
+ }
+ if (!AM.IndexReg.Val) {
+ AM.IndexReg = CurDAG->getRegister(0, MVT::i32);
+ } else {
+ AM.IndexReg = Select(AM.IndexReg);
+ }
+}
+
+/// FIXME: copied from X86ISelPattern.cpp
+/// MatchAddress - Add the specified node to the specified addressing mode,
+/// returning true if it cannot be done. This just pattern matches for the
+/// addressing mode
+bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM) {
+ switch (N.getOpcode()) {
+ default: break;
+ case ISD::FrameIndex:
+ if (AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0) {
+ AM.BaseType = X86ISelAddressMode::FrameIndexBase;
+ AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
+ return false;
+ }
+ break;
+ case ISD::GlobalAddress:
+ if (AM.GV == 0) {
+ GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal();
+ // For Darwin, external and weak symbols are indirect, so we want to load
+ // the value at address GV, not the value of GV itself. This means that
+ // the GlobalAddress must be in the base or index register of the address,
+ // not the GV offset field.
+ if (Subtarget->getIndirectExternAndWeakGlobals() &&
+ (GV->hasWeakLinkage() || GV->isExternal())) {
+ break;
+ } else {
+ AM.GV = GV;
+ return false;
+ }
+ }
+ break;
+ case ISD::Constant:
+ AM.Disp += cast<ConstantSDNode>(N)->getValue();
+ return false;
+ case ISD::SHL:
+ if (AM.IndexReg.Val == 0 && AM.Scale == 1)
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1))) {
+ unsigned Val = CN->getValue();
+ if (Val == 1 || Val == 2 || Val == 3) {
+ AM.Scale = 1 << Val;
+ SDOperand ShVal = N.Val->getOperand(0);
+
+ // Okay, we know that we have a scale by now. However, if the scaled
+ // value is an add of something and a constant, we can fold the
+ // constant into the disp field here.
+ if (ShVal.Val->getOpcode() == ISD::ADD && ShVal.hasOneUse() &&
+ isa<ConstantSDNode>(ShVal.Val->getOperand(1))) {
+ AM.IndexReg = ShVal.Val->getOperand(0);
+ ConstantSDNode *AddVal =
+ cast<ConstantSDNode>(ShVal.Val->getOperand(1));
+ AM.Disp += AddVal->getValue() << Val;
+ } else {
+ AM.IndexReg = ShVal;
+ }
+ return false;
+ }
+ }
+ break;
+ case ISD::MUL:
+ // X*[3,5,9] -> X+X*[2,4,8]
+ if (AM.IndexReg.Val == 0 && AM.BaseType == X86ISelAddressMode::RegBase &&
+ AM.Base.Reg.Val == 0)
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1)))
+ if (CN->getValue() == 3 || CN->getValue() == 5 || CN->getValue() == 9) {
+ AM.Scale = unsigned(CN->getValue())-1;
+
+ SDOperand MulVal = N.Val->getOperand(0);
+ SDOperand Reg;
+
+ // Okay, we know that we have a scale by now. However, if the scaled
+ // value is an add of something and a constant, we can fold the
+ // constant into the disp field here.
+ if (MulVal.Val->getOpcode() == ISD::ADD && MulVal.hasOneUse() &&
+ isa<ConstantSDNode>(MulVal.Val->getOperand(1))) {
+ Reg = MulVal.Val->getOperand(0);
+ ConstantSDNode *AddVal =
+ cast<ConstantSDNode>(MulVal.Val->getOperand(1));
+ AM.Disp += AddVal->getValue() * CN->getValue();
+ } else {
+ Reg = N.Val->getOperand(0);
+ }
+
+ AM.IndexReg = AM.Base.Reg = Reg;
+ return false;
+ }
+ break;
+
+ case ISD::ADD: {
+ X86ISelAddressMode Backup = AM;
+ if (!MatchAddress(N.Val->getOperand(0), AM) &&
+ !MatchAddress(N.Val->getOperand(1), AM))
+ return false;
+ AM = Backup;
+ if (!MatchAddress(N.Val->getOperand(1), AM) &&
+ !MatchAddress(N.Val->getOperand(0), AM))
+ return false;
+ AM = Backup;
+ break;
+ }
+ }
+
+ // Is the base register already occupied?
+ if (AM.BaseType != X86ISelAddressMode::RegBase || AM.Base.Reg.Val) {
+ // If so, check to see if the scale index register is set.
+ if (AM.IndexReg.Val == 0) {
+ AM.IndexReg = N;
+ AM.Scale = 1;
+ return false;
+ }
+
+ // Otherwise, we cannot select it.
+ return true;
+ }
+
+ // Default, generate it as a register.
+ AM.BaseType = X86ISelAddressMode::RegBase;
+ AM.Base.Reg = N;
+ return false;
+}
+
SDOperand X86DAGToDAGISel::Select(SDOperand Op) {
SDNode *N = Op.Val;
MVT::ValueType OpVT = Op.getValueType();
@@ -103,6 +275,21 @@
switch (N->getOpcode()) {
default: break;
+ case ISD::SHL:
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
+ if (CN->getValue() == 1) { // X = SHL Y, 1 -> X = ADD Y, Y
+ switch (OpVT) {
+ default: assert(0 && "Cannot shift this type!");
+ case MVT::i8: Opc = X86::ADD8rr; break;
+ case MVT::i16: Opc = X86::ADD16rr; break;
+ case MVT::i32: Opc = X86::ADD32rr; break;
+ }
+ SDOperand Tmp0 = Select(N->getOperand(0));
+ CurDAG->SelectNodeTo(N, Opc, MVT::i32, Tmp0, Tmp0);
+ return SDOperand(N, 0);
+ }
+ }
+
case ISD::RET: {
SDOperand Chain = Select(N->getOperand(0)); // Token chain.
switch (N->getNumOperands()) {
@@ -131,11 +318,47 @@
if (X86Lowering.getBytesToPopOnReturn() == 0)
CurDAG->SelectNodeTo(N, X86::RET, MVT::Other, Chain);
else
- CurDAG->SelectNodeTo(N, X86::RET, MVT::Other, Chain,
- getI16Imm(X86Lowering.getBytesToPopOnReturn()));
+ CurDAG->SelectNodeTo(N, X86::RET, MVT::Other,
+ getI16Imm(X86Lowering.getBytesToPopOnReturn()),
+ Chain);
return SDOperand(N, 0);
}
+
+ case ISD::LOAD: {
+ switch (N->getValueType(0)) {
+ default: assert(0 && "Cannot load this type!");
+ case MVT::i1:
+ case MVT::i8: Opc = X86::MOV8rm; break;
+ case MVT::i16: Opc = X86::MOV16rm; break;
+ case MVT::i32: Opc = X86::MOV32rm; break;
+ case MVT::f32: Opc = X86::MOVSSrm; break;
+ case MVT::f64: Opc = X86::FLD64m; ContainsFPCode = true; break;
+ }
+
+ if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N->getOperand(1))){
+ unsigned CPIdx = BB->getParent()->getConstantPool()->
+ getConstantPoolIndex(CP->get());
+ // ???
+ assert(0 && "Can't handle load from constant pool!");
+ } else {
+ SDOperand Chain = Select(N->getOperand(0)); // Token chain.
+ X86ISelAddressMode AM;
+ SelectAddress(N->getOperand(1), AM);
+ SDOperand Scale = getI8Imm (AM.Scale);
+ SDOperand Disp = AM.GV ? CurDAG->getTargetGlobalAddress(AM.GV, MVT::i32)
+ : getI32Imm(AM.Disp);
+ if (AM.BaseType == X86ISelAddressMode::RegBase) {
+ CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other,
+ AM.Base.Reg, Scale, AM.IndexReg, Disp, Chain);
+ } else {
+ SDOperand Base = CurDAG->getFrameIndex(AM.Base.FrameIndex, MVT::i32);
+ CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other,
+ Base, Scale, AM.IndexReg, Disp, Chain);
+ }
+ }
+ return SDOperand(N, Op.ResNo);
+ }
}
return SelectCode(Op);
More information about the llvm-commits
mailing list