Add support for the Sparc implementation-defined "ASR" registers.

(Note that register "Y" is essentially just ASR0).

Also added some test cases for divide and multiply, which had none before.

Differential Revision: http://reviews.llvm.org/D8670

llvm-svn: 237580
This commit is contained in:
James Y Knight 2015-05-18 16:29:48 +00:00
parent 0c553afe6a
commit 807563df22
8 changed files with 172 additions and 20 deletions

View File

@ -124,6 +124,15 @@ public:
Sparc::Q8, Sparc::Q9, Sparc::Q10, Sparc::Q11,
Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 };
static unsigned ASRRegs[32] = {
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};
/// SparcOperand - Instances of this class represent a parsed Sparc machine
/// instruction.
@ -136,7 +145,7 @@ public:
rk_DoubleReg,
rk_QuadReg,
rk_CCReg,
rk_Y
rk_ASRReg
};
private:
enum KindTy {
@ -661,9 +670,6 @@ SparcAsmParser::parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Op,
default:
Op = SparcOperand::CreateReg(RegNo, RegKind, S, E);
break;
case Sparc::Y:
Op = SparcOperand::CreateToken("%y", S);
break;
case Sparc::ICC:
if (name == "xcc")
@ -753,7 +759,15 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
if (name.equals("y")) {
RegNo = Sparc::Y;
RegKind = SparcOperand::rk_Y;
RegKind = SparcOperand::rk_ASRReg;
return true;
}
if (name.substr(0, 3).equals_lower("asr")
&& !name.substr(3).getAsInteger(10, intVal)
&& intVal > 0 && intVal < 32) {
RegNo = ASRRegs[intVal];
RegKind = SparcOperand::rk_ASRReg;
return true;
}

View File

@ -107,6 +107,16 @@ static const unsigned QFPRegDecoderTable[] = {
static const unsigned FCCRegDecoderTable[] = {
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};
static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst,
unsigned RegNo,
uint64_t Address,
@ -177,6 +187,15 @@ static DecodeStatus DecodeFCCRegsRegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}
static DecodeStatus DecodeASRRegsRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createReg(ASRRegDecoderTable[RegNo]));
return MCDisassembler::Success;
}
static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder);

View File

@ -168,8 +168,10 @@ SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
} else {
TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
}
TopPart = SDValue(CurDAG->getMachineNode(SP::WRYrr, dl, MVT::Glue, TopPart,
CurDAG->getRegister(SP::G0, MVT::i32)), 0);
TopPart = SDValue(CurDAG->getMachineNode(SP::WRASRrr, dl, MVT::i32,
TopPart,
CurDAG->getRegister(SP::G0, MVT::i32)), 0);
TopPart = CurDAG->getCopyToReg(TopPart, dl, SP::Y, TopPart, SDValue()).getValue(1);
// FIXME: Handle div by immediate.
unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
@ -185,7 +187,9 @@ SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
SDNode *Mul = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Glue,
MulLHS, MulRHS);
// The high part is in the Y register.
return CurDAG->SelectNodeTo(N, SP::RDY, MVT::i32, SDValue(Mul, 1));
return CurDAG->SelectNodeTo(N, SP::RDASR, MVT::i32,
CurDAG->getRegister(SP::Y, MVT::i32),
SDValue(Mul, 1));
}
}

View File

@ -705,20 +705,19 @@ let Uses = [O6],
}
// Section B.28 - Read State Register Instructions
let Uses = [Y], rs1 = 0, rs2 = 0 in
def RDY : F3_1<2, 0b101000,
(outs IntRegs:$dst), (ins),
"rd %y, $dst", []>;
let rs2 = 0 in
def RDASR : F3_1<2, 0b101000,
(outs IntRegs:$rd), (ins ASRRegs:$rs1),
"rd $rs1, $rd", []>;
// Section B.29 - Write State Register Instructions
let Defs = [Y], rd = 0 in {
def WRYrr : F3_1<2, 0b110000,
(outs), (ins IntRegs:$rs1, IntRegs:$rs2),
"wr $rs1, $rs2, %y", []>;
def WRYri : F3_2<2, 0b110000,
(outs), (ins IntRegs:$rs1, simm13Op:$simm13),
"wr $rs1, $simm13, %y", []>;
}
def WRASRrr : F3_1<2, 0b110000,
(outs ASRRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
"wr $rs1, $rs2, $rd", []>;
def WRASRri : F3_2<2, 0b110000,
(outs ASRRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13),
"wr $rs1, $simm13, $rd", []>;
// Convert Integer to Floating-point Instructions, p. 141
def FITOS : F3_3u<2, 0b110100, 0b011000100,
(outs FPRegs:$rd), (ins FPRegs:$rs2),

View File

@ -56,6 +56,38 @@ foreach I = 0-3 in
// Y register
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">;
def ASR7 : SparcCtrlReg<7, "ASR7">;
def ASR8 : SparcCtrlReg<8, "ASR8">;
def ASR9 : SparcCtrlReg<9, "ASR9">;
def ASR10 : SparcCtrlReg<10, "ASR10">;
def ASR11 : SparcCtrlReg<11, "ASR11">;
def ASR12 : SparcCtrlReg<12, "ASR12">;
def ASR13 : SparcCtrlReg<13, "ASR13">;
def ASR14 : SparcCtrlReg<14, "ASR14">;
def ASR15 : SparcCtrlReg<15, "ASR15">;
def ASR16 : SparcCtrlReg<16, "ASR16">;
def ASR17 : SparcCtrlReg<17, "ASR17">;
def ASR18 : SparcCtrlReg<18, "ASR18">;
def ASR19 : SparcCtrlReg<19, "ASR19">;
def ASR20 : SparcCtrlReg<20, "ASR20">;
def ASR21 : SparcCtrlReg<21, "ASR21">;
def ASR22 : SparcCtrlReg<22, "ASR22">;
def ASR23 : SparcCtrlReg<23, "ASR23">;
def ASR24 : SparcCtrlReg<24, "ASR24">;
def ASR25 : SparcCtrlReg<25, "ASR25">;
def ASR26 : SparcCtrlReg<26, "ASR26">;
def ASR27 : SparcCtrlReg<27, "ASR27">;
def ASR28 : SparcCtrlReg<28, "ASR28">;
def ASR29 : SparcCtrlReg<29, "ASR29">;
def ASR30 : SparcCtrlReg<30, "ASR30">;
def ASR31 : SparcCtrlReg<31, "ASR31">;
// Integer registers
def G0 : Ri< 0, "G0">, DwarfRegNum<[0]>;
@ -209,3 +241,7 @@ def QFPRegs : RegisterClass<"SP", [f128], 128, (sequence "Q%u", 0, 15)>;
// 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))>;

View File

@ -36,3 +36,51 @@ entry:
ret i32 0
}
; CHECK-LABEL: signed_divide:
; CHECK: sra %o0, 31, %o2
; CHECK: wr %o2, %g0, %y
; CHECK: sdiv %o0, %o1, %o0
define i32 @signed_divide(i32 %a, i32 %b) {
%r = sdiv i32 %a, %b
ret i32 %r
}
; CHECK-LABEL: unsigned_divide:
; CHECK: wr %g0, %g0, %y
; CHECK: udiv %o0, %o1, %o0
define i32 @unsigned_divide(i32 %a, i32 %b) {
%r = udiv i32 %a, %b
ret i32 %r
}
; CHECK-LABEL: multiply_32x32:
; CHECK: smul %o0, %o1, %o0
define i32 @multiply_32x32(i32 %a, i32 %b) {
%r = mul i32 %a, %b
ret i32 %r
}
; CHECK-LABEL: signed_multiply_32x32_64:
; CHECK: smul %o0, %o1, %o1
; CHECK: rd %y, %o0
define i64 @signed_multiply_32x32_64(i32 %a, i32 %b) {
%xa = sext i32 %a to i64
%xb = sext i32 %b to i64
%r = mul i64 %xa, %xb
ret i64 %r
}
; CHECK-LABEL: unsigned_multiply_32x32_64:
; CHECK: umul %o0, %o1, %o2
; CHECK: rd %y, %o2
;FIXME: the smul in the output is totally redundant and should not there.
; CHECK: smul %o0, %o1, %o1
; CHECK: retl
; CHECK: mov %o2, %o0
define i64 @unsigned_multiply_32x32_64(i32 %a, i32 %b) {
%xa = zext i32 %a to i64
%xb = zext i32 %b to i64
%r = mul i64 %xa, %xb
ret i64 %r
}

View File

@ -200,3 +200,18 @@
# CHECK: rett %i7+8
0x81 0xcf 0xe0 0x08
# CHECK: rd %y, %i0
0xb1 0x40 0x00 0x00
# CHECK: rd %asr1, %i0
0xb1 0x40 0x40 0x00
# CHECK: wr %i0, 5, %y
0x81 0x86 0x20 0x05
# CHECK: wr %i0, %i1, %asr15
0x9f 0x86 0x00 0x19
# CHECK: stbar
0x81 0x43 0xc0 0x00

View File

@ -0,0 +1,17 @@
! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s
! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
! CHECK: rd %y, %i0 ! encoding: [0xb1,0x40,0x00,0x00]
rd %y, %i0
! CHECK: rd %asr1, %i0 ! encoding: [0xb1,0x40,0x40,0x00]
rd %asr1, %i0
! CHECK: wr %i0, 5, %y ! encoding: [0x81,0x86,0x20,0x05]
wr %i0, 5, %y
! CHECK: wr %i0, %i1, %asr15 ! encoding: [0x9f,0x86,0x00,0x19]
wr %i0, %i1, %asr15
! CHECK: rd %asr15, %g0 ! encoding: [0x81,0x43,0xc0,0x00]
rd %asr15, %g0