]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file defines an instruction selector for the XCore target. | |
11 | // | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
14 | #include "XCore.h" | |
15 | #include "XCoreTargetMachine.h" | |
223e47cc LB |
16 | #include "llvm/CodeGen/MachineFrameInfo.h" |
17 | #include "llvm/CodeGen/MachineFunction.h" | |
18 | #include "llvm/CodeGen/MachineInstrBuilder.h" | |
19 | #include "llvm/CodeGen/MachineRegisterInfo.h" | |
20 | #include "llvm/CodeGen/SelectionDAG.h" | |
21 | #include "llvm/CodeGen/SelectionDAGISel.h" | |
970d7e83 LB |
22 | #include "llvm/IR/CallingConv.h" |
23 | #include "llvm/IR/Constants.h" | |
24 | #include "llvm/IR/DerivedTypes.h" | |
25 | #include "llvm/IR/Function.h" | |
26 | #include "llvm/IR/Intrinsics.h" | |
27 | #include "llvm/IR/LLVMContext.h" | |
223e47cc LB |
28 | #include "llvm/Support/Compiler.h" |
29 | #include "llvm/Support/Debug.h" | |
30 | #include "llvm/Support/ErrorHandling.h" | |
31 | #include "llvm/Support/raw_ostream.h" | |
970d7e83 | 32 | #include "llvm/Target/TargetLowering.h" |
223e47cc LB |
33 | using namespace llvm; |
34 | ||
35 | /// XCoreDAGToDAGISel - XCore specific code to select XCore machine | |
36 | /// instructions for SelectionDAG operations. | |
37 | /// | |
38 | namespace { | |
39 | class XCoreDAGToDAGISel : public SelectionDAGISel { | |
223e47cc LB |
40 | const XCoreSubtarget &Subtarget; |
41 | ||
42 | public: | |
43 | XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel) | |
44 | : SelectionDAGISel(TM, OptLevel), | |
223e47cc LB |
45 | Subtarget(*TM.getSubtargetImpl()) { } |
46 | ||
1a4d82fc | 47 | SDNode *Select(SDNode *N) override; |
223e47cc LB |
48 | SDNode *SelectBRIND(SDNode *N); |
49 | ||
50 | /// getI32Imm - Return a target constant with the specified value, of type | |
51 | /// i32. | |
52 | inline SDValue getI32Imm(unsigned Imm) { | |
53 | return CurDAG->getTargetConstant(Imm, MVT::i32); | |
54 | } | |
55 | ||
56 | inline bool immMskBitp(SDNode *inN) const { | |
57 | ConstantSDNode *N = cast<ConstantSDNode>(inN); | |
58 | uint32_t value = (uint32_t)N->getZExtValue(); | |
59 | if (!isMask_32(value)) { | |
60 | return false; | |
61 | } | |
1a4d82fc | 62 | int msksize = 32 - countLeadingZeros(value); |
223e47cc LB |
63 | return (msksize >= 1 && msksize <= 8) || |
64 | msksize == 16 || msksize == 24 || msksize == 32; | |
65 | } | |
66 | ||
67 | // Complex Pattern Selectors. | |
68 | bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset); | |
1a4d82fc JJ |
69 | |
70 | bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, | |
71 | std::vector<SDValue> &OutOps) override; | |
72 | ||
73 | const char *getPassName() const override { | |
223e47cc LB |
74 | return "XCore DAG->DAG Pattern Instruction Selection"; |
75 | } | |
76 | ||
77 | // Include the pieces autogenerated from the target description. | |
78 | #include "XCoreGenDAGISel.inc" | |
79 | }; | |
80 | } // end anonymous namespace | |
81 | ||
82 | /// createXCoreISelDag - This pass converts a legalized DAG into a | |
83 | /// XCore-specific DAG, ready for instruction scheduling. | |
84 | /// | |
85 | FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM, | |
86 | CodeGenOpt::Level OptLevel) { | |
87 | return new XCoreDAGToDAGISel(TM, OptLevel); | |
88 | } | |
89 | ||
90 | bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base, | |
91 | SDValue &Offset) { | |
1a4d82fc | 92 | FrameIndexSDNode *FIN = nullptr; |
223e47cc LB |
93 | if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { |
94 | Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); | |
95 | Offset = CurDAG->getTargetConstant(0, MVT::i32); | |
96 | return true; | |
97 | } | |
98 | if (Addr.getOpcode() == ISD::ADD) { | |
1a4d82fc | 99 | ConstantSDNode *CN = nullptr; |
223e47cc LB |
100 | if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) |
101 | && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) | |
102 | && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { | |
103 | // Constant positive word offset from frame index | |
104 | Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); | |
105 | Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32); | |
106 | return true; | |
107 | } | |
108 | } | |
109 | return false; | |
110 | } | |
111 | ||
1a4d82fc JJ |
112 | bool XCoreDAGToDAGISel:: |
113 | SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, | |
114 | std::vector<SDValue> &OutOps) { | |
115 | SDValue Reg; | |
116 | switch (ConstraintCode) { | |
117 | default: return true; | |
118 | case 'm': // Memory. | |
119 | switch (Op.getOpcode()) { | |
120 | default: return true; | |
121 | case XCoreISD::CPRelativeWrapper: | |
122 | Reg = CurDAG->getRegister(XCore::CP, MVT::i32); | |
123 | break; | |
124 | case XCoreISD::DPRelativeWrapper: | |
125 | Reg = CurDAG->getRegister(XCore::DP, MVT::i32); | |
126 | break; | |
223e47cc LB |
127 | } |
128 | } | |
1a4d82fc JJ |
129 | OutOps.push_back(Reg); |
130 | OutOps.push_back(Op.getOperand(0)); | |
223e47cc LB |
131 | return false; |
132 | } | |
133 | ||
134 | SDNode *XCoreDAGToDAGISel::Select(SDNode *N) { | |
1a4d82fc | 135 | SDLoc dl(N); |
223e47cc LB |
136 | switch (N->getOpcode()) { |
137 | default: break; | |
138 | case ISD::Constant: { | |
139 | uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue(); | |
140 | if (immMskBitp(N)) { | |
141 | // Transformation function: get the size of a mask | |
142 | // Look for the first non-zero bit | |
1a4d82fc | 143 | SDValue MskSize = getI32Imm(32 - countLeadingZeros((uint32_t)Val)); |
223e47cc LB |
144 | return CurDAG->getMachineNode(XCore::MKMSK_rus, dl, |
145 | MVT::i32, MskSize); | |
146 | } | |
147 | else if (!isUInt<16>(Val)) { | |
148 | SDValue CPIdx = | |
149 | CurDAG->getTargetConstantPool(ConstantInt::get( | |
150 | Type::getInt32Ty(*CurDAG->getContext()), Val), | |
1a4d82fc | 151 | getTargetLowering()->getPointerTy()); |
223e47cc LB |
152 | SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32, |
153 | MVT::Other, CPIdx, | |
154 | CurDAG->getEntryNode()); | |
155 | MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); | |
156 | MemOp[0] = MF->getMachineMemOperand( | |
157 | MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4); | |
158 | cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1); | |
159 | return node; | |
160 | } | |
161 | break; | |
162 | } | |
163 | case XCoreISD::LADD: { | |
164 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | |
165 | N->getOperand(2) }; | |
166 | return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32, | |
1a4d82fc | 167 | Ops); |
223e47cc LB |
168 | } |
169 | case XCoreISD::LSUB: { | |
170 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | |
171 | N->getOperand(2) }; | |
172 | return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32, | |
1a4d82fc | 173 | Ops); |
223e47cc LB |
174 | } |
175 | case XCoreISD::MACCU: { | |
176 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | |
177 | N->getOperand(2), N->getOperand(3) }; | |
178 | return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32, | |
1a4d82fc | 179 | Ops); |
223e47cc LB |
180 | } |
181 | case XCoreISD::MACCS: { | |
182 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | |
183 | N->getOperand(2), N->getOperand(3) }; | |
184 | return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32, | |
1a4d82fc | 185 | Ops); |
223e47cc LB |
186 | } |
187 | case XCoreISD::LMUL: { | |
188 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | |
189 | N->getOperand(2), N->getOperand(3) }; | |
190 | return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32, | |
1a4d82fc | 191 | Ops); |
223e47cc | 192 | } |
970d7e83 LB |
193 | case XCoreISD::CRC8: { |
194 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) }; | |
195 | return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32, | |
1a4d82fc | 196 | Ops); |
223e47cc LB |
197 | } |
198 | case ISD::BRIND: | |
199 | if (SDNode *ResNode = SelectBRIND(N)) | |
200 | return ResNode; | |
201 | break; | |
202 | // Other cases are autogenerated. | |
203 | } | |
204 | return SelectCode(N); | |
205 | } | |
206 | ||
207 | /// Given a chain return a new chain where any appearance of Old is replaced | |
208 | /// by New. There must be at most one instruction between Old and Chain and | |
209 | /// this instruction must be a TokenFactor. Returns an empty SDValue if | |
210 | /// these conditions don't hold. | |
211 | static SDValue | |
212 | replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New) | |
213 | { | |
214 | if (Chain == Old) | |
215 | return New; | |
216 | if (Chain->getOpcode() != ISD::TokenFactor) | |
217 | return SDValue(); | |
218 | SmallVector<SDValue, 8> Ops; | |
219 | bool found = false; | |
220 | for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) { | |
221 | if (Chain->getOperand(i) == Old) { | |
222 | Ops.push_back(New); | |
223 | found = true; | |
224 | } else { | |
225 | Ops.push_back(Chain->getOperand(i)); | |
226 | } | |
227 | } | |
228 | if (!found) | |
229 | return SDValue(); | |
1a4d82fc | 230 | return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops); |
223e47cc LB |
231 | } |
232 | ||
233 | SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) { | |
1a4d82fc | 234 | SDLoc dl(N); |
223e47cc LB |
235 | // (brind (int_xcore_checkevent (addr))) |
236 | SDValue Chain = N->getOperand(0); | |
237 | SDValue Addr = N->getOperand(1); | |
238 | if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN) | |
1a4d82fc | 239 | return nullptr; |
223e47cc LB |
240 | unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue(); |
241 | if (IntNo != Intrinsic::xcore_checkevent) | |
1a4d82fc | 242 | return nullptr; |
223e47cc LB |
243 | SDValue nextAddr = Addr->getOperand(2); |
244 | SDValue CheckEventChainOut(Addr.getNode(), 1); | |
245 | if (!CheckEventChainOut.use_empty()) { | |
246 | // If the chain out of the checkevent intrinsic is an operand of the | |
247 | // indirect branch or used in a TokenFactor which is the operand of the | |
248 | // indirect branch then build a new chain which uses the chain coming into | |
249 | // the checkevent intrinsic instead. | |
250 | SDValue CheckEventChainIn = Addr->getOperand(0); | |
251 | SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut, | |
252 | CheckEventChainIn); | |
253 | if (!NewChain.getNode()) | |
1a4d82fc | 254 | return nullptr; |
223e47cc LB |
255 | Chain = NewChain; |
256 | } | |
257 | // Enable events on the thread using setsr 1 and then disable them immediately | |
258 | // after with clrsr 1. If any resources owned by the thread are ready an event | |
259 | // will be taken. If no resource is ready we branch to the address which was | |
260 | // the operand to the checkevent intrinsic. | |
261 | SDValue constOne = getI32Imm(1); | |
262 | SDValue Glue = | |
263 | SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue, | |
264 | constOne, Chain), 0); | |
265 | Glue = | |
266 | SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue, | |
267 | constOne, Glue), 0); | |
268 | if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper && | |
269 | nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) { | |
270 | return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other, | |
271 | nextAddr->getOperand(0), Glue); | |
272 | } | |
273 | return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue); | |
274 | } |