mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-24 04:56:51 +00:00
Give V8 select_cc, in the spirit of the PPC backend
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24823 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
98f853698c
commit
3308449afc
@ -16,6 +16,7 @@
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||||
#include "llvm/CodeGen/SSARegMap.h"
|
||||
@ -40,6 +41,9 @@ namespace V8ISD {
|
||||
|
||||
FTOI, // FP to Int within a FP register.
|
||||
ITOF, // Int to FP within a FP register.
|
||||
|
||||
SELECT_ICC, // Select between two values using the current ICC flags.
|
||||
SELECT_FCC, // Select between two values using the current FCC flags.
|
||||
};
|
||||
}
|
||||
|
||||
@ -66,6 +70,8 @@ namespace {
|
||||
virtual std::pair<SDOperand, SDOperand>
|
||||
LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth,
|
||||
SelectionDAG &DAG);
|
||||
virtual MachineBasicBlock *InsertAtEndOfBasicBlock(MachineInstr *MI,
|
||||
MachineBasicBlock *MBB);
|
||||
};
|
||||
}
|
||||
|
||||
@ -82,9 +88,9 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::ConstantPool , MVT::i32, Custom);
|
||||
|
||||
// Sparc doesn't have sext_inreg, replace them with shl/sra
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16 , Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
|
||||
|
||||
// Sparc has no REM operation.
|
||||
setOperationAction(ISD::UREM, MVT::i32, Expand);
|
||||
@ -116,6 +122,10 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::BR_CC, MVT::f32, Custom);
|
||||
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
|
||||
|
||||
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
|
||||
|
||||
computeRegisterProperties();
|
||||
}
|
||||
|
||||
@ -243,22 +253,6 @@ SDOperand SparcV8TargetLowering::
|
||||
LowerOperation(SDOperand Op, SelectionDAG &DAG) {
|
||||
switch (Op.getOpcode()) {
|
||||
default: assert(0 && "Should not custom lower this!");
|
||||
case ISD::BR_CC: {
|
||||
SDOperand Chain = Op.getOperand(0);
|
||||
SDOperand CC = Op.getOperand(1);
|
||||
SDOperand LHS = Op.getOperand(2);
|
||||
SDOperand RHS = Op.getOperand(3);
|
||||
SDOperand Dest = Op.getOperand(4);
|
||||
|
||||
// Get the condition flag.
|
||||
if (LHS.getValueType() == MVT::i32) {
|
||||
SDOperand Cond = DAG.getNode(V8ISD::CMPICC, MVT::Flag, LHS, RHS);
|
||||
return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond);
|
||||
} else {
|
||||
SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
|
||||
return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond);
|
||||
}
|
||||
}
|
||||
case ISD::GlobalAddress: {
|
||||
GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
|
||||
SDOperand GA = DAG.getTargetGlobalAddress(GV, MVT::i32);
|
||||
@ -298,10 +292,134 @@ LowerOperation(SDOperand Op, SelectionDAG &DAG) {
|
||||
// Convert the int value to FP in an FP register.
|
||||
return DAG.getNode(V8ISD::ITOF, Op.getValueType(), Op);
|
||||
}
|
||||
case ISD::BR_CC: {
|
||||
SDOperand Chain = Op.getOperand(0);
|
||||
SDOperand CC = Op.getOperand(1);
|
||||
SDOperand LHS = Op.getOperand(2);
|
||||
SDOperand RHS = Op.getOperand(3);
|
||||
SDOperand Dest = Op.getOperand(4);
|
||||
|
||||
// Get the condition flag.
|
||||
if (LHS.getValueType() == MVT::i32) {
|
||||
SDOperand Cond = DAG.getNode(V8ISD::CMPICC, MVT::Flag, LHS, RHS);
|
||||
return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond);
|
||||
} else {
|
||||
SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
|
||||
return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond);
|
||||
}
|
||||
}
|
||||
case ISD::SELECT_CC: {
|
||||
SDOperand LHS = Op.getOperand(0);
|
||||
SDOperand RHS = Op.getOperand(1);
|
||||
unsigned CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
||||
SDOperand TrueVal = Op.getOperand(2);
|
||||
SDOperand FalseVal = Op.getOperand(3);
|
||||
|
||||
unsigned Opc;
|
||||
Opc = LHS.getValueType() == MVT::i32 ? V8ISD::CMPICC : V8ISD::CMPFCC;
|
||||
SDOperand CompareFlag = DAG.getNode(Opc, MVT::Flag, LHS, RHS);
|
||||
|
||||
Opc = LHS.getValueType() == MVT::i32 ?
|
||||
V8ISD::SELECT_ICC : V8ISD::SELECT_FCC;
|
||||
return DAG.getNode(Opc, TrueVal.getValueType(), TrueVal, FalseVal,
|
||||
DAG.getConstant(CC, MVT::i32), CompareFlag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MachineBasicBlock *
|
||||
SparcV8TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
|
||||
MachineBasicBlock *BB) {
|
||||
unsigned BROpcode;
|
||||
// Figure out the conditional branch opcode to use for this select_cc.
|
||||
switch (MI->getOpcode()) {
|
||||
default: assert(0 && "Unknown SELECT_CC!");
|
||||
case V8::SELECT_CC_Int_ICC:
|
||||
case V8::SELECT_CC_FP_ICC:
|
||||
case V8::SELECT_CC_DFP_ICC:
|
||||
// Integer compare.
|
||||
switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) {
|
||||
default: assert(0 && "Unknown integer condition code!");
|
||||
case ISD::SETEQ: BROpcode = V8::BE; break;
|
||||
case ISD::SETNE: BROpcode = V8::BNE; break;
|
||||
case ISD::SETLT: BROpcode = V8::BL; break;
|
||||
case ISD::SETGT: BROpcode = V8::BG; break;
|
||||
case ISD::SETLE: BROpcode = V8::BLE; break;
|
||||
case ISD::SETGE: BROpcode = V8::BGE; break;
|
||||
case ISD::SETULT: BROpcode = V8::BCS; break;
|
||||
case ISD::SETULE: BROpcode = V8::BLEU; break;
|
||||
case ISD::SETUGT: BROpcode = V8::BGU; break;
|
||||
case ISD::SETUGE: BROpcode = V8::BCC; break;
|
||||
}
|
||||
break;
|
||||
case V8::SELECT_CC_Int_FCC:
|
||||
case V8::SELECT_CC_FP_FCC:
|
||||
case V8::SELECT_CC_DFP_FCC:
|
||||
// FP compare.
|
||||
switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) {
|
||||
default: assert(0 && "Unknown fp condition code!");
|
||||
case ISD::SETEQ: BROpcode = V8::FBE; break;
|
||||
case ISD::SETNE: BROpcode = V8::FBNE; break;
|
||||
case ISD::SETLT: BROpcode = V8::FBL; break;
|
||||
case ISD::SETGT: BROpcode = V8::FBG; break;
|
||||
case ISD::SETLE: BROpcode = V8::FBLE; break;
|
||||
case ISD::SETGE: BROpcode = V8::FBGE; break;
|
||||
case ISD::SETULT: BROpcode = V8::FBUL; break;
|
||||
case ISD::SETULE: BROpcode = V8::FBULE; break;
|
||||
case ISD::SETUGT: BROpcode = V8::FBUG; break;
|
||||
case ISD::SETUGE: BROpcode = V8::FBUGE; break;
|
||||
case ISD::SETUO: BROpcode = V8::FBU; break;
|
||||
case ISD::SETO: BROpcode = V8::FBO; break;
|
||||
case ISD::SETONE: BROpcode = V8::FBLG; break;
|
||||
case ISD::SETUEQ: BROpcode = V8::FBUE; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// To "insert" a SELECT_CC instruction, we actually have to insert the diamond
|
||||
// control-flow pattern. The incoming instruction knows the destination vreg
|
||||
// to set, the condition code register to branch on, the true/false values to
|
||||
// select between, and a branch opcode to use.
|
||||
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
||||
ilist<MachineBasicBlock>::iterator It = BB;
|
||||
++It;
|
||||
|
||||
// thisMBB:
|
||||
// ...
|
||||
// TrueVal = ...
|
||||
// [f]bCC copy1MBB
|
||||
// fallthrough --> copy0MBB
|
||||
MachineBasicBlock *thisMBB = BB;
|
||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
||||
BuildMI(BB, BROpcode, 1).addMBB(sinkMBB);
|
||||
MachineFunction *F = BB->getParent();
|
||||
F->getBasicBlockList().insert(It, copy0MBB);
|
||||
F->getBasicBlockList().insert(It, sinkMBB);
|
||||
// Update machine-CFG edges
|
||||
BB->addSuccessor(copy0MBB);
|
||||
BB->addSuccessor(sinkMBB);
|
||||
|
||||
// copy0MBB:
|
||||
// %FalseValue = ...
|
||||
// # fallthrough to sinkMBB
|
||||
BB = copy0MBB;
|
||||
|
||||
// Update machine-CFG edges
|
||||
BB->addSuccessor(sinkMBB);
|
||||
|
||||
// sinkMBB:
|
||||
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
||||
// ...
|
||||
BB = sinkMBB;
|
||||
BuildMI(BB, V8::PHI, 4, MI->getOperand(0).getReg())
|
||||
.addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB)
|
||||
.addReg(MI->getOperand(1).getReg()).addMBB(thisMBB);
|
||||
|
||||
delete MI; // The pseudo instruction is gone now.
|
||||
return BB;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction Selector Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -77,7 +77,10 @@ def SDTV8cmpfcc :
|
||||
SDTypeProfile<1, 2, [SDTCisVT<0, FlagVT>, SDTCisFP<1>, SDTCisSameAs<1, 2>]>;
|
||||
def SDTV8brcc :
|
||||
SDTypeProfile<0, 3, [SDTCisVT<0, OtherVT>, SDTCisVT<1, OtherVT>,
|
||||
SDTCisVT<2, FlagVT>]>;
|
||||
SDTCisVT<2, FlagVT>]>;
|
||||
def SDTV8selectcc :
|
||||
SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>,
|
||||
SDTCisVT<3, i32>, SDTCisVT<4, FlagVT>]>;
|
||||
|
||||
def V8cmpicc : SDNode<"V8ISD::CMPICC", SDTV8cmpicc>;
|
||||
def V8cmpfcc : SDNode<"V8ISD::CMPFCC", SDTV8cmpfcc>;
|
||||
@ -90,25 +93,61 @@ def V8lo : SDNode<"V8ISD::Lo", SDTIntUnaryOp>;
|
||||
def V8ftoi : SDNode<"V8ISD::FTOI", SDTFPUnaryOp>;
|
||||
def V8itof : SDNode<"V8ISD::ITOF", SDTFPUnaryOp>;
|
||||
|
||||
def V8selecticc : SDNode<"V8ISD::SELECT_ICC", SDTV8selectcc>;
|
||||
def V8selectfcc : SDNode<"V8ISD::SELECT_FCC", SDTV8selectcc>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Pseudo instructions.
|
||||
class PseudoInstV8<string asmstr, dag ops> : InstV8 {
|
||||
class Pseudo<dag ops, string asmstr, list<dag> pattern> : InstV8 {
|
||||
let AsmString = asmstr;
|
||||
dag OperandList = ops;
|
||||
let Pattern = pattern;
|
||||
}
|
||||
def PHI : Pseudo<(ops variable_ops), "PHI", []>;
|
||||
def ADJCALLSTACKDOWN : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKDOWN $amt",[]>;
|
||||
def ADJCALLSTACKUP : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKUP $amt", []>;
|
||||
def IMPLICIT_DEF : Pseudo<(ops IntRegs:$dst), "!IMPLICIT_DEF $dst", []>;
|
||||
def FpMOVD : Pseudo<(ops DFPRegs:$dst, DFPRegs:$src),
|
||||
"!FpMOVD", []>; // pseudo 64-bit double move
|
||||
|
||||
// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded by the
|
||||
// scheduler into a branch sequence. This has to handle all permutations of
|
||||
// selection between i32/f32/f64 on ICC and FCC.
|
||||
let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler.
|
||||
def SELECT_CC_Int_ICC
|
||||
: Pseudo<(ops IntRegs:$dst, IntRegs:$T, IntRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_Int_ICC PSEUDO!",
|
||||
[(set IntRegs:$dst, (V8selecticc IntRegs:$T, IntRegs:$F,
|
||||
imm:$Cond, ICC))]>;
|
||||
def SELECT_CC_Int_FCC
|
||||
: Pseudo<(ops IntRegs:$dst, IntRegs:$T, IntRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_Int_FCC PSEUDO!",
|
||||
[(set IntRegs:$dst, (V8selectfcc IntRegs:$T, IntRegs:$F,
|
||||
imm:$Cond, FCC))]>;
|
||||
def SELECT_CC_FP_ICC
|
||||
: Pseudo<(ops FPRegs:$dst, FPRegs:$T, FPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_FP_ICC PSEUDO!",
|
||||
[(set FPRegs:$dst, (V8selecticc FPRegs:$T, FPRegs:$F,
|
||||
imm:$Cond, ICC))]>;
|
||||
def SELECT_CC_FP_FCC
|
||||
: Pseudo<(ops FPRegs:$dst, FPRegs:$T, FPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_FP_FCC PSEUDO!",
|
||||
[(set FPRegs:$dst, (V8selectfcc FPRegs:$T, FPRegs:$F,
|
||||
imm:$Cond, FCC))]>;
|
||||
def SELECT_CC_DFP_ICC
|
||||
: Pseudo<(ops DFPRegs:$dst, DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_DFP_ICC PSEUDO!",
|
||||
[(set DFPRegs:$dst, (V8selecticc DFPRegs:$T, DFPRegs:$F,
|
||||
imm:$Cond, ICC))]>;
|
||||
def SELECT_CC_DFP_FCC
|
||||
: Pseudo<(ops DFPRegs:$dst, DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_DFP_FCC PSEUDO!",
|
||||
[(set DFPRegs:$dst, (V8selectfcc DFPRegs:$T, DFPRegs:$F,
|
||||
imm:$Cond, FCC))]>;
|
||||
}
|
||||
def PHI : PseudoInstV8<"PHI", (ops variable_ops)>;
|
||||
def ADJCALLSTACKDOWN : PseudoInstV8<"!ADJCALLSTACKDOWN $amt",
|
||||
(ops i32imm:$amt)>;
|
||||
def ADJCALLSTACKUP : PseudoInstV8<"!ADJCALLSTACKUP $amt",
|
||||
(ops i32imm:$amt)>;
|
||||
//def IMPLICIT_USE : PseudoInstV8<"!IMPLICIT_USE",(ops variable_ops)>;
|
||||
def IMPLICIT_DEF : PseudoInstV8<"!IMPLICIT_DEF $dst",
|
||||
(ops IntRegs:$dst)>;
|
||||
def FpMOVD : PseudoInstV8<"!FpMOVD", // pseudo 64-bit double move
|
||||
(ops DFPRegs:$dst, DFPRegs:$src)>;
|
||||
|
||||
// Section A.3 - Synthetic Instructions, p. 85
|
||||
// special cases of JMPL:
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||||
#include "llvm/CodeGen/SSARegMap.h"
|
||||
@ -40,6 +41,9 @@ namespace V8ISD {
|
||||
|
||||
FTOI, // FP to Int within a FP register.
|
||||
ITOF, // Int to FP within a FP register.
|
||||
|
||||
SELECT_ICC, // Select between two values using the current ICC flags.
|
||||
SELECT_FCC, // Select between two values using the current FCC flags.
|
||||
};
|
||||
}
|
||||
|
||||
@ -66,6 +70,8 @@ namespace {
|
||||
virtual std::pair<SDOperand, SDOperand>
|
||||
LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth,
|
||||
SelectionDAG &DAG);
|
||||
virtual MachineBasicBlock *InsertAtEndOfBasicBlock(MachineInstr *MI,
|
||||
MachineBasicBlock *MBB);
|
||||
};
|
||||
}
|
||||
|
||||
@ -82,9 +88,9 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::ConstantPool , MVT::i32, Custom);
|
||||
|
||||
// Sparc doesn't have sext_inreg, replace them with shl/sra
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16 , Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
|
||||
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
|
||||
|
||||
// Sparc has no REM operation.
|
||||
setOperationAction(ISD::UREM, MVT::i32, Expand);
|
||||
@ -116,6 +122,10 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::BR_CC, MVT::f32, Custom);
|
||||
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
|
||||
|
||||
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
|
||||
|
||||
computeRegisterProperties();
|
||||
}
|
||||
|
||||
@ -243,22 +253,6 @@ SDOperand SparcV8TargetLowering::
|
||||
LowerOperation(SDOperand Op, SelectionDAG &DAG) {
|
||||
switch (Op.getOpcode()) {
|
||||
default: assert(0 && "Should not custom lower this!");
|
||||
case ISD::BR_CC: {
|
||||
SDOperand Chain = Op.getOperand(0);
|
||||
SDOperand CC = Op.getOperand(1);
|
||||
SDOperand LHS = Op.getOperand(2);
|
||||
SDOperand RHS = Op.getOperand(3);
|
||||
SDOperand Dest = Op.getOperand(4);
|
||||
|
||||
// Get the condition flag.
|
||||
if (LHS.getValueType() == MVT::i32) {
|
||||
SDOperand Cond = DAG.getNode(V8ISD::CMPICC, MVT::Flag, LHS, RHS);
|
||||
return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond);
|
||||
} else {
|
||||
SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
|
||||
return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond);
|
||||
}
|
||||
}
|
||||
case ISD::GlobalAddress: {
|
||||
GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
|
||||
SDOperand GA = DAG.getTargetGlobalAddress(GV, MVT::i32);
|
||||
@ -298,10 +292,134 @@ LowerOperation(SDOperand Op, SelectionDAG &DAG) {
|
||||
// Convert the int value to FP in an FP register.
|
||||
return DAG.getNode(V8ISD::ITOF, Op.getValueType(), Op);
|
||||
}
|
||||
case ISD::BR_CC: {
|
||||
SDOperand Chain = Op.getOperand(0);
|
||||
SDOperand CC = Op.getOperand(1);
|
||||
SDOperand LHS = Op.getOperand(2);
|
||||
SDOperand RHS = Op.getOperand(3);
|
||||
SDOperand Dest = Op.getOperand(4);
|
||||
|
||||
// Get the condition flag.
|
||||
if (LHS.getValueType() == MVT::i32) {
|
||||
SDOperand Cond = DAG.getNode(V8ISD::CMPICC, MVT::Flag, LHS, RHS);
|
||||
return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond);
|
||||
} else {
|
||||
SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
|
||||
return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond);
|
||||
}
|
||||
}
|
||||
case ISD::SELECT_CC: {
|
||||
SDOperand LHS = Op.getOperand(0);
|
||||
SDOperand RHS = Op.getOperand(1);
|
||||
unsigned CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
||||
SDOperand TrueVal = Op.getOperand(2);
|
||||
SDOperand FalseVal = Op.getOperand(3);
|
||||
|
||||
unsigned Opc;
|
||||
Opc = LHS.getValueType() == MVT::i32 ? V8ISD::CMPICC : V8ISD::CMPFCC;
|
||||
SDOperand CompareFlag = DAG.getNode(Opc, MVT::Flag, LHS, RHS);
|
||||
|
||||
Opc = LHS.getValueType() == MVT::i32 ?
|
||||
V8ISD::SELECT_ICC : V8ISD::SELECT_FCC;
|
||||
return DAG.getNode(Opc, TrueVal.getValueType(), TrueVal, FalseVal,
|
||||
DAG.getConstant(CC, MVT::i32), CompareFlag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MachineBasicBlock *
|
||||
SparcV8TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
|
||||
MachineBasicBlock *BB) {
|
||||
unsigned BROpcode;
|
||||
// Figure out the conditional branch opcode to use for this select_cc.
|
||||
switch (MI->getOpcode()) {
|
||||
default: assert(0 && "Unknown SELECT_CC!");
|
||||
case V8::SELECT_CC_Int_ICC:
|
||||
case V8::SELECT_CC_FP_ICC:
|
||||
case V8::SELECT_CC_DFP_ICC:
|
||||
// Integer compare.
|
||||
switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) {
|
||||
default: assert(0 && "Unknown integer condition code!");
|
||||
case ISD::SETEQ: BROpcode = V8::BE; break;
|
||||
case ISD::SETNE: BROpcode = V8::BNE; break;
|
||||
case ISD::SETLT: BROpcode = V8::BL; break;
|
||||
case ISD::SETGT: BROpcode = V8::BG; break;
|
||||
case ISD::SETLE: BROpcode = V8::BLE; break;
|
||||
case ISD::SETGE: BROpcode = V8::BGE; break;
|
||||
case ISD::SETULT: BROpcode = V8::BCS; break;
|
||||
case ISD::SETULE: BROpcode = V8::BLEU; break;
|
||||
case ISD::SETUGT: BROpcode = V8::BGU; break;
|
||||
case ISD::SETUGE: BROpcode = V8::BCC; break;
|
||||
}
|
||||
break;
|
||||
case V8::SELECT_CC_Int_FCC:
|
||||
case V8::SELECT_CC_FP_FCC:
|
||||
case V8::SELECT_CC_DFP_FCC:
|
||||
// FP compare.
|
||||
switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) {
|
||||
default: assert(0 && "Unknown fp condition code!");
|
||||
case ISD::SETEQ: BROpcode = V8::FBE; break;
|
||||
case ISD::SETNE: BROpcode = V8::FBNE; break;
|
||||
case ISD::SETLT: BROpcode = V8::FBL; break;
|
||||
case ISD::SETGT: BROpcode = V8::FBG; break;
|
||||
case ISD::SETLE: BROpcode = V8::FBLE; break;
|
||||
case ISD::SETGE: BROpcode = V8::FBGE; break;
|
||||
case ISD::SETULT: BROpcode = V8::FBUL; break;
|
||||
case ISD::SETULE: BROpcode = V8::FBULE; break;
|
||||
case ISD::SETUGT: BROpcode = V8::FBUG; break;
|
||||
case ISD::SETUGE: BROpcode = V8::FBUGE; break;
|
||||
case ISD::SETUO: BROpcode = V8::FBU; break;
|
||||
case ISD::SETO: BROpcode = V8::FBO; break;
|
||||
case ISD::SETONE: BROpcode = V8::FBLG; break;
|
||||
case ISD::SETUEQ: BROpcode = V8::FBUE; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// To "insert" a SELECT_CC instruction, we actually have to insert the diamond
|
||||
// control-flow pattern. The incoming instruction knows the destination vreg
|
||||
// to set, the condition code register to branch on, the true/false values to
|
||||
// select between, and a branch opcode to use.
|
||||
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
||||
ilist<MachineBasicBlock>::iterator It = BB;
|
||||
++It;
|
||||
|
||||
// thisMBB:
|
||||
// ...
|
||||
// TrueVal = ...
|
||||
// [f]bCC copy1MBB
|
||||
// fallthrough --> copy0MBB
|
||||
MachineBasicBlock *thisMBB = BB;
|
||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
||||
BuildMI(BB, BROpcode, 1).addMBB(sinkMBB);
|
||||
MachineFunction *F = BB->getParent();
|
||||
F->getBasicBlockList().insert(It, copy0MBB);
|
||||
F->getBasicBlockList().insert(It, sinkMBB);
|
||||
// Update machine-CFG edges
|
||||
BB->addSuccessor(copy0MBB);
|
||||
BB->addSuccessor(sinkMBB);
|
||||
|
||||
// copy0MBB:
|
||||
// %FalseValue = ...
|
||||
// # fallthrough to sinkMBB
|
||||
BB = copy0MBB;
|
||||
|
||||
// Update machine-CFG edges
|
||||
BB->addSuccessor(sinkMBB);
|
||||
|
||||
// sinkMBB:
|
||||
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
||||
// ...
|
||||
BB = sinkMBB;
|
||||
BuildMI(BB, V8::PHI, 4, MI->getOperand(0).getReg())
|
||||
.addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB)
|
||||
.addReg(MI->getOperand(1).getReg()).addMBB(thisMBB);
|
||||
|
||||
delete MI; // The pseudo instruction is gone now.
|
||||
return BB;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instruction Selector Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -77,7 +77,10 @@ def SDTV8cmpfcc :
|
||||
SDTypeProfile<1, 2, [SDTCisVT<0, FlagVT>, SDTCisFP<1>, SDTCisSameAs<1, 2>]>;
|
||||
def SDTV8brcc :
|
||||
SDTypeProfile<0, 3, [SDTCisVT<0, OtherVT>, SDTCisVT<1, OtherVT>,
|
||||
SDTCisVT<2, FlagVT>]>;
|
||||
SDTCisVT<2, FlagVT>]>;
|
||||
def SDTV8selectcc :
|
||||
SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>,
|
||||
SDTCisVT<3, i32>, SDTCisVT<4, FlagVT>]>;
|
||||
|
||||
def V8cmpicc : SDNode<"V8ISD::CMPICC", SDTV8cmpicc>;
|
||||
def V8cmpfcc : SDNode<"V8ISD::CMPFCC", SDTV8cmpfcc>;
|
||||
@ -90,25 +93,61 @@ def V8lo : SDNode<"V8ISD::Lo", SDTIntUnaryOp>;
|
||||
def V8ftoi : SDNode<"V8ISD::FTOI", SDTFPUnaryOp>;
|
||||
def V8itof : SDNode<"V8ISD::ITOF", SDTFPUnaryOp>;
|
||||
|
||||
def V8selecticc : SDNode<"V8ISD::SELECT_ICC", SDTV8selectcc>;
|
||||
def V8selectfcc : SDNode<"V8ISD::SELECT_FCC", SDTV8selectcc>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Pseudo instructions.
|
||||
class PseudoInstV8<string asmstr, dag ops> : InstV8 {
|
||||
class Pseudo<dag ops, string asmstr, list<dag> pattern> : InstV8 {
|
||||
let AsmString = asmstr;
|
||||
dag OperandList = ops;
|
||||
let Pattern = pattern;
|
||||
}
|
||||
def PHI : Pseudo<(ops variable_ops), "PHI", []>;
|
||||
def ADJCALLSTACKDOWN : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKDOWN $amt",[]>;
|
||||
def ADJCALLSTACKUP : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKUP $amt", []>;
|
||||
def IMPLICIT_DEF : Pseudo<(ops IntRegs:$dst), "!IMPLICIT_DEF $dst", []>;
|
||||
def FpMOVD : Pseudo<(ops DFPRegs:$dst, DFPRegs:$src),
|
||||
"!FpMOVD", []>; // pseudo 64-bit double move
|
||||
|
||||
// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded by the
|
||||
// scheduler into a branch sequence. This has to handle all permutations of
|
||||
// selection between i32/f32/f64 on ICC and FCC.
|
||||
let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler.
|
||||
def SELECT_CC_Int_ICC
|
||||
: Pseudo<(ops IntRegs:$dst, IntRegs:$T, IntRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_Int_ICC PSEUDO!",
|
||||
[(set IntRegs:$dst, (V8selecticc IntRegs:$T, IntRegs:$F,
|
||||
imm:$Cond, ICC))]>;
|
||||
def SELECT_CC_Int_FCC
|
||||
: Pseudo<(ops IntRegs:$dst, IntRegs:$T, IntRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_Int_FCC PSEUDO!",
|
||||
[(set IntRegs:$dst, (V8selectfcc IntRegs:$T, IntRegs:$F,
|
||||
imm:$Cond, FCC))]>;
|
||||
def SELECT_CC_FP_ICC
|
||||
: Pseudo<(ops FPRegs:$dst, FPRegs:$T, FPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_FP_ICC PSEUDO!",
|
||||
[(set FPRegs:$dst, (V8selecticc FPRegs:$T, FPRegs:$F,
|
||||
imm:$Cond, ICC))]>;
|
||||
def SELECT_CC_FP_FCC
|
||||
: Pseudo<(ops FPRegs:$dst, FPRegs:$T, FPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_FP_FCC PSEUDO!",
|
||||
[(set FPRegs:$dst, (V8selectfcc FPRegs:$T, FPRegs:$F,
|
||||
imm:$Cond, FCC))]>;
|
||||
def SELECT_CC_DFP_ICC
|
||||
: Pseudo<(ops DFPRegs:$dst, DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_DFP_ICC PSEUDO!",
|
||||
[(set DFPRegs:$dst, (V8selecticc DFPRegs:$T, DFPRegs:$F,
|
||||
imm:$Cond, ICC))]>;
|
||||
def SELECT_CC_DFP_FCC
|
||||
: Pseudo<(ops DFPRegs:$dst, DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_DFP_FCC PSEUDO!",
|
||||
[(set DFPRegs:$dst, (V8selectfcc DFPRegs:$T, DFPRegs:$F,
|
||||
imm:$Cond, FCC))]>;
|
||||
}
|
||||
def PHI : PseudoInstV8<"PHI", (ops variable_ops)>;
|
||||
def ADJCALLSTACKDOWN : PseudoInstV8<"!ADJCALLSTACKDOWN $amt",
|
||||
(ops i32imm:$amt)>;
|
||||
def ADJCALLSTACKUP : PseudoInstV8<"!ADJCALLSTACKUP $amt",
|
||||
(ops i32imm:$amt)>;
|
||||
//def IMPLICIT_USE : PseudoInstV8<"!IMPLICIT_USE",(ops variable_ops)>;
|
||||
def IMPLICIT_DEF : PseudoInstV8<"!IMPLICIT_DEF $dst",
|
||||
(ops IntRegs:$dst)>;
|
||||
def FpMOVD : PseudoInstV8<"!FpMOVD", // pseudo 64-bit double move
|
||||
(ops DFPRegs:$dst, DFPRegs:$src)>;
|
||||
|
||||
// Section A.3 - Synthetic Instructions, p. 85
|
||||
// special cases of JMPL:
|
||||
|
Loading…
Reference in New Issue
Block a user