Pairing Registers on a Target Similar to Mips?

I’m working on a target based on the MIPS target, and when I copy f64 values into 32 bit registers for calling functions, I need the operation to work on a of 32 bit registers (because the language I’m translating to isn’t actually mips). I’ve been looking at how to do this, but I haven’t been able to figure it out. Since the Mips target code is still really close to mine, I’ll use it’s code to explain relavent details. Any help would be highly appreciated.

The idea I tried to implement to accomplish this is to create a 64 bit register class that is set up to span two 32 bit registers in the same way as the 64 bit floats span two 32 bit floating point registers in mips. Creating the register class is easy enough to implement in the RegisterInfo.td file.

The next thing I wanted to do is create a Pseudo-Element similar to the ExtractElementF64 in mips. I added the following Code to InstrFPU.td (and added the CopyF64 ISD to another file):

def SDT_MipsCopyF64 : SDTypeProfile<1, 1, [SDTCisVT<0, i64>,
SDTCisVT<1, f64>]>;

def MipsCopyF64 : SDNode<“MIPSISD::CopyF64”,
SDT_MIPSCopyF64>;

I also changed CPU64Regs to CPU64PRegs ( My 64 bit paired register class) in the DMFC1 rule for testing.

Next, I added the code in ExpandPseudo to use the following pseudo instruction expansion:

void MipsExpandPseudo::ExpandCopyF64(MachineBasicBlock& MBB,
MachineBasicBlock::iterator I) {
unsigned DstReg = I->getOperand(0).getReg();
unsigned SrcReg = I->getOperand(1).getReg();
const MCInstrDesc& Dmfc1Tdd = TII->get(MIPS::DMFC1);

DebugLoc dl = I->getDebugLoc();
const uint16_t* SubReg = TM.getRegisterInfo()->getSubRegisters(SrcReg);

BuildMI(MBB, I, dl, Dmfc1Tdd, DstReg).addReg(*SubReg);
}

Finally, I want to add the rule to ISelLowering to actually use these rules. Under the CCValAssign::Full case in the LowerCall function, here is the old code:
SDValue Lo = DAG.getNode(MIPSISD::ExtractElementF64, dl, MVT::i32,
Arg, DAG.getConstant(0, MVT::i32));
SDValue Hi = DAG.getNode(MIPSISD::ExtractElementF64, dl, MVT::i32,
Arg, DAG.getConstant(1, MVT::i32));

if (!Subtarget->isLittle())
std::swap(Lo, Hi);

unsigned LocRegLo = VA.getLocReg();
unsigned LocRegHigh = getNextIntArgReg(LocRegLo);

RegsToPass.push_back(std::make_pair(LocRegLo, Lo));
RegsToPass.push_back(std::make_pair(LocRegHigh, Hi));

I added this SDValue:
SDValue Num = DAG.getNode(MIPSISD::CopyF64,dl,MVT::i32, Arg);

But I need to create a Hi and a Lo SDValue to add to the RegsToPass pairs seen in the code above. If someone would help me figure out what goes here, I would be very thankful:
SDValue Hi = ?
SDValue Lo = ?

Ryan,

I don’t think I fully understand the problem you described, but please see the comments below.
Hope this helps you solve the problem.

I’m working on a target based on the MIPS target, and when I copy f64 values into 32 bit registers for calling functions, I need the operation to work on a of 32 bit registers (because the language I’m translating to isn’t actually mips). I’ve been looking at how to do this, but I haven’t been able to figure it out. Since the Mips target code is still really close to mine, I’ll use it’s code to explain relavent details. Any help would be highly appreciated.

The idea I tried to implement to accomplish this is to create a 64 bit register class that is set up to span two 32 bit registers in the same way as the 64 bit floats span two 32 bit floating point registers in mips. Creating the register class is easy enough to implement in the RegisterInfo.td file.

The next thing I wanted to do is create a Pseudo-Element similar to the ExtractElementF64 in mips. I added the following Code to InstrFPU.td (and added the CopyF64 ISD to another file):

def SDT_MipsCopyF64 : SDTypeProfile<1, 1, [SDTCisVT<0, i64>,
SDTCisVT<1, f64>]>;

def MipsCopyF64 : SDNode<“MIPSISD::CopyF64”,
SDT_MIPSCopyF64>;

I also changed CPU64Regs to CPU64PRegs ( My 64 bit paired register class) in the DMFC1 rule for testing.

Next, I added the code in ExpandPseudo to use the following pseudo instruction expansion:

void MipsExpandPseudo::ExpandCopyF64(MachineBasicBlock& MBB,
MachineBasicBlock::iterator I) {
unsigned DstReg = I->getOperand(0).getReg();
unsigned SrcReg = I->getOperand(1).getReg();
const MCInstrDesc& Dmfc1Tdd = TII->get(MIPS::DMFC1);

DebugLoc dl = I->getDebugLoc();
const uint16_t* SubReg = TM.getRegisterInfo()->getSubRegisters(SrcReg);

BuildMI(MBB, I, dl, Dmfc1Tdd, DstReg).addReg(*SubReg);
}

If I understand correctly what you are trying to do, DMFC1 is supposed to read a f64 register and copy it to a pair of i32 registers. This code doesn’t seem to be doing that. Why do you need a sub-register of SrcReg, if it is a f64 register?

Finally, I want to add the rule to ISelLowering to actually use these rules. Under the CCValAssign::Full case in the LowerCall function, here is the old code:
SDValue Lo = DAG.getNode(MIPSISD::ExtractElementF64, dl, MVT::i32,
Arg, DAG.getConstant(0, MVT::i32));
SDValue Hi = DAG.getNode(MIPSISD::ExtractElementF64, dl, MVT::i32,
Arg, DAG.getConstant(1, MVT::i32));

if (!Subtarget->isLittle())
std::swap(Lo, Hi);

unsigned LocRegLo = VA.getLocReg();
unsigned LocRegHigh = getNextIntArgReg(LocRegLo);

RegsToPass.push_back(std::make_pair(LocRegLo, Lo));
RegsToPass.push_back(std::make_pair(LocRegHigh, Hi));

I added this SDValue:
SDValue Num = DAG.getNode(MIPSISD::CopyF64,dl,MVT::i32, Arg);

Doesn’t this code violate SDT_MipsCopyF64’s constraint? CopyF64’s value type should be i64, but the value type of the node created is i32.

But I need to create a Hi and a Lo SDValue to add to the RegsToPass pairs seen in the code above. If someone would help me figure out what goes here, I would be very thankful:
SDValue Hi = ?
SDValue Lo = ?

Is it possible to just emit a DMFC1 instruction with physical register operands?
Something like this:

(A0, A1) = DMFC1 vreg0
JALR T9, A0, A1

I think it’s easier than trying to force or guide register allocator to assign successive even-odd i32 registers to DMFC1’s destination registers.

I fixed some of the clear issues you mentioned, I think I was messing with the code and when I sent the email it was in a state that didn’t quite make sense for the reasons you mentioned. I think you’re approach of using physical register operands would work, if I can implement a multiple destination DMC1 instruction, or get the superRegister that I created which spans my calculated argument registers.

I don’t see any examples of multiple destination instructions, and I don’t know how to implement them in the DAG, so the second option seems pretty viable. If I have two registers (like a0 and a1), how do I get the register that spans them?