summaryrefslogtreecommitdiff
path: root/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/RISCV/RISCVISelDAGToDAG.cpp')
-rw-r--r--lib/Target/RISCV/RISCVISelDAGToDAG.cpp126
1 files changed, 74 insertions, 52 deletions
diff --git a/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 04441b9a9b15a..aa80365feb830 100644
--- a/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "RISCV.h"
#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "RISCV.h"
#include "RISCVTargetMachine.h"
+#include "Utils/RISCVMatInt.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Support/Debug.h"
@@ -56,20 +57,47 @@ public:
private:
void doPeepholeLoadStoreADDI();
- void doPeepholeBuildPairF64SplitF64();
};
}
void RISCVDAGToDAGISel::PostprocessISelDAG() {
doPeepholeLoadStoreADDI();
- doPeepholeBuildPairF64SplitF64();
}
-void RISCVDAGToDAGISel::Select(SDNode *Node) {
- unsigned Opcode = Node->getOpcode();
- MVT XLenVT = Subtarget->getXLenVT();
+static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, int64_t Imm,
+ MVT XLenVT) {
+ RISCVMatInt::InstSeq Seq;
+ RISCVMatInt::generateInstSeq(Imm, XLenVT == MVT::i64, Seq);
+
+ SDNode *Result;
+ SDValue SrcReg = CurDAG->getRegister(RISCV::X0, XLenVT);
+ for (RISCVMatInt::Inst &Inst : Seq) {
+ SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, XLenVT);
+ if (Inst.Opc == RISCV::LUI)
+ Result = CurDAG->getMachineNode(RISCV::LUI, DL, XLenVT, SDImm);
+ else
+ Result = CurDAG->getMachineNode(Inst.Opc, DL, XLenVT, SrcReg, SDImm);
+
+ // Only the first instruction has X0 as its source.
+ SrcReg = SDValue(Result, 0);
+ }
+
+ return Result;
+}
+
+// Returns true if the Node is an ISD::AND with a constant argument. If so,
+// set Mask to that constant value.
+static bool isConstantMask(SDNode *Node, uint64_t &Mask) {
+ if (Node->getOpcode() == ISD::AND &&
+ Node->getOperand(1).getOpcode() == ISD::Constant) {
+ Mask = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
+ return true;
+ }
+ return false;
+}
- // If we have a custom node, we have already selected
+void RISCVDAGToDAGISel::Select(SDNode *Node) {
+ // If we have a custom node, we have already selected.
if (Node->isMachineOpcode()) {
LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
Node->setNodeId(-1);
@@ -78,27 +106,58 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
// Instruction Selection not handled by the auto-generated tablegen selection
// should be handled here.
+ unsigned Opcode = Node->getOpcode();
+ MVT XLenVT = Subtarget->getXLenVT();
+ SDLoc DL(Node);
EVT VT = Node->getValueType(0);
- if (Opcode == ISD::Constant && VT == XLenVT) {
- auto *ConstNode = cast<ConstantSDNode>(Node);
- // Materialize zero constants as copies from X0. This allows the coalescer
- // to propagate these into other instructions.
- if (ConstNode->isNullValue()) {
+
+ switch (Opcode) {
+ case ISD::Constant: {
+ auto ConstNode = cast<ConstantSDNode>(Node);
+ if (VT == XLenVT && ConstNode->isNullValue()) {
SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node),
RISCV::X0, XLenVT);
ReplaceNode(Node, New.getNode());
return;
}
+ int64_t Imm = ConstNode->getSExtValue();
+ if (XLenVT == MVT::i64) {
+ ReplaceNode(Node, selectImm(CurDAG, SDLoc(Node), Imm, XLenVT));
+ return;
+ }
+ break;
}
- if (Opcode == ISD::FrameIndex) {
- SDLoc DL(Node);
+ case ISD::FrameIndex: {
SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
int FI = cast<FrameIndexSDNode>(Node)->getIndex();
- EVT VT = Node->getValueType(0);
SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
return;
}
+ case ISD::SRL: {
+ if (!Subtarget->is64Bit())
+ break;
+ SDValue Op0 = Node->getOperand(0);
+ SDValue Op1 = Node->getOperand(1);
+ uint64_t Mask;
+ // Match (srl (and val, mask), imm) where the result would be a
+ // zero-extended 32-bit integer. i.e. the mask is 0xffffffff or the result
+ // is equivalent to this (SimplifyDemandedBits may have removed lower bits
+ // from the mask that aren't necessary due to the right-shifting).
+ if (Op1.getOpcode() == ISD::Constant &&
+ isConstantMask(Op0.getNode(), Mask)) {
+ uint64_t ShAmt = cast<ConstantSDNode>(Op1.getNode())->getZExtValue();
+
+ if ((Mask | maskTrailingOnes<uint64_t>(ShAmt)) == 0xffffffff) {
+ SDValue ShAmtVal =
+ CurDAG->getTargetConstant(ShAmt, SDLoc(Node), XLenVT);
+ CurDAG->SelectNodeTo(Node, RISCV::SRLIW, XLenVT, Op0.getOperand(0),
+ ShAmtVal);
+ return;
+ }
+ }
+ }
+ }
// Select the default instruction.
SelectCode(Node);
@@ -216,43 +275,6 @@ void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() {
}
}
-// Remove redundant BuildPairF64+SplitF64 pairs. i.e. cases where an f64 is
-// built of two i32 values, only to be split apart again. This must be done
-// here as a peephole optimisation as the DAG has not been fully legalized at
-// the point BuildPairF64/SplitF64 nodes are created in RISCVISelLowering, so
-// some nodes would not yet have been replaced with libcalls.
-void RISCVDAGToDAGISel::doPeepholeBuildPairF64SplitF64() {
- SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
- ++Position;
-
- while (Position != CurDAG->allnodes_begin()) {
- SDNode *N = &*--Position;
- // Skip dead nodes and any nodes other than SplitF64Pseudo.
- if (N->use_empty() || !N->isMachineOpcode() ||
- !(N->getMachineOpcode() == RISCV::SplitF64Pseudo))
- continue;
-
- // If the operand to SplitF64 is a BuildPairF64, the split operation is
- // redundant. Just use the operands to BuildPairF64 as the result.
- SDValue F64Val = N->getOperand(0);
- if (F64Val.isMachineOpcode() &&
- F64Val.getMachineOpcode() == RISCV::BuildPairF64Pseudo) {
- LLVM_DEBUG(
- dbgs() << "Removing redundant SplitF64Pseudo and replacing uses "
- "with BuildPairF64Pseudo operands:\n");
- LLVM_DEBUG(dbgs() << "N: ");
- LLVM_DEBUG(N->dump(CurDAG));
- LLVM_DEBUG(dbgs() << "F64Val: ");
- LLVM_DEBUG(F64Val->dump(CurDAG));
- LLVM_DEBUG(dbgs() << "\n");
- SDValue From[] = {SDValue(N, 0), SDValue(N, 1)};
- SDValue To[] = {F64Val.getOperand(0), F64Val.getOperand(1)};
- CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
- }
- }
- CurDAG->RemoveDeadNodes();
-}
-
// This pass converts a legalized DAG into a RISCV-specific DAG, ready
// for instruction scheduling.
FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {