xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp (revision 979e22ff1ac2a50acbf94e28576a058db89003b5)
10b57cec5SDimitry Andric //===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines an instruction selector for the RISCV target.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
135ffd83dbSDimitry Andric #include "RISCVISelDAGToDAG.h"
140b57cec5SDimitry Andric #include "MCTargetDesc/RISCVMCTargetDesc.h"
150b57cec5SDimitry Andric #include "Utils/RISCVMatInt.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
175ffd83dbSDimitry Andric #include "llvm/Support/Alignment.h"
180b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
190b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
215ffd83dbSDimitry Andric 
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #define DEBUG_TYPE "riscv-isel"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() {
270b57cec5SDimitry Andric   doPeepholeLoadStoreADDI();
280b57cec5SDimitry Andric }
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, int64_t Imm,
310b57cec5SDimitry Andric                          MVT XLenVT) {
320b57cec5SDimitry Andric   RISCVMatInt::InstSeq Seq;
330b57cec5SDimitry Andric   RISCVMatInt::generateInstSeq(Imm, XLenVT == MVT::i64, Seq);
340b57cec5SDimitry Andric 
358bcb0991SDimitry Andric   SDNode *Result = nullptr;
360b57cec5SDimitry Andric   SDValue SrcReg = CurDAG->getRegister(RISCV::X0, XLenVT);
370b57cec5SDimitry Andric   for (RISCVMatInt::Inst &Inst : Seq) {
380b57cec5SDimitry Andric     SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, XLenVT);
390b57cec5SDimitry Andric     if (Inst.Opc == RISCV::LUI)
400b57cec5SDimitry Andric       Result = CurDAG->getMachineNode(RISCV::LUI, DL, XLenVT, SDImm);
410b57cec5SDimitry Andric     else
420b57cec5SDimitry Andric       Result = CurDAG->getMachineNode(Inst.Opc, DL, XLenVT, SrcReg, SDImm);
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric     // Only the first instruction has X0 as its source.
450b57cec5SDimitry Andric     SrcReg = SDValue(Result, 0);
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   return Result;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric // Returns true if the Node is an ISD::AND with a constant argument. If so,
520b57cec5SDimitry Andric // set Mask to that constant value.
530b57cec5SDimitry Andric static bool isConstantMask(SDNode *Node, uint64_t &Mask) {
540b57cec5SDimitry Andric   if (Node->getOpcode() == ISD::AND &&
550b57cec5SDimitry Andric       Node->getOperand(1).getOpcode() == ISD::Constant) {
560b57cec5SDimitry Andric     Mask = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
570b57cec5SDimitry Andric     return true;
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric   return false;
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) {
630b57cec5SDimitry Andric   // If we have a custom node, we have already selected.
640b57cec5SDimitry Andric   if (Node->isMachineOpcode()) {
650b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
660b57cec5SDimitry Andric     Node->setNodeId(-1);
670b57cec5SDimitry Andric     return;
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   // Instruction Selection not handled by the auto-generated tablegen selection
710b57cec5SDimitry Andric   // should be handled here.
720b57cec5SDimitry Andric   unsigned Opcode = Node->getOpcode();
730b57cec5SDimitry Andric   MVT XLenVT = Subtarget->getXLenVT();
740b57cec5SDimitry Andric   SDLoc DL(Node);
750b57cec5SDimitry Andric   EVT VT = Node->getValueType(0);
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   switch (Opcode) {
785ffd83dbSDimitry Andric   case ISD::ADD: {
795ffd83dbSDimitry Andric     // Optimize (add r, imm) to (addi (addi r, imm0) imm1) if applicable. The
805ffd83dbSDimitry Andric     // immediate must be in specific ranges and have a single use.
815ffd83dbSDimitry Andric     if (auto *ConstOp = dyn_cast<ConstantSDNode>(Node->getOperand(1))) {
825ffd83dbSDimitry Andric       if (!(ConstOp->hasOneUse()))
835ffd83dbSDimitry Andric         break;
845ffd83dbSDimitry Andric       // The imm must be in range [-4096,-2049] or [2048,4094].
855ffd83dbSDimitry Andric       int64_t Imm = ConstOp->getSExtValue();
865ffd83dbSDimitry Andric       if (!(-4096 <= Imm && Imm <= -2049) && !(2048 <= Imm && Imm <= 4094))
875ffd83dbSDimitry Andric         break;
885ffd83dbSDimitry Andric       // Break the imm to imm0+imm1.
895ffd83dbSDimitry Andric       SDLoc DL(Node);
905ffd83dbSDimitry Andric       EVT VT = Node->getValueType(0);
915ffd83dbSDimitry Andric       const SDValue ImmOp0 = CurDAG->getTargetConstant(Imm - Imm / 2, DL, VT);
925ffd83dbSDimitry Andric       const SDValue ImmOp1 = CurDAG->getTargetConstant(Imm / 2, DL, VT);
935ffd83dbSDimitry Andric       auto *NodeAddi0 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT,
945ffd83dbSDimitry Andric                                                Node->getOperand(0), ImmOp0);
955ffd83dbSDimitry Andric       auto *NodeAddi1 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT,
965ffd83dbSDimitry Andric                                                SDValue(NodeAddi0, 0), ImmOp1);
975ffd83dbSDimitry Andric       ReplaceNode(Node, NodeAddi1);
985ffd83dbSDimitry Andric       return;
995ffd83dbSDimitry Andric     }
1005ffd83dbSDimitry Andric     break;
1015ffd83dbSDimitry Andric   }
1020b57cec5SDimitry Andric   case ISD::Constant: {
1030b57cec5SDimitry Andric     auto ConstNode = cast<ConstantSDNode>(Node);
1040b57cec5SDimitry Andric     if (VT == XLenVT && ConstNode->isNullValue()) {
1050b57cec5SDimitry Andric       SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node),
1060b57cec5SDimitry Andric                                            RISCV::X0, XLenVT);
1070b57cec5SDimitry Andric       ReplaceNode(Node, New.getNode());
1080b57cec5SDimitry Andric       return;
1090b57cec5SDimitry Andric     }
1100b57cec5SDimitry Andric     int64_t Imm = ConstNode->getSExtValue();
1110b57cec5SDimitry Andric     if (XLenVT == MVT::i64) {
1120b57cec5SDimitry Andric       ReplaceNode(Node, selectImm(CurDAG, SDLoc(Node), Imm, XLenVT));
1130b57cec5SDimitry Andric       return;
1140b57cec5SDimitry Andric     }
1150b57cec5SDimitry Andric     break;
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric   case ISD::FrameIndex: {
1180b57cec5SDimitry Andric     SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
1190b57cec5SDimitry Andric     int FI = cast<FrameIndexSDNode>(Node)->getIndex();
1200b57cec5SDimitry Andric     SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
1210b57cec5SDimitry Andric     ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
1220b57cec5SDimitry Andric     return;
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric   case ISD::SRL: {
1250b57cec5SDimitry Andric     if (!Subtarget->is64Bit())
1260b57cec5SDimitry Andric       break;
1270b57cec5SDimitry Andric     SDValue Op0 = Node->getOperand(0);
1280b57cec5SDimitry Andric     SDValue Op1 = Node->getOperand(1);
1290b57cec5SDimitry Andric     uint64_t Mask;
1300b57cec5SDimitry Andric     // Match (srl (and val, mask), imm) where the result would be a
1310b57cec5SDimitry Andric     // zero-extended 32-bit integer. i.e. the mask is 0xffffffff or the result
1320b57cec5SDimitry Andric     // is equivalent to this (SimplifyDemandedBits may have removed lower bits
1330b57cec5SDimitry Andric     // from the mask that aren't necessary due to the right-shifting).
1340b57cec5SDimitry Andric     if (Op1.getOpcode() == ISD::Constant &&
1350b57cec5SDimitry Andric         isConstantMask(Op0.getNode(), Mask)) {
1360b57cec5SDimitry Andric       uint64_t ShAmt = cast<ConstantSDNode>(Op1.getNode())->getZExtValue();
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric       if ((Mask | maskTrailingOnes<uint64_t>(ShAmt)) == 0xffffffff) {
1390b57cec5SDimitry Andric         SDValue ShAmtVal =
1400b57cec5SDimitry Andric             CurDAG->getTargetConstant(ShAmt, SDLoc(Node), XLenVT);
1410b57cec5SDimitry Andric         CurDAG->SelectNodeTo(Node, RISCV::SRLIW, XLenVT, Op0.getOperand(0),
1420b57cec5SDimitry Andric                              ShAmtVal);
1430b57cec5SDimitry Andric         return;
1440b57cec5SDimitry Andric       }
1450b57cec5SDimitry Andric     }
1460b57cec5SDimitry Andric     break;
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric   case RISCVISD::READ_CYCLE_WIDE:
1490b57cec5SDimitry Andric     assert(!Subtarget->is64Bit() && "READ_CYCLE_WIDE is only used on riscv32");
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric     ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ReadCycleWide, DL, MVT::i32,
1520b57cec5SDimitry Andric                                              MVT::i32, MVT::Other,
1530b57cec5SDimitry Andric                                              Node->getOperand(0)));
1540b57cec5SDimitry Andric     return;
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   // Select the default instruction.
1580b57cec5SDimitry Andric   SelectCode(Node);
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(
1620b57cec5SDimitry Andric     const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
1630b57cec5SDimitry Andric   switch (ConstraintID) {
1640b57cec5SDimitry Andric   case InlineAsm::Constraint_m:
1650b57cec5SDimitry Andric     // We just support simple memory operands that have a single address
1660b57cec5SDimitry Andric     // operand and need no special handling.
1670b57cec5SDimitry Andric     OutOps.push_back(Op);
1680b57cec5SDimitry Andric     return false;
1690b57cec5SDimitry Andric   case InlineAsm::Constraint_A:
1700b57cec5SDimitry Andric     OutOps.push_back(Op);
1710b57cec5SDimitry Andric     return false;
1720b57cec5SDimitry Andric   default:
1730b57cec5SDimitry Andric     break;
1740b57cec5SDimitry Andric   }
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   return true;
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
1800b57cec5SDimitry Andric   if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
1810b57cec5SDimitry Andric     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
1820b57cec5SDimitry Andric     return true;
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric   return false;
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric 
187*979e22ffSDimitry Andric // Check that it is a SLOI (Shift Left Ones Immediate). We first check that
188*979e22ffSDimitry Andric // it is the right node tree:
189*979e22ffSDimitry Andric //
190*979e22ffSDimitry Andric //  (OR (SHL RS1, VC2), VC1)
191*979e22ffSDimitry Andric //
192*979e22ffSDimitry Andric // and then we check that VC1, the mask used to fill with ones, is compatible
193*979e22ffSDimitry Andric // with VC2, the shamt:
194*979e22ffSDimitry Andric //
195*979e22ffSDimitry Andric //  VC1 == maskTrailingOnes<uint64_t>(VC2)
196*979e22ffSDimitry Andric 
197*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSLOI(SDValue N, SDValue &RS1, SDValue &Shamt) {
198*979e22ffSDimitry Andric   MVT XLenVT = Subtarget->getXLenVT();
199*979e22ffSDimitry Andric   if (N.getOpcode() == ISD::OR) {
200*979e22ffSDimitry Andric     SDValue Or = N;
201*979e22ffSDimitry Andric     if (Or.getOperand(0).getOpcode() == ISD::SHL) {
202*979e22ffSDimitry Andric       SDValue Shl = Or.getOperand(0);
203*979e22ffSDimitry Andric       if (isa<ConstantSDNode>(Shl.getOperand(1)) &&
204*979e22ffSDimitry Andric           isa<ConstantSDNode>(Or.getOperand(1))) {
205*979e22ffSDimitry Andric         if (XLenVT == MVT::i64) {
206*979e22ffSDimitry Andric           uint64_t VC1 = Or.getConstantOperandVal(1);
207*979e22ffSDimitry Andric           uint64_t VC2 = Shl.getConstantOperandVal(1);
208*979e22ffSDimitry Andric           if (VC1 == maskTrailingOnes<uint64_t>(VC2)) {
209*979e22ffSDimitry Andric             RS1 = Shl.getOperand(0);
210*979e22ffSDimitry Andric             Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N),
211*979e22ffSDimitry Andric                            Shl.getOperand(1).getValueType());
212*979e22ffSDimitry Andric             return true;
213*979e22ffSDimitry Andric           }
214*979e22ffSDimitry Andric         }
215*979e22ffSDimitry Andric         if (XLenVT == MVT::i32) {
216*979e22ffSDimitry Andric           uint32_t VC1 = Or.getConstantOperandVal(1);
217*979e22ffSDimitry Andric           uint32_t VC2 = Shl.getConstantOperandVal(1);
218*979e22ffSDimitry Andric           if (VC1 == maskTrailingOnes<uint32_t>(VC2)) {
219*979e22ffSDimitry Andric             RS1 = Shl.getOperand(0);
220*979e22ffSDimitry Andric             Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N),
221*979e22ffSDimitry Andric                            Shl.getOperand(1).getValueType());
222*979e22ffSDimitry Andric             return true;
223*979e22ffSDimitry Andric           }
224*979e22ffSDimitry Andric         }
225*979e22ffSDimitry Andric       }
226*979e22ffSDimitry Andric     }
227*979e22ffSDimitry Andric   }
228*979e22ffSDimitry Andric   return false;
229*979e22ffSDimitry Andric }
230*979e22ffSDimitry Andric 
231*979e22ffSDimitry Andric // Check that it is a SROI (Shift Right Ones Immediate). We first check that
232*979e22ffSDimitry Andric // it is the right node tree:
233*979e22ffSDimitry Andric //
234*979e22ffSDimitry Andric //  (OR (SRL RS1, VC2), VC1)
235*979e22ffSDimitry Andric //
236*979e22ffSDimitry Andric // and then we check that VC1, the mask used to fill with ones, is compatible
237*979e22ffSDimitry Andric // with VC2, the shamt:
238*979e22ffSDimitry Andric //
239*979e22ffSDimitry Andric //  VC1 == maskLeadingOnes<uint64_t>(VC2)
240*979e22ffSDimitry Andric 
241*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSROI(SDValue N, SDValue &RS1, SDValue &Shamt) {
242*979e22ffSDimitry Andric   MVT XLenVT = Subtarget->getXLenVT();
243*979e22ffSDimitry Andric   if (N.getOpcode() == ISD::OR) {
244*979e22ffSDimitry Andric     SDValue Or = N;
245*979e22ffSDimitry Andric     if (Or.getOperand(0).getOpcode() == ISD::SRL) {
246*979e22ffSDimitry Andric       SDValue Srl = Or.getOperand(0);
247*979e22ffSDimitry Andric       if (isa<ConstantSDNode>(Srl.getOperand(1)) &&
248*979e22ffSDimitry Andric           isa<ConstantSDNode>(Or.getOperand(1))) {
249*979e22ffSDimitry Andric         if (XLenVT == MVT::i64) {
250*979e22ffSDimitry Andric           uint64_t VC1 = Or.getConstantOperandVal(1);
251*979e22ffSDimitry Andric           uint64_t VC2 = Srl.getConstantOperandVal(1);
252*979e22ffSDimitry Andric           if (VC1 == maskLeadingOnes<uint64_t>(VC2)) {
253*979e22ffSDimitry Andric             RS1 = Srl.getOperand(0);
254*979e22ffSDimitry Andric             Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N),
255*979e22ffSDimitry Andric                            Srl.getOperand(1).getValueType());
256*979e22ffSDimitry Andric             return true;
257*979e22ffSDimitry Andric           }
258*979e22ffSDimitry Andric         }
259*979e22ffSDimitry Andric         if (XLenVT == MVT::i32) {
260*979e22ffSDimitry Andric           uint32_t VC1 = Or.getConstantOperandVal(1);
261*979e22ffSDimitry Andric           uint32_t VC2 = Srl.getConstantOperandVal(1);
262*979e22ffSDimitry Andric           if (VC1 == maskLeadingOnes<uint32_t>(VC2)) {
263*979e22ffSDimitry Andric             RS1 = Srl.getOperand(0);
264*979e22ffSDimitry Andric             Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N),
265*979e22ffSDimitry Andric                            Srl.getOperand(1).getValueType());
266*979e22ffSDimitry Andric             return true;
267*979e22ffSDimitry Andric           }
268*979e22ffSDimitry Andric         }
269*979e22ffSDimitry Andric       }
270*979e22ffSDimitry Andric     }
271*979e22ffSDimitry Andric   }
272*979e22ffSDimitry Andric   return false;
273*979e22ffSDimitry Andric }
274*979e22ffSDimitry Andric 
275*979e22ffSDimitry Andric // Check that it is a RORI (Rotate Right Immediate). We first check that
276*979e22ffSDimitry Andric // it is the right node tree:
277*979e22ffSDimitry Andric //
278*979e22ffSDimitry Andric //  (ROTL RS1, VC)
279*979e22ffSDimitry Andric //
280*979e22ffSDimitry Andric // The compiler translates immediate rotations to the right given by the call
281*979e22ffSDimitry Andric // to the rotateright32/rotateright64 intrinsics as rotations to the left.
282*979e22ffSDimitry Andric // Since the rotation to the left can be easily emulated as a rotation to the
283*979e22ffSDimitry Andric // right by negating the constant, there is no encoding for ROLI.
284*979e22ffSDimitry Andric // We then select the immediate left rotations as RORI by the complementary
285*979e22ffSDimitry Andric // constant:
286*979e22ffSDimitry Andric //
287*979e22ffSDimitry Andric //  Shamt == XLen - VC
288*979e22ffSDimitry Andric 
289*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectRORI(SDValue N, SDValue &RS1, SDValue &Shamt) {
290*979e22ffSDimitry Andric   MVT XLenVT = Subtarget->getXLenVT();
291*979e22ffSDimitry Andric   if (N.getOpcode() == ISD::ROTL) {
292*979e22ffSDimitry Andric     if (isa<ConstantSDNode>(N.getOperand(1))) {
293*979e22ffSDimitry Andric       if (XLenVT == MVT::i64) {
294*979e22ffSDimitry Andric         uint64_t VC = N.getConstantOperandVal(1);
295*979e22ffSDimitry Andric         Shamt = CurDAG->getTargetConstant((64 - VC), SDLoc(N),
296*979e22ffSDimitry Andric                                           N.getOperand(1).getValueType());
297*979e22ffSDimitry Andric         RS1 = N.getOperand(0);
298*979e22ffSDimitry Andric         return true;
299*979e22ffSDimitry Andric       }
300*979e22ffSDimitry Andric       if (XLenVT == MVT::i32) {
301*979e22ffSDimitry Andric         uint32_t VC = N.getConstantOperandVal(1);
302*979e22ffSDimitry Andric         Shamt = CurDAG->getTargetConstant((32 - VC), SDLoc(N),
303*979e22ffSDimitry Andric                                           N.getOperand(1).getValueType());
304*979e22ffSDimitry Andric         RS1 = N.getOperand(0);
305*979e22ffSDimitry Andric         return true;
306*979e22ffSDimitry Andric       }
307*979e22ffSDimitry Andric     }
308*979e22ffSDimitry Andric   }
309*979e22ffSDimitry Andric   return false;
310*979e22ffSDimitry Andric }
311*979e22ffSDimitry Andric 
312*979e22ffSDimitry Andric 
313*979e22ffSDimitry Andric // Check that it is a SLLIUW (Shift Logical Left Immediate Unsigned i32
314*979e22ffSDimitry Andric // on RV64).
315*979e22ffSDimitry Andric // SLLIUW is the same as SLLI except for the fact that it clears the bits
316*979e22ffSDimitry Andric // XLEN-1:32 of the input RS1 before shifting.
317*979e22ffSDimitry Andric // We first check that it is the right node tree:
318*979e22ffSDimitry Andric //
319*979e22ffSDimitry Andric //  (AND (SHL RS1, VC2), VC1)
320*979e22ffSDimitry Andric //
321*979e22ffSDimitry Andric // We check that VC2, the shamt is less than 32, otherwise the pattern is
322*979e22ffSDimitry Andric // exactly the same as SLLI and we give priority to that.
323*979e22ffSDimitry Andric // Eventually we check that that VC1, the mask used to clear the upper 32 bits
324*979e22ffSDimitry Andric // of RS1, is correct:
325*979e22ffSDimitry Andric //
326*979e22ffSDimitry Andric //  VC1 == (0xFFFFFFFF << VC2)
327*979e22ffSDimitry Andric 
328*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSLLIUW(SDValue N, SDValue &RS1, SDValue &Shamt) {
329*979e22ffSDimitry Andric   if (N.getOpcode() == ISD::AND && Subtarget->getXLenVT() == MVT::i64) {
330*979e22ffSDimitry Andric     SDValue And = N;
331*979e22ffSDimitry Andric     if (And.getOperand(0).getOpcode() == ISD::SHL) {
332*979e22ffSDimitry Andric       SDValue Shl = And.getOperand(0);
333*979e22ffSDimitry Andric       if (isa<ConstantSDNode>(Shl.getOperand(1)) &&
334*979e22ffSDimitry Andric           isa<ConstantSDNode>(And.getOperand(1))) {
335*979e22ffSDimitry Andric         uint64_t VC1 = And.getConstantOperandVal(1);
336*979e22ffSDimitry Andric         uint64_t VC2 = Shl.getConstantOperandVal(1);
337*979e22ffSDimitry Andric         if (VC2 < 32 && VC1 == ((uint64_t)0xFFFFFFFF << VC2)) {
338*979e22ffSDimitry Andric           RS1 = Shl.getOperand(0);
339*979e22ffSDimitry Andric           Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N),
340*979e22ffSDimitry Andric                                             Shl.getOperand(1).getValueType());
341*979e22ffSDimitry Andric           return true;
342*979e22ffSDimitry Andric         }
343*979e22ffSDimitry Andric       }
344*979e22ffSDimitry Andric     }
345*979e22ffSDimitry Andric   }
346*979e22ffSDimitry Andric   return false;
347*979e22ffSDimitry Andric }
348*979e22ffSDimitry Andric 
349*979e22ffSDimitry Andric // Check that it is a SLOIW (Shift Left Ones Immediate i32 on RV64).
350*979e22ffSDimitry Andric // We first check that it is the right node tree:
351*979e22ffSDimitry Andric //
352*979e22ffSDimitry Andric //  (SIGN_EXTEND_INREG (OR (SHL RS1, VC2), VC1))
353*979e22ffSDimitry Andric //
354*979e22ffSDimitry Andric // and then we check that VC1, the mask used to fill with ones, is compatible
355*979e22ffSDimitry Andric // with VC2, the shamt:
356*979e22ffSDimitry Andric //
357*979e22ffSDimitry Andric //  VC1 == maskTrailingOnes<uint32_t>(VC2)
358*979e22ffSDimitry Andric 
359*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSLOIW(SDValue N, SDValue &RS1, SDValue &Shamt) {
360*979e22ffSDimitry Andric   if (Subtarget->getXLenVT() == MVT::i64 &&
361*979e22ffSDimitry Andric       N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
362*979e22ffSDimitry Andric       cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
363*979e22ffSDimitry Andric     if (N.getOperand(0).getOpcode() == ISD::OR) {
364*979e22ffSDimitry Andric       SDValue Or = N.getOperand(0);
365*979e22ffSDimitry Andric       if (Or.getOperand(0).getOpcode() == ISD::SHL) {
366*979e22ffSDimitry Andric         SDValue Shl = Or.getOperand(0);
367*979e22ffSDimitry Andric         if (isa<ConstantSDNode>(Shl.getOperand(1)) &&
368*979e22ffSDimitry Andric             isa<ConstantSDNode>(Or.getOperand(1))) {
369*979e22ffSDimitry Andric           uint32_t VC1 = Or.getConstantOperandVal(1);
370*979e22ffSDimitry Andric           uint32_t VC2 = Shl.getConstantOperandVal(1);
371*979e22ffSDimitry Andric           if (VC1 == maskTrailingOnes<uint32_t>(VC2)) {
372*979e22ffSDimitry Andric             RS1 = Shl.getOperand(0);
373*979e22ffSDimitry Andric             Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N),
374*979e22ffSDimitry Andric                                               Shl.getOperand(1).getValueType());
375*979e22ffSDimitry Andric             return true;
376*979e22ffSDimitry Andric           }
377*979e22ffSDimitry Andric         }
378*979e22ffSDimitry Andric       }
379*979e22ffSDimitry Andric     }
380*979e22ffSDimitry Andric   }
381*979e22ffSDimitry Andric   return false;
382*979e22ffSDimitry Andric }
383*979e22ffSDimitry Andric 
384*979e22ffSDimitry Andric // Check that it is a SROIW (Shift Right Ones Immediate i32 on RV64).
385*979e22ffSDimitry Andric // We first check that it is the right node tree:
386*979e22ffSDimitry Andric //
387*979e22ffSDimitry Andric //  (OR (SHL RS1, VC2), VC1)
388*979e22ffSDimitry Andric //
389*979e22ffSDimitry Andric // and then we check that VC1, the mask used to fill with ones, is compatible
390*979e22ffSDimitry Andric // with VC2, the shamt:
391*979e22ffSDimitry Andric //
392*979e22ffSDimitry Andric //  VC1 == maskLeadingOnes<uint32_t>(VC2)
393*979e22ffSDimitry Andric 
394*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSROIW(SDValue N, SDValue &RS1, SDValue &Shamt) {
395*979e22ffSDimitry Andric   if (N.getOpcode() == ISD::OR && Subtarget->getXLenVT() == MVT::i64) {
396*979e22ffSDimitry Andric     SDValue Or = N;
397*979e22ffSDimitry Andric     if (Or.getOperand(0).getOpcode() == ISD::SRL) {
398*979e22ffSDimitry Andric       SDValue Srl = Or.getOperand(0);
399*979e22ffSDimitry Andric       if (isa<ConstantSDNode>(Srl.getOperand(1)) &&
400*979e22ffSDimitry Andric           isa<ConstantSDNode>(Or.getOperand(1))) {
401*979e22ffSDimitry Andric         uint32_t VC1 = Or.getConstantOperandVal(1);
402*979e22ffSDimitry Andric         uint32_t VC2 = Srl.getConstantOperandVal(1);
403*979e22ffSDimitry Andric         if (VC1 == maskLeadingOnes<uint32_t>(VC2)) {
404*979e22ffSDimitry Andric           RS1 = Srl.getOperand(0);
405*979e22ffSDimitry Andric           Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N),
406*979e22ffSDimitry Andric                                             Srl.getOperand(1).getValueType());
407*979e22ffSDimitry Andric           return true;
408*979e22ffSDimitry Andric         }
409*979e22ffSDimitry Andric       }
410*979e22ffSDimitry Andric     }
411*979e22ffSDimitry Andric   }
412*979e22ffSDimitry Andric   return false;
413*979e22ffSDimitry Andric }
414*979e22ffSDimitry Andric 
415*979e22ffSDimitry Andric // Check that it is a RORIW (i32 Right Rotate Immediate on RV64).
416*979e22ffSDimitry Andric // We first check that it is the right node tree:
417*979e22ffSDimitry Andric //
418*979e22ffSDimitry Andric //  (SIGN_EXTEND_INREG (OR (SHL (AsserSext RS1, i32), VC2),
419*979e22ffSDimitry Andric //                         (SRL (AND (AssertSext RS2, i32), VC3), VC1)))
420*979e22ffSDimitry Andric //
421*979e22ffSDimitry Andric // Then we check that the constant operands respect these constraints:
422*979e22ffSDimitry Andric //
423*979e22ffSDimitry Andric // VC2 == 32 - VC1
424*979e22ffSDimitry Andric // VC3 == maskLeadingOnes<uint32_t>(VC2)
425*979e22ffSDimitry Andric //
426*979e22ffSDimitry Andric // being VC1 the Shamt we need, VC2 the complementary of Shamt over 32
427*979e22ffSDimitry Andric // and VC3 a 32 bit mask of (32 - VC1) leading ones.
428*979e22ffSDimitry Andric 
429*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectRORIW(SDValue N, SDValue &RS1, SDValue &Shamt) {
430*979e22ffSDimitry Andric   if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
431*979e22ffSDimitry Andric       Subtarget->getXLenVT() == MVT::i64 &&
432*979e22ffSDimitry Andric       cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
433*979e22ffSDimitry Andric     if (N.getOperand(0).getOpcode() == ISD::OR) {
434*979e22ffSDimitry Andric       SDValue Or = N.getOperand(0);
435*979e22ffSDimitry Andric       if (Or.getOperand(0).getOpcode() == ISD::SHL &&
436*979e22ffSDimitry Andric           Or.getOperand(1).getOpcode() == ISD::SRL) {
437*979e22ffSDimitry Andric         SDValue Shl = Or.getOperand(0);
438*979e22ffSDimitry Andric         SDValue Srl = Or.getOperand(1);
439*979e22ffSDimitry Andric         if (Srl.getOperand(0).getOpcode() == ISD::AND) {
440*979e22ffSDimitry Andric           SDValue And = Srl.getOperand(0);
441*979e22ffSDimitry Andric           if (isa<ConstantSDNode>(Srl.getOperand(1)) &&
442*979e22ffSDimitry Andric               isa<ConstantSDNode>(Shl.getOperand(1)) &&
443*979e22ffSDimitry Andric               isa<ConstantSDNode>(And.getOperand(1))) {
444*979e22ffSDimitry Andric             uint32_t VC1 = Srl.getConstantOperandVal(1);
445*979e22ffSDimitry Andric             uint32_t VC2 = Shl.getConstantOperandVal(1);
446*979e22ffSDimitry Andric             uint32_t VC3 = And.getConstantOperandVal(1);
447*979e22ffSDimitry Andric             if (VC2 == (32 - VC1) &&
448*979e22ffSDimitry Andric                 VC3 == maskLeadingOnes<uint32_t>(VC2)) {
449*979e22ffSDimitry Andric               RS1 = Shl.getOperand(0);
450*979e22ffSDimitry Andric               Shamt = CurDAG->getTargetConstant(VC1, SDLoc(N),
451*979e22ffSDimitry Andric                                               Srl.getOperand(1).getValueType());
452*979e22ffSDimitry Andric               return true;
453*979e22ffSDimitry Andric             }
454*979e22ffSDimitry Andric           }
455*979e22ffSDimitry Andric         }
456*979e22ffSDimitry Andric       }
457*979e22ffSDimitry Andric     }
458*979e22ffSDimitry Andric   }
459*979e22ffSDimitry Andric   return false;
460*979e22ffSDimitry Andric }
461*979e22ffSDimitry Andric 
462*979e22ffSDimitry Andric // Check that it is a FSRIW (i32 Funnel Shift Right Immediate on RV64).
463*979e22ffSDimitry Andric // We first check that it is the right node tree:
464*979e22ffSDimitry Andric //
465*979e22ffSDimitry Andric //  (SIGN_EXTEND_INREG (OR (SHL (AsserSext RS1, i32), VC2),
466*979e22ffSDimitry Andric //                         (SRL (AND (AssertSext RS2, i32), VC3), VC1)))
467*979e22ffSDimitry Andric //
468*979e22ffSDimitry Andric // Then we check that the constant operands respect these constraints:
469*979e22ffSDimitry Andric //
470*979e22ffSDimitry Andric // VC2 == 32 - VC1
471*979e22ffSDimitry Andric // VC3 == maskLeadingOnes<uint32_t>(VC2)
472*979e22ffSDimitry Andric //
473*979e22ffSDimitry Andric // being VC1 the Shamt we need, VC2 the complementary of Shamt over 32
474*979e22ffSDimitry Andric // and VC3 a 32 bit mask of (32 - VC1) leading ones.
475*979e22ffSDimitry Andric 
476*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectFSRIW(SDValue N, SDValue &RS1, SDValue &RS2,
477*979e22ffSDimitry Andric                                     SDValue &Shamt) {
478*979e22ffSDimitry Andric   if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
479*979e22ffSDimitry Andric       Subtarget->getXLenVT() == MVT::i64 &&
480*979e22ffSDimitry Andric       cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
481*979e22ffSDimitry Andric     if (N.getOperand(0).getOpcode() == ISD::OR) {
482*979e22ffSDimitry Andric       SDValue Or = N.getOperand(0);
483*979e22ffSDimitry Andric       if (Or.getOperand(0).getOpcode() == ISD::SHL &&
484*979e22ffSDimitry Andric           Or.getOperand(1).getOpcode() == ISD::SRL) {
485*979e22ffSDimitry Andric         SDValue Shl = Or.getOperand(0);
486*979e22ffSDimitry Andric         SDValue Srl = Or.getOperand(1);
487*979e22ffSDimitry Andric         if (Srl.getOperand(0).getOpcode() == ISD::AND) {
488*979e22ffSDimitry Andric           SDValue And = Srl.getOperand(0);
489*979e22ffSDimitry Andric           if (isa<ConstantSDNode>(Srl.getOperand(1)) &&
490*979e22ffSDimitry Andric               isa<ConstantSDNode>(Shl.getOperand(1)) &&
491*979e22ffSDimitry Andric               isa<ConstantSDNode>(And.getOperand(1))) {
492*979e22ffSDimitry Andric             uint32_t VC1 = Srl.getConstantOperandVal(1);
493*979e22ffSDimitry Andric             uint32_t VC2 = Shl.getConstantOperandVal(1);
494*979e22ffSDimitry Andric             uint32_t VC3 = And.getConstantOperandVal(1);
495*979e22ffSDimitry Andric             if (VC2 == (32 - VC1) &&
496*979e22ffSDimitry Andric                 VC3 == maskLeadingOnes<uint32_t>(VC2)) {
497*979e22ffSDimitry Andric               RS1 = Shl.getOperand(0);
498*979e22ffSDimitry Andric               RS2 = And.getOperand(0);
499*979e22ffSDimitry Andric               Shamt = CurDAG->getTargetConstant(VC1, SDLoc(N),
500*979e22ffSDimitry Andric                                               Srl.getOperand(1).getValueType());
501*979e22ffSDimitry Andric               return true;
502*979e22ffSDimitry Andric             }
503*979e22ffSDimitry Andric           }
504*979e22ffSDimitry Andric         }
505*979e22ffSDimitry Andric       }
506*979e22ffSDimitry Andric     }
507*979e22ffSDimitry Andric   }
508*979e22ffSDimitry Andric   return false;
509*979e22ffSDimitry Andric }
510*979e22ffSDimitry Andric 
5110b57cec5SDimitry Andric // Merge an ADDI into the offset of a load/store instruction where possible.
5125ffd83dbSDimitry Andric // (load (addi base, off1), off2) -> (load base, off1+off2)
5135ffd83dbSDimitry Andric // (store val, (addi base, off1), off2) -> (store val, base, off1+off2)
5145ffd83dbSDimitry Andric // This is possible when off1+off2 fits a 12-bit immediate.
5150b57cec5SDimitry Andric void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() {
5160b57cec5SDimitry Andric   SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode());
5170b57cec5SDimitry Andric   ++Position;
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   while (Position != CurDAG->allnodes_begin()) {
5200b57cec5SDimitry Andric     SDNode *N = &*--Position;
5210b57cec5SDimitry Andric     // Skip dead nodes and any non-machine opcodes.
5220b57cec5SDimitry Andric     if (N->use_empty() || !N->isMachineOpcode())
5230b57cec5SDimitry Andric       continue;
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric     int OffsetOpIdx;
5260b57cec5SDimitry Andric     int BaseOpIdx;
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric     // Only attempt this optimisation for I-type loads and S-type stores.
5290b57cec5SDimitry Andric     switch (N->getMachineOpcode()) {
5300b57cec5SDimitry Andric     default:
5310b57cec5SDimitry Andric       continue;
5320b57cec5SDimitry Andric     case RISCV::LB:
5330b57cec5SDimitry Andric     case RISCV::LH:
5340b57cec5SDimitry Andric     case RISCV::LW:
5350b57cec5SDimitry Andric     case RISCV::LBU:
5360b57cec5SDimitry Andric     case RISCV::LHU:
5370b57cec5SDimitry Andric     case RISCV::LWU:
5380b57cec5SDimitry Andric     case RISCV::LD:
5390b57cec5SDimitry Andric     case RISCV::FLW:
5400b57cec5SDimitry Andric     case RISCV::FLD:
5410b57cec5SDimitry Andric       BaseOpIdx = 0;
5420b57cec5SDimitry Andric       OffsetOpIdx = 1;
5430b57cec5SDimitry Andric       break;
5440b57cec5SDimitry Andric     case RISCV::SB:
5450b57cec5SDimitry Andric     case RISCV::SH:
5460b57cec5SDimitry Andric     case RISCV::SW:
5470b57cec5SDimitry Andric     case RISCV::SD:
5480b57cec5SDimitry Andric     case RISCV::FSW:
5490b57cec5SDimitry Andric     case RISCV::FSD:
5500b57cec5SDimitry Andric       BaseOpIdx = 1;
5510b57cec5SDimitry Andric       OffsetOpIdx = 2;
5520b57cec5SDimitry Andric       break;
5530b57cec5SDimitry Andric     }
5540b57cec5SDimitry Andric 
5555ffd83dbSDimitry Andric     if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx)))
5560b57cec5SDimitry Andric       continue;
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric     SDValue Base = N->getOperand(BaseOpIdx);
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric     // If the base is an ADDI, we can merge it in to the load/store.
5610b57cec5SDimitry Andric     if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI)
5620b57cec5SDimitry Andric       continue;
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric     SDValue ImmOperand = Base.getOperand(1);
5655ffd83dbSDimitry Andric     uint64_t Offset2 = N->getConstantOperandVal(OffsetOpIdx);
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric     if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) {
5685ffd83dbSDimitry Andric       int64_t Offset1 = Const->getSExtValue();
5695ffd83dbSDimitry Andric       int64_t CombinedOffset = Offset1 + Offset2;
5705ffd83dbSDimitry Andric       if (!isInt<12>(CombinedOffset))
5715ffd83dbSDimitry Andric         continue;
5725ffd83dbSDimitry Andric       ImmOperand = CurDAG->getTargetConstant(CombinedOffset, SDLoc(ImmOperand),
5735ffd83dbSDimitry Andric                                              ImmOperand.getValueType());
5740b57cec5SDimitry Andric     } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) {
5755ffd83dbSDimitry Andric       // If the off1 in (addi base, off1) is a global variable's address (its
5765ffd83dbSDimitry Andric       // low part, really), then we can rely on the alignment of that variable
5775ffd83dbSDimitry Andric       // to provide a margin of safety before off1 can overflow the 12 bits.
5785ffd83dbSDimitry Andric       // Check if off2 falls within that margin; if so off1+off2 can't overflow.
5795ffd83dbSDimitry Andric       const DataLayout &DL = CurDAG->getDataLayout();
5805ffd83dbSDimitry Andric       Align Alignment = GA->getGlobal()->getPointerAlignment(DL);
5815ffd83dbSDimitry Andric       if (Offset2 != 0 && Alignment <= Offset2)
5825ffd83dbSDimitry Andric         continue;
5835ffd83dbSDimitry Andric       int64_t Offset1 = GA->getOffset();
5845ffd83dbSDimitry Andric       int64_t CombinedOffset = Offset1 + Offset2;
5850b57cec5SDimitry Andric       ImmOperand = CurDAG->getTargetGlobalAddress(
5860b57cec5SDimitry Andric           GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(),
5875ffd83dbSDimitry Andric           CombinedOffset, GA->getTargetFlags());
5885ffd83dbSDimitry Andric     } else if (auto CP = dyn_cast<ConstantPoolSDNode>(ImmOperand)) {
5895ffd83dbSDimitry Andric       // Ditto.
5905ffd83dbSDimitry Andric       Align Alignment = CP->getAlign();
5915ffd83dbSDimitry Andric       if (Offset2 != 0 && Alignment <= Offset2)
5925ffd83dbSDimitry Andric         continue;
5935ffd83dbSDimitry Andric       int64_t Offset1 = CP->getOffset();
5945ffd83dbSDimitry Andric       int64_t CombinedOffset = Offset1 + Offset2;
5955ffd83dbSDimitry Andric       ImmOperand = CurDAG->getTargetConstantPool(
5965ffd83dbSDimitry Andric           CP->getConstVal(), ImmOperand.getValueType(), CP->getAlign(),
5975ffd83dbSDimitry Andric           CombinedOffset, CP->getTargetFlags());
5980b57cec5SDimitry Andric     } else {
5990b57cec5SDimitry Andric       continue;
6000b57cec5SDimitry Andric     }
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase:    ");
6030b57cec5SDimitry Andric     LLVM_DEBUG(Base->dump(CurDAG));
6040b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\nN: ");
6050b57cec5SDimitry Andric     LLVM_DEBUG(N->dump(CurDAG));
6060b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\n");
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric     // Modify the offset operand of the load/store.
6090b57cec5SDimitry Andric     if (BaseOpIdx == 0) // Load
6100b57cec5SDimitry Andric       CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand,
6110b57cec5SDimitry Andric                                  N->getOperand(2));
6120b57cec5SDimitry Andric     else // Store
6130b57cec5SDimitry Andric       CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0),
6140b57cec5SDimitry Andric                                  ImmOperand, N->getOperand(3));
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric     // The add-immediate may now be dead, in which case remove it.
6170b57cec5SDimitry Andric     if (Base.getNode()->use_empty())
6180b57cec5SDimitry Andric       CurDAG->RemoveDeadNode(Base.getNode());
6190b57cec5SDimitry Andric   }
6200b57cec5SDimitry Andric }
6210b57cec5SDimitry Andric 
6220b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready
6230b57cec5SDimitry Andric // for instruction scheduling.
6240b57cec5SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
6250b57cec5SDimitry Andric   return new RISCVDAGToDAGISel(TM);
6260b57cec5SDimitry Andric }
627