Index: llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp =================================================================== --- llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -1220,9 +1220,6 @@ case Sparc::TBR: Op = SparcOperand::CreateToken("%tbr", S); break; - case Sparc::PC: - Op = SparcOperand::CreateToken("%pc", S); - break; case Sparc::ICC: if (name == "xcc") Op = SparcOperand::CreateToken("%xcc", S); @@ -1319,9 +1316,8 @@ return true; } - // %fprs is an alias of %asr6. if (name.equals("fprs")) { - RegNo = ASRRegs[6]; + RegNo = Sparc::ASR6; RegKind = SparcOperand::rk_Special; return true; } @@ -1525,7 +1521,27 @@ return true; } if (name.equals("pc")) { - RegNo = Sparc::PC; + RegNo = Sparc::ASR5; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("asi")) { + RegNo = Sparc::ASR3; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("ccr")) { + RegNo = Sparc::ASR2; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("gl")) { + RegNo = Sparc::GL; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("ver")) { + RegNo = Sparc::VER; RegKind = SparcOperand::rk_Special; return true; } Index: llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp =================================================================== --- llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +++ llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp @@ -101,20 +101,16 @@ SP::FCC0, SP::FCC1, SP::FCC2, SP::FCC3 }; static const unsigned ASRRegDecoderTable[] = { - SP::Y, SP::ASR1, SP::ASR2, SP::ASR3, - SP::ASR4, SP::ASR5, SP::ASR6, SP::ASR7, - SP::ASR8, SP::ASR9, SP::ASR10, SP::ASR11, - SP::ASR12, SP::ASR13, SP::ASR14, SP::ASR15, - SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19, - SP::ASR20, SP::ASR21, SP::ASR22, SP::ASR23, - SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27, - SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31}; + SP::Y, SP::ASR1, SP::ASR2, SP::ASR3, SP::ASR4, SP::ASR5, SP::ASR6, + SP::ASR7, SP::ASR8, SP::ASR9, SP::ASR10, SP::ASR11, SP::ASR12, SP::ASR13, + SP::ASR14, SP::ASR15, SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19, SP::ASR20, + SP::ASR21, SP::ASR22, SP::ASR23, SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27, + SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31}; static const unsigned PRRegDecoderTable[] = { - SP::TPC, SP::TNPC, SP::TSTATE, SP::TT, SP::TICK, SP::TBA, SP::PSTATE, - SP::TL, SP::PIL, SP::CWP, SP::CANSAVE, SP::CANRESTORE, SP::CLEANWIN, - SP::OTHERWIN, SP::WSTATE, SP::PC -}; + SP::TPC, SP::TNPC, SP::TSTATE, SP::TT, SP::TICK, + SP::TBA, SP::PSTATE, SP::TL, SP::PIL, SP::CWP, + SP::CANSAVE, SP::CANRESTORE, SP::CLEANWIN, SP::OTHERWIN, SP::WSTATE}; static const uint16_t IntPairDecoderTable[] = { SP::G0_G1, SP::G2_G3, SP::G4_G5, SP::G6_G7, Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h @@ -13,6 +13,7 @@ #ifndef LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCINSTPRINTER_H #define LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCINSTPRINTER_H +#include "SparcMCTargetDesc.h" #include "llvm/MC/MCInstPrinter.h" namespace llvm { @@ -24,6 +25,7 @@ : MCInstPrinter(MAI, MII, MRI) {} void printRegName(raw_ostream &OS, MCRegister Reg) const override; + void printRegName(raw_ostream &OS, MCRegister Reg, unsigned AltIdx) const; void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &O) override; bool printSparcAliasInstr(const MCInst *MI, const MCSubtargetInfo &STI, @@ -39,7 +41,8 @@ void printCustomAliasOperand(const MCInst *MI, uint64_t Address, unsigned OpIdx, unsigned PrintMethodIdx, const MCSubtargetInfo &STI, raw_ostream &O); - static const char *getRegisterName(MCRegister Reg); + static const char *getRegisterName(MCRegister Reg, + unsigned AltIdx = SP::NoRegAltName); void printOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI, raw_ostream &OS); Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp @@ -42,6 +42,11 @@ OS << '%' << StringRef(getRegisterName(Reg)).lower(); } +void SparcInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg, + unsigned AltIdx) const { + OS << '%' << StringRef(getRegisterName(Reg, AltIdx)).lower(); +} + void SparcInstPrinter::printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &O) { @@ -111,7 +116,11 @@ const MCOperand &MO = MI->getOperand (opNum); if (MO.isReg()) { - printRegName(O, MO.getReg()); + unsigned Reg = MO.getReg(); + if (isV9(STI)) + printRegName(O, Reg, SP::RegNamesStateReg); + else + printRegName(O, Reg); return ; } Index: llvm/lib/Target/Sparc/SparcInstrAliases.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrAliases.td +++ llvm/lib/Target/Sparc/SparcInstrAliases.td @@ -524,7 +524,6 @@ def : InstAlias<"mov %psr, $rd", (RDPSR IntRegs:$rd), 0>; def : InstAlias<"mov %wim, $rd", (RDWIM IntRegs:$rd), 0>; def : InstAlias<"mov %tbr, $rd", (RDTBR IntRegs:$rd), 0>; -def : InstAlias<"mov %pc, $rd", (RDPC IntRegs:$rd), 0>; // mov reg_or_imm, specialreg -> wr %g0, reg_or_imm, specialreg def : InstAlias<"mov $rs2, $asr", (WRASRrr ASRRegs:$asr, G0, IntRegs:$rs2), 0>; Index: llvm/lib/Target/Sparc/SparcInstrInfo.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrInfo.td +++ llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -1123,14 +1123,6 @@ "rd %tbr, $rd", []>; } -// PC don't exist on the SparcV8, only the V9. -let Predicates = [HasV9] in { - let rs2 = 0, rs1 = 5 in - def RDPC : F3_1<2, 0b101000, - (outs IntRegs:$rd), (ins), - "rd %pc, $rd", []>; -} - // Section B.29 - Write State Register Instructions def WRASRrr : F3_1<2, 0b110000, (outs ASRRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), Index: llvm/lib/Target/Sparc/SparcRegisterInfo.td =================================================================== --- llvm/lib/Target/Sparc/SparcRegisterInfo.td +++ llvm/lib/Target/Sparc/SparcRegisterInfo.td @@ -15,7 +15,8 @@ let Namespace = "SP"; } -class SparcCtrlReg Enc, string n>: Register { +class SparcCtrlReg Enc, string n, + list altNames = []>: Register { let HWEncoding = Enc; let Namespace = "SP"; } @@ -27,6 +28,11 @@ def sub_odd64 : SubRegIndex<64, 64>; } +let Namespace = "SP", + FallbackRegAltNameIndex = NoRegAltName in { + def RegNamesStateReg : RegAltNameIndex; +} + // Registers are identified with 5-bit ID numbers. // Ri - 32-bit integer registers class Ri Enc, string n> : SparcReg; @@ -71,11 +77,18 @@ def Y : SparcCtrlReg<0, "Y">, DwarfRegNum<[64]>; // Ancillary state registers (implementation defined) def ASR1 : SparcCtrlReg<1, "ASR1">; -def ASR2 : SparcCtrlReg<2, "ASR2">; -def ASR3 : SparcCtrlReg<3, "ASR3">; -def ASR4 : SparcCtrlReg<4, "ASR4">; -def ASR5 : SparcCtrlReg<5, "ASR5">; -def ASR6 : SparcCtrlReg<6, "ASR6">; +let RegAltNameIndices = [RegNamesStateReg] in { +// FIXME: Currently this results in the assembler accepting +// the alternate names (%ccr, %asi, etc.) when targeting V8. +// Make sure that the alternate names are available for V9 only: +// %asr2-asr6 : valid on both V8 and V9. +// %ccr, %asi, etc.: valid on V9, returns "no such register" error on V8. +def ASR2 : SparcCtrlReg<2, "ASR2", ["CCR"]>; +def ASR3 : SparcCtrlReg<3, "ASR3", ["ASI"]>; +def ASR4 : SparcCtrlReg<4, "ASR4", ["TICK"]>; +def ASR5 : SparcCtrlReg<5, "ASR5", ["PC"]>; +def ASR6 : SparcCtrlReg<6, "ASR6", ["FPRS"]>; +} def ASR7 : SparcCtrlReg<7, "ASR7">; def ASR8 : SparcCtrlReg<8, "ASR8">; def ASR9 : SparcCtrlReg<9, "ASR9">; @@ -106,24 +119,25 @@ def PSR : SparcCtrlReg<0, "PSR">; def WIM : SparcCtrlReg<0, "WIM">; def TBR : SparcCtrlReg<0, "TBR">; -// PC on the other hand is only available for SparcV9. -def PC : SparcCtrlReg<5, "PC">; - -def TPC : SparcCtrlReg<0, "TPC">; -def TNPC : SparcCtrlReg<1, "TNPC">; -def TSTATE : SparcCtrlReg<2, "TSTATE">; -def TT : SparcCtrlReg<3, "TT">; -def TICK : SparcCtrlReg<4, "TICK">; -def TBA : SparcCtrlReg<5, "TBA">; -def PSTATE : SparcCtrlReg<6, "PSTATE">; -def TL : SparcCtrlReg<7, "TL">; -def PIL : SparcCtrlReg<8, "PIL">; -def CWP : SparcCtrlReg<9, "CWP">; -def CANSAVE : SparcCtrlReg<10, "CANSAVE">; + +// Privileged V9 state registers +def TPC : SparcCtrlReg<0, "TPC">; +def TNPC : SparcCtrlReg<1, "TNPC">; +def TSTATE : SparcCtrlReg<2, "TSTATE">; +def TT : SparcCtrlReg<3, "TT">; +def TICK : SparcCtrlReg<4, "TICK">; +def TBA : SparcCtrlReg<5, "TBA">; +def PSTATE : SparcCtrlReg<6, "PSTATE">; +def TL : SparcCtrlReg<7, "TL">; +def PIL : SparcCtrlReg<8, "PIL">; +def CWP : SparcCtrlReg<9, "CWP">; +def CANSAVE : SparcCtrlReg<10, "CANSAVE">; def CANRESTORE : SparcCtrlReg<11, "CANRESTORE">; -def CLEANWIN : SparcCtrlReg<12, "CLEANWIN">; -def OTHERWIN : SparcCtrlReg<13, "OTHERWIN">; -def WSTATE : SparcCtrlReg<14, "WSTATE">; +def CLEANWIN : SparcCtrlReg<12, "CLEANWIN">; +def OTHERWIN : SparcCtrlReg<13, "OTHERWIN">; +def WSTATE : SparcCtrlReg<14, "WSTATE">; +def GL : SparcCtrlReg<16, "GL">; +def VER : SparcCtrlReg<31, "VER">; // Integer registers def G0 : Ri< 0, "G0">, DwarfRegNum<[0]> { @@ -361,8 +375,11 @@ let isAllocatable = 0 in { // Ancillary state registers + // FIXME: TICK is special-cased here as it can be accessed + // from the ASR (as ASR4) or the privileged register set. + // For now this is required for the parser to work. def ASRRegs : RegisterClass<"SP", [i32], 32, - (add Y, (sequence "ASR%u", 1, 31))>; + (add Y, TICK, (sequence "ASR%u", 1, 31))>; // This register class should not be used to hold i64 values. def CoprocRegs : RegisterClass<"SP", [i32], 32, @@ -379,5 +396,4 @@ // Privileged Registers def PRRegs : RegisterClass<"SP", [i64], 64, (add TPC, TNPC, TSTATE, TT, TICK, TBA, PSTATE, TL, PIL, CWP, - CANSAVE, CANRESTORE, CLEANWIN, OTHERWIN, WSTATE)>; - + CANSAVE, CANRESTORE, CLEANWIN, OTHERWIN, WSTATE, GL, VER)>; Index: llvm/test/MC/Disassembler/Sparc/sparc-special-registers.txt =================================================================== --- llvm/test/MC/Disassembler/Sparc/sparc-special-registers.txt +++ llvm/test/MC/Disassembler/Sparc/sparc-special-registers.txt @@ -1,4 +1,5 @@ -# RUN: llvm-mc --disassemble %s -triple=sparc-unknown-linux | FileCheck %s +# RUN: llvm-mc --disassemble %s -triple=sparc-unknown-linux | FileCheck %s --check-prefixes=CHECK,V8 +# RUN: llvm-mc --disassemble %s -triple=sparcv9-unknown-linux | FileCheck %s --check-prefixes=CHECK,V9 # CHECK: wr %g1, -2, %y 0x81 0x80 0x7f 0xfe @@ -38,3 +39,41 @@ # CHECK: std %fq, [%i5+%l1] 0xc1 0x37 0x40 0x11 + + +## Those instructions are processed differently on V8 and V9. + +# V8: rd %asr2, %i0 +# V9: rd %ccr, %i0 +0xb1 0x40 0x80 0x00 +# V8: wr %i0, 7, %asr2 +# V9: wr %i0, 7, %ccr +0x85 0x86 0x20 0x07 + +# V8: rd %asr3, %i0 +# V9: rd %asi, %i0 +0xb1 0x40 0xc0 0x00 +# V8: wr %i0, 7, %asr3 +# V9: wr %i0, 7, %asi +0x87 0x86 0x20 0x07 + +# V8: rd %asr4, %i0 +# V9: rd %tick, %i0 +0xb1 0x41 0x00 0x00 +# V8: wr %i0, 7, %asr4 +# V9: wr %i0, 7, %tick +0x89 0x86 0x20 0x07 + +# V8: rd %asr5, %i0 +# V9: rd %pc, %i0 +0xb1 0x41 0x40 0x00 +# V8: wr %i0, 7, %asr5 +# V9: wr %i0, 7, %pc +0x8b 0x86 0x20 0x07 + +# V8: rd %asr6, %i0 +# V9: rd %fprs, %i0 +0xb1 0x41 0x80 0x00 +# V8: wr %i0, 7, %asr6 +# V9: wr %i0, 7, %fprs +0x8d 0x86 0x20 0x07 Index: llvm/test/MC/Sparc/sparc-special-registers.s =================================================================== --- llvm/test/MC/Sparc/sparc-special-registers.s +++ llvm/test/MC/Sparc/sparc-special-registers.s @@ -1,5 +1,5 @@ -! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s -! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s +! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s --check-prefixes=CHECK,V8 +! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s --check-prefixes=CHECK,V9 ! CHECK: rd %y, %i0 ! encoding: [0xb1,0x40,0x00,0x00] rd %y, %i0 @@ -34,12 +34,6 @@ ! CHECK: wr %i0, 5, %tbr ! encoding: [0x81,0x9e,0x20,0x05] wr %i0, 5, %tbr - ! CHECK: rd %asr6, %i0 ! encoding: [0xb1,0x41,0x80,0x00] - rd %fprs, %i0 - - ! CHECK: wr %i0, 7, %asr6 ! encoding: [0x8d,0x86,0x20,0x07] - wr %i0, 7, %fprs - ! CHECK: ld [%g2+20], %fsr ! encoding: [0xc1,0x08,0xa0,0x14] ld [%g2 + 20],%fsr @@ -54,3 +48,69 @@ ! CHECK: std %fq, [%g6+%i2] ! encoding: [0xc1,0x31,0x80,0x1a] std %fq, [%g6 + %i2] + +!! Those instructions are processed differently on V8 and V9. + +! V8: rd %asr2, %i0 ! encoding: [0xb1,0x40,0x80,0x00] +! V9: rd %ccr, %i0 ! encoding: [0xb1,0x40,0x80,0x00] +rd %asr2, %i0 +! V8: wr %i0, 7, %asr2 ! encoding: [0x85,0x86,0x20,0x07] +! V9: wr %i0, 7, %ccr ! encoding: [0x85,0x86,0x20,0x07] +wr %i0, 7, %asr2 + +! V8: rd %asr3, %i0 ! encoding: [0xb1,0x40,0xc0,0x00] +! V9: rd %asi, %i0 ! encoding: [0xb1,0x40,0xc0,0x00] +rd %asr3, %i0 +! V8: wr %i0, 7, %asr3 ! encoding: [0x87,0x86,0x20,0x07] +! V9: wr %i0, 7, %asi ! encoding: [0x87,0x86,0x20,0x07] +wr %i0, 7, %asr3 + +! V8: rd %asr4, %i0 ! encoding: [0xb1,0x41,0x00,0x00] +! V9: rd %tick, %i0 ! encoding: [0xb1,0x41,0x00,0x00] +rd %asr4, %i0 +! V8: wr %i0, 7, %asr4 ! encoding: [0x89,0x86,0x20,0x07] +! V9: wr %i0, 7, %tick ! encoding: [0x89,0x86,0x20,0x07] +wr %i0, 7, %asr4 + +! V8: rd %asr5, %i0 ! encoding: [0xb1,0x41,0x40,0x00] +! V9: rd %pc, %i0 ! encoding: [0xb1,0x41,0x40,0x00] +rd %asr5, %i0 +! V8: wr %i0, 7, %asr5 ! encoding: [0x8b,0x86,0x20,0x07] +! V9: wr %i0, 7, %pc ! encoding: [0x8b,0x86,0x20,0x07] +wr %i0, 7, %asr5 + +! V8: rd %asr6, %i0 ! encoding: [0xb1,0x41,0x80,0x00] +! V9: rd %fprs, %i0 ! encoding: [0xb1,0x41,0x80,0x00] +rd %asr6, %i0 +! V8: wr %i0, 7, %asr6 ! encoding: [0x8d,0x86,0x20,0x07] +! V9: wr %i0, 7, %fprs ! encoding: [0x8d,0x86,0x20,0x07] +wr %i0, 7, %asr6 + +!! Alternate names for %asr2-%asr6 are only for V9. +!! TODO: make sure that using alternate names returns +!! an error on V8 (currently it doesn't, see SparcRegisterInfo.td). + +! V9: rd %ccr, %i0 ! encoding: [0xb1,0x40,0x80,0x00] +rd %ccr, %i0 +! V9: wr %i0, 7, %ccr ! encoding: [0x85,0x86,0x20,0x07] +wr %i0, 7, %ccr + +! V9: rd %asi, %i0 ! encoding: [0xb1,0x40,0xc0,0x00] +rd %asi, %i0 +! V9: wr %i0, 7, %asi ! encoding: [0x87,0x86,0x20,0x07] +wr %i0, 7, %asi + +! V9: rd %tick, %i0 ! encoding: [0xb1,0x41,0x00,0x00] +rd %tick, %i0 +! V9: wr %i0, 7, %tick ! encoding: [0x89,0x86,0x20,0x07] +wr %i0, 7, %tick + +! V9: rd %pc, %i0 ! encoding: [0xb1,0x41,0x40,0x00] +rd %pc, %i0 +! V9: wr %i0, 7, %pc ! encoding: [0x8b,0x86,0x20,0x07] +wr %i0, 7, %pc + +! V9: rd %fprs, %i0 ! encoding: [0xb1,0x41,0x80,0x00] +rd %fprs, %i0 +! V9: wr %i0, 7, %fprs ! encoding: [0x8d,0x86,0x20,0x07] +wr %i0, 7, %fprs Index: llvm/test/MC/Sparc/sparcv9-instructions.s =================================================================== --- llvm/test/MC/Sparc/sparcv9-instructions.s +++ llvm/test/MC/Sparc/sparcv9-instructions.s @@ -417,9 +417,27 @@ rdpr %wstate,%i5 ! V8: error: instruction requires a CPU feature not currently enabled - ! V8-NEXT: rd %pc, %o7 + ! V8-NEXT: rdpr %ver,%i5 + ! V9: rdpr %ver, %i5 ! encoding: [0xbb,0x57,0xc0,0x00] + rdpr %ver,%i5 + ! V9: rd %pc, %o7 ! encoding: [0x9f,0x41,0x40,0x00] rd %pc, %o7 + ! V9: rd %asi, %g1 ! encoding: [0x83,0x40,0xc0,0x00] + rd %asi, %g1 + ! V9: rd %ccr, %g1 ! encoding: [0x83,0x40,0x80,0x00] + rd %ccr, %g1 + ! V9: rd %tick, %i5 ! encoding: [0xbb,0x41,0x00,0x00] + rd %tick,%i5 + + ! V9: wr %i0, %i1, %asi ! encoding: [0x87,0x86,0x00,0x19] + wr %i0, %i1, %asi + ! V9: wr %i0, 1, %asi ! encoding: [0x87,0x86,0x20,0x01] + wr %i0, 1, %asi + ! V9: wr %i0, %i1, %ccr ! encoding: [0x85,0x86,0x00,0x19] + wr %i0, %i1, %ccr + ! V9: wr %i0, 1, %ccr ! encoding: [0x85,0x86,0x20,0x01] + wr %i0, 1, %ccr ! V9: st %o1, [%o0] ! encoding: [0xd2,0x22,0x00,0x00] stw %o1, [%o0]