Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp =================================================================== --- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -125,6 +125,12 @@ Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 }; + static unsigned IntPairRegs[] = { + Sparc::G0_G1, Sparc::G2_G3, Sparc::G4_G5, Sparc::G6_G7, + Sparc::O0_O1, Sparc::O2_O3, Sparc::O4_O5, Sparc::O6_O7, + Sparc::L0_L1, Sparc::L2_L3, Sparc::L4_L5, Sparc::L6_L7, + Sparc::I0_I1, Sparc::I2_I3, Sparc::I4_I5, Sparc::I6_I7}; + /// SparcOperand - Instances of this class represent a parsed Sparc machine /// instruction. class SparcOperand : public MCParsedAsmOperand { @@ -132,6 +138,7 @@ enum RegisterKind { rk_None, rk_IntReg, + rk_IntPairReg, rk_FloatReg, rk_DoubleReg, rk_QuadReg, @@ -185,6 +192,10 @@ bool isMEMrr() const { return Kind == k_MemoryReg; } bool isMEMri() const { return Kind == k_MemoryImm; } + bool isIntReg() const { + return (Kind == k_Register && Reg.Kind == rk_IntReg); + } + bool isFloatReg() const { return (Kind == k_Register && Reg.Kind == rk_FloatReg); } @@ -315,6 +326,25 @@ return Op; } + static bool MorphToIntPairReg(SparcOperand &Op) { + unsigned Reg = Op.getReg(); + assert(Op.Reg.Kind == rk_IntReg); + unsigned regIdx = 32; + if (Reg >= Sparc::G0 && Reg <= Sparc::G7) + regIdx = Reg - Sparc::G0; + else if (Reg >= Sparc::O0 && Reg <= Sparc::O7) + regIdx = Reg - Sparc::O0 + 8; + else if (Reg >= Sparc::L0 && Reg <= Sparc::L7) + regIdx = Reg - Sparc::L0 + 16; + else if (Reg >= Sparc::I0 && Reg <= Sparc::I7) + regIdx = Reg - Sparc::I0 + 24; + if (regIdx % 2 || regIdx > 31) + return false; + Op.Reg.RegNum = IntPairRegs[regIdx / 2]; + Op.Reg.Kind = rk_IntPairReg; + return true; + } + static bool MorphToDoubleReg(SparcOperand &Op) { unsigned Reg = Op.getReg(); assert(Op.Reg.Kind == rk_FloatReg); @@ -932,5 +962,9 @@ break; } } + if (Op.isIntReg() && Kind == MCK_IntPair) { + if (SparcOperand::MorphToIntPairReg(Op)) + return MCTargetAsmParser::Match_Success; + } return Match_InvalidOperand; } Index: lib/Target/Sparc/Disassembler/SparcDisassembler.cpp =================================================================== --- lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +++ lib/Target/Sparc/Disassembler/SparcDisassembler.cpp @@ -106,6 +106,13 @@ static const unsigned FCCRegDecoderTable[] = { SP::FCC0, SP::FCC1, SP::FCC2, SP::FCC3 }; +static const uint16_t IntPairDecoderTable[] = { + SP::G0_G1, SP::G2_G3, SP::G4_G5, SP::G6_G7, + SP::O0_O1, SP::O2_O3, SP::O4_O5, SP::O6_O7, + SP::L0_L1, SP::L2_L3, SP::L4_L5, SP::L6_L7, + SP::I0_I1, SP::I2_I3, SP::I4_I5, SP::I6_I7, +}; + static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, @@ -176,9 +183,25 @@ return MCDisassembler::Success; } +static DecodeStatus DecodeIntPairRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + if (RegNo > 31) + return MCDisassembler::Fail; + + if ((RegNo & 1)) + S = MCDisassembler::SoftFail; + + unsigned RegisterPair = IntPairDecoderTable[RegNo/2]; + Inst.addOperand(MCOperand::CreateReg(RegisterPair)); + return S; +} static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeLoadIntPair(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder); static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeLoadDFP(MCInst &Inst, unsigned insn, uint64_t Address, @@ -187,6 +210,8 @@ const void *Decoder); static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeStoreIntPair(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeStoreFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeStoreDFP(MCInst &Inst, unsigned insn, @@ -298,6 +323,12 @@ DecodeIntRegsRegisterClass); } +static DecodeStatus DecodeLoadIntPair(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, true, + DecodeIntPairRegisterClass); +} + static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder) { return DecodeMem(Inst, insn, Address, Decoder, true, @@ -322,6 +353,12 @@ DecodeIntRegsRegisterClass); } +static DecodeStatus DecodeStoreIntPair(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, false, + DecodeIntPairRegisterClass); +} + static DecodeStatus DecodeStoreFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder) { return DecodeMem(Inst, insn, Address, Decoder, false, Index: lib/Target/Sparc/SparcInstrInfo.td =================================================================== --- lib/Target/Sparc/SparcInstrInfo.td +++ lib/Target/Sparc/SparcInstrInfo.td @@ -423,6 +423,17 @@ defm LD : Load<"ld", 0b000000, load, IntRegs, i32>; } +let DecoderMethod = "DecodeLoadIntPair" in { + def LDDrr : F3_1<3, 0b000011, + (outs IntPair:$dst), (ins MEMrr:$addr), + "ldd [$addr], $dst", + []>; + def LDDri : F3_2<3, 0b000011, + (outs IntPair:$dst), (ins MEMri:$addr), + "ldd [$addr], $dst", + []>; +} + // Section B.2 - Load Floating-point Instructions, p. 92 let DecoderMethod = "DecodeLoadFP" in defm LDF : Load<"ld", 0b100000, load, FPRegs, f32>; @@ -439,6 +450,26 @@ defm ST : Store<"st", 0b000100, store, IntRegs, i32>; } +let DecoderMethod = "DecodeStoreIntPair" in { + def STDrr : F3_1<3, 0b000111, + (outs), (ins MEMrr:$addr, IntPair:$rd), + "std $rd, [$addr]", + []>; + def STDri : F3_2<3, 0b000111, + (outs), (ins MEMri:$addr, IntPair:$rd), + "std $rd, [$addr]", + []>; +} + +// Define 64bit store/loads, but for 32bit sparc only. +let Predicates = [Is32Bit, HasNoV9] in { + def : Pat<(i64 (load ADDRri:$addr)), (LDDri ADDRri:$addr)>; + def : Pat<(i64 (load ADDRrr:$addr)), (LDDrr ADDRrr:$addr)>; + + def : Pat<(store ADDRri:$addr, i64:$rd), (STDri ADDRri:$addr, i64:$rd)>; + def : Pat<(store ADDRrr:$addr, i64:$rd), (STDrr ADDRrr:$addr, i64:$rd)>; +} + // Section B.5 - Store Floating-point Instructions, p. 97 let DecoderMethod = "DecodeStoreFP" in defm STF : Store<"st", 0b100100, store, FPRegs, f32>; Index: lib/Target/Sparc/SparcRegisterInfo.td =================================================================== --- lib/Target/Sparc/SparcRegisterInfo.td +++ lib/Target/Sparc/SparcRegisterInfo.td @@ -32,6 +32,12 @@ // Ri - 32-bit integer registers class Ri Enc, string n> : SparcReg; +// Rdi - pairs of 32-bit integer registers +class Rdi Enc, string n, list subregs> : SparcReg { + let SubRegs = subregs; + let SubRegIndices = [sub_even, sub_odd]; + let CoveredBySubRegs = 1; +} // Rf - 32-bit floating-point registers class Rf Enc, string n> : SparcReg; @@ -180,6 +186,24 @@ def Q14 : Rq<25, "F56", [D28, D29]>; def Q15 : Rq<29, "F60", [D30, D31]>; +// Aliases of the integer registers used for LDD/STD double-word operations +def G0_G1 : Rdi<0, "G0", [G0, G1]>; +def G2_G3 : Rdi<2, "G2", [G2, G3]>; +def G4_G5 : Rdi<4, "G4", [G4, G5]>; +def G6_G7 : Rdi<6, "G6", [G6, G7]>; +def O0_O1 : Rdi<8, "O0", [O0, O1]>; +def O2_O3 : Rdi<10, "O2", [O2, O3]>; +def O4_O5 : Rdi<12, "O4", [O4, O5]>; +def O6_O7 : Rdi<14, "O6", [O6, O7]>; +def L0_L1 : Rdi<16, "L0", [L0, L1]>; +def L2_L3 : Rdi<18, "L2", [L2, L3]>; +def L4_L5 : Rdi<20, "L4", [L4, L5]>; +def L6_L7 : Rdi<22, "L6", [L6, L7]>; +def I0_I1 : Rdi<24, "I0", [I0, I1]>; +def I2_I3 : Rdi<26, "I2", [I2, I3]>; +def I4_I5 : Rdi<28, "I4", [I4, I5]>; +def I6_I7 : Rdi<30, "I6", [I6, I7]>; + // Register classes. // // FIXME: the register order should be defined in terms of the preferred @@ -194,6 +218,12 @@ (sequence "L%u", 0, 7), (sequence "O%u", 0, 7))>; +def IntPair : RegisterClass<"SP", [i64], 64, + (add G0_G1, G2_G3, G4_G5, G6_G7, + O0_O1, O2_O3, O4_O5, O6_O7, + L0_L1, L2_L3, L4_L5, L6_L7, + I0_I1, I2_I3, I4_I5, I6_I7)>; + // Register class for 64-bit mode, with a 64-bit spill slot size. // These are the same as the 32-bit registers, so TableGen will consider this // to be a sub-class of IntRegs. That works out because requiring a 64-bit Index: test/MC/Disassembler/Sparc/sparc-mem.txt =================================================================== --- test/MC/Disassembler/Sparc/sparc-mem.txt +++ test/MC/Disassembler/Sparc/sparc-mem.txt @@ -161,3 +161,21 @@ # CHECK: swap [%g1], %o2 0xd4 0x78 0x60 0x00 + +# CHECK: ldd [%i0+%l6], %o2 +0xd4 0x1e 0x00 0x16 + +# CHECK: ldd [%i0+32], %o2 +0xd4 0x1e 0x20 0x20 + +# CHECK: ldd [%g1], %o2 +0xd4 0x18 0x60 0x00 + +# CHECK: std %o2, [%i0+%l6] +0xd4 0x3e 0x00 0x16 + +# CHECK: std %o2, [%i0+32] +0xd4 0x3e 0x20 0x20 + +# CHECK: std %o2, [%g1] +0xd4 0x38 0x60 0x00 Index: test/MC/Sparc/sparc-mem-instructions.s =================================================================== --- test/MC/Sparc/sparc-mem-instructions.s +++ test/MC/Sparc/sparc-mem-instructions.s @@ -36,6 +36,13 @@ ! CHECK: ld [%g1], %o2 ! encoding: [0xd4,0x00,0x60,0x00] ld [%g1], %o2 + ! CHECK: ldd [%i0+%l6], %o2 ! encoding: [0xd4,0x1e,0x00,0x16] + ldd [%i0 + %l6], %o2 + ! CHECK: ldd [%i0+32], %o2 ! encoding: [0xd4,0x1e,0x20,0x20] + ldd [%i0 + 32], %o2 + ! CHECK: ldd [%g1], %o2 ! encoding: [0xd4,0x18,0x60,0x00] + ldd [%g1], %o2 + ! CHECK: stb %o2, [%i0+%l6] ! encoding: [0xd4,0x2e,0x00,0x16] stb %o2, [%i0 + %l6] ! CHECK: stb %o2, [%i0+32] ! encoding: [0xd4,0x2e,0x20,0x20] @@ -56,3 +63,10 @@ st %o2, [%i0 + 32] ! CHECK: st %o2, [%g1] ! encoding: [0xd4,0x20,0x60,0x00] st %o2, [%g1] + + ! CHECK: std %o2, [%i0+%l6] ! encoding: [0xd4,0x3e,0x00,0x16] + std %o2, [%i0 + %l6] + ! CHECK: std %o2, [%i0+32] ! encoding: [0xd4,0x3e,0x20,0x20] + std %o2, [%i0 + 32] + ! CHECK: std %o2, [%g1] ! encoding: [0xd4,0x38,0x60,0x00] + std %o2, [%g1]