LLVM 20.0.0git
MSP430ISelDAGToDAG.cpp
Go to the documentation of this file.
1//===-- MSP430ISelDAGToDAG.cpp - A dag to dag inst selector for MSP430 ----===//
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 MSP430 target.
10//
11//===----------------------------------------------------------------------===//
12
13#include "MSP430.h"
14#include "MSP430TargetMachine.h"
19#include "llvm/Config/llvm-config.h"
20#include "llvm/IR/Constants.h"
21#include "llvm/IR/Function.h"
22#include "llvm/Support/Debug.h"
25using namespace llvm;
26
27#define DEBUG_TYPE "msp430-isel"
28#define PASS_NAME "MSP430 DAG->DAG Pattern Instruction Selection"
29
30namespace {
31 struct MSP430ISelAddressMode {
32 enum {
33 RegBase,
34 FrameIndexBase
35 } BaseType = RegBase;
36
37 struct { // This is really a union, discriminated by BaseType!
38 SDValue Reg;
39 int FrameIndex = 0;
40 } Base;
41
42 int16_t Disp = 0;
43 const GlobalValue *GV = nullptr;
44 const Constant *CP = nullptr;
45 const BlockAddress *BlockAddr = nullptr;
46 const char *ES = nullptr;
47 int JT = -1;
48 Align Alignment; // CP alignment.
49
50 MSP430ISelAddressMode() = default;
51
52 bool hasSymbolicDisplacement() const {
53 return GV != nullptr || CP != nullptr || ES != nullptr || JT != -1;
54 }
55
56#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
57 LLVM_DUMP_METHOD void dump() {
58 errs() << "MSP430ISelAddressMode " << this << '\n';
59 if (BaseType == RegBase && Base.Reg.getNode() != nullptr) {
60 errs() << "Base.Reg ";
61 Base.Reg.getNode()->dump();
62 } else if (BaseType == FrameIndexBase) {
63 errs() << " Base.FrameIndex " << Base.FrameIndex << '\n';
64 }
65 errs() << " Disp " << Disp << '\n';
66 if (GV) {
67 errs() << "GV ";
68 GV->dump();
69 } else if (CP) {
70 errs() << " CP ";
71 CP->dump();
72 errs() << " Align" << Alignment.value() << '\n';
73 } else if (ES) {
74 errs() << "ES ";
75 errs() << ES << '\n';
76 } else if (JT != -1)
77 errs() << " JT" << JT << " Align" << Alignment.value() << '\n';
78 }
79#endif
80 };
81}
82
83/// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine
84/// instructions for SelectionDAG operations.
85///
86namespace {
87 class MSP430DAGToDAGISel : public SelectionDAGISel {
88 public:
89 MSP430DAGToDAGISel() = delete;
90
91 MSP430DAGToDAGISel(MSP430TargetMachine &TM, CodeGenOptLevel OptLevel)
92 : SelectionDAGISel(TM, OptLevel) {}
93
94 private:
95 bool MatchAddress(SDValue N, MSP430ISelAddressMode &AM);
96 bool MatchWrapper(SDValue N, MSP430ISelAddressMode &AM);
97 bool MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM);
98
100 InlineAsm::ConstraintCode ConstraintID,
101 std::vector<SDValue> &OutOps) override;
102
103 // Include the pieces autogenerated from the target description.
104 #include "MSP430GenDAGISel.inc"
105
106 // Main method to transform nodes into machine nodes.
107 void Select(SDNode *N) override;
108
109 bool tryIndexedLoad(SDNode *Op);
110 bool tryIndexedBinOp(SDNode *Op, SDValue N1, SDValue N2, unsigned Opc8,
111 unsigned Opc16);
112
113 bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Disp);
114 };
115
116 class MSP430DAGToDAGISelLegacy : public SelectionDAGISelLegacy {
117 public:
118 static char ID;
119 MSP430DAGToDAGISelLegacy(MSP430TargetMachine &TM, CodeGenOptLevel OptLevel)
121 ID, std::make_unique<MSP430DAGToDAGISel>(TM, OptLevel)) {}
122 };
123} // end anonymous namespace
124
125char MSP430DAGToDAGISelLegacy::ID;
126
127INITIALIZE_PASS(MSP430DAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
128
129/// createMSP430ISelDag - This pass converts a legalized DAG into a
130/// MSP430-specific DAG, ready for instruction scheduling.
131///
133 CodeGenOptLevel OptLevel) {
134 return new MSP430DAGToDAGISelLegacy(TM, OptLevel);
135}
136
137/// MatchWrapper - Try to match MSP430ISD::Wrapper node into an addressing mode.
138/// These wrap things that will resolve down into a symbol reference. If no
139/// match is possible, this returns true, otherwise it returns false.
140bool MSP430DAGToDAGISel::MatchWrapper(SDValue N, MSP430ISelAddressMode &AM) {
141 // If the addressing mode already has a symbol as the displacement, we can
142 // never match another symbol.
143 if (AM.hasSymbolicDisplacement())
144 return true;
145
146 SDValue N0 = N.getOperand(0);
147
148 if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(N0)) {
149 AM.GV = G->getGlobal();
150 AM.Disp += G->getOffset();
151 //AM.SymbolFlags = G->getTargetFlags();
152 } else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
153 AM.CP = CP->getConstVal();
154 AM.Alignment = CP->getAlign();
155 AM.Disp += CP->getOffset();
156 //AM.SymbolFlags = CP->getTargetFlags();
157 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(N0)) {
158 AM.ES = S->getSymbol();
159 //AM.SymbolFlags = S->getTargetFlags();
160 } else if (JumpTableSDNode *J = dyn_cast<JumpTableSDNode>(N0)) {
161 AM.JT = J->getIndex();
162 //AM.SymbolFlags = J->getTargetFlags();
163 } else {
164 AM.BlockAddr = cast<BlockAddressSDNode>(N0)->getBlockAddress();
165 //AM.SymbolFlags = cast<BlockAddressSDNode>(N0)->getTargetFlags();
166 }
167 return false;
168}
169
170/// MatchAddressBase - Helper for MatchAddress. Add the specified node to the
171/// specified addressing mode without any further recursion.
172bool MSP430DAGToDAGISel::MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM) {
173 // Is the base register already occupied?
174 if (AM.BaseType != MSP430ISelAddressMode::RegBase || AM.Base.Reg.getNode()) {
175 // If so, we cannot select it.
176 return true;
177 }
178
179 // Default, generate it as a register.
180 AM.BaseType = MSP430ISelAddressMode::RegBase;
181 AM.Base.Reg = N;
182 return false;
183}
184
185bool MSP430DAGToDAGISel::MatchAddress(SDValue N, MSP430ISelAddressMode &AM) {
186 LLVM_DEBUG(errs() << "MatchAddress: "; AM.dump());
187
188 switch (N.getOpcode()) {
189 default: break;
190 case ISD::Constant: {
191 uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
192 AM.Disp += Val;
193 return false;
194 }
195
197 if (!MatchWrapper(N, AM))
198 return false;
199 break;
200
201 case ISD::FrameIndex:
202 if (AM.BaseType == MSP430ISelAddressMode::RegBase
203 && AM.Base.Reg.getNode() == nullptr) {
204 AM.BaseType = MSP430ISelAddressMode::FrameIndexBase;
205 AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
206 return false;
207 }
208 break;
209
210 case ISD::ADD: {
211 MSP430ISelAddressMode Backup = AM;
212 if (!MatchAddress(N.getNode()->getOperand(0), AM) &&
213 !MatchAddress(N.getNode()->getOperand(1), AM))
214 return false;
215 AM = Backup;
216 if (!MatchAddress(N.getNode()->getOperand(1), AM) &&
217 !MatchAddress(N.getNode()->getOperand(0), AM))
218 return false;
219 AM = Backup;
220
221 break;
222 }
223
224 case ISD::OR:
225 // Handle "X | C" as "X + C" iff X is known to have C bits clear.
226 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
227 MSP430ISelAddressMode Backup = AM;
228 uint64_t Offset = CN->getSExtValue();
229 // Start with the LHS as an addr mode.
230 if (!MatchAddress(N.getOperand(0), AM) &&
231 // Address could not have picked a GV address for the displacement.
232 AM.GV == nullptr &&
233 // Check to see if the LHS & C is zero.
234 CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) {
235 AM.Disp += Offset;
236 return false;
237 }
238 AM = Backup;
239 }
240 break;
241 }
242
243 return MatchAddressBase(N, AM);
244}
245
246/// SelectAddr - returns true if it is able pattern match an addressing mode.
247/// It returns the operands which make up the maximal addressing mode it can
248/// match by reference.
249bool MSP430DAGToDAGISel::SelectAddr(SDValue N,
250 SDValue &Base, SDValue &Disp) {
251 MSP430ISelAddressMode AM;
252
253 if (MatchAddress(N, AM))
254 return false;
255
256 if (AM.BaseType == MSP430ISelAddressMode::RegBase)
257 if (!AM.Base.Reg.getNode())
258 AM.Base.Reg = CurDAG->getRegister(MSP430::SR, MVT::i16);
259
260 Base = (AM.BaseType == MSP430ISelAddressMode::FrameIndexBase)
261 ? CurDAG->getTargetFrameIndex(
262 AM.Base.FrameIndex,
263 N.getValueType())
264 : AM.Base.Reg;
265
266 if (AM.GV)
267 Disp = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(N),
268 MVT::i16, AM.Disp,
269 0/*AM.SymbolFlags*/);
270 else if (AM.CP)
271 Disp = CurDAG->getTargetConstantPool(AM.CP, MVT::i16, AM.Alignment, AM.Disp,
272 0 /*AM.SymbolFlags*/);
273 else if (AM.ES)
274 Disp = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i16, 0/*AM.SymbolFlags*/);
275 else if (AM.JT != -1)
276 Disp = CurDAG->getTargetJumpTable(AM.JT, MVT::i16, 0/*AM.SymbolFlags*/);
277 else if (AM.BlockAddr)
278 Disp = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, 0,
279 0/*AM.SymbolFlags*/);
280 else
281 Disp = CurDAG->getSignedTargetConstant(AM.Disp, SDLoc(N), MVT::i16);
282
283 return true;
284}
285
286bool MSP430DAGToDAGISel::SelectInlineAsmMemoryOperand(
287 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
288 std::vector<SDValue> &OutOps) {
289 SDValue Op0, Op1;
290 switch (ConstraintID) {
291 default: return true;
292 case InlineAsm::ConstraintCode::m: // memory
293 if (!SelectAddr(Op, Op0, Op1))
294 return true;
295 break;
296 }
297
298 OutOps.push_back(Op0);
299 OutOps.push_back(Op1);
300 return false;
301}
302
303static bool isValidIndexedLoad(const LoadSDNode *LD) {
304 ISD::MemIndexedMode AM = LD->getAddressingMode();
305 if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD)
306 return false;
307
308 EVT VT = LD->getMemoryVT();
309
310 switch (VT.getSimpleVT().SimpleTy) {
311 case MVT::i8:
312 if (LD->getOffset()->getAsZExtVal() != 1)
313 return false;
314
315 break;
316 case MVT::i16:
317 if (LD->getOffset()->getAsZExtVal() != 2)
318 return false;
319
320 break;
321 default:
322 return false;
323 }
324
325 return true;
326}
327
328bool MSP430DAGToDAGISel::tryIndexedLoad(SDNode *N) {
329 LoadSDNode *LD = cast<LoadSDNode>(N);
330 if (!isValidIndexedLoad(LD))
331 return false;
332
333 MVT VT = LD->getMemoryVT().getSimpleVT();
334
335 unsigned Opcode = 0;
336 switch (VT.SimpleTy) {
337 case MVT::i8:
338 Opcode = MSP430::MOV8rp;
339 break;
340 case MVT::i16:
341 Opcode = MSP430::MOV16rp;
342 break;
343 default:
344 return false;
345 }
346
347 ReplaceNode(N,
348 CurDAG->getMachineNode(Opcode, SDLoc(N), VT, MVT::i16, MVT::Other,
349 LD->getBasePtr(), LD->getChain()));
350 return true;
351}
352
353bool MSP430DAGToDAGISel::tryIndexedBinOp(SDNode *Op, SDValue N1, SDValue N2,
354 unsigned Opc8, unsigned Opc16) {
355 if (N1.getOpcode() == ISD::LOAD &&
356 N1.hasOneUse() &&
357 IsLegalToFold(N1, Op, Op, OptLevel)) {
358 LoadSDNode *LD = cast<LoadSDNode>(N1);
359 if (!isValidIndexedLoad(LD))
360 return false;
361
362 MVT VT = LD->getMemoryVT().getSimpleVT();
363 unsigned Opc = (VT == MVT::i16 ? Opc16 : Opc8);
364 MachineMemOperand *MemRef = cast<MemSDNode>(N1)->getMemOperand();
365 SDValue Ops0[] = { N2, LD->getBasePtr(), LD->getChain() };
366 SDNode *ResNode =
367 CurDAG->SelectNodeTo(Op, Opc, VT, MVT::i16, MVT::Other, Ops0);
368 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemRef});
369 // Transfer chain.
370 ReplaceUses(SDValue(N1.getNode(), 2), SDValue(ResNode, 2));
371 // Transfer writeback.
372 ReplaceUses(SDValue(N1.getNode(), 1), SDValue(ResNode, 1));
373 return true;
374 }
375
376 return false;
377}
378
379
380void MSP430DAGToDAGISel::Select(SDNode *Node) {
381 SDLoc dl(Node);
382
383 // If we have a custom node, we already have selected!
384 if (Node->isMachineOpcode()) {
385 LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
386 Node->setNodeId(-1);
387 return;
388 }
389
390 // Few custom selection stuff.
391 switch (Node->getOpcode()) {
392 default: break;
393 case ISD::FrameIndex: {
394 assert(Node->getValueType(0) == MVT::i16);
395 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
396 SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i16);
397 if (Node->hasOneUse()) {
398 CurDAG->SelectNodeTo(Node, MSP430::ADDframe, MVT::i16, TFI,
399 CurDAG->getTargetConstant(0, dl, MVT::i16));
400 return;
401 }
402 ReplaceNode(Node, CurDAG->getMachineNode(
403 MSP430::ADDframe, dl, MVT::i16, TFI,
404 CurDAG->getTargetConstant(0, dl, MVT::i16)));
405 return;
406 }
407 case ISD::LOAD:
408 if (tryIndexedLoad(Node))
409 return;
410 // Other cases are autogenerated.
411 break;
412 case ISD::ADD:
413 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),
414 MSP430::ADD8rp, MSP430::ADD16rp))
415 return;
416 else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0),
417 MSP430::ADD8rp, MSP430::ADD16rp))
418 return;
419
420 // Other cases are autogenerated.
421 break;
422 case ISD::SUB:
423 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),
424 MSP430::SUB8rp, MSP430::SUB16rp))
425 return;
426
427 // Other cases are autogenerated.
428 break;
429 case ISD::AND:
430 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),
431 MSP430::AND8rp, MSP430::AND16rp))
432 return;
433 else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0),
434 MSP430::AND8rp, MSP430::AND16rp))
435 return;
436
437 // Other cases are autogenerated.
438 break;
439 case ISD::OR:
440 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),
441 MSP430::BIS8rp, MSP430::BIS16rp))
442 return;
443 else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0),
444 MSP430::BIS8rp, MSP430::BIS16rp))
445 return;
446
447 // Other cases are autogenerated.
448 break;
449 case ISD::XOR:
450 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),
451 MSP430::XOR8rp, MSP430::XOR16rp))
452 return;
453 else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0),
454 MSP430::XOR8rp, MSP430::XOR16rp))
455 return;
456
457 // Other cases are autogenerated.
458 break;
459 }
460
461 // Select the default instruction
462 SelectCode(Node);
463}
AMDGPU Register Bank Select
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:622
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define LLVM_DEBUG(...)
Definition: Debug.h:106
uint64_t Addr
#define G(x, y, z)
Definition: MD5.cpp:56
static bool isValidIndexedLoad(const LoadSDNode *LD)
#define PASS_NAME
#define DEBUG_TYPE
if(PassOpts->AAPipeline)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
DEMANGLE_DUMP_METHOD void dump() const
The address of a basic block.
Definition: Constants.h:893
This is an important base class in LLVM.
Definition: Constant.h:42
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
This class is used to represent ISD::LOAD nodes.
Machine Value Type.
SimpleValueType SimpleTy
A description of a memory reference used in the backend.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
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
bool hasOneUse() const
Return true if there is exactly one node using value ResNo of Node.
unsigned getOpcode() const
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,...
void dump() const
Support for debugging, callable in GDB: V->dump()
Definition: AsmWriter.cpp:5304
Definition: Lint.cpp:87
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:246
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
Definition: ISDOpcodes.h:1102
@ FrameIndex
Definition: ISDOpcodes.h:80
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:709
MemIndexedMode
MemIndexedMode enum - This enum defines the load / store indexed addressing modes.
Definition: ISDOpcodes.h:1562
@ Wrapper
Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol, and TargetGlobalAddress.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
@ Offset
Definition: DWP.cpp:480
CodeGenOptLevel
Code generation optimization level.
Definition: CodeGen.h:54
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
FunctionPass * createMSP430ISelDag(MSP430TargetMachine &TM, CodeGenOptLevel OptLevel)
createMSP430ISelDag - This pass converts a legalized DAG into a MSP430-specific DAG,...
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
uint64_t value() const
This is a hole in the type system and should not be abused.
Definition: Alignment.h:85
Extended Value Type.
Definition: ValueTypes.h:35
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition: ValueTypes.h:311