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