Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp =================================================================== --- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -150,6 +150,22 @@ Sparc::L0_L1, Sparc::L2_L3, Sparc::L4_L5, Sparc::L6_L7, Sparc::I0_I1, Sparc::I2_I3, Sparc::I4_I5, Sparc::I6_I7}; + static const MCPhysReg CoProRegs[32] = { + Sparc::C0, Sparc::C1, Sparc::C2, Sparc::C3, + Sparc::C4, Sparc::C5, Sparc::C6, Sparc::C7, + Sparc::C8, Sparc::C9, Sparc::C10, Sparc::C11, + Sparc::C12, Sparc::C13, Sparc::C14, Sparc::C15, + Sparc::C16, Sparc::C17, Sparc::C18, Sparc::C19, + Sparc::C20, Sparc::C21, Sparc::C22, Sparc::C23, + Sparc::C24, Sparc::C25, Sparc::C26, Sparc::C27, + Sparc::C28, Sparc::C29, Sparc::C30, Sparc::C31 }; + + static const MCPhysReg CoProPairRegs[] = { + Sparc::C0_C1, Sparc::C2_C3, Sparc::C4_C5, Sparc::C6_C7, + Sparc::C8_C9, Sparc::C10_C11, Sparc::C12_C13, Sparc::C14_C15, + Sparc::C16_C17, Sparc::C18_C19, Sparc::C20_C21, Sparc::C22_C23, + Sparc::C24_C25, Sparc::C26_C27, Sparc::C28_C29, Sparc::C30_C31}; + /// SparcOperand - Instances of this class represent a parsed Sparc machine /// instruction. class SparcOperand : public MCParsedAsmOperand { @@ -161,6 +177,8 @@ rk_FloatReg, rk_DoubleReg, rk_QuadReg, + rk_CoProReg, + rk_CoProPairReg, rk_Special, }; @@ -224,6 +242,9 @@ || Reg.Kind == rk_DoubleReg)); } + bool isCoProReg() const { + return (Kind == k_Register && Reg.Kind == rk_CoProReg); + } StringRef getToken() const { assert(Kind == k_Token && "Invalid access!"); @@ -398,6 +419,19 @@ return true; } + static bool MorphToCoProPairReg(SparcOperand &Op) { + unsigned Reg = Op.getReg(); + assert(Op.Reg.Kind == rk_CoProReg); + unsigned regIdx = 32; + if (Reg >= Sparc::C0 && Reg <= Sparc::C31) + regIdx = Reg - Sparc::C0; + if (regIdx % 2 || regIdx > 31) + return false; + Op.Reg.RegNum = CoProPairRegs[regIdx / 2]; + Op.Reg.Kind = rk_CoProPairReg; + return true; + } + static std::unique_ptr MorphToMEMrr(unsigned Base, std::unique_ptr Op) { unsigned offsetReg = Op->getReg(); @@ -809,6 +843,15 @@ case Sparc::FSR: Op = SparcOperand::CreateToken("%fsr", S); break; + case Sparc::FQ: + Op = SparcOperand::CreateToken("%fq", S); + break; + case Sparc::CPSR: + Op = SparcOperand::CreateToken("%csr", S); + break; + case Sparc::CPQ: + Op = SparcOperand::CreateToken("%cq", S); + break; case Sparc::WIM: Op = SparcOperand::CreateToken("%wim", S); break; @@ -941,6 +984,24 @@ return true; } + if (name.equals("fq")) { + RegNo = Sparc::FQ; + RegKind = SparcOperand::rk_Special; + return true; + } + + if (name.equals("csr")) { + RegNo = Sparc::CPSR; + RegKind = SparcOperand::rk_Special; + return true; + } + + if (name.equals("cq")) { + RegNo = Sparc::CPQ; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("wim")) { RegNo = Sparc::WIM; RegKind = SparcOperand::rk_Special; @@ -1025,6 +1086,15 @@ return true; } + // %c0 - %c31 + if (name.substr(0, 1).equals_lower("c") + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 32) { + RegNo = CoProRegs[intVal]; + RegKind = SparcOperand::rk_CoProReg; + return true; + } + if (name.equals("tpc")) { RegNo = Sparc::TPC; RegKind = SparcOperand::rk_Special; @@ -1215,5 +1285,9 @@ if (SparcOperand::MorphToIntPairReg(Op)) return MCTargetAsmParser::Match_Success; } + if (Op.isCoProReg() && Kind == MCK_CoProPair) { + if (SparcOperand::MorphToCoProPairReg(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 @@ -130,6 +130,25 @@ SP::I0_I1, SP::I2_I3, SP::I4_I5, SP::I6_I7, }; +static const unsigned CPRegDecoderTable[] = { + SP::C0, SP::C1, SP::C2, SP::C3, + SP::C4, SP::C5, SP::C6, SP::C7, + SP::C8, SP::C9, SP::C10, SP::C11, + SP::C12, SP::C13, SP::C14, SP::C15, + SP::C16, SP::C17, SP::C18, SP::C19, + SP::C20, SP::C21, SP::C22, SP::C23, + SP::C24, SP::C25, SP::C26, SP::C27, + SP::C28, SP::C29, SP::C30, SP::C31 +}; + + +static const uint16_t CPPairDecoderTable[] = { + SP::C0_C1, SP::C2_C3, SP::C4_C5, SP::C6_C7, + SP::C8_C9, SP::C10_C11, SP::C12_C13, SP::C14_C15, + SP::C16_C17, SP::C18_C19, SP::C20_C21, SP::C22_C23, + SP::C24_C25, SP::C26_C27, SP::C28_C29, SP::C30_C31 +}; + static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, @@ -191,6 +210,17 @@ return MCDisassembler::Success; } +static DecodeStatus DecodeCPRegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = CPRegDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeFCCRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder) { @@ -233,6 +263,16 @@ return S; } +static DecodeStatus DecodeCPPairRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned RegisterPair = CPPairDecoderTable[RegNo/2]; + Inst.addOperand(MCOperand::createReg(RegisterPair)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeLoadIntPair(MCInst &Inst, unsigned insn, uint64_t Address, @@ -243,6 +283,10 @@ const void *Decoder); static DecodeStatus DecodeLoadQFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeLoadCP(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder); +static DecodeStatus DecodeLoadCPPair(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder); static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeStoreIntPair(MCInst &Inst, unsigned insn, @@ -253,6 +297,10 @@ uint64_t Address, const void *Decoder); static DecodeStatus DecodeStoreQFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeStoreCP(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder); +static DecodeStatus DecodeStoreCPPair(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeCall(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeSIMM13(MCInst &Inst, unsigned insn, @@ -390,6 +438,18 @@ DecodeQFPRegsRegisterClass); } +static DecodeStatus DecodeLoadCP(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, true, + DecodeCPRegsRegisterClass); +} + +static DecodeStatus DecodeLoadCPPair(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, true, + DecodeCPPairRegisterClass); +} + static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder) { return DecodeMem(Inst, insn, Address, Decoder, false, @@ -420,6 +480,18 @@ DecodeQFPRegsRegisterClass); } +static DecodeStatus DecodeStoreCP(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, false, + DecodeCPRegsRegisterClass); +} + +static DecodeStatus DecodeStoreCPPair(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, false, + DecodeCPPairRegisterClass); +} + static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch, uint64_t Address, uint64_t Offset, uint64_t Width, MCInst &MI, Index: lib/Target/Sparc/SparcInstrInfo.td =================================================================== --- lib/Target/Sparc/SparcInstrInfo.td +++ lib/Target/Sparc/SparcInstrInfo.td @@ -235,12 +235,28 @@ def FCC_LG : FCC_VAL<18>; // Less or Greater def FCC_NE : FCC_VAL<17>; // Not Equal def FCC_E : FCC_VAL<25>; // Equal -def FCC_UE : FCC_VAL<24>; // Unordered or Equal -def FCC_GE : FCC_VAL<25>; // Greater or Equal -def FCC_UGE : FCC_VAL<26>; // Unordered or Greater or Equal -def FCC_LE : FCC_VAL<27>; // Less or Equal -def FCC_ULE : FCC_VAL<28>; // Unordered or Less or Equal -def FCC_O : FCC_VAL<29>; // Ordered +def FCC_UE : FCC_VAL<26>; // Unordered or Equal +def FCC_GE : FCC_VAL<27>; // Greater or Equal +def FCC_UGE : FCC_VAL<28>; // Unordered or Greater or Equal +def FCC_LE : FCC_VAL<29>; // Less or Equal +def FCC_ULE : FCC_VAL<30>; // Unordered or Less or Equal +def FCC_O : FCC_VAL<31>; // Ordered + +class CPCC_VAL : PatLeaf<(i32 N)>; +def CPCC_3 : CPCC_VAL<39>; // 3 +def CPCC_2 : CPCC_VAL<38>; // 2 +def CPCC_23 : CPCC_VAL<37>; // 2 or 3 +def CPCC_1 : CPCC_VAL<36>; // 1 +def CPCC_13 : CPCC_VAL<35>; // 1 or 3 +def CPCC_12 : CPCC_VAL<34>; // 1 or 2 +def CPCC_123 : CPCC_VAL<33>; // 1 or 2 or 3 +def CPCC_0 : CPCC_VAL<41>; // 0 +def CPCC_03 : CPCC_VAL<42>; // 0 or 3 +def CPCC_02 : CPCC_VAL<43>; // 0 or 2 +def CPCC_023 : CPCC_VAL<44>; // 0 or 2 or 3 +def CPCC_01 : CPCC_VAL<45>; // 0 or 1 +def CPCC_013 : CPCC_VAL<46>; // 0 or 1 or 3 +def CPCC_012 : CPCC_VAL<47>; // 0 or 1 or 2 //===----------------------------------------------------------------------===// // Instruction Class Templates @@ -445,6 +461,20 @@ defm LDQF : LoadA<"ldq", 0b100010, 0b110010, load, QFPRegs, f128>, Requires<[HasV9, HasHardQuad]>; +let DecoderMethod = "DecodeLoadCP" in + defm LDC : Load<"ld", 0b110000, load, CoProRegs, i32>; +let DecoderMethod = "DecodeLoadCPPair" in + defm LDDC : Load<"ldd", 0b110011, load, CoProPair, v2i32>; + +let DecoderMethod = "DecodeLoadCP", Defs = [CPSR] in { + let rd = 0 in { + def LDCSRrr : F3_1<3, 0b110001, (outs), (ins MEMrr:$addr), + "ld [$addr], %csr", []>; + def LDCSRri : F3_2<3, 0b110001, (outs), (ins MEMri:$addr), + "ld [$addr], %csr", []>; + } +} + let DecoderMethod = "DecodeLoadFP" in let Defs = [FSR] in { let rd = 0 in { @@ -486,6 +516,27 @@ defm STQF : StoreA<"stq", 0b100110, 0b110110, store, QFPRegs, f128>, Requires<[HasV9, HasHardQuad]>; +let DecoderMethod = "DecodeStoreCP" in + defm STC : Store<"st", 0b110100, store, CoProRegs, i32>; + +let DecoderMethod = "DecodeStoreCPPair" in + defm STDC : Store<"std", 0b110111, store, CoProPair, v2i32>; + +let DecoderMethod = "DecodeStoreCP", rd = 0 in { + let Defs = [CPSR] in { + def STCSRrr : F3_1<3, 0b110101, (outs MEMrr:$addr), (ins), + "st %csr, [$addr]", []>; + def STCSRri : F3_2<3, 0b110101, (outs MEMri:$addr), (ins), + "st %csr, [$addr]", []>; + } + let Defs = [CPQ] in { + def STDCQrr : F3_1<3, 0b110110, (outs MEMrr:$addr), (ins), + "std %cq, [$addr]", []>; + def STDCQri : F3_2<3, 0b110110, (outs MEMri:$addr), (ins), + "std %cq, [$addr]", []>; + } +} + let DecoderMethod = "DecodeStoreFP" in let Defs = [FSR] in { let rd = 0 in { @@ -501,6 +552,14 @@ "stx %fsr, [$addr]", []>, Requires<[HasV9]>; } } + let Defs = [FQ] in { + let rd = 0 in { + def STDFQrr : F3_1<3, 0b100110, (outs MEMrr:$addr), (ins), + "std %fq, [$addr]", []>; + def STDFQri : F3_2<3, 0b100110, (outs MEMri:$addr), (ins), + "std %fq, [$addr]", []>; + } + } // Section B.8 - SWAP Register with Memory Instruction // (Atomic swap) @@ -755,7 +814,25 @@ let Predicates = [HasV9] in defm BPF : FPredBranch; +// Section B.22 - Branch on Co-processor Condition Codes Instructions, p. 123 +let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in { + +// co-processor conditional branch class: +class CPBranchSP pattern> + : F2_2<0b111, 0, (outs), ins, asmstr, pattern>; + +// co-processor conditional branch with annul class: +class CPBranchSPA pattern> + : F2_2<0b111, 1, (outs), ins, asmstr, pattern>; + +} // let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 +def CBCOND : CPBranchSP<(ins brtarget:$imm22, CCOp:$cond), + "cb$cond $imm22", + [(SPbrfcc bb:$imm22, imm:$cond)]>; +def CBCONDA : CPBranchSPA<(ins brtarget:$imm22, CCOp:$cond), + "cb$cond,a $imm22", []>; + // Section B.24 - Call and Link Instruction, p. 125 // This is the only Format 1 instruction let Uses = [O6], Index: lib/Target/Sparc/SparcRegisterInfo.td =================================================================== --- lib/Target/Sparc/SparcRegisterInfo.td +++ lib/Target/Sparc/SparcRegisterInfo.td @@ -62,6 +62,12 @@ def FSR : SparcCtrlReg<0, "FSR">; // Floating-point state register. +def FQ : SparcCtrlReg<0, "FQ">; // Floating-point deferred-trap queue. + +def CPSR : SparcCtrlReg<0, "CPSR">; // Co-processor state register. + +def CPQ : SparcCtrlReg<0, "CPQ">; // Co-processor queue. + // Y register def Y : SparcCtrlReg<0, "Y">, DwarfRegNum<[64]>; // Ancillary state registers (implementation defined) @@ -204,6 +210,40 @@ def D14 : Rd<28, "F28", [F28, F29]>, DwarfRegNum<[86]>; def D15 : Rd<30, "F30", [F30, F31]>, DwarfRegNum<[87]>; +// Co-processor registers +def C0 : Ri< 0, "C0">; +def C1 : Ri< 1, "C1">; +def C2 : Ri< 2, "C2">; +def C3 : Ri< 3, "C3">; +def C4 : Ri< 4, "C4">; +def C5 : Ri< 5, "C5">; +def C6 : Ri< 6, "C6">; +def C7 : Ri< 7, "C7">; +def C8 : Ri< 8, "C8">; +def C9 : Ri< 9, "C9">; +def C10 : Ri< 10, "C10">; +def C11 : Ri< 11, "C11">; +def C12 : Ri< 12, "C12">; +def C13 : Ri< 13, "C13">; +def C14 : Ri< 14, "C14">; +def C15 : Ri< 15, "C15">; +def C16 : Ri< 16, "C16">; +def C17 : Ri< 17, "C17">; +def C18 : Ri< 18, "C18">; +def C19 : Ri< 19, "C19">; +def C20 : Ri< 20, "C20">; +def C21 : Ri< 21, "C21">; +def C22 : Ri< 22, "C22">; +def C23 : Ri< 23, "C23">; +def C24 : Ri< 24, "C24">; +def C25 : Ri< 25, "C25">; +def C26 : Ri< 26, "C26">; +def C27 : Ri< 27, "C27">; +def C28 : Ri< 28, "C28">; +def C29 : Ri< 29, "C29">; +def C30 : Ri< 30, "C30">; +def C31 : Ri< 31, "C31">; + // Unaliased double precision floating point registers. // FIXME: Define DwarfRegNum for these registers. def D16 : SparcReg< 1, "F32">; @@ -259,6 +299,24 @@ def I4_I5 : Rdi<28, "I4", [I4, I5]>; def I6_I7 : Rdi<30, "I6", [I6, I7]>; +// Aliases of the co-processor registers used for LDD/STD double-word operations +def C0_C1 : Rdi<0, "C0", [C0, C1]>; +def C2_C3 : Rdi<2, "C2", [C2, C3]>; +def C4_C5 : Rdi<4, "C4", [C4, C5]>; +def C6_C7 : Rdi<6, "C6", [C6, C7]>; +def C8_C9 : Rdi<8, "C8", [C8, C9]>; +def C10_C11 : Rdi<10, "C10", [C10, C11]>; +def C12_C13 : Rdi<12, "C12", [C12, C13]>; +def C14_C15 : Rdi<14, "C14", [C14, C15]>; +def C16_C17 : Rdi<16, "C16", [C16, C17]>; +def C18_C19 : Rdi<18, "C18", [C18, C19]>; +def C20_C21 : Rdi<20, "C20", [C20, C21]>; +def C22_C23 : Rdi<22, "C22", [C22, C23]>; +def C24_C25 : Rdi<24, "C24", [C24, C25]>; +def C26_C27 : Rdi<26, "C26", [C26, C27]>; +def C28_C29 : Rdi<28, "C28", [C28, C29]>; +def C30_C31 : Rdi<30, "C30", [C30, C31]>; + // Register classes. // // FIXME: the register order should be defined in terms of the preferred @@ -273,6 +331,7 @@ (sequence "L%u", 0, 7), (sequence "O%u", 0, 7))>; + // Should be in the same order as IntRegs. def IntPair : RegisterClass<"SP", [v2i32], 64, (add I0_I1, I2_I3, I4_I5, I6_I7, @@ -296,10 +355,21 @@ // Floating point control register classes. def FCCRegs : RegisterClass<"SP", [i1], 1, (sequence "FCC%u", 0, 3)>; -// Ancillary state registers -def ASRRegs : RegisterClass<"SP", [i32], 32, - (add Y, (sequence "ASR%u", 1, 31))> { - let isAllocatable = 0; +let isAllocatable = 0 in { + // Ancillary state registers + def ASRRegs : RegisterClass<"SP", [i32], 32, + (add Y, (sequence "ASR%u", 1, 31))>; + + // This register class should not be used to hold i64 values. + def CoProRegs : RegisterClass<"SP", [i32], 32, + (add (sequence "C%u", 0, 31))>; + + // Should be in the same order as CoProRegs. + def CoProPair : RegisterClass<"SP", [v2i32], 64, + (add C0_C1, C2_C3, C4_C5, C6_C7, + C8_C9, C10_C11, C12_C13, C14_C15, + C16_C17, C18_C19, C20_C21, C22_C23, + C24_C25, C26_C27, C28_C29, C30_C31)>; } // Privileged Registers Index: test/MC/Sparc/sparc-copro.s =================================================================== --- test/MC/Sparc/sparc-copro.s +++ test/MC/Sparc/sparc-copro.s @@ -0,0 +1,67 @@ +! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s + + ! CHECK: ld [%i1], %c4 ! encoding: [0xc9,0x86,0x40,0x00] + ld [%i1], %c4 + + ! CHECK: ld [%i1+-15], %c4 ! encoding: [0xc9,0x86,0x7f,0xf1] + ld [%i1 - 15], %c4 + + ! CHECK: ld [%i7], %c4 ! encoding: [0xc9,0x87,0xc0,0x00] + ld [%i7], %c4 + + ! CHECK: ld [%i1], %c19 ! encoding: [0xe7,0x86,0x40,0x00] + ld [%i1], %c19 + + + ! CHECK: ldd [%i1], %c4 ! encoding: [0xc9,0x9e,0x40,0x00] + ldd [%i1], %c4 + + ! CHECK: ldd [%i7], %c4 ! encoding: [0xc9,0x9f,0xc0,0x00] + ldd [%i7], %c4 + + ! CHECK: ldd [%i1], %c30 ! encoding: [0xfd,0x9e,0x40,0x00] + ldd [%i1], %c30 + + + ! CHECK: st %c4, [%i1] ! encoding: [0xc9,0xa6,0x40,0x00] + st %c4, [%i1] + + ! CHECK: st %c4, [%i7] ! encoding: [0xc9,0xa7,0xc0,0x00] + st %c4, [%i7] + + ! CHECK: st %c19, [%i1] ! encoding: [0xe7,0xa6,0x40,0x00] + st %c19, [%i1] + + + ! CHECK: std %c4, [%i1] ! encoding: [0xc9,0xbe,0x40,0x00] + std %c4, [%i1] + + ! CHECK: std %c4, [%i7] ! encoding: [0xc9,0xbf,0xc0,0x00] + std %c4, [%i7] + + ! CHECK: std %c30, [%i1] ! encoding: [0xfd,0xbe,0x40,0x00] + std %c30, [%i1] + + + ! CHECK: ld [%i5], %csr ! encoding: [0xc1,0x8f,0x40,0x00] + ld [%i5], %csr + + + ! CHECK: st %csr, [%i2] ! encoding: [0xc1,0xae,0x80,0x00] + st %csr, [%i2] + + + ! CHECK: std %cq, [%o3] ! encoding: [0xc1,0xb2,0xc0,0x00] + std %cq, [%o3] + + + ! CHECK: std %fq, [%o4] ! encoding: [0xc1,0x33,0x00,0x00] + std %fq, [%o4] + + + ! CHECK: wr %l3, %l4, %y ! encoding: [0x81,0x84,0xc0,0x14] + wr %l3, %l4, %y + + + ! CHECK: rd %y, %l5 ! encoding: [0xab,0x40,0x00,0x00] + rd %y, %l5