mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-21 03:29:40 +00:00
- Add sugregister logic to handle f64=(f32,f32).
- Support mips1 like load/store of doubles: Instead of: sdc $f0, X($3) Generate: swc $f0, X($3) swc $f1, X+4($3) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@89322 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0046de0550
commit
2045c47aff
@ -365,6 +365,8 @@ void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
|
|||||||
case MachineOperand::MO_ConstantPoolIndex:
|
case MachineOperand::MO_ConstantPoolIndex:
|
||||||
O << MAI->getPrivateGlobalPrefix() << "CPI"
|
O << MAI->getPrivateGlobalPrefix() << "CPI"
|
||||||
<< getFunctionNumber() << "_" << MO.getIndex();
|
<< getFunctionNumber() << "_" << MO.getIndex();
|
||||||
|
if (MO.getOffset())
|
||||||
|
O << "+" << MO.getOffset();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -90,6 +90,8 @@ private:
|
|||||||
bool SelectAddr(SDValue Op, SDValue N,
|
bool SelectAddr(SDValue Op, SDValue N,
|
||||||
SDValue &Base, SDValue &Offset);
|
SDValue &Base, SDValue &Offset);
|
||||||
|
|
||||||
|
SDNode *SelectLoadFp64(SDValue N);
|
||||||
|
SDNode *SelectStoreFp64(SDValue N);
|
||||||
|
|
||||||
// getI32Imm - Return a target constant with the specified
|
// getI32Imm - Return a target constant with the specified
|
||||||
// value, of type i32.
|
// value, of type i32.
|
||||||
@ -198,6 +200,121 @@ SelectAddr(SDValue Op, SDValue Addr, SDValue &Offset, SDValue &Base)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDNode *MipsDAGToDAGISel::SelectLoadFp64(SDValue N) {
|
||||||
|
MVT::SimpleValueType NVT =
|
||||||
|
N.getNode()->getValueType(0).getSimpleVT().SimpleTy;
|
||||||
|
|
||||||
|
if (!Subtarget.isMips1() || NVT != MVT::f64)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!Predicate_unindexedload(N.getNode()) ||
|
||||||
|
!Predicate_load(N.getNode()))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
SDValue Chain = N.getOperand(0);
|
||||||
|
SDValue N1 = N.getOperand(1);
|
||||||
|
SDValue Offset0, Offset1, Base;
|
||||||
|
|
||||||
|
if (!SelectAddr(N, N1, Offset0, Base) ||
|
||||||
|
N1.getValueType() != MVT::i32)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1);
|
||||||
|
MemRefs0[0] = cast<MemSDNode>(N)->getMemOperand();
|
||||||
|
DebugLoc dl = N.getDebugLoc();
|
||||||
|
|
||||||
|
// The second load should start after for 4 bytes.
|
||||||
|
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Offset0))
|
||||||
|
Offset1 = CurDAG->getTargetConstant(C->getSExtValue()+4, MVT::i32);
|
||||||
|
else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Offset0))
|
||||||
|
Offset1 = CurDAG->getTargetConstantPool(CP->getConstVal(),
|
||||||
|
MVT::i32,
|
||||||
|
CP->getAlignment(),
|
||||||
|
CP->getOffset()+4,
|
||||||
|
CP->getTargetFlags());
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Instead of:
|
||||||
|
// ldc $f0, X($3)
|
||||||
|
// Generate:
|
||||||
|
// lwc $f0, X($3)
|
||||||
|
// lwc $f1, X+4($3)
|
||||||
|
SDNode *LD0 = CurDAG->getMachineNode(Mips::LWC1, dl, MVT::f32,
|
||||||
|
MVT::Other, Offset0, Base, Chain);
|
||||||
|
SDValue Undef = SDValue(CurDAG->getMachineNode(TargetInstrInfo::IMPLICIT_DEF,
|
||||||
|
dl, NVT), 0);
|
||||||
|
SDValue I0 = CurDAG->getTargetInsertSubreg(Mips::SUBREG_FPEVEN, dl,
|
||||||
|
MVT::f64, Undef, SDValue(LD0, 0));
|
||||||
|
|
||||||
|
SDNode *LD1 = CurDAG->getMachineNode(Mips::LWC1, dl, MVT::f32,
|
||||||
|
MVT::Other, Offset1, Base, SDValue(LD0, 1));
|
||||||
|
SDValue I1 = CurDAG->getTargetInsertSubreg(Mips::SUBREG_FPODD, dl,
|
||||||
|
MVT::f64, I0, SDValue(LD1, 0));
|
||||||
|
|
||||||
|
ReplaceUses(N, I1);
|
||||||
|
ReplaceUses(N.getValue(1), Chain);
|
||||||
|
cast<MachineSDNode>(LD0)->setMemRefs(MemRefs0, MemRefs0 + 1);
|
||||||
|
cast<MachineSDNode>(LD1)->setMemRefs(MemRefs0, MemRefs0 + 1);
|
||||||
|
return I1.getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
SDNode *MipsDAGToDAGISel::SelectStoreFp64(SDValue N) {
|
||||||
|
|
||||||
|
if (!Subtarget.isMips1() ||
|
||||||
|
N.getOperand(1).getValueType() != MVT::f64)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
SDValue Chain = N.getOperand(0);
|
||||||
|
|
||||||
|
if (!Predicate_unindexedstore(N.getNode()) ||
|
||||||
|
!Predicate_store(N.getNode()))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
SDValue N1 = N.getOperand(1);
|
||||||
|
SDValue N2 = N.getOperand(2);
|
||||||
|
SDValue Offset0, Offset1, Base;
|
||||||
|
|
||||||
|
if (!SelectAddr(N, N2, Offset0, Base) ||
|
||||||
|
N1.getValueType() != MVT::f64 ||
|
||||||
|
N2.getValueType() != MVT::i32)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1);
|
||||||
|
MemRefs0[0] = cast<MemSDNode>(N)->getMemOperand();
|
||||||
|
DebugLoc dl = N.getDebugLoc();
|
||||||
|
|
||||||
|
// Get the even and odd part from the f64 register
|
||||||
|
SDValue FPOdd = CurDAG->getTargetExtractSubreg(Mips::SUBREG_FPODD,
|
||||||
|
dl, MVT::f32, N1);
|
||||||
|
SDValue FPEven = CurDAG->getTargetExtractSubreg(Mips::SUBREG_FPEVEN,
|
||||||
|
dl, MVT::f32, N1);
|
||||||
|
|
||||||
|
// The second store should start after for 4 bytes.
|
||||||
|
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Offset0))
|
||||||
|
Offset1 = CurDAG->getTargetConstant(C->getSExtValue()+4, MVT::i32);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Instead of:
|
||||||
|
// sdc $f0, X($3)
|
||||||
|
// Generate:
|
||||||
|
// swc $f0, X($3)
|
||||||
|
// swc $f1, X+4($3)
|
||||||
|
SDValue Ops0[] = { FPEven, Offset0, Base, Chain };
|
||||||
|
Chain = SDValue(CurDAG->getMachineNode(Mips::SWC1, dl,
|
||||||
|
MVT::Other, Ops0, 4), 0);
|
||||||
|
cast<MachineSDNode>(Chain.getNode())->setMemRefs(MemRefs0, MemRefs0 + 1);
|
||||||
|
|
||||||
|
SDValue Ops1[] = { FPOdd, Offset1, Base, Chain };
|
||||||
|
Chain = SDValue(CurDAG->getMachineNode(Mips::SWC1, dl,
|
||||||
|
MVT::Other, Ops1, 4), 0);
|
||||||
|
cast<MachineSDNode>(Chain.getNode())->setMemRefs(MemRefs0, MemRefs0 + 1);
|
||||||
|
|
||||||
|
ReplaceUses(N.getValue(0), Chain);
|
||||||
|
return Chain.getNode();
|
||||||
|
}
|
||||||
|
|
||||||
/// Select instructions not customized! Used for
|
/// Select instructions not customized! Used for
|
||||||
/// expanded, promoted and normal instructions
|
/// expanded, promoted and normal instructions
|
||||||
SDNode* MipsDAGToDAGISel::Select(SDValue N) {
|
SDNode* MipsDAGToDAGISel::Select(SDValue N) {
|
||||||
@ -345,6 +462,18 @@ SDNode* MipsDAGToDAGISel::Select(SDValue N) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ISD::LOAD:
|
||||||
|
if (SDNode *ResNode = SelectLoadFp64(N))
|
||||||
|
return ResNode;
|
||||||
|
// Other cases are autogenerated.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ISD::STORE:
|
||||||
|
if (SDNode *ResNode = SelectStoreFp64(N))
|
||||||
|
return ResNode;
|
||||||
|
// Other cases are autogenerated.
|
||||||
|
break;
|
||||||
|
|
||||||
/// Handle direct and indirect calls when using PIC. On PIC, when
|
/// Handle direct and indirect calls when using PIC. On PIC, when
|
||||||
/// GOT is smaller than about 64k (small code) the GA target is
|
/// GOT is smaller than about 64k (small code) the GA target is
|
||||||
/// loaded with only one instruction. Otherwise GA's target must
|
/// loaded with only one instruction. Otherwise GA's target must
|
||||||
|
@ -23,6 +23,15 @@ class MipsSubtarget;
|
|||||||
class TargetInstrInfo;
|
class TargetInstrInfo;
|
||||||
class Type;
|
class Type;
|
||||||
|
|
||||||
|
namespace Mips {
|
||||||
|
/// SubregIndex - The index of various sized subregister classes. Note that
|
||||||
|
/// these indices must be kept in sync with the class indices in the
|
||||||
|
/// MipsRegisterInfo.td file.
|
||||||
|
enum SubregIndex {
|
||||||
|
SUBREG_FPEVEN = 1, SUBREG_FPODD = 2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
struct MipsRegisterInfo : public MipsGenRegisterInfo {
|
struct MipsRegisterInfo : public MipsGenRegisterInfo {
|
||||||
const MipsSubtarget &Subtarget;
|
const MipsSubtarget &Subtarget;
|
||||||
const TargetInstrInfo &TII;
|
const TargetInstrInfo &TII;
|
||||||
|
@ -17,6 +17,12 @@ class MipsReg<string n> : Register<n> {
|
|||||||
let Namespace = "Mips";
|
let Namespace = "Mips";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MipsRegWithSubRegs<string n, list<Register> subregs>
|
||||||
|
: RegisterWithSubRegs<n, subregs> {
|
||||||
|
field bits<5> Num;
|
||||||
|
let Namespace = "Mips";
|
||||||
|
}
|
||||||
|
|
||||||
// Mips CPU Registers
|
// Mips CPU Registers
|
||||||
class MipsGPRReg<bits<5> num, string n> : MipsReg<n> {
|
class MipsGPRReg<bits<5> num, string n> : MipsReg<n> {
|
||||||
let Num = num;
|
let Num = num;
|
||||||
@ -28,9 +34,9 @@ class FPR<bits<5> num, string n> : MipsReg<n> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mips 64-bit (aliased) FPU Registers
|
// Mips 64-bit (aliased) FPU Registers
|
||||||
class AFPR<bits<5> num, string n, list<Register> aliases> : MipsReg<n> {
|
class AFPR<bits<5> num, string n, list<Register> subregs>
|
||||||
|
: MipsRegWithSubRegs<n, subregs> {
|
||||||
let Num = num;
|
let Num = num;
|
||||||
let Aliases = aliases;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -134,6 +140,23 @@ let Namespace = "Mips" in {
|
|||||||
def FCR31 : Register<"31">;
|
def FCR31 : Register<"31">;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Subregister Set Definitions
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
def mips_subreg_fpeven : PatLeaf<(i32 1)>;
|
||||||
|
def mips_subreg_fpodd : PatLeaf<(i32 2)>;
|
||||||
|
|
||||||
|
def : SubRegSet<1, [D0, D1, D2, D3, D4, D5, D6, D7,
|
||||||
|
D8, D9, D10, D11, D12, D13, D14, D15],
|
||||||
|
[F0, F2, F4, F6, F8, F10, F12, F14,
|
||||||
|
F16, F18, F20, F22, F24, F26, F28, F30]>;
|
||||||
|
|
||||||
|
def : SubRegSet<2, [D0, D1, D2, D3, D4, D5, D6, D7,
|
||||||
|
D8, D9, D10, D11, D12, D13, D14, D15],
|
||||||
|
[F1, F3, F5, F7, F9, F11, F13, F15,
|
||||||
|
F17, F19, F21, F23, F25, F27, F29, F31]>;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Register Classes
|
// Register Classes
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -232,6 +255,7 @@ def AFGR64 : RegisterClass<"Mips", [f64], 64,
|
|||||||
// Reserved
|
// Reserved
|
||||||
D15]>
|
D15]>
|
||||||
{
|
{
|
||||||
|
let SubRegClassList = [FGR32, FGR32];
|
||||||
let MethodProtos = [{
|
let MethodProtos = [{
|
||||||
iterator allocation_order_end(const MachineFunction &MF) const;
|
iterator allocation_order_end(const MachineFunction &MF) const;
|
||||||
}];
|
}];
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
; Double return in abicall (default)
|
; Double return in abicall (default)
|
||||||
; RUN: llc < %s -march=mips
|
; RUN: llc < %s -march=mips | FileCheck %s
|
||||||
; PR2615
|
; PR2615
|
||||||
; XFAIL: *
|
|
||||||
|
|
||||||
define double @main(...) {
|
define double @main(...) {
|
||||||
entry:
|
entry:
|
||||||
|
Loading…
Reference in New Issue
Block a user