LLVM 20.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"
20#include "llvm/IR/Constants.h"
21#include "llvm/IR/Function.h"
22#include "llvm/IR/Intrinsics.h"
23#include "llvm/IR/IntrinsicsXCore.h"
24#include "llvm/IR/LLVMContext.h"
26using namespace llvm;
27
28#define DEBUG_TYPE "xcore-isel"
29#define PASS_NAME "XCore DAG->DAG Pattern Instruction Selection"
30
31/// XCoreDAGToDAGISel - XCore specific code to select XCore machine
32/// instructions for SelectionDAG operations.
33///
34namespace {
35 class XCoreDAGToDAGISel : public SelectionDAGISel {
36
37 public:
38 XCoreDAGToDAGISel() = delete;
39
40 XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOptLevel OptLevel)
41 : SelectionDAGISel(TM, OptLevel) {}
42
43 void Select(SDNode *N) override;
44 bool tryBRIND(SDNode *N);
45
46 /// getI32Imm - Return a target constant with the specified value, of type
47 /// i32.
48 inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
49 return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
50 }
51
52 inline bool immMskBitp(SDNode *inN) const {
53 ConstantSDNode *N = cast<ConstantSDNode>(inN);
54 uint32_t value = (uint32_t)N->getZExtValue();
55 if (!isMask_32(value)) {
56 return false;
57 }
58 int msksize = llvm::bit_width(value);
59 return (msksize >= 1 && msksize <= 8) ||
60 msksize == 16 || msksize == 24 || msksize == 32;
61 }
62
63 // Complex Pattern Selectors.
64 bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
65
67 InlineAsm::ConstraintCode ConstraintID,
68 std::vector<SDValue> &OutOps) override;
69
70 // Include the pieces autogenerated from the target description.
71 #include "XCoreGenDAGISel.inc"
72 };
73
74 class XCoreDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
75 public:
76 static char ID;
77 explicit XCoreDAGToDAGISelLegacy(XCoreTargetMachine &TM,
78 CodeGenOptLevel OptLevel)
80 ID, std::make_unique<XCoreDAGToDAGISel>(TM, OptLevel)) {}
81 };
82} // end anonymous namespace
83
84char XCoreDAGToDAGISelLegacy::ID = 0;
85
86INITIALIZE_PASS(XCoreDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
87
88/// createXCoreISelDag - This pass converts a legalized DAG into a
89/// XCore-specific DAG, ready for instruction scheduling.
90///
92 CodeGenOptLevel OptLevel) {
93 return new XCoreDAGToDAGISelLegacy(TM, OptLevel);
94}
95
96bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
97 SDValue &Offset) {
98 FrameIndexSDNode *FIN = nullptr;
99 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
100 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
101 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
102 return true;
103 }
104 if (Addr.getOpcode() == ISD::ADD) {
105 ConstantSDNode *CN = nullptr;
106 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
107 && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
108 && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
109 // Constant positive word offset from frame index
110 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
111 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr),
112 MVT::i32);
113 return true;
114 }
115 }
116 return false;
117}
118
119bool XCoreDAGToDAGISel::SelectInlineAsmMemoryOperand(
120 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
121 std::vector<SDValue> &OutOps) {
122 SDValue Reg;
123 switch (ConstraintID) {
124 default: return true;
125 case InlineAsm::ConstraintCode::m: // Memory.
126 switch (Op.getOpcode()) {
127 default: return true;
129 Reg = CurDAG->getRegister(XCore::CP, MVT::i32);
130 break;
132 Reg = CurDAG->getRegister(XCore::DP, MVT::i32);
133 break;
134 }
135 }
136 OutOps.push_back(Reg);
137 OutOps.push_back(Op.getOperand(0));
138 return false;
139}
140
141void XCoreDAGToDAGISel::Select(SDNode *N) {
142 SDLoc dl(N);
143 switch (N->getOpcode()) {
144 default: break;
145 case ISD::Constant: {
146 uint64_t Val = N->getAsZExtVal();
147 if (immMskBitp(N)) {
148 // Transformation function: get the size of a mask
149 // Look for the first non-zero bit
150 SDValue MskSize = getI32Imm(llvm::bit_width((uint32_t)Val), dl);
151 ReplaceNode(
152 N, CurDAG->getMachineNode(XCore::MKMSK_rus, dl, MVT::i32, MskSize));
153 return;
154 }
155 else if (!isUInt<16>(Val)) {
156 SDValue CPIdx = CurDAG->getTargetConstantPool(
157 ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
158 getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
159 SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
160 MVT::Other, CPIdx,
161 CurDAG->getEntryNode());
163 MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF),
165 CurDAG->setNodeMemRefs(cast<MachineSDNode>(node), {MemOp});
166 ReplaceNode(N, node);
167 return;
168 }
169 break;
170 }
171 case ISD::BRIND:
172 if (tryBRIND(N))
173 return;
174 break;
175 // Other cases are autogenerated.
176 }
177 SelectCode(N);
178}
179
180/// Given a chain return a new chain where any appearance of Old is replaced
181/// by New. There must be at most one instruction between Old and Chain and
182/// this instruction must be a TokenFactor. Returns an empty SDValue if
183/// these conditions don't hold.
184static SDValue
186{
187 if (Chain == Old)
188 return New;
189 if (Chain->getOpcode() != ISD::TokenFactor)
190 return SDValue();
192 bool found = false;
193 for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
194 if (Chain->getOperand(i) == Old) {
195 Ops.push_back(New);
196 found = true;
197 } else {
198 Ops.push_back(Chain->getOperand(i));
199 }
200 }
201 if (!found)
202 return SDValue();
203 return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);
204}
205
206bool XCoreDAGToDAGISel::tryBRIND(SDNode *N) {
207 SDLoc dl(N);
208 // (brind (int_xcore_checkevent (addr)))
209 SDValue Chain = N->getOperand(0);
210 SDValue Addr = N->getOperand(1);
211 if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
212 return false;
213 unsigned IntNo = Addr->getConstantOperandVal(1);
214 if (IntNo != Intrinsic::xcore_checkevent)
215 return false;
216 SDValue nextAddr = Addr->getOperand(2);
217 SDValue CheckEventChainOut(Addr.getNode(), 1);
218 if (!CheckEventChainOut.use_empty()) {
219 // If the chain out of the checkevent intrinsic is an operand of the
220 // indirect branch or used in a TokenFactor which is the operand of the
221 // indirect branch then build a new chain which uses the chain coming into
222 // the checkevent intrinsic instead.
223 SDValue CheckEventChainIn = Addr->getOperand(0);
224 SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
225 CheckEventChainIn);
226 if (!NewChain.getNode())
227 return false;
228 Chain = NewChain;
229 }
230 // Enable events on the thread using setsr 1 and then disable them immediately
231 // after with clrsr 1. If any resources owned by the thread are ready an event
232 // will be taken. If no resource is ready we branch to the address which was
233 // the operand to the checkevent intrinsic.
234 SDValue constOne = getI32Imm(1, dl);
235 SDValue Glue =
236 SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
237 constOne, Chain), 0);
238 Glue =
239 SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
240 constOne, Glue), 0);
241 if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
242 nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
243 CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
244 nextAddr->getOperand(0), Glue);
245 return true;
246 }
247 CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
248 return true;
249}
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
#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:310
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:228
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:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
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:1123
@ 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:267
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.