1 //===-- MSP430ISelDAGToDAG.cpp - A dag to dag inst selector for MSP430 ----===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines an instruction selector for the MSP430 target.
11 //===----------------------------------------------------------------------===//
14 #include "MSP430TargetMachine.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/Config/llvm-config.h"
23 #include "llvm/IR/CallingConv.h"
24 #include "llvm/IR/Constants.h"
25 #include "llvm/IR/DerivedTypes.h"
26 #include "llvm/IR/Function.h"
27 #include "llvm/IR/Intrinsics.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/raw_ostream.h"
33 #define DEBUG_TYPE "msp430-isel"
36 struct MSP430ISelAddressMode
{
42 struct { // This is really a union, discriminated by BaseType!
48 const GlobalValue
*GV
= nullptr;
49 const Constant
*CP
= nullptr;
50 const BlockAddress
*BlockAddr
= nullptr;
51 const char *ES
= nullptr;
53 Align Alignment
; // CP alignment.
55 MSP430ISelAddressMode() = default;
57 bool hasSymbolicDisplacement() const {
58 return GV
!= nullptr || CP
!= nullptr || ES
!= nullptr || JT
!= -1;
61 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
62 LLVM_DUMP_METHOD
void dump() {
63 errs() << "MSP430ISelAddressMode " << this << '\n';
64 if (BaseType
== RegBase
&& Base
.Reg
.getNode() != nullptr) {
65 errs() << "Base.Reg ";
66 Base
.Reg
.getNode()->dump();
67 } else if (BaseType
== FrameIndexBase
) {
68 errs() << " Base.FrameIndex " << Base
.FrameIndex
<< '\n';
70 errs() << " Disp " << Disp
<< '\n';
77 errs() << " Align" << Alignment
.value() << '\n';
82 errs() << " JT" << JT
<< " Align" << Alignment
.value() << '\n';
88 /// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine
89 /// instructions for SelectionDAG operations.
92 class MSP430DAGToDAGISel
: public SelectionDAGISel
{
94 MSP430DAGToDAGISel(MSP430TargetMachine
&TM
, CodeGenOpt::Level OptLevel
)
95 : SelectionDAGISel(TM
, OptLevel
) {}
98 StringRef
getPassName() const override
{
99 return "MSP430 DAG->DAG Pattern Instruction Selection";
102 bool MatchAddress(SDValue N
, MSP430ISelAddressMode
&AM
);
103 bool MatchWrapper(SDValue N
, MSP430ISelAddressMode
&AM
);
104 bool MatchAddressBase(SDValue N
, MSP430ISelAddressMode
&AM
);
106 bool SelectInlineAsmMemoryOperand(const SDValue
&Op
, unsigned ConstraintID
,
107 std::vector
<SDValue
> &OutOps
) override
;
109 // Include the pieces autogenerated from the target description.
110 #include "MSP430GenDAGISel.inc"
112 // Main method to transform nodes into machine nodes.
113 void Select(SDNode
*N
) override
;
115 bool tryIndexedLoad(SDNode
*Op
);
116 bool tryIndexedBinOp(SDNode
*Op
, SDValue N1
, SDValue N2
, unsigned Opc8
,
119 bool SelectAddr(SDValue Addr
, SDValue
&Base
, SDValue
&Disp
);
121 } // end anonymous namespace
123 /// createMSP430ISelDag - This pass converts a legalized DAG into a
124 /// MSP430-specific DAG, ready for instruction scheduling.
126 FunctionPass
*llvm::createMSP430ISelDag(MSP430TargetMachine
&TM
,
127 CodeGenOpt::Level OptLevel
) {
128 return new MSP430DAGToDAGISel(TM
, OptLevel
);
132 /// MatchWrapper - Try to match MSP430ISD::Wrapper node into an addressing mode.
133 /// These wrap things that will resolve down into a symbol reference. If no
134 /// match is possible, this returns true, otherwise it returns false.
135 bool MSP430DAGToDAGISel::MatchWrapper(SDValue N
, MSP430ISelAddressMode
&AM
) {
136 // If the addressing mode already has a symbol as the displacement, we can
137 // never match another symbol.
138 if (AM
.hasSymbolicDisplacement())
141 SDValue N0
= N
.getOperand(0);
143 if (GlobalAddressSDNode
*G
= dyn_cast
<GlobalAddressSDNode
>(N0
)) {
144 AM
.GV
= G
->getGlobal();
145 AM
.Disp
+= G
->getOffset();
146 //AM.SymbolFlags = G->getTargetFlags();
147 } else if (ConstantPoolSDNode
*CP
= dyn_cast
<ConstantPoolSDNode
>(N0
)) {
148 AM
.CP
= CP
->getConstVal();
149 AM
.Alignment
= CP
->getAlign();
150 AM
.Disp
+= CP
->getOffset();
151 //AM.SymbolFlags = CP->getTargetFlags();
152 } else if (ExternalSymbolSDNode
*S
= dyn_cast
<ExternalSymbolSDNode
>(N0
)) {
153 AM
.ES
= S
->getSymbol();
154 //AM.SymbolFlags = S->getTargetFlags();
155 } else if (JumpTableSDNode
*J
= dyn_cast
<JumpTableSDNode
>(N0
)) {
156 AM
.JT
= J
->getIndex();
157 //AM.SymbolFlags = J->getTargetFlags();
159 AM
.BlockAddr
= cast
<BlockAddressSDNode
>(N0
)->getBlockAddress();
160 //AM.SymbolFlags = cast<BlockAddressSDNode>(N0)->getTargetFlags();
165 /// MatchAddressBase - Helper for MatchAddress. Add the specified node to the
166 /// specified addressing mode without any further recursion.
167 bool MSP430DAGToDAGISel::MatchAddressBase(SDValue N
, MSP430ISelAddressMode
&AM
) {
168 // Is the base register already occupied?
169 if (AM
.BaseType
!= MSP430ISelAddressMode::RegBase
|| AM
.Base
.Reg
.getNode()) {
170 // If so, we cannot select it.
174 // Default, generate it as a register.
175 AM
.BaseType
= MSP430ISelAddressMode::RegBase
;
180 bool MSP430DAGToDAGISel::MatchAddress(SDValue N
, MSP430ISelAddressMode
&AM
) {
181 LLVM_DEBUG(errs() << "MatchAddress: "; AM
.dump());
183 switch (N
.getOpcode()) {
185 case ISD::Constant
: {
186 uint64_t Val
= cast
<ConstantSDNode
>(N
)->getSExtValue();
191 case MSP430ISD::Wrapper
:
192 if (!MatchWrapper(N
, AM
))
196 case ISD::FrameIndex
:
197 if (AM
.BaseType
== MSP430ISelAddressMode::RegBase
198 && AM
.Base
.Reg
.getNode() == nullptr) {
199 AM
.BaseType
= MSP430ISelAddressMode::FrameIndexBase
;
200 AM
.Base
.FrameIndex
= cast
<FrameIndexSDNode
>(N
)->getIndex();
206 MSP430ISelAddressMode Backup
= AM
;
207 if (!MatchAddress(N
.getNode()->getOperand(0), AM
) &&
208 !MatchAddress(N
.getNode()->getOperand(1), AM
))
211 if (!MatchAddress(N
.getNode()->getOperand(1), AM
) &&
212 !MatchAddress(N
.getNode()->getOperand(0), AM
))
220 // Handle "X | C" as "X + C" iff X is known to have C bits clear.
221 if (ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(N
.getOperand(1))) {
222 MSP430ISelAddressMode Backup
= AM
;
223 uint64_t Offset
= CN
->getSExtValue();
224 // Start with the LHS as an addr mode.
225 if (!MatchAddress(N
.getOperand(0), AM
) &&
226 // Address could not have picked a GV address for the displacement.
228 // Check to see if the LHS & C is zero.
229 CurDAG
->MaskedValueIsZero(N
.getOperand(0), CN
->getAPIntValue())) {
238 return MatchAddressBase(N
, AM
);
241 /// SelectAddr - returns true if it is able pattern match an addressing mode.
242 /// It returns the operands which make up the maximal addressing mode it can
243 /// match by reference.
244 bool MSP430DAGToDAGISel::SelectAddr(SDValue N
,
245 SDValue
&Base
, SDValue
&Disp
) {
246 MSP430ISelAddressMode AM
;
248 if (MatchAddress(N
, AM
))
251 if (AM
.BaseType
== MSP430ISelAddressMode::RegBase
)
252 if (!AM
.Base
.Reg
.getNode())
253 AM
.Base
.Reg
= CurDAG
->getRegister(MSP430::SR
, MVT::i16
);
255 Base
= (AM
.BaseType
== MSP430ISelAddressMode::FrameIndexBase
)
256 ? CurDAG
->getTargetFrameIndex(
258 getTargetLowering()->getPointerTy(CurDAG
->getDataLayout()))
262 Disp
= CurDAG
->getTargetGlobalAddress(AM
.GV
, SDLoc(N
),
264 0/*AM.SymbolFlags*/);
266 Disp
= CurDAG
->getTargetConstantPool(AM
.CP
, MVT::i16
, AM
.Alignment
, AM
.Disp
,
267 0 /*AM.SymbolFlags*/);
269 Disp
= CurDAG
->getTargetExternalSymbol(AM
.ES
, MVT::i16
, 0/*AM.SymbolFlags*/);
270 else if (AM
.JT
!= -1)
271 Disp
= CurDAG
->getTargetJumpTable(AM
.JT
, MVT::i16
, 0/*AM.SymbolFlags*/);
272 else if (AM
.BlockAddr
)
273 Disp
= CurDAG
->getTargetBlockAddress(AM
.BlockAddr
, MVT::i32
, 0,
274 0/*AM.SymbolFlags*/);
276 Disp
= CurDAG
->getTargetConstant(AM
.Disp
, SDLoc(N
), MVT::i16
);
281 bool MSP430DAGToDAGISel::
282 SelectInlineAsmMemoryOperand(const SDValue
&Op
, unsigned ConstraintID
,
283 std::vector
<SDValue
> &OutOps
) {
285 switch (ConstraintID
) {
286 default: return true;
287 case InlineAsm::Constraint_m
: // memory
288 if (!SelectAddr(Op
, Op0
, Op1
))
293 OutOps
.push_back(Op0
);
294 OutOps
.push_back(Op1
);
298 static bool isValidIndexedLoad(const LoadSDNode
*LD
) {
299 ISD::MemIndexedMode AM
= LD
->getAddressingMode();
300 if (AM
!= ISD::POST_INC
|| LD
->getExtensionType() != ISD::NON_EXTLOAD
)
303 EVT VT
= LD
->getMemoryVT();
305 switch (VT
.getSimpleVT().SimpleTy
) {
308 if (cast
<ConstantSDNode
>(LD
->getOffset())->getZExtValue() != 1)
314 if (cast
<ConstantSDNode
>(LD
->getOffset())->getZExtValue() != 2)
325 bool MSP430DAGToDAGISel::tryIndexedLoad(SDNode
*N
) {
326 LoadSDNode
*LD
= cast
<LoadSDNode
>(N
);
327 if (!isValidIndexedLoad(LD
))
330 MVT VT
= LD
->getMemoryVT().getSimpleVT();
333 switch (VT
.SimpleTy
) {
335 Opcode
= MSP430::MOV8rp
;
338 Opcode
= MSP430::MOV16rp
;
345 CurDAG
->getMachineNode(Opcode
, SDLoc(N
), VT
, MVT::i16
, MVT::Other
,
346 LD
->getBasePtr(), LD
->getChain()));
350 bool MSP430DAGToDAGISel::tryIndexedBinOp(SDNode
*Op
, SDValue N1
, SDValue N2
,
351 unsigned Opc8
, unsigned Opc16
) {
352 if (N1
.getOpcode() == ISD::LOAD
&&
354 IsLegalToFold(N1
, Op
, Op
, OptLevel
)) {
355 LoadSDNode
*LD
= cast
<LoadSDNode
>(N1
);
356 if (!isValidIndexedLoad(LD
))
359 MVT VT
= LD
->getMemoryVT().getSimpleVT();
360 unsigned Opc
= (VT
== MVT::i16
? Opc16
: Opc8
);
361 MachineMemOperand
*MemRef
= cast
<MemSDNode
>(N1
)->getMemOperand();
362 SDValue Ops0
[] = { N2
, LD
->getBasePtr(), LD
->getChain() };
364 CurDAG
->SelectNodeTo(Op
, Opc
, VT
, MVT::i16
, MVT::Other
, Ops0
);
365 CurDAG
->setNodeMemRefs(cast
<MachineSDNode
>(ResNode
), {MemRef
});
367 ReplaceUses(SDValue(N1
.getNode(), 2), SDValue(ResNode
, 2));
368 // Transfer writeback.
369 ReplaceUses(SDValue(N1
.getNode(), 1), SDValue(ResNode
, 1));
377 void MSP430DAGToDAGISel::Select(SDNode
*Node
) {
380 // If we have a custom node, we already have selected!
381 if (Node
->isMachineOpcode()) {
382 LLVM_DEBUG(errs() << "== "; Node
->dump(CurDAG
); errs() << "\n");
387 // Few custom selection stuff.
388 switch (Node
->getOpcode()) {
390 case ISD::FrameIndex
: {
391 assert(Node
->getValueType(0) == MVT::i16
);
392 int FI
= cast
<FrameIndexSDNode
>(Node
)->getIndex();
393 SDValue TFI
= CurDAG
->getTargetFrameIndex(FI
, MVT::i16
);
394 if (Node
->hasOneUse()) {
395 CurDAG
->SelectNodeTo(Node
, MSP430::ADDframe
, MVT::i16
, TFI
,
396 CurDAG
->getTargetConstant(0, dl
, MVT::i16
));
399 ReplaceNode(Node
, CurDAG
->getMachineNode(
400 MSP430::ADDframe
, dl
, MVT::i16
, TFI
,
401 CurDAG
->getTargetConstant(0, dl
, MVT::i16
)));
405 if (tryIndexedLoad(Node
))
407 // Other cases are autogenerated.
410 if (tryIndexedBinOp(Node
, Node
->getOperand(0), Node
->getOperand(1),
411 MSP430::ADD8rp
, MSP430::ADD16rp
))
413 else if (tryIndexedBinOp(Node
, Node
->getOperand(1), Node
->getOperand(0),
414 MSP430::ADD8rp
, MSP430::ADD16rp
))
417 // Other cases are autogenerated.
420 if (tryIndexedBinOp(Node
, Node
->getOperand(0), Node
->getOperand(1),
421 MSP430::SUB8rp
, MSP430::SUB16rp
))
424 // Other cases are autogenerated.
427 if (tryIndexedBinOp(Node
, Node
->getOperand(0), Node
->getOperand(1),
428 MSP430::AND8rp
, MSP430::AND16rp
))
430 else if (tryIndexedBinOp(Node
, Node
->getOperand(1), Node
->getOperand(0),
431 MSP430::AND8rp
, MSP430::AND16rp
))
434 // Other cases are autogenerated.
437 if (tryIndexedBinOp(Node
, Node
->getOperand(0), Node
->getOperand(1),
438 MSP430::BIS8rp
, MSP430::BIS16rp
))
440 else if (tryIndexedBinOp(Node
, Node
->getOperand(1), Node
->getOperand(0),
441 MSP430::BIS8rp
, MSP430::BIS16rp
))
444 // Other cases are autogenerated.
447 if (tryIndexedBinOp(Node
, Node
->getOperand(0), Node
->getOperand(1),
448 MSP430::XOR8rp
, MSP430::XOR16rp
))
450 else if (tryIndexedBinOp(Node
, Node
->getOperand(1), Node
->getOperand(0),
451 MSP430::XOR8rp
, MSP430::XOR16rp
))
454 // Other cases are autogenerated.
458 // Select the default instruction