Skip to content

Commit

Permalink
[SPARC] Cleanup handling of the Y/ASR registers.
Browse files Browse the repository at this point in the history
- Implement copying ASR to/from GPR regs.
- Mark ASRs as non-allocatable, so it won't try to arbitrarily use
  them inappropriately.
- Instead of inserting explicit WRASR/RDASR nodes in the MUL/DIV
  routines, just do normal register copies.
- Also...mark div as using Y, not just writing it.

Added a test case with some code which previously died with an
assertion failure (with -O0), or produced wrong code (otherwise).

(Third time's the charm?)

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

llvm-svn: 241686
  • Loading branch information
jyknight committed Jul 8, 2015
1 parent 51271bd commit f238d17
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 14 deletions.
18 changes: 8 additions & 10 deletions llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,9 @@ SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
} else {
TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
}
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);
TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
SDValue())
.getValue(1);

// FIXME: Handle div by immediate.
unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
Expand All @@ -184,12 +183,11 @@ SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
SDValue MulLHS = N->getOperand(0);
SDValue MulRHS = N->getOperand(1);
unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr;
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::RDASR, MVT::i32,
CurDAG->getRegister(SP::Y, MVT::i32),
SDValue(Mul, 1));
SDNode *Mul =
CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32, MulLHS, MulRHS);
SDValue ResultHigh = SDValue(Mul, 1);
ReplaceUses(SDValue(N, 0), ResultHigh);
return nullptr;
}
}

Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/Target/Sparc/SparcInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,15 @@ void SparcInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
numSubRegs = 4;
movOpc = SP::FMOVS;
}
} else if (SP::ASRRegsRegClass.contains(DestReg) &&
SP::IntRegsRegClass.contains(SrcReg)) {
BuildMI(MBB, I, DL, get(SP::WRASRrr), DestReg)
.addReg(SP::G0)
.addReg(SrcReg, getKillRegState(KillSrc));
} else if (SP::IntRegsRegClass.contains(DestReg) &&
SP::ASRRegsRegClass.contains(SrcReg)) {
BuildMI(MBB, I, DL, get(SP::RDASR), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
} else
llvm_unreachable("Impossible reg-to-reg copy");

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/Sparc/SparcInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -560,12 +560,12 @@ let Defs = [Y, ICC] in {
}

// Section B.19 - Divide Instructions, p. 115
let Defs = [Y] in {
let Uses = [Y], Defs = [Y] in {
defm UDIV : F3_12np<"udiv", 0b001110>;
defm SDIV : F3_12np<"sdiv", 0b001111>;
}

let Defs = [Y, ICC] in {
let Uses = [Y], Defs = [Y, ICC] in {
defm UDIVCC : F3_12np<"udivcc", 0b011110>;
defm SDIVCC : F3_12np<"sdivcc", 0b011111>;
}
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Target/Sparc/SparcRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,6 @@ 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))>;
(add Y, (sequence "ASR%u", 1, 31))> {
let isAllocatable = 0;
}
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/SPARC/basictest.ll
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ entry:

; CHECK-LABEL: signed_divide:
; CHECK: sra %o0, 31, %o2
; CHECK: wr %o2, %g0, %y
; CHECK: wr %g0, %o2, %y
; CHECK: sdiv %o0, %o1, %o0
define i32 @signed_divide(i32 %a, i32 %b) {
%r = sdiv i32 %a, %b
Expand Down
21 changes: 21 additions & 0 deletions llvm/test/CodeGen/SPARC/multiple-div.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
; RUN: llc < %s -march=sparc | FileCheck %s
; RUN: llc -O0 < %s -march=sparc | FileCheck %s

;; llc -O0 used to try to spill Y to the stack, which isn't possible,
;; and then crashed. Additionally, in -O1, it would omit the second
;; apparently-redundant wr to %y, which is not actually redundant
;; because the spec says to treat %y as potentially-written by udiv.

; CHECK-LABEL: two_divides:
; CHECK: wr %g0, %g0, %y
; CHECK: udiv
; CHECK: wr %g0, %g0, %y
; CHECK: udiv
; CHECK: add

define i32 @two_divides(i32 %a, i32 %b) {
%r = udiv i32 %a, %b
%r2 = udiv i32 %b, %a
%r3 = add i32 %r, %r2
ret i32 %r3
}

0 comments on commit f238d17

Please sign in to comment.