// SelectionDAG operations.
namespace {
class RISCVDAGToDAGISel final : public SelectionDAGISel {
+ const RISCVSubtarget *Subtarget;
+
public:
explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine)
: SelectionDAGISel(TargetMachine) {}
return "RISCV DAG->DAG Pattern Instruction Selection";
}
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ Subtarget = &MF.getSubtarget<RISCVSubtarget>();
+ return SelectionDAGISel::runOnMachineFunction(MF);
+ }
+
void Select(SDNode *Node) override;
// Include the pieces autogenerated from the target description.
}
void RISCVDAGToDAGISel::Select(SDNode *Node) {
+ unsigned Opcode = Node->getOpcode();
+ MVT XLenVT = Subtarget->getXLenVT();
+
// Dump information about the Node being selected.
DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << "\n");
return;
}
+ // Instruction Selection not handled by the auto-generated tablegen selection
+ // should be handled here.
+ EVT VT = Node->getValueType(0);
+ switch (Opcode) {
+ case ISD::Constant:
+ if (VT == XLenVT) {
+ ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node);
+ // Materialize zero constants as copies from X0. This allows the coalescer
+ // to propagate these into other instructions.
+ if (ConstNode->isNullValue()) {
+ SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
+ SDLoc(Node), RISCV::X0, XLenVT);
+ return ReplaceNode(Node, New.getNode());
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
// Select the default instruction.
SelectCode(Node);
}
; RV32I-NEXT: addi a1, a0, 0
; RV32I-NEXT: addi a0, zero, 8
; RV32I-NEXT: andi a2, a1, 255
-; RV32I-NEXT: addi a3, zero, 0
-; RV32I-NEXT: beq a2, a3, .LBB3_2
+; RV32I-NEXT: beq a2, zero, .LBB3_2
; RV32I-NEXT: jal zero, .LBB3_1
; RV32I-NEXT: .LBB3_1: # %cond.false
; RV32I-NEXT: addi a0, a1, -1
; RV32I-NEXT: lui a2, 16
; RV32I-NEXT: addi a2, a2, -1
; RV32I-NEXT: and a2, a1, a2
-; RV32I-NEXT: addi a3, zero, 0
-; RV32I-NEXT: beq a2, a3, .LBB4_2
+; RV32I-NEXT: beq a2, zero, .LBB4_2
; RV32I-NEXT: jal zero, .LBB4_1
; RV32I-NEXT: .LBB4_1: # %cond.false
; RV32I-NEXT: addi a0, a1, -1
; RV32I-NEXT: sw ra, 12(s0)
; RV32I-NEXT: addi a1, a0, 0
; RV32I-NEXT: addi a0, zero, 32
-; RV32I-NEXT: addi a2, zero, 0
-; RV32I-NEXT: beq a1, a2, .LBB5_2
+; RV32I-NEXT: beq a1, zero, .LBB5_2
; RV32I-NEXT: jal zero, .LBB5_1
; RV32I-NEXT: .LBB5_1: # %cond.false
; RV32I-NEXT: addi a0, a1, -1
; RV32I-NEXT: sw ra, 12(s0)
; RV32I-NEXT: addi a1, a0, 0
; RV32I-NEXT: addi a0, zero, 32
-; RV32I-NEXT: addi a2, zero, 0
-; RV32I-NEXT: beq a1, a2, .LBB6_2
+; RV32I-NEXT: beq a1, zero, .LBB6_2
; RV32I-NEXT: jal zero, .LBB6_1
; RV32I-NEXT: .LBB6_1: # %cond.false
; RV32I-NEXT: srli a0, a1, 1
; RV32I-NEXT: addi a0, a1, 0
; RV32I-NEXT: addi a1, s3, 0
; RV32I-NEXT: jalr ra, s6, 0
-; RV32I-NEXT: addi a1, zero, 0
-; RV32I-NEXT: bne s2, a1, .LBB7_2
+; RV32I-NEXT: bne s2, zero, .LBB7_2
; RV32I-NEXT: # BB#1:
; RV32I-NEXT: srli a0, a0, 24
; RV32I-NEXT: addi s1, a0, 32
; RV32I-NEXT: .LBB7_2:
; RV32I-NEXT: addi a0, s1, 0
+; RV32I-NEXT: addi a1, zero, 0
; RV32I-NEXT: lw s7, 0(s0)
; RV32I-NEXT: lw s6, 4(s0)
; RV32I-NEXT: lw s5, 8(s0)
; RV32I-NEXT: addi a0, a1, 0
; RV32I-NEXT: addi a1, s3, 0
; RV32I-NEXT: jalr ra, s6, 0
-; RV32I-NEXT: addi a1, zero, 0
-; RV32I-NEXT: bne s2, a1, .LBB11_2
+; RV32I-NEXT: bne s2, zero, .LBB11_2
; RV32I-NEXT: # BB#1:
; RV32I-NEXT: srli a0, a0, 24
; RV32I-NEXT: addi s1, a0, 32
; RV32I-NEXT: .LBB11_2:
; RV32I-NEXT: addi a0, s1, 0
+; RV32I-NEXT: addi a1, zero, 0
; RV32I-NEXT: lw s7, 0(s0)
; RV32I-NEXT: lw s6, 4(s0)
; RV32I-NEXT: lw s5, 8(s0)
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
; RUN: | FileCheck %s -check-prefix=RV32I
-; FIXME: an unncessary register is allocated just to store 0. X0 should be
-; used instead
-
define i8 @sext_i1_to_i8(i1 %a) {
-; TODO: the addi that stores 0 in t1 is unnecessary
; RV32I-LABEL: sext_i1_to_i8:
; RV32I: # BB#0:
; RV32I-NEXT: andi a0, a0, 1
-; RV32I-NEXT: addi a1, zero, 0
-; RV32I-NEXT: sub a0, a1, a0
+; RV32I-NEXT: sub a0, zero, a0
; RV32I-NEXT: jalr zero, ra, 0
%1 = sext i1 %a to i8
ret i8 %1
}
define i16 @sext_i1_to_i16(i1 %a) {
-; TODO: the addi that stores 0 in t1 is unnecessary
; RV32I-LABEL: sext_i1_to_i16:
; RV32I: # BB#0:
; RV32I-NEXT: andi a0, a0, 1
-; RV32I-NEXT: addi a1, zero, 0
-; RV32I-NEXT: sub a0, a1, a0
+; RV32I-NEXT: sub a0, zero, a0
; RV32I-NEXT: jalr zero, ra, 0
%1 = sext i1 %a to i16
ret i16 %1
}
define i32 @sext_i1_to_i32(i1 %a) {
-; TODO: the addi that stores 0 in t1 is unnecessary
; RV32I-LABEL: sext_i1_to_i32:
; RV32I: # BB#0:
; RV32I-NEXT: andi a0, a0, 1
-; RV32I-NEXT: addi a1, zero, 0
-; RV32I-NEXT: sub a0, a1, a0
+; RV32I-NEXT: sub a0, zero, a0
; RV32I-NEXT: jalr zero, ra, 0
%1 = sext i1 %a to i32
ret i32 %1
}
define i64 @sext_i1_to_i64(i1 %a) {
-; TODO: the addi that stores 0 in t1 is unnecessary
; RV32I-LABEL: sext_i1_to_i64:
; RV32I: # BB#0:
; RV32I-NEXT: andi a0, a0, 1
-; RV32I-NEXT: addi a1, zero, 0
-; RV32I-NEXT: sub a0, a1, a0
+; RV32I-NEXT: sub a0, zero, a0
; RV32I-NEXT: addi a1, a0, 0
; RV32I-NEXT: jalr zero, ra, 0
%1 = sext i1 %a to i64