LLVM 19.0.0git
XCoreISelDAGToDAG.cpp
Go to the documentation of this file.
1//===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===//
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 XCore target.
10//
11//===----------------------------------------------------------------------===//
12
13#include "XCore.h"
14#include "XCoreTargetMachine.h"
22#include "llvm/IR/CallingConv.h"
23#include "llvm/IR/Constants.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/Intrinsics.h"
27#include "llvm/IR/IntrinsicsXCore.h"
28#include "llvm/IR/LLVMContext.h"
29#include "llvm/Support/Debug.h"
32using namespace llvm;
33
34#define DEBUG_TYPE "xcore-isel"
35#define PASS_NAME "XCore DAG->DAG Pattern Instruction Selection"
36
37/// XCoreDAGToDAGISel - XCore specific code to select XCore machine
38/// instructions for SelectionDAG operations.
39///
40namespace {
41 class XCoreDAGToDAGISel : public SelectionDAGISel {
42
43 public:
44 XCoreDAGToDAGISel() = delete;
45
46 XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOptLevel OptLevel)
47 : SelectionDAGISel(TM, OptLevel) {}
48
49 void Select(SDNode *N) override;
50 bool tryBRIND(SDNode *N);
51
52 /// getI32Imm - Return a target constant with the specified value, of type
53 /// i32.
54 inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
55 return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
56 }
57
58 inline bool immMskBitp(SDNode *inN) const {
59 ConstantSDNode *N = cast<ConstantSDNode>(inN);
60 uint32_t value = (uint32_t)N->getZExtValue();
61 if (!isMask_32(value)) {
62 return false;
63 }
64 int msksize = llvm::bit_width(value);
65 return (msksize >= 1 && msksize <= 8) ||
66 msksize == 16 || msksize == 24 || msksize == 32;
67 }
68
69 // Complex Pattern Selectors.
70 bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
71
73 InlineAsm::ConstraintCode ConstraintID,
74 std::vector<SDValue> &OutOps) override;
75
76 // Include the pieces autogenerated from the target description.
77 #include "XCoreGenDAGISel.inc"
78 };
79
80 class XCoreDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
81 public:
82 static char ID;
83 explicit XCoreDAGToDAGISelLegacy(XCoreTargetMachine &TM,
84 CodeGenOptLevel OptLevel)
86 ID, std::make_unique<XCoreDAGToDAGISel>(TM, OptLevel)) {}
87 };
88} // end anonymous namespace
89
90char XCoreDAGToDAGISelLegacy::ID = 0;
91
92INITIALIZE_PASS(XCoreDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
93
94/// createXCoreISelDag - This pass converts a legalized DAG into a
95/// XCore-specific DAG, ready for instruction scheduling.
96///
98 CodeGenOptLevel OptLevel) {
99 return new XCoreDAGToDAGISelLegacy(TM, OptLevel);
100}
101
102bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
103 SDValue &Offset) {
104 FrameIndexSDNode *FIN = nullptr;
105 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
106 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
107 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
108 return true;
109 }
110 if (Addr.getOpcode() == ISD::ADD) {
111 ConstantSDNode *CN = nullptr;
112 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
113 && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
114 && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
115 // Constant positive word offset from frame index
116 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
117 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr),
118 MVT::i32);
119 return true;
120 }
121 }
122 return false;
123}
124
125bool XCoreDAGToDAGISel::SelectInlineAsmMemoryOperand(
126 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
127 std::vector<SDValue> &OutOps) {
128 SDValue Reg;
129 switch (ConstraintID) {
130 default: return true;
131 case InlineAsm::ConstraintCode::m: // Memory.
132 switch (Op.getOpcode()) {
133 default: return true;
135 Reg = CurDAG->getRegister(XCore::CP, MVT::i32);
136 break;
138 Reg = CurDAG->getRegister(XCore::DP, MVT::i32);
139 break;
140 }
141 }
142 OutOps.push_back(Reg);
143 OutOps.push_back(Op.getOperand(0));
144 return false;
145}
146
147void XCoreDAGToDAGISel::Select(SDNode *N) {
148 SDLoc dl(N);
149 switch (N->getOpcode()) {
150 default: break;
151 case ISD::Constant: {
152 uint64_t Val = N->getAsZExtVal();
153 if (immMskBitp(N)) {
154 // Transformation function: get the size of a mask
155 // Look for the first non-zero bit
156 SDValue MskSize = getI32Imm(llvm::bit_width((uint32_t)Val), dl);
157 ReplaceNode(
158 N, CurDAG->getMachineNode(XCore::MKMSK_rus, dl, MVT::i32, MskSize));
159 return;
160 }
161 else if (!isUInt<16>(Val)) {
162 SDValue CPIdx = CurDAG->getTargetConstantPool(
163 ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
164 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
165 SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
166 MVT::Other, CPIdx,
167 CurDAG->getEntryNode());
169 MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF),
171 CurDAG->setNodeMemRefs(cast<MachineSDNode>(node), {MemOp});
172 ReplaceNode(N, node);
173 return;
174 }
175 break;
176 }
177 case XCoreISD::LADD: {
178 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
179 N->getOperand(2) };
180 ReplaceNode(N, CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32,
181 MVT::i32, Ops));
182 return;
183 }
184 case XCoreISD::LSUB: {
185 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
186 N->getOperand(2) };
187 ReplaceNode(N, CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32,
188 MVT::i32, Ops));
189 return;
190 }
191 case XCoreISD::MACCU: {
192 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
193 N->getOperand(2), N->getOperand(3) };
194 ReplaceNode(N, CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32,
195 MVT::i32, Ops));
196 return;
197 }
198 case XCoreISD::MACCS: {
199 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
200 N->getOperand(2), N->getOperand(3) };
201 ReplaceNode(N, CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32,
202 MVT::i32, Ops));
203 return;
204 }
205 case XCoreISD::LMUL: {
206 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
207 N->getOperand(2), N->getOperand(3) };
208 ReplaceNode(N, CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32,
209 MVT::i32, Ops));
210 return;
211 }
212 case XCoreISD::CRC8: {
213 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
214 ReplaceNode(N, CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32,
215 MVT::i32, Ops));
216 return;
217 }
218 case ISD::BRIND:
219 if (tryBRIND(N))
220 return;
221 break;
222 // Other cases are autogenerated.
223 }
224 SelectCode(N);
225}
226
227/// Given a chain return a new chain where any appearance of Old is replaced
228/// by New. There must be at most one instruction between Old and Chain and
229/// this instruction must be a TokenFactor. Returns an empty SDValue if
230/// these conditions don't hold.
231static SDValue
233{
234 if (Chain == Old)
235 return New;
236 if (Chain->getOpcode() != ISD::TokenFactor)
237 return SDValue();
239 bool found = false;
240 for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
241 if (Chain->getOperand(i) == Old) {
242 Ops.push_back(New);
243 found = true;
244 } else {
245 Ops.push_back(Chain->getOperand(i));
246 }
247 }
248 if (!found)
249 return SDValue();
250 return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);
251}
252
253bool XCoreDAGToDAGISel::tryBRIND(SDNode *N) {
254 SDLoc dl(N);
255 // (brind (int_xcore_checkevent (addr)))
256 SDValue Chain = N->getOperand(0);
257 SDValue Addr = N->getOperand(1);
258 if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
259 return false;
260 unsigned IntNo = Addr->getConstantOperandVal(1);
261 if (IntNo != Intrinsic::xcore_checkevent)
262 return false;
263 SDValue nextAddr = Addr->getOperand(2);
264 SDValue CheckEventChainOut(Addr.getNode(), 1);
265 if (!CheckEventChainOut.use_empty()) {
266 // If the chain out of the checkevent intrinsic is an operand of the
267 // indirect branch or used in a TokenFactor which is the operand of the
268 // indirect branch then build a new chain which uses the chain coming into
269 // the checkevent intrinsic instead.
270 SDValue CheckEventChainIn = Addr->getOperand(0);
271 SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
272 CheckEventChainIn);
273 if (!NewChain.getNode())
274 return false;
275 Chain = NewChain;
276 }
277 // Enable events on the thread using setsr 1 and then disable them immediately
278 // after with clrsr 1. If any resources owned by the thread are ready an event
279 // will be taken. If no resource is ready we branch to the address which was
280 // the operand to the checkevent intrinsic.
281 SDValue constOne = getI32Imm(1, dl);
282 SDValue Glue =
283 SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
284 constOne, Chain), 0);
285 Glue =
286 SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
287 constOne, Glue), 0);
288 if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
289 nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
290 CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
291 nextAddr->getOperand(0), Glue);
292 return true;
293 }
294 CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
295 return true;
296}
amdgpu AMDGPU Register Bank Select
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Given that RA is a live value
uint64_t Addr
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
This file describes how to lower LLVM code to machine code.
#define PASS_NAME
#define DEBUG_TYPE
static SDValue replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
Given a chain return a new chain where any appearance of Old is replaced by New.
int64_t getSExtValue() const
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
A description of a memory reference used in the backend.
@ MOLoad
The memory access reads data.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
Definition: SelectionDAG.h:227
SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
static IntegerType * getInt32Ty(LLVMContext &C)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ TargetBlockAddress
Definition: ISDOpcodes.h:176
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:246
@ BRIND
BRIND - Indirect branch.
Definition: ISDOpcodes.h:1073
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition: ISDOpcodes.h:52
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition: ISDOpcodes.h:198
Reg
All possible values of the reg field in the ModR/M byte.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
constexpr bool isMask_32(uint32_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition: MathExtras.h:251
int bit_width(T Value)
Returns the number of bits needed to represent Value if Value is nonzero.
Definition: bit.h:317
CodeGenOptLevel
Code generation optimization level.
Definition: CodeGen.h:54
FunctionPass * createXCoreISelDag(XCoreTargetMachine &TM, CodeGenOptLevel OptLevel)
createXCoreISelDag - This pass converts a legalized DAG into a XCore-specific DAG,...
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
static MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.