[LoongArch] Eliminate the redundant sign extension of division (#107971)
[llvm-project.git] / llvm / lib / Target / ARC / ARCISelDAGToDAG.cpp
blob5e6cfa539b6d84c73d9fbef81136639bc539c086
1 //===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines an instruction selector for the ARC target.
11 //===----------------------------------------------------------------------===//
13 #include "ARC.h"
14 #include "ARCTargetMachine.h"
15 #include "llvm/CodeGen/MachineFrameInfo.h"
16 #include "llvm/CodeGen/MachineFunction.h"
17 #include "llvm/CodeGen/MachineInstrBuilder.h"
18 #include "llvm/CodeGen/MachineRegisterInfo.h"
19 #include "llvm/CodeGen/SelectionDAG.h"
20 #include "llvm/CodeGen/SelectionDAGISel.h"
21 #include "llvm/CodeGen/TargetLowering.h"
22 #include "llvm/IR/CallingConv.h"
23 #include "llvm/IR/Constants.h"
24 #include "llvm/IR/DerivedTypes.h"
25 #include "llvm/IR/Function.h"
26 #include "llvm/IR/Intrinsics.h"
27 #include "llvm/IR/LLVMContext.h"
28 #include "llvm/Support/Compiler.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/raw_ostream.h"
33 using namespace llvm;
35 #define DEBUG_TYPE "arc-isel"
36 #define PASS_NAME "ARC DAG->DAG Pattern Instruction Selection"
38 /// ARCDAGToDAGISel - ARC specific code to select ARC machine
39 /// instructions for SelectionDAG operations.
40 namespace {
42 class ARCDAGToDAGISel : public SelectionDAGISel {
43 public:
44 ARCDAGToDAGISel() = delete;
46 ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOptLevel OptLevel)
47 : SelectionDAGISel(TM, OptLevel) {}
49 void Select(SDNode *N) override;
51 // Complex Pattern Selectors.
52 bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset);
53 bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset);
54 bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset);
55 bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset);
57 // Include the pieces autogenerated from the target description.
58 #include "ARCGenDAGISel.inc"
61 class ARCDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
62 public:
63 static char ID;
64 explicit ARCDAGToDAGISelLegacy(ARCTargetMachine &TM, CodeGenOptLevel OptLevel)
65 : SelectionDAGISelLegacy(
66 ID, std::make_unique<ARCDAGToDAGISel>(TM, OptLevel)) {}
69 char ARCDAGToDAGISelLegacy::ID;
71 } // end anonymous namespace
73 INITIALIZE_PASS(ARCDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
75 /// This pass converts a legalized DAG into a ARC-specific DAG, ready for
76 /// instruction scheduling.
77 FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM,
78 CodeGenOptLevel OptLevel) {
79 return new ARCDAGToDAGISelLegacy(TM, OptLevel);
82 bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base,
83 SDValue &Offset) {
84 if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
85 Base = Addr.getOperand(0);
86 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
87 return true;
89 return false;
92 bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base,
93 SDValue &Offset) {
94 if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
95 return false;
98 if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB &&
99 !CurDAG->isBaseWithConstantOffset(Addr)) {
100 if (Addr.getOpcode() == ISD::FrameIndex) {
101 // Match frame index.
102 int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
103 Base = CurDAG->getTargetFrameIndex(
104 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
105 } else {
106 Base = Addr;
108 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
109 return true;
112 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
113 int32_t RHSC = RHS->getSExtValue();
114 if (Addr.getOpcode() == ISD::SUB)
115 RHSC = -RHSC;
117 // Do we need more than 9 bits to encode?
118 if (!isInt<9>(RHSC))
119 return false;
120 Base = Addr.getOperand(0);
121 if (Base.getOpcode() == ISD::FrameIndex) {
122 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
123 Base = CurDAG->getTargetFrameIndex(
124 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
126 Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
127 return true;
129 Base = Addr;
130 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
131 return true;
134 bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base,
135 SDValue &Offset) {
136 if (SelectAddrModeS9(Addr, Base, Offset))
137 return false;
138 if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
139 return false;
141 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
142 int32_t RHSC = RHS->getSExtValue();
143 if (Addr.getOpcode() == ISD::SUB)
144 RHSC = -RHSC;
145 Base = Addr.getOperand(0);
146 Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
147 return true;
149 return false;
152 // Is this a legal frame index addressing expression.
153 bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base,
154 SDValue &Offset) {
155 FrameIndexSDNode *FIN = nullptr;
156 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
157 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
158 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
159 return true;
161 if (Addr.getOpcode() == ISD::ADD) {
162 ConstantSDNode *CN = nullptr;
163 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
164 (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
165 (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
166 // Constant positive word offset from frame index
167 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
168 Offset =
169 CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32);
170 return true;
173 return false;
176 void ARCDAGToDAGISel::Select(SDNode *N) {
177 switch (N->getOpcode()) {
178 case ISD::Constant: {
179 uint64_t CVal = N->getAsZExtVal();
180 ReplaceNode(N, CurDAG->getMachineNode(
181 isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm,
182 SDLoc(N), MVT::i32,
183 CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32)));
184 return;
187 SelectCode(N);