LLVM 17.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 static char ID;
45
46 XCoreDAGToDAGISel() = delete;
47
48 XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel)
49 : SelectionDAGISel(ID, TM, OptLevel) {}
50
51 void Select(SDNode *N) override;
52 bool tryBRIND(SDNode *N);
53
54 /// getI32Imm - Return a target constant with the specified value, of type
55 /// i32.
56 inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
57 return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
58 }
59
60 inline bool immMskBitp(SDNode *inN) const {
61 ConstantSDNode *N = cast<ConstantSDNode>(inN);
62 uint32_t value = (uint32_t)N->getZExtValue();
63 if (!isMask_32(value)) {
64 return false;
65 }
66 int msksize = llvm::bit_width(value);
67 return (msksize >= 1 && msksize <= 8) ||
68 msksize == 16 || msksize == 24 || msksize == 32;
69 }
70
71 // Complex Pattern Selectors.
72 bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
73
74 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
75 std::vector<SDValue> &OutOps) override;
76
77 // Include the pieces autogenerated from the target description.
78 #include "XCoreGenDAGISel.inc"
79 };
80} // end anonymous namespace
81
82char XCoreDAGToDAGISel::ID = 0;
83
84INITIALIZE_PASS(XCoreDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false)
85
86/// createXCoreISelDag - This pass converts a legalized DAG into a
87/// XCore-specific DAG, ready for instruction scheduling.
88///
90 CodeGenOpt::Level OptLevel) {
91 return new XCoreDAGToDAGISel(TM, OptLevel);
92}
93
94bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
95 SDValue &Offset) {
96 FrameIndexSDNode *FIN = nullptr;
97 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
98 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
99 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
100 return true;
101 }
102 if (Addr.getOpcode() == ISD::ADD) {
103 ConstantSDNode *CN = nullptr;
104 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
105 && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
106 && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
107 // Constant positive word offset from frame index
108 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
109 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr),
110 MVT::i32);
111 return true;
112 }
113 }
114 return false;
115}
116
117bool XCoreDAGToDAGISel::
118SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
119 std::vector<SDValue> &OutOps) {
120 SDValue Reg;
121 switch (ConstraintID) {
122 default: return true;
123 case InlineAsm::Constraint_m: // Memory.
124 switch (Op.getOpcode()) {
125 default: return true;
127 Reg = CurDAG->getRegister(XCore::CP, MVT::i32);
128 break;
130 Reg = CurDAG->getRegister(XCore::DP, MVT::i32);
131 break;
132 }
133 }
134 OutOps.push_back(Reg);
135 OutOps.push_back(Op.getOperand(0));
136 return false;
137}
138
139void XCoreDAGToDAGISel::Select(SDNode *N) {
140 SDLoc dl(N);
141 switch (N->getOpcode()) {
142 default: break;
143 case ISD::Constant: {
144 uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
145 if (immMskBitp(N)) {
146 // Transformation function: get the size of a mask
147 // Look for the first non-zero bit
148 SDValue MskSize = getI32Imm(llvm::bit_width((uint32_t)Val), dl);
149 ReplaceNode(
150 N, CurDAG->getMachineNode(XCore::MKMSK_rus, dl, MVT::i32, MskSize));
151 return;
152 }
153 else if (!isUInt<16>(Val)) {
154 SDValue CPIdx = CurDAG->getTargetConstantPool(
155 ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
156 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
157 SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
158 MVT::Other, CPIdx,
159 CurDAG->getEntryNode());
161 MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF),
163 CurDAG->setNodeMemRefs(cast<MachineSDNode>(node), {MemOp});
164 ReplaceNode(N, node);
165 return;
166 }
167 break;
168 }
169 case XCoreISD::LADD: {
170 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
171 N->getOperand(2) };
172 ReplaceNode(N, CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32,
173 MVT::i32, Ops));
174 return;
175 }
176 case XCoreISD::LSUB: {
177 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
178 N->getOperand(2) };
179 ReplaceNode(N, CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32,
180 MVT::i32, Ops));
181 return;
182 }
183 case XCoreISD::MACCU: {
184 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
185 N->getOperand(2), N->getOperand(3) };
186 ReplaceNode(N, CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32,
187 MVT::i32, Ops));
188 return;
189 }
190 case XCoreISD::MACCS: {
191 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
192 N->getOperand(2), N->getOperand(3) };
193 ReplaceNode(N, CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32,
194 MVT::i32, Ops));
195 return;
196 }
197 case XCoreISD::LMUL: {
198 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
199 N->getOperand(2), N->getOperand(3) };
200 ReplaceNode(N, CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32,
201 MVT::i32, Ops));
202 return;
203 }
204 case XCoreISD::CRC8: {
205 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
206 ReplaceNode(N, CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32,
207 MVT::i32, Ops));
208 return;
209 }
210 case ISD::BRIND:
211 if (tryBRIND(N))
212 return;
213 break;
214 // Other cases are autogenerated.
215 }
216 SelectCode(N);
217}
218
219/// Given a chain return a new chain where any appearance of Old is replaced
220/// by New. There must be at most one instruction between Old and Chain and
221/// this instruction must be a TokenFactor. Returns an empty SDValue if
222/// these conditions don't hold.
223static SDValue
225{
226 if (Chain == Old)
227 return New;
228 if (Chain->getOpcode() != ISD::TokenFactor)
229 return SDValue();
231 bool found = false;
232 for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
233 if (Chain->getOperand(i) == Old) {
234 Ops.push_back(New);
235 found = true;
236 } else {
237 Ops.push_back(Chain->getOperand(i));
238 }
239 }
240 if (!found)
241 return SDValue();
242 return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);
243}
244
245bool XCoreDAGToDAGISel::tryBRIND(SDNode *N) {
246 SDLoc dl(N);
247 // (brind (int_xcore_checkevent (addr)))
248 SDValue Chain = N->getOperand(0);
249 SDValue Addr = N->getOperand(1);
250 if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
251 return false;
252 unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
253 if (IntNo != Intrinsic::xcore_checkevent)
254 return false;
255 SDValue nextAddr = Addr->getOperand(2);
256 SDValue CheckEventChainOut(Addr.getNode(), 1);
257 if (!CheckEventChainOut.use_empty()) {
258 // If the chain out of the checkevent intrinsic is an operand of the
259 // indirect branch or used in a TokenFactor which is the operand of the
260 // indirect branch then build a new chain which uses the chain coming into
261 // the checkevent intrinsic instead.
262 SDValue CheckEventChainIn = Addr->getOperand(0);
263 SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
264 CheckEventChainIn);
265 if (!NewChain.getNode())
266 return false;
267 Chain = NewChain;
268 }
269 // Enable events on the thread using setsr 1 and then disable them immediately
270 // after with clrsr 1. If any resources owned by the thread are ready an event
271 // will be taken. If no resource is ready we branch to the address which was
272 // the operand to the checkevent intrinsic.
273 SDValue constOne = getI32Imm(1, dl);
274 SDValue Glue =
275 SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
276 constOne, Chain), 0);
277 Glue =
278 SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
279 constOne, Glue), 0);
280 if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
281 nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
282 CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
283 nextAddr->getOperand(0), Glue);
284 return true;
285 }
286 CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
287 return true;
288}
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.
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
Definition: Constants.cpp:888
int64_t getSExtValue() const
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
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, unsigned 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:225
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:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
static IntegerType * getInt32Ty(LLVMContext &C)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
Level
Code generation optimization level.
Definition: CodeGen.h:57
@ TargetBlockAddress
Definition: ISDOpcodes.h:170
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:239
@ BRIND
BRIND - Indirect branch.
Definition: ISDOpcodes.h:999
@ 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:192
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:406
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:268
int bit_width(T Value)
Returns the number of bits needed to represent Value if Value is nonzero.
Definition: bit.h:281
FunctionPass * createXCoreISelDag(XCoreTargetMachine &TM, CodeGenOpt::Level 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.