1 | //===-- LanaiISelLowering.cpp - Lanai DAG Lowering Implementation ---------===// |
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 implements the LanaiTargetLowering class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "LanaiISelLowering.h" |
14 | #include "Lanai.h" |
15 | #include "LanaiCondCode.h" |
16 | #include "LanaiMachineFunctionInfo.h" |
17 | #include "LanaiSubtarget.h" |
18 | #include "LanaiTargetObjectFile.h" |
19 | #include "MCTargetDesc/LanaiBaseInfo.h" |
20 | #include "llvm/ADT/APInt.h" |
21 | #include "llvm/ADT/ArrayRef.h" |
22 | #include "llvm/ADT/SmallVector.h" |
23 | #include "llvm/ADT/StringRef.h" |
24 | #include "llvm/ADT/StringSwitch.h" |
25 | #include "llvm/CodeGen/CallingConvLower.h" |
26 | #include "llvm/CodeGen/MachineFrameInfo.h" |
27 | #include "llvm/CodeGen/MachineFunction.h" |
28 | #include "llvm/CodeGen/MachineMemOperand.h" |
29 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
30 | #include "llvm/CodeGen/RuntimeLibcallUtil.h" |
31 | #include "llvm/CodeGen/SelectionDAG.h" |
32 | #include "llvm/CodeGen/SelectionDAGNodes.h" |
33 | #include "llvm/CodeGen/TargetCallingConv.h" |
34 | #include "llvm/CodeGen/ValueTypes.h" |
35 | #include "llvm/CodeGenTypes/MachineValueType.h" |
36 | #include "llvm/IR/CallingConv.h" |
37 | #include "llvm/IR/DerivedTypes.h" |
38 | #include "llvm/IR/Function.h" |
39 | #include "llvm/IR/GlobalValue.h" |
40 | #include "llvm/Support/Casting.h" |
41 | #include "llvm/Support/CodeGen.h" |
42 | #include "llvm/Support/CommandLine.h" |
43 | #include "llvm/Support/Debug.h" |
44 | #include "llvm/Support/ErrorHandling.h" |
45 | #include "llvm/Support/KnownBits.h" |
46 | #include "llvm/Support/MathExtras.h" |
47 | #include "llvm/Support/raw_ostream.h" |
48 | #include "llvm/Target/TargetMachine.h" |
49 | #include <cassert> |
50 | #include <cmath> |
51 | #include <cstdint> |
52 | #include <cstdlib> |
53 | #include <utility> |
54 | |
55 | #define DEBUG_TYPE "lanai-lower" |
56 | |
57 | using namespace llvm; |
58 | |
59 | // Limit on number of instructions the lowered multiplication may have before a |
60 | // call to the library function should be generated instead. The threshold is |
61 | // currently set to 14 as this was the smallest threshold that resulted in all |
62 | // constant multiplications being lowered. A threshold of 5 covered all cases |
63 | // except for one multiplication which required 14. mulsi3 requires 16 |
64 | // instructions (including the prologue and epilogue but excluding instructions |
65 | // at call site). Until we can inline mulsi3, generating at most 14 instructions |
66 | // will be faster than invoking mulsi3. |
67 | static cl::opt<int> LanaiLowerConstantMulThreshold( |
68 | "lanai-constant-mul-threshold" , cl::Hidden, |
69 | cl::desc("Maximum number of instruction to generate when lowering constant " |
70 | "multiplication instead of calling library function [default=14]" ), |
71 | cl::init(Val: 14)); |
72 | |
73 | LanaiTargetLowering::LanaiTargetLowering(const TargetMachine &TM, |
74 | const LanaiSubtarget &STI) |
75 | : TargetLowering(TM) { |
76 | // Set up the register classes. |
77 | addRegisterClass(VT: MVT::i32, RC: &Lanai::GPRRegClass); |
78 | |
79 | // Compute derived properties from the register classes |
80 | TRI = STI.getRegisterInfo(); |
81 | computeRegisterProperties(TRI); |
82 | |
83 | setStackPointerRegisterToSaveRestore(Lanai::SP); |
84 | |
85 | setOperationAction(Op: ISD::BR_CC, VT: MVT::i32, Action: Custom); |
86 | setOperationAction(Op: ISD::BR_JT, VT: MVT::Other, Action: Expand); |
87 | setOperationAction(Op: ISD::BRCOND, VT: MVT::Other, Action: Expand); |
88 | setOperationAction(Op: ISD::SETCC, VT: MVT::i32, Action: Custom); |
89 | setOperationAction(Op: ISD::SELECT, VT: MVT::i32, Action: Expand); |
90 | setOperationAction(Op: ISD::SELECT_CC, VT: MVT::i32, Action: Custom); |
91 | |
92 | setOperationAction(Op: ISD::GlobalAddress, VT: MVT::i32, Action: Custom); |
93 | setOperationAction(Op: ISD::BlockAddress, VT: MVT::i32, Action: Custom); |
94 | setOperationAction(Op: ISD::JumpTable, VT: MVT::i32, Action: Custom); |
95 | setOperationAction(Op: ISD::ConstantPool, VT: MVT::i32, Action: Custom); |
96 | |
97 | setOperationAction(Op: ISD::DYNAMIC_STACKALLOC, VT: MVT::i32, Action: Custom); |
98 | setOperationAction(Op: ISD::STACKSAVE, VT: MVT::Other, Action: Expand); |
99 | setOperationAction(Op: ISD::STACKRESTORE, VT: MVT::Other, Action: Expand); |
100 | |
101 | setOperationAction(Op: ISD::VASTART, VT: MVT::Other, Action: Custom); |
102 | setOperationAction(Op: ISD::VAARG, VT: MVT::Other, Action: Expand); |
103 | setOperationAction(Op: ISD::VACOPY, VT: MVT::Other, Action: Expand); |
104 | setOperationAction(Op: ISD::VAEND, VT: MVT::Other, Action: Expand); |
105 | |
106 | setOperationAction(Op: ISD::SDIV, VT: MVT::i32, Action: Expand); |
107 | setOperationAction(Op: ISD::UDIV, VT: MVT::i32, Action: Expand); |
108 | setOperationAction(Op: ISD::SDIVREM, VT: MVT::i32, Action: Expand); |
109 | setOperationAction(Op: ISD::UDIVREM, VT: MVT::i32, Action: Expand); |
110 | setOperationAction(Op: ISD::SREM, VT: MVT::i32, Action: Expand); |
111 | setOperationAction(Op: ISD::UREM, VT: MVT::i32, Action: Expand); |
112 | |
113 | setOperationAction(Op: ISD::MUL, VT: MVT::i32, Action: Custom); |
114 | setOperationAction(Op: ISD::MULHU, VT: MVT::i32, Action: Expand); |
115 | setOperationAction(Op: ISD::MULHS, VT: MVT::i32, Action: Expand); |
116 | setOperationAction(Op: ISD::UMUL_LOHI, VT: MVT::i32, Action: Expand); |
117 | setOperationAction(Op: ISD::SMUL_LOHI, VT: MVT::i32, Action: Expand); |
118 | |
119 | setOperationAction(Op: ISD::ROTR, VT: MVT::i32, Action: Expand); |
120 | setOperationAction(Op: ISD::ROTL, VT: MVT::i32, Action: Expand); |
121 | setOperationAction(Op: ISD::SHL_PARTS, VT: MVT::i32, Action: Custom); |
122 | setOperationAction(Op: ISD::SRL_PARTS, VT: MVT::i32, Action: Custom); |
123 | setOperationAction(Op: ISD::SRA_PARTS, VT: MVT::i32, Action: Expand); |
124 | |
125 | setOperationAction(Op: ISD::BSWAP, VT: MVT::i32, Action: Expand); |
126 | setOperationAction(Op: ISD::CTPOP, VT: MVT::i32, Action: Legal); |
127 | setOperationAction(Op: ISD::CTLZ, VT: MVT::i32, Action: Legal); |
128 | setOperationAction(Op: ISD::CTTZ, VT: MVT::i32, Action: Legal); |
129 | |
130 | setOperationAction(Op: ISD::SIGN_EXTEND_INREG, VT: MVT::i1, Action: Expand); |
131 | setOperationAction(Op: ISD::SIGN_EXTEND_INREG, VT: MVT::i8, Action: Expand); |
132 | setOperationAction(Op: ISD::SIGN_EXTEND_INREG, VT: MVT::i16, Action: Expand); |
133 | |
134 | // Extended load operations for i1 types must be promoted |
135 | for (MVT VT : MVT::integer_valuetypes()) { |
136 | setLoadExtAction(ExtType: ISD::EXTLOAD, ValVT: VT, MemVT: MVT::i1, Action: Promote); |
137 | setLoadExtAction(ExtType: ISD::ZEXTLOAD, ValVT: VT, MemVT: MVT::i1, Action: Promote); |
138 | setLoadExtAction(ExtType: ISD::SEXTLOAD, ValVT: VT, MemVT: MVT::i1, Action: Promote); |
139 | } |
140 | |
141 | setTargetDAGCombine({ISD::ADD, ISD::SUB, ISD::AND, ISD::OR, ISD::XOR}); |
142 | |
143 | // Function alignments |
144 | setMinFunctionAlignment(Align(4)); |
145 | setPrefFunctionAlignment(Align(4)); |
146 | |
147 | setJumpIsExpensive(true); |
148 | |
149 | // TODO: Setting the minimum jump table entries needed before a |
150 | // switch is transformed to a jump table to 100 to avoid creating jump tables |
151 | // as this was causing bad performance compared to a large group of if |
152 | // statements. Re-evaluate this on new benchmarks. |
153 | setMinimumJumpTableEntries(100); |
154 | |
155 | // Use fast calling convention for library functions. |
156 | for (int I = 0; I < RTLIB::UNKNOWN_LIBCALL; ++I) { |
157 | setLibcallCallingConv(Call: static_cast<RTLIB::Libcall>(I), CC: CallingConv::Fast); |
158 | } |
159 | |
160 | MaxStoresPerMemset = 16; // For @llvm.memset -> sequence of stores |
161 | MaxStoresPerMemsetOptSize = 8; |
162 | MaxStoresPerMemcpy = 16; // For @llvm.memcpy -> sequence of stores |
163 | MaxStoresPerMemcpyOptSize = 8; |
164 | MaxStoresPerMemmove = 16; // For @llvm.memmove -> sequence of stores |
165 | MaxStoresPerMemmoveOptSize = 8; |
166 | |
167 | // Booleans always contain 0 or 1. |
168 | setBooleanContents(ZeroOrOneBooleanContent); |
169 | |
170 | setMaxAtomicSizeInBitsSupported(0); |
171 | } |
172 | |
173 | SDValue LanaiTargetLowering::LowerOperation(SDValue Op, |
174 | SelectionDAG &DAG) const { |
175 | switch (Op.getOpcode()) { |
176 | case ISD::MUL: |
177 | return LowerMUL(Op, DAG); |
178 | case ISD::BR_CC: |
179 | return LowerBR_CC(Op, DAG); |
180 | case ISD::ConstantPool: |
181 | return LowerConstantPool(Op, DAG); |
182 | case ISD::GlobalAddress: |
183 | return LowerGlobalAddress(Op, DAG); |
184 | case ISD::BlockAddress: |
185 | return LowerBlockAddress(Op, DAG); |
186 | case ISD::JumpTable: |
187 | return LowerJumpTable(Op, DAG); |
188 | case ISD::SELECT_CC: |
189 | return LowerSELECT_CC(Op, DAG); |
190 | case ISD::SETCC: |
191 | return LowerSETCC(Op, DAG); |
192 | case ISD::SHL_PARTS: |
193 | return LowerSHL_PARTS(Op, DAG); |
194 | case ISD::SRL_PARTS: |
195 | return LowerSRL_PARTS(Op, DAG); |
196 | case ISD::VASTART: |
197 | return LowerVASTART(Op, DAG); |
198 | case ISD::DYNAMIC_STACKALLOC: |
199 | return LowerDYNAMIC_STACKALLOC(Op, DAG); |
200 | case ISD::RETURNADDR: |
201 | return LowerRETURNADDR(Op, DAG); |
202 | case ISD::FRAMEADDR: |
203 | return LowerFRAMEADDR(Op, DAG); |
204 | default: |
205 | llvm_unreachable("unimplemented operand" ); |
206 | } |
207 | } |
208 | |
209 | //===----------------------------------------------------------------------===// |
210 | // Lanai Inline Assembly Support |
211 | //===----------------------------------------------------------------------===// |
212 | |
213 | Register LanaiTargetLowering::getRegisterByName( |
214 | const char *RegName, LLT /*VT*/, |
215 | const MachineFunction & /*MF*/) const { |
216 | // Only unallocatable registers should be matched here. |
217 | Register Reg = StringSwitch<unsigned>(RegName) |
218 | .Case(S: "pc" , Value: Lanai::PC) |
219 | .Case(S: "sp" , Value: Lanai::SP) |
220 | .Case(S: "fp" , Value: Lanai::FP) |
221 | .Case(S: "rr1" , Value: Lanai::RR1) |
222 | .Case(S: "r10" , Value: Lanai::R10) |
223 | .Case(S: "rr2" , Value: Lanai::RR2) |
224 | .Case(S: "r11" , Value: Lanai::R11) |
225 | .Case(S: "rca" , Value: Lanai::RCA) |
226 | .Default(Value: 0); |
227 | |
228 | if (Reg) |
229 | return Reg; |
230 | report_fatal_error(reason: "Invalid register name global variable" ); |
231 | } |
232 | |
233 | std::pair<unsigned, const TargetRegisterClass *> |
234 | LanaiTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, |
235 | StringRef Constraint, |
236 | MVT VT) const { |
237 | if (Constraint.size() == 1) |
238 | // GCC Constraint Letters |
239 | switch (Constraint[0]) { |
240 | case 'r': // GENERAL_REGS |
241 | return std::make_pair(x: 0U, y: &Lanai::GPRRegClass); |
242 | default: |
243 | break; |
244 | } |
245 | |
246 | return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); |
247 | } |
248 | |
249 | // Examine constraint type and operand type and determine a weight value. |
250 | // This object must already have been set up with the operand type |
251 | // and the current alternative constraint selected. |
252 | TargetLowering::ConstraintWeight |
253 | LanaiTargetLowering::getSingleConstraintMatchWeight( |
254 | AsmOperandInfo &Info, const char *Constraint) const { |
255 | ConstraintWeight Weight = CW_Invalid; |
256 | Value *CallOperandVal = Info.CallOperandVal; |
257 | // If we don't have a value, we can't do a match, |
258 | // but allow it at the lowest weight. |
259 | if (CallOperandVal == nullptr) |
260 | return CW_Default; |
261 | // Look at the constraint type. |
262 | switch (*Constraint) { |
263 | case 'I': // signed 16 bit immediate |
264 | case 'J': // integer zero |
265 | case 'K': // unsigned 16 bit immediate |
266 | case 'L': // immediate in the range 0 to 31 |
267 | case 'M': // signed 32 bit immediate where lower 16 bits are 0 |
268 | case 'N': // signed 26 bit immediate |
269 | case 'O': // integer zero |
270 | if (isa<ConstantInt>(Val: CallOperandVal)) |
271 | Weight = CW_Constant; |
272 | break; |
273 | default: |
274 | Weight = TargetLowering::getSingleConstraintMatchWeight(info&: Info, constraint: Constraint); |
275 | break; |
276 | } |
277 | return Weight; |
278 | } |
279 | |
280 | // LowerAsmOperandForConstraint - Lower the specified operand into the Ops |
281 | // vector. If it is invalid, don't add anything to Ops. |
282 | void LanaiTargetLowering::LowerAsmOperandForConstraint( |
283 | SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops, |
284 | SelectionDAG &DAG) const { |
285 | SDValue Result; |
286 | |
287 | // Only support length 1 constraints for now. |
288 | if (Constraint.size() > 1) |
289 | return; |
290 | |
291 | char ConstraintLetter = Constraint[0]; |
292 | switch (ConstraintLetter) { |
293 | case 'I': // Signed 16 bit constant |
294 | // If this fails, the parent routine will give an error |
295 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val&: Op)) { |
296 | if (isInt<16>(x: C->getSExtValue())) { |
297 | Result = DAG.getTargetConstant(Val: C->getSExtValue(), DL: SDLoc(C), |
298 | VT: Op.getValueType()); |
299 | break; |
300 | } |
301 | } |
302 | return; |
303 | case 'J': // integer zero |
304 | case 'O': |
305 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val&: Op)) { |
306 | if (C->getZExtValue() == 0) { |
307 | Result = DAG.getTargetConstant(Val: 0, DL: SDLoc(C), VT: Op.getValueType()); |
308 | break; |
309 | } |
310 | } |
311 | return; |
312 | case 'K': // unsigned 16 bit immediate |
313 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val&: Op)) { |
314 | if (isUInt<16>(x: C->getZExtValue())) { |
315 | Result = DAG.getTargetConstant(Val: C->getSExtValue(), DL: SDLoc(C), |
316 | VT: Op.getValueType()); |
317 | break; |
318 | } |
319 | } |
320 | return; |
321 | case 'L': // immediate in the range 0 to 31 |
322 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val&: Op)) { |
323 | if (C->getZExtValue() <= 31) { |
324 | Result = DAG.getTargetConstant(Val: C->getZExtValue(), DL: SDLoc(C), |
325 | VT: Op.getValueType()); |
326 | break; |
327 | } |
328 | } |
329 | return; |
330 | case 'M': // signed 32 bit immediate where lower 16 bits are 0 |
331 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val&: Op)) { |
332 | int64_t Val = C->getSExtValue(); |
333 | if ((isInt<32>(x: Val)) && ((Val & 0xffff) == 0)) { |
334 | Result = DAG.getTargetConstant(Val, DL: SDLoc(C), VT: Op.getValueType()); |
335 | break; |
336 | } |
337 | } |
338 | return; |
339 | case 'N': // signed 26 bit immediate |
340 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val&: Op)) { |
341 | int64_t Val = C->getSExtValue(); |
342 | if ((Val >= -33554432) && (Val <= 33554431)) { |
343 | Result = DAG.getTargetConstant(Val, DL: SDLoc(C), VT: Op.getValueType()); |
344 | break; |
345 | } |
346 | } |
347 | return; |
348 | default: |
349 | break; // This will fall through to the generic implementation |
350 | } |
351 | |
352 | if (Result.getNode()) { |
353 | Ops.push_back(x: Result); |
354 | return; |
355 | } |
356 | |
357 | TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); |
358 | } |
359 | |
360 | //===----------------------------------------------------------------------===// |
361 | // Calling Convention Implementation |
362 | //===----------------------------------------------------------------------===// |
363 | |
364 | #include "LanaiGenCallingConv.inc" |
365 | |
366 | static unsigned NumFixedArgs; |
367 | static bool CC_Lanai32_VarArg(unsigned ValNo, MVT ValVT, MVT LocVT, |
368 | CCValAssign::LocInfo LocInfo, |
369 | ISD::ArgFlagsTy ArgFlags, CCState &State) { |
370 | // Handle fixed arguments with default CC. |
371 | // Note: Both the default and fast CC handle VarArg the same and hence the |
372 | // calling convention of the function is not considered here. |
373 | if (ValNo < NumFixedArgs) { |
374 | return CC_Lanai32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State); |
375 | } |
376 | |
377 | // Promote i8/i16 args to i32 |
378 | if (LocVT == MVT::i8 || LocVT == MVT::i16) { |
379 | LocVT = MVT::i32; |
380 | if (ArgFlags.isSExt()) |
381 | LocInfo = CCValAssign::SExt; |
382 | else if (ArgFlags.isZExt()) |
383 | LocInfo = CCValAssign::ZExt; |
384 | else |
385 | LocInfo = CCValAssign::AExt; |
386 | } |
387 | |
388 | // VarArgs get passed on stack |
389 | unsigned Offset = State.AllocateStack(Size: 4, Alignment: Align(4)); |
390 | State.addLoc(V: CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, HTP: LocInfo)); |
391 | return false; |
392 | } |
393 | |
394 | SDValue LanaiTargetLowering::LowerFormalArguments( |
395 | SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, |
396 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, |
397 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { |
398 | switch (CallConv) { |
399 | case CallingConv::C: |
400 | case CallingConv::Fast: |
401 | return LowerCCCArguments(Chain, CallConv, IsVarArg, Ins, DL, DAG, InVals); |
402 | default: |
403 | report_fatal_error(reason: "Unsupported calling convention" ); |
404 | } |
405 | } |
406 | |
407 | SDValue LanaiTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, |
408 | SmallVectorImpl<SDValue> &InVals) const { |
409 | SelectionDAG &DAG = CLI.DAG; |
410 | SDLoc &DL = CLI.DL; |
411 | SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; |
412 | SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; |
413 | SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; |
414 | SDValue Chain = CLI.Chain; |
415 | SDValue Callee = CLI.Callee; |
416 | bool &IsTailCall = CLI.IsTailCall; |
417 | CallingConv::ID CallConv = CLI.CallConv; |
418 | bool IsVarArg = CLI.IsVarArg; |
419 | |
420 | // Lanai target does not yet support tail call optimization. |
421 | IsTailCall = false; |
422 | |
423 | switch (CallConv) { |
424 | case CallingConv::Fast: |
425 | case CallingConv::C: |
426 | return LowerCCCCallTo(Chain, Callee, CallConv, IsVarArg, IsTailCall, Outs, |
427 | OutVals, Ins, dl: DL, DAG, InVals); |
428 | default: |
429 | report_fatal_error(reason: "Unsupported calling convention" ); |
430 | } |
431 | } |
432 | |
433 | // LowerCCCArguments - transform physical registers into virtual registers and |
434 | // generate load operations for arguments places on the stack. |
435 | SDValue LanaiTargetLowering::LowerCCCArguments( |
436 | SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, |
437 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, |
438 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { |
439 | MachineFunction &MF = DAG.getMachineFunction(); |
440 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
441 | MachineRegisterInfo &RegInfo = MF.getRegInfo(); |
442 | LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo<LanaiMachineFunctionInfo>(); |
443 | |
444 | // Assign locations to all of the incoming arguments. |
445 | SmallVector<CCValAssign, 16> ArgLocs; |
446 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, |
447 | *DAG.getContext()); |
448 | if (CallConv == CallingConv::Fast) { |
449 | CCInfo.AnalyzeFormalArguments(Ins, Fn: CC_Lanai32_Fast); |
450 | } else { |
451 | CCInfo.AnalyzeFormalArguments(Ins, Fn: CC_Lanai32); |
452 | } |
453 | |
454 | for (const CCValAssign &VA : ArgLocs) { |
455 | if (VA.isRegLoc()) { |
456 | // Arguments passed in registers |
457 | EVT RegVT = VA.getLocVT(); |
458 | switch (RegVT.getSimpleVT().SimpleTy) { |
459 | case MVT::i32: { |
460 | Register VReg = RegInfo.createVirtualRegister(RegClass: &Lanai::GPRRegClass); |
461 | RegInfo.addLiveIn(Reg: VA.getLocReg(), vreg: VReg); |
462 | SDValue ArgValue = DAG.getCopyFromReg(Chain, dl: DL, Reg: VReg, VT: RegVT); |
463 | |
464 | // If this is an 8/16-bit value, it is really passed promoted to 32 |
465 | // bits. Insert an assert[sz]ext to capture this, then truncate to the |
466 | // right size. |
467 | if (VA.getLocInfo() == CCValAssign::SExt) |
468 | ArgValue = DAG.getNode(Opcode: ISD::AssertSext, DL, VT: RegVT, N1: ArgValue, |
469 | N2: DAG.getValueType(VA.getValVT())); |
470 | else if (VA.getLocInfo() == CCValAssign::ZExt) |
471 | ArgValue = DAG.getNode(Opcode: ISD::AssertZext, DL, VT: RegVT, N1: ArgValue, |
472 | N2: DAG.getValueType(VA.getValVT())); |
473 | |
474 | if (VA.getLocInfo() != CCValAssign::Full) |
475 | ArgValue = DAG.getNode(Opcode: ISD::TRUNCATE, DL, VT: VA.getValVT(), Operand: ArgValue); |
476 | |
477 | InVals.push_back(Elt: ArgValue); |
478 | break; |
479 | } |
480 | default: |
481 | LLVM_DEBUG(dbgs() << "LowerFormalArguments Unhandled argument type: " |
482 | << RegVT << "\n" ); |
483 | llvm_unreachable("unhandled argument type" ); |
484 | } |
485 | } else { |
486 | // Only arguments passed on the stack should make it here. |
487 | assert(VA.isMemLoc()); |
488 | // Load the argument to a virtual register |
489 | unsigned ObjSize = VA.getLocVT().getSizeInBits() / 8; |
490 | // Check that the argument fits in stack slot |
491 | if (ObjSize > 4) { |
492 | errs() << "LowerFormalArguments Unhandled argument type: " |
493 | << VA.getLocVT() << "\n" ; |
494 | } |
495 | // Create the frame index object for this incoming parameter... |
496 | int FI = MFI.CreateFixedObject(Size: ObjSize, SPOffset: VA.getLocMemOffset(), IsImmutable: true); |
497 | |
498 | // Create the SelectionDAG nodes corresponding to a load |
499 | // from this parameter |
500 | SDValue FIN = DAG.getFrameIndex(FI, VT: MVT::i32); |
501 | InVals.push_back(Elt: DAG.getLoad( |
502 | VT: VA.getLocVT(), dl: DL, Chain, Ptr: FIN, |
503 | PtrInfo: MachinePointerInfo::getFixedStack(MF&: DAG.getMachineFunction(), FI))); |
504 | } |
505 | } |
506 | |
507 | // The Lanai ABI for returning structs by value requires that we copy |
508 | // the sret argument into rv for the return. Save the argument into |
509 | // a virtual register so that we can access it from the return points. |
510 | if (MF.getFunction().hasStructRetAttr()) { |
511 | Register Reg = LanaiMFI->getSRetReturnReg(); |
512 | if (!Reg) { |
513 | Reg = MF.getRegInfo().createVirtualRegister(RegClass: getRegClassFor(VT: MVT::i32)); |
514 | LanaiMFI->setSRetReturnReg(Reg); |
515 | } |
516 | SDValue Copy = DAG.getCopyToReg(Chain: DAG.getEntryNode(), dl: DL, Reg, N: InVals[0]); |
517 | Chain = DAG.getNode(Opcode: ISD::TokenFactor, DL, VT: MVT::Other, N1: Copy, N2: Chain); |
518 | } |
519 | |
520 | if (IsVarArg) { |
521 | // Record the frame index of the first variable argument |
522 | // which is a value necessary to VASTART. |
523 | int FI = MFI.CreateFixedObject(Size: 4, SPOffset: CCInfo.getStackSize(), IsImmutable: true); |
524 | LanaiMFI->setVarArgsFrameIndex(FI); |
525 | } |
526 | |
527 | return Chain; |
528 | } |
529 | |
530 | bool LanaiTargetLowering::CanLowerReturn( |
531 | CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, |
532 | const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { |
533 | SmallVector<CCValAssign, 16> RVLocs; |
534 | CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); |
535 | |
536 | return CCInfo.CheckReturn(Outs, Fn: RetCC_Lanai32); |
537 | } |
538 | |
539 | SDValue |
540 | LanaiTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, |
541 | bool IsVarArg, |
542 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
543 | const SmallVectorImpl<SDValue> &OutVals, |
544 | const SDLoc &DL, SelectionDAG &DAG) const { |
545 | // CCValAssign - represent the assignment of the return value to a location |
546 | SmallVector<CCValAssign, 16> RVLocs; |
547 | |
548 | // CCState - Info about the registers and stack slot. |
549 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, |
550 | *DAG.getContext()); |
551 | |
552 | // Analize return values. |
553 | CCInfo.AnalyzeReturn(Outs, Fn: RetCC_Lanai32); |
554 | |
555 | SDValue Glue; |
556 | SmallVector<SDValue, 4> RetOps(1, Chain); |
557 | |
558 | // Copy the result values into the output registers. |
559 | for (unsigned i = 0; i != RVLocs.size(); ++i) { |
560 | CCValAssign &VA = RVLocs[i]; |
561 | assert(VA.isRegLoc() && "Can only return in registers!" ); |
562 | |
563 | Chain = DAG.getCopyToReg(Chain, dl: DL, Reg: VA.getLocReg(), N: OutVals[i], Glue); |
564 | |
565 | // Guarantee that all emitted copies are stuck together with flags. |
566 | Glue = Chain.getValue(R: 1); |
567 | RetOps.push_back(Elt: DAG.getRegister(Reg: VA.getLocReg(), VT: VA.getLocVT())); |
568 | } |
569 | |
570 | // The Lanai ABI for returning structs by value requires that we copy |
571 | // the sret argument into rv for the return. We saved the argument into |
572 | // a virtual register in the entry block, so now we copy the value out |
573 | // and into rv. |
574 | if (DAG.getMachineFunction().getFunction().hasStructRetAttr()) { |
575 | MachineFunction &MF = DAG.getMachineFunction(); |
576 | LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo<LanaiMachineFunctionInfo>(); |
577 | Register Reg = LanaiMFI->getSRetReturnReg(); |
578 | assert(Reg && |
579 | "SRetReturnReg should have been set in LowerFormalArguments()." ); |
580 | SDValue Val = |
581 | DAG.getCopyFromReg(Chain, dl: DL, Reg, VT: getPointerTy(DL: DAG.getDataLayout())); |
582 | |
583 | Chain = DAG.getCopyToReg(Chain, dl: DL, Reg: Lanai::RV, N: Val, Glue); |
584 | Glue = Chain.getValue(R: 1); |
585 | RetOps.push_back( |
586 | Elt: DAG.getRegister(Reg: Lanai::RV, VT: getPointerTy(DL: DAG.getDataLayout()))); |
587 | } |
588 | |
589 | RetOps[0] = Chain; // Update chain |
590 | |
591 | unsigned Opc = LanaiISD::RET_GLUE; |
592 | if (Glue.getNode()) |
593 | RetOps.push_back(Elt: Glue); |
594 | |
595 | // Return Void |
596 | return DAG.getNode(Opcode: Opc, DL, VT: MVT::Other, |
597 | Ops: ArrayRef<SDValue>(&RetOps[0], RetOps.size())); |
598 | } |
599 | |
600 | // LowerCCCCallTo - functions arguments are copied from virtual regs to |
601 | // (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. |
602 | SDValue LanaiTargetLowering::LowerCCCCallTo( |
603 | SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool IsVarArg, |
604 | bool /*IsTailCall*/, const SmallVectorImpl<ISD::OutputArg> &Outs, |
605 | const SmallVectorImpl<SDValue> &OutVals, |
606 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, |
607 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { |
608 | // Analyze operands of the call, assigning locations to each operand. |
609 | SmallVector<CCValAssign, 16> ArgLocs; |
610 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, |
611 | *DAG.getContext()); |
612 | GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Val&: Callee); |
613 | MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); |
614 | |
615 | NumFixedArgs = 0; |
616 | if (IsVarArg && G) { |
617 | const Function *CalleeFn = dyn_cast<Function>(Val: G->getGlobal()); |
618 | if (CalleeFn) |
619 | NumFixedArgs = CalleeFn->getFunctionType()->getNumParams(); |
620 | } |
621 | if (NumFixedArgs) |
622 | CCInfo.AnalyzeCallOperands(Outs, Fn: CC_Lanai32_VarArg); |
623 | else { |
624 | if (CallConv == CallingConv::Fast) |
625 | CCInfo.AnalyzeCallOperands(Outs, Fn: CC_Lanai32_Fast); |
626 | else |
627 | CCInfo.AnalyzeCallOperands(Outs, Fn: CC_Lanai32); |
628 | } |
629 | |
630 | // Get a count of how many bytes are to be pushed on the stack. |
631 | unsigned NumBytes = CCInfo.getStackSize(); |
632 | |
633 | // Create local copies for byval args. |
634 | SmallVector<SDValue, 8> ByValArgs; |
635 | for (unsigned I = 0, E = Outs.size(); I != E; ++I) { |
636 | ISD::ArgFlagsTy Flags = Outs[I].Flags; |
637 | if (!Flags.isByVal()) |
638 | continue; |
639 | |
640 | SDValue Arg = OutVals[I]; |
641 | unsigned Size = Flags.getByValSize(); |
642 | Align Alignment = Flags.getNonZeroByValAlign(); |
643 | |
644 | int FI = MFI.CreateStackObject(Size, Alignment, isSpillSlot: false); |
645 | SDValue FIPtr = DAG.getFrameIndex(FI, VT: getPointerTy(DL: DAG.getDataLayout())); |
646 | SDValue SizeNode = DAG.getConstant(Val: Size, DL, VT: MVT::i32); |
647 | |
648 | Chain = DAG.getMemcpy(Chain, dl: DL, Dst: FIPtr, Src: Arg, Size: SizeNode, Alignment, |
649 | /*IsVolatile=*/isVol: false, |
650 | /*AlwaysInline=*/false, |
651 | /*CI=*/nullptr, OverrideTailCall: std::nullopt, DstPtrInfo: MachinePointerInfo(), |
652 | SrcPtrInfo: MachinePointerInfo()); |
653 | ByValArgs.push_back(Elt: FIPtr); |
654 | } |
655 | |
656 | Chain = DAG.getCALLSEQ_START(Chain, InSize: NumBytes, OutSize: 0, DL); |
657 | |
658 | SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; |
659 | SmallVector<SDValue, 12> MemOpChains; |
660 | SDValue StackPtr; |
661 | |
662 | // Walk the register/memloc assignments, inserting copies/loads. |
663 | for (unsigned I = 0, J = 0, E = ArgLocs.size(); I != E; ++I) { |
664 | CCValAssign &VA = ArgLocs[I]; |
665 | SDValue Arg = OutVals[I]; |
666 | ISD::ArgFlagsTy Flags = Outs[I].Flags; |
667 | |
668 | // Promote the value if needed. |
669 | switch (VA.getLocInfo()) { |
670 | case CCValAssign::Full: |
671 | break; |
672 | case CCValAssign::SExt: |
673 | Arg = DAG.getNode(Opcode: ISD::SIGN_EXTEND, DL, VT: VA.getLocVT(), Operand: Arg); |
674 | break; |
675 | case CCValAssign::ZExt: |
676 | Arg = DAG.getNode(Opcode: ISD::ZERO_EXTEND, DL, VT: VA.getLocVT(), Operand: Arg); |
677 | break; |
678 | case CCValAssign::AExt: |
679 | Arg = DAG.getNode(Opcode: ISD::ANY_EXTEND, DL, VT: VA.getLocVT(), Operand: Arg); |
680 | break; |
681 | default: |
682 | llvm_unreachable("Unknown loc info!" ); |
683 | } |
684 | |
685 | // Use local copy if it is a byval arg. |
686 | if (Flags.isByVal()) |
687 | Arg = ByValArgs[J++]; |
688 | |
689 | // Arguments that can be passed on register must be kept at RegsToPass |
690 | // vector |
691 | if (VA.isRegLoc()) { |
692 | RegsToPass.push_back(Elt: std::make_pair(x: VA.getLocReg(), y&: Arg)); |
693 | } else { |
694 | assert(VA.isMemLoc()); |
695 | |
696 | if (StackPtr.getNode() == nullptr) |
697 | StackPtr = DAG.getCopyFromReg(Chain, dl: DL, Reg: Lanai::SP, |
698 | VT: getPointerTy(DL: DAG.getDataLayout())); |
699 | |
700 | SDValue PtrOff = |
701 | DAG.getNode(Opcode: ISD::ADD, DL, VT: getPointerTy(DL: DAG.getDataLayout()), N1: StackPtr, |
702 | N2: DAG.getIntPtrConstant(Val: VA.getLocMemOffset(), DL)); |
703 | |
704 | MemOpChains.push_back( |
705 | Elt: DAG.getStore(Chain, dl: DL, Val: Arg, Ptr: PtrOff, PtrInfo: MachinePointerInfo())); |
706 | } |
707 | } |
708 | |
709 | // Transform all store nodes into one single node because all store nodes are |
710 | // independent of each other. |
711 | if (!MemOpChains.empty()) |
712 | Chain = DAG.getNode(Opcode: ISD::TokenFactor, DL, VT: MVT::Other, |
713 | Ops: ArrayRef<SDValue>(&MemOpChains[0], MemOpChains.size())); |
714 | |
715 | SDValue InGlue; |
716 | |
717 | // Build a sequence of copy-to-reg nodes chained together with token chain and |
718 | // flag operands which copy the outgoing args into registers. The InGlue in |
719 | // necessary since all emitted instructions must be stuck together. |
720 | for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { |
721 | Chain = DAG.getCopyToReg(Chain, dl: DL, Reg: RegsToPass[I].first, |
722 | N: RegsToPass[I].second, Glue: InGlue); |
723 | InGlue = Chain.getValue(R: 1); |
724 | } |
725 | |
726 | // If the callee is a GlobalAddress node (quite common, every direct call is) |
727 | // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. |
728 | // Likewise ExternalSymbol -> TargetExternalSymbol. |
729 | uint8_t OpFlag = LanaiII::MO_NO_FLAG; |
730 | if (G) { |
731 | Callee = DAG.getTargetGlobalAddress( |
732 | GV: G->getGlobal(), DL, VT: getPointerTy(DL: DAG.getDataLayout()), offset: 0, TargetFlags: OpFlag); |
733 | } else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Val&: Callee)) { |
734 | Callee = DAG.getTargetExternalSymbol( |
735 | Sym: E->getSymbol(), VT: getPointerTy(DL: DAG.getDataLayout()), TargetFlags: OpFlag); |
736 | } |
737 | |
738 | // Returns a chain & a flag for retval copy to use. |
739 | SDVTList NodeTys = DAG.getVTList(VT1: MVT::Other, VT2: MVT::Glue); |
740 | SmallVector<SDValue, 8> Ops; |
741 | Ops.push_back(Elt: Chain); |
742 | Ops.push_back(Elt: Callee); |
743 | |
744 | // Add a register mask operand representing the call-preserved registers. |
745 | // TODO: Should return-twice functions be handled? |
746 | const uint32_t *Mask = |
747 | TRI->getCallPreservedMask(MF: DAG.getMachineFunction(), CallConv); |
748 | assert(Mask && "Missing call preserved mask for calling convention" ); |
749 | Ops.push_back(Elt: DAG.getRegisterMask(RegMask: Mask)); |
750 | |
751 | // Add argument registers to the end of the list so that they are |
752 | // known live into the call. |
753 | for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) |
754 | Ops.push_back(Elt: DAG.getRegister(Reg: RegsToPass[I].first, |
755 | VT: RegsToPass[I].second.getValueType())); |
756 | |
757 | if (InGlue.getNode()) |
758 | Ops.push_back(Elt: InGlue); |
759 | |
760 | Chain = DAG.getNode(Opcode: LanaiISD::CALL, DL, VTList: NodeTys, |
761 | Ops: ArrayRef<SDValue>(&Ops[0], Ops.size())); |
762 | InGlue = Chain.getValue(R: 1); |
763 | |
764 | // Create the CALLSEQ_END node. |
765 | Chain = DAG.getCALLSEQ_END(Chain, Size1: NumBytes, Size2: 0, Glue: InGlue, DL); |
766 | InGlue = Chain.getValue(R: 1); |
767 | |
768 | // Handle result values, copying them out of physregs into vregs that we |
769 | // return. |
770 | return LowerCallResult(Chain, InGlue, CallConv, IsVarArg, Ins, DL, DAG, |
771 | InVals); |
772 | } |
773 | |
774 | // LowerCallResult - Lower the result values of a call into the |
775 | // appropriate copies out of appropriate physical registers. |
776 | SDValue LanaiTargetLowering::LowerCallResult( |
777 | SDValue Chain, SDValue InGlue, CallingConv::ID CallConv, bool IsVarArg, |
778 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, |
779 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { |
780 | // Assign locations to each value returned by this call. |
781 | SmallVector<CCValAssign, 16> RVLocs; |
782 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, |
783 | *DAG.getContext()); |
784 | |
785 | CCInfo.AnalyzeCallResult(Ins, Fn: RetCC_Lanai32); |
786 | |
787 | // Copy all of the result registers out of their specified physreg. |
788 | for (unsigned I = 0; I != RVLocs.size(); ++I) { |
789 | Chain = DAG.getCopyFromReg(Chain, dl: DL, Reg: RVLocs[I].getLocReg(), |
790 | VT: RVLocs[I].getValVT(), Glue: InGlue) |
791 | .getValue(R: 1); |
792 | InGlue = Chain.getValue(R: 2); |
793 | InVals.push_back(Elt: Chain.getValue(R: 0)); |
794 | } |
795 | |
796 | return Chain; |
797 | } |
798 | |
799 | //===----------------------------------------------------------------------===// |
800 | // Custom Lowerings |
801 | //===----------------------------------------------------------------------===// |
802 | |
803 | static LPCC::CondCode IntCondCCodeToICC(SDValue CC, const SDLoc &DL, |
804 | SDValue &RHS, SelectionDAG &DAG) { |
805 | ISD::CondCode SetCCOpcode = cast<CondCodeSDNode>(Val&: CC)->get(); |
806 | |
807 | // For integer, only the SETEQ, SETNE, SETLT, SETLE, SETGT, SETGE, SETULT, |
808 | // SETULE, SETUGT, and SETUGE opcodes are used (see CodeGen/ISDOpcodes.h) |
809 | // and Lanai only supports integer comparisons, so only provide definitions |
810 | // for them. |
811 | switch (SetCCOpcode) { |
812 | case ISD::SETEQ: |
813 | return LPCC::ICC_EQ; |
814 | case ISD::SETGT: |
815 | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Val&: RHS)) |
816 | if (RHSC->getZExtValue() == 0xFFFFFFFF) { |
817 | // X > -1 -> X >= 0 -> is_plus(X) |
818 | RHS = DAG.getConstant(Val: 0, DL, VT: RHS.getValueType()); |
819 | return LPCC::ICC_PL; |
820 | } |
821 | return LPCC::ICC_GT; |
822 | case ISD::SETUGT: |
823 | return LPCC::ICC_UGT; |
824 | case ISD::SETLT: |
825 | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Val&: RHS)) |
826 | if (RHSC->getZExtValue() == 0) |
827 | // X < 0 -> is_minus(X) |
828 | return LPCC::ICC_MI; |
829 | return LPCC::ICC_LT; |
830 | case ISD::SETULT: |
831 | return LPCC::ICC_ULT; |
832 | case ISD::SETLE: |
833 | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Val&: RHS)) |
834 | if (RHSC->getZExtValue() == 0xFFFFFFFF) { |
835 | // X <= -1 -> X < 0 -> is_minus(X) |
836 | RHS = DAG.getConstant(Val: 0, DL, VT: RHS.getValueType()); |
837 | return LPCC::ICC_MI; |
838 | } |
839 | return LPCC::ICC_LE; |
840 | case ISD::SETULE: |
841 | return LPCC::ICC_ULE; |
842 | case ISD::SETGE: |
843 | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Val&: RHS)) |
844 | if (RHSC->getZExtValue() == 0) |
845 | // X >= 0 -> is_plus(X) |
846 | return LPCC::ICC_PL; |
847 | return LPCC::ICC_GE; |
848 | case ISD::SETUGE: |
849 | return LPCC::ICC_UGE; |
850 | case ISD::SETNE: |
851 | return LPCC::ICC_NE; |
852 | case ISD::SETONE: |
853 | case ISD::SETUNE: |
854 | case ISD::SETOGE: |
855 | case ISD::SETOLE: |
856 | case ISD::SETOLT: |
857 | case ISD::SETOGT: |
858 | case ISD::SETOEQ: |
859 | case ISD::SETUEQ: |
860 | case ISD::SETO: |
861 | case ISD::SETUO: |
862 | llvm_unreachable("Unsupported comparison." ); |
863 | default: |
864 | llvm_unreachable("Unknown integer condition code!" ); |
865 | } |
866 | } |
867 | |
868 | SDValue LanaiTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { |
869 | SDValue Chain = Op.getOperand(i: 0); |
870 | SDValue Cond = Op.getOperand(i: 1); |
871 | SDValue LHS = Op.getOperand(i: 2); |
872 | SDValue RHS = Op.getOperand(i: 3); |
873 | SDValue Dest = Op.getOperand(i: 4); |
874 | SDLoc DL(Op); |
875 | |
876 | LPCC::CondCode CC = IntCondCCodeToICC(CC: Cond, DL, RHS, DAG); |
877 | SDValue TargetCC = DAG.getConstant(Val: CC, DL, VT: MVT::i32); |
878 | SDValue Glue = |
879 | DAG.getNode(Opcode: LanaiISD::SET_FLAG, DL, VT: MVT::Glue, N1: LHS, N2: RHS, N3: TargetCC); |
880 | |
881 | return DAG.getNode(Opcode: LanaiISD::BR_CC, DL, VT: Op.getValueType(), N1: Chain, N2: Dest, |
882 | N3: TargetCC, N4: Glue); |
883 | } |
884 | |
885 | SDValue LanaiTargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const { |
886 | EVT VT = Op->getValueType(ResNo: 0); |
887 | if (VT != MVT::i32) |
888 | return SDValue(); |
889 | |
890 | ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val: Op->getOperand(Num: 1)); |
891 | if (!C) |
892 | return SDValue(); |
893 | |
894 | int64_t MulAmt = C->getSExtValue(); |
895 | int32_t HighestOne = -1; |
896 | uint32_t NonzeroEntries = 0; |
897 | int SignedDigit[32] = {0}; |
898 | |
899 | // Convert to non-adjacent form (NAF) signed-digit representation. |
900 | // NAF is a signed-digit form where no adjacent digits are non-zero. It is the |
901 | // minimal Hamming weight representation of a number (on average 1/3 of the |
902 | // digits will be non-zero vs 1/2 for regular binary representation). And as |
903 | // the non-zero digits will be the only digits contributing to the instruction |
904 | // count, this is desirable. The next loop converts it to NAF (following the |
905 | // approach in 'Guide to Elliptic Curve Cryptography' [ISBN: 038795273X]) by |
906 | // choosing the non-zero coefficients such that the resulting quotient is |
907 | // divisible by 2 which will cause the next coefficient to be zero. |
908 | int64_t E = std::abs(i: MulAmt); |
909 | int S = (MulAmt < 0 ? -1 : 1); |
910 | int I = 0; |
911 | while (E > 0) { |
912 | int ZI = 0; |
913 | if (E % 2 == 1) { |
914 | ZI = 2 - (E % 4); |
915 | if (ZI != 0) |
916 | ++NonzeroEntries; |
917 | } |
918 | SignedDigit[I] = S * ZI; |
919 | if (SignedDigit[I] == 1) |
920 | HighestOne = I; |
921 | E = (E - ZI) / 2; |
922 | ++I; |
923 | } |
924 | |
925 | // Compute number of instructions required. Due to differences in lowering |
926 | // between the different processors this count is not exact. |
927 | // Start by assuming a shift and a add/sub for every non-zero entry (hence |
928 | // every non-zero entry requires 1 shift and 1 add/sub except for the first |
929 | // entry). |
930 | int32_t InstrRequired = 2 * NonzeroEntries - 1; |
931 | // Correct possible over-adding due to shift by 0 (which is not emitted). |
932 | if (std::abs(i: MulAmt) % 2 == 1) |
933 | --InstrRequired; |
934 | // Return if the form generated would exceed the instruction threshold. |
935 | if (InstrRequired > LanaiLowerConstantMulThreshold) |
936 | return SDValue(); |
937 | |
938 | SDValue Res; |
939 | SDLoc DL(Op); |
940 | SDValue V = Op->getOperand(Num: 0); |
941 | |
942 | // Initialize the running sum. Set the running sum to the maximal shifted |
943 | // positive value (i.e., largest i such that zi == 1 and MulAmt has V<<i as a |
944 | // term NAF). |
945 | if (HighestOne == -1) |
946 | Res = DAG.getConstant(Val: 0, DL, VT: MVT::i32); |
947 | else { |
948 | Res = DAG.getNode(Opcode: ISD::SHL, DL, VT, N1: V, |
949 | N2: DAG.getConstant(Val: HighestOne, DL, VT: MVT::i32)); |
950 | SignedDigit[HighestOne] = 0; |
951 | } |
952 | |
953 | // Assemble multiplication from shift, add, sub using NAF form and running |
954 | // sum. |
955 | for (unsigned int I = 0; I < std::size(SignedDigit); ++I) { |
956 | if (SignedDigit[I] == 0) |
957 | continue; |
958 | |
959 | // Shifted multiplicand (v<<i). |
960 | SDValue Op = |
961 | DAG.getNode(Opcode: ISD::SHL, DL, VT, N1: V, N2: DAG.getConstant(Val: I, DL, VT: MVT::i32)); |
962 | if (SignedDigit[I] == 1) |
963 | Res = DAG.getNode(Opcode: ISD::ADD, DL, VT, N1: Res, N2: Op); |
964 | else if (SignedDigit[I] == -1) |
965 | Res = DAG.getNode(Opcode: ISD::SUB, DL, VT, N1: Res, N2: Op); |
966 | } |
967 | return Res; |
968 | } |
969 | |
970 | SDValue LanaiTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { |
971 | SDValue LHS = Op.getOperand(i: 0); |
972 | SDValue RHS = Op.getOperand(i: 1); |
973 | SDValue Cond = Op.getOperand(i: 2); |
974 | SDLoc DL(Op); |
975 | |
976 | LPCC::CondCode CC = IntCondCCodeToICC(CC: Cond, DL, RHS, DAG); |
977 | SDValue TargetCC = DAG.getConstant(Val: CC, DL, VT: MVT::i32); |
978 | SDValue Glue = |
979 | DAG.getNode(Opcode: LanaiISD::SET_FLAG, DL, VT: MVT::Glue, N1: LHS, N2: RHS, N3: TargetCC); |
980 | |
981 | return DAG.getNode(Opcode: LanaiISD::SETCC, DL, VT: Op.getValueType(), N1: TargetCC, N2: Glue); |
982 | } |
983 | |
984 | SDValue LanaiTargetLowering::LowerSELECT_CC(SDValue Op, |
985 | SelectionDAG &DAG) const { |
986 | SDValue LHS = Op.getOperand(i: 0); |
987 | SDValue RHS = Op.getOperand(i: 1); |
988 | SDValue TrueV = Op.getOperand(i: 2); |
989 | SDValue FalseV = Op.getOperand(i: 3); |
990 | SDValue Cond = Op.getOperand(i: 4); |
991 | SDLoc DL(Op); |
992 | |
993 | LPCC::CondCode CC = IntCondCCodeToICC(CC: Cond, DL, RHS, DAG); |
994 | SDValue TargetCC = DAG.getConstant(Val: CC, DL, VT: MVT::i32); |
995 | SDValue Glue = |
996 | DAG.getNode(Opcode: LanaiISD::SET_FLAG, DL, VT: MVT::Glue, N1: LHS, N2: RHS, N3: TargetCC); |
997 | |
998 | SDVTList VTs = DAG.getVTList(VT1: Op.getValueType(), VT2: MVT::Glue); |
999 | return DAG.getNode(Opcode: LanaiISD::SELECT_CC, DL, VTList: VTs, N1: TrueV, N2: FalseV, N3: TargetCC, |
1000 | N4: Glue); |
1001 | } |
1002 | |
1003 | SDValue LanaiTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { |
1004 | MachineFunction &MF = DAG.getMachineFunction(); |
1005 | LanaiMachineFunctionInfo *FuncInfo = MF.getInfo<LanaiMachineFunctionInfo>(); |
1006 | |
1007 | SDLoc DL(Op); |
1008 | SDValue FI = DAG.getFrameIndex(FI: FuncInfo->getVarArgsFrameIndex(), |
1009 | VT: getPointerTy(DL: DAG.getDataLayout())); |
1010 | |
1011 | // vastart just stores the address of the VarArgsFrameIndex slot into the |
1012 | // memory location argument. |
1013 | const Value *SV = cast<SrcValueSDNode>(Val: Op.getOperand(i: 2))->getValue(); |
1014 | return DAG.getStore(Chain: Op.getOperand(i: 0), dl: DL, Val: FI, Ptr: Op.getOperand(i: 1), |
1015 | PtrInfo: MachinePointerInfo(SV)); |
1016 | } |
1017 | |
1018 | SDValue LanaiTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, |
1019 | SelectionDAG &DAG) const { |
1020 | SDValue Chain = Op.getOperand(i: 0); |
1021 | SDValue Size = Op.getOperand(i: 1); |
1022 | SDLoc DL(Op); |
1023 | |
1024 | Register SPReg = getStackPointerRegisterToSaveRestore(); |
1025 | |
1026 | // Get a reference to the stack pointer. |
1027 | SDValue StackPointer = DAG.getCopyFromReg(Chain, dl: DL, Reg: SPReg, VT: MVT::i32); |
1028 | |
1029 | // Subtract the dynamic size from the actual stack size to |
1030 | // obtain the new stack size. |
1031 | SDValue Sub = DAG.getNode(Opcode: ISD::SUB, DL, VT: MVT::i32, N1: StackPointer, N2: Size); |
1032 | |
1033 | // For Lanai, the outgoing memory arguments area should be on top of the |
1034 | // alloca area on the stack i.e., the outgoing memory arguments should be |
1035 | // at a lower address than the alloca area. Move the alloca area down the |
1036 | // stack by adding back the space reserved for outgoing arguments to SP |
1037 | // here. |
1038 | // |
1039 | // We do not know what the size of the outgoing args is at this point. |
1040 | // So, we add a pseudo instruction ADJDYNALLOC that will adjust the |
1041 | // stack pointer. We replace this instruction with on that has the correct, |
1042 | // known offset in emitPrologue(). |
1043 | SDValue ArgAdjust = DAG.getNode(Opcode: LanaiISD::ADJDYNALLOC, DL, VT: MVT::i32, Operand: Sub); |
1044 | |
1045 | // The Sub result contains the new stack start address, so it |
1046 | // must be placed in the stack pointer register. |
1047 | SDValue CopyChain = DAG.getCopyToReg(Chain, dl: DL, Reg: SPReg, N: Sub); |
1048 | |
1049 | SDValue Ops[2] = {ArgAdjust, CopyChain}; |
1050 | return DAG.getMergeValues(Ops, dl: DL); |
1051 | } |
1052 | |
1053 | SDValue LanaiTargetLowering::LowerRETURNADDR(SDValue Op, |
1054 | SelectionDAG &DAG) const { |
1055 | MachineFunction &MF = DAG.getMachineFunction(); |
1056 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
1057 | MFI.setReturnAddressIsTaken(true); |
1058 | |
1059 | EVT VT = Op.getValueType(); |
1060 | SDLoc DL(Op); |
1061 | unsigned Depth = Op.getConstantOperandVal(i: 0); |
1062 | if (Depth) { |
1063 | SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); |
1064 | const unsigned Offset = -4; |
1065 | SDValue Ptr = DAG.getNode(Opcode: ISD::ADD, DL, VT, N1: FrameAddr, |
1066 | N2: DAG.getIntPtrConstant(Val: Offset, DL)); |
1067 | return DAG.getLoad(VT, dl: DL, Chain: DAG.getEntryNode(), Ptr, PtrInfo: MachinePointerInfo()); |
1068 | } |
1069 | |
1070 | // Return the link register, which contains the return address. |
1071 | // Mark it an implicit live-in. |
1072 | Register Reg = MF.addLiveIn(PReg: TRI->getRARegister(), RC: getRegClassFor(VT: MVT::i32)); |
1073 | return DAG.getCopyFromReg(Chain: DAG.getEntryNode(), dl: DL, Reg, VT); |
1074 | } |
1075 | |
1076 | SDValue LanaiTargetLowering::LowerFRAMEADDR(SDValue Op, |
1077 | SelectionDAG &DAG) const { |
1078 | MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); |
1079 | MFI.setFrameAddressIsTaken(true); |
1080 | |
1081 | EVT VT = Op.getValueType(); |
1082 | SDLoc DL(Op); |
1083 | SDValue FrameAddr = DAG.getCopyFromReg(Chain: DAG.getEntryNode(), dl: DL, Reg: Lanai::FP, VT); |
1084 | unsigned Depth = Op.getConstantOperandVal(i: 0); |
1085 | while (Depth--) { |
1086 | const unsigned Offset = -8; |
1087 | SDValue Ptr = DAG.getNode(Opcode: ISD::ADD, DL, VT, N1: FrameAddr, |
1088 | N2: DAG.getIntPtrConstant(Val: Offset, DL)); |
1089 | FrameAddr = |
1090 | DAG.getLoad(VT, dl: DL, Chain: DAG.getEntryNode(), Ptr, PtrInfo: MachinePointerInfo()); |
1091 | } |
1092 | return FrameAddr; |
1093 | } |
1094 | |
1095 | const char *LanaiTargetLowering::getTargetNodeName(unsigned Opcode) const { |
1096 | switch (Opcode) { |
1097 | case LanaiISD::ADJDYNALLOC: |
1098 | return "LanaiISD::ADJDYNALLOC" ; |
1099 | case LanaiISD::RET_GLUE: |
1100 | return "LanaiISD::RET_GLUE" ; |
1101 | case LanaiISD::CALL: |
1102 | return "LanaiISD::CALL" ; |
1103 | case LanaiISD::SELECT_CC: |
1104 | return "LanaiISD::SELECT_CC" ; |
1105 | case LanaiISD::SETCC: |
1106 | return "LanaiISD::SETCC" ; |
1107 | case LanaiISD::SUBBF: |
1108 | return "LanaiISD::SUBBF" ; |
1109 | case LanaiISD::SET_FLAG: |
1110 | return "LanaiISD::SET_FLAG" ; |
1111 | case LanaiISD::BR_CC: |
1112 | return "LanaiISD::BR_CC" ; |
1113 | case LanaiISD::Wrapper: |
1114 | return "LanaiISD::Wrapper" ; |
1115 | case LanaiISD::HI: |
1116 | return "LanaiISD::HI" ; |
1117 | case LanaiISD::LO: |
1118 | return "LanaiISD::LO" ; |
1119 | case LanaiISD::SMALL: |
1120 | return "LanaiISD::SMALL" ; |
1121 | default: |
1122 | return nullptr; |
1123 | } |
1124 | } |
1125 | |
1126 | SDValue LanaiTargetLowering::LowerConstantPool(SDValue Op, |
1127 | SelectionDAG &DAG) const { |
1128 | SDLoc DL(Op); |
1129 | ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Val&: Op); |
1130 | const Constant *C = N->getConstVal(); |
1131 | const LanaiTargetObjectFile *TLOF = |
1132 | static_cast<const LanaiTargetObjectFile *>( |
1133 | getTargetMachine().getObjFileLowering()); |
1134 | |
1135 | // If the code model is small or constant will be placed in the small section, |
1136 | // then assume address will fit in 21-bits. |
1137 | if (getTargetMachine().getCodeModel() == CodeModel::Small || |
1138 | TLOF->isConstantInSmallSection(DL: DAG.getDataLayout(), CN: C)) { |
1139 | SDValue Small = DAG.getTargetConstantPool( |
1140 | C, VT: MVT::i32, Align: N->getAlign(), Offset: N->getOffset(), TargetFlags: LanaiII::MO_NO_FLAG); |
1141 | return DAG.getNode(Opcode: ISD::OR, DL, VT: MVT::i32, |
1142 | N1: DAG.getRegister(Reg: Lanai::R0, VT: MVT::i32), |
1143 | N2: DAG.getNode(Opcode: LanaiISD::SMALL, DL, VT: MVT::i32, Operand: Small)); |
1144 | } else { |
1145 | uint8_t OpFlagHi = LanaiII::MO_ABS_HI; |
1146 | uint8_t OpFlagLo = LanaiII::MO_ABS_LO; |
1147 | |
1148 | SDValue Hi = DAG.getTargetConstantPool(C, VT: MVT::i32, Align: N->getAlign(), |
1149 | Offset: N->getOffset(), TargetFlags: OpFlagHi); |
1150 | SDValue Lo = DAG.getTargetConstantPool(C, VT: MVT::i32, Align: N->getAlign(), |
1151 | Offset: N->getOffset(), TargetFlags: OpFlagLo); |
1152 | Hi = DAG.getNode(Opcode: LanaiISD::HI, DL, VT: MVT::i32, Operand: Hi); |
1153 | Lo = DAG.getNode(Opcode: LanaiISD::LO, DL, VT: MVT::i32, Operand: Lo); |
1154 | SDValue Result = DAG.getNode(Opcode: ISD::OR, DL, VT: MVT::i32, N1: Hi, N2: Lo); |
1155 | return Result; |
1156 | } |
1157 | } |
1158 | |
1159 | SDValue LanaiTargetLowering::LowerGlobalAddress(SDValue Op, |
1160 | SelectionDAG &DAG) const { |
1161 | SDLoc DL(Op); |
1162 | const GlobalValue *GV = cast<GlobalAddressSDNode>(Val&: Op)->getGlobal(); |
1163 | int64_t Offset = cast<GlobalAddressSDNode>(Val&: Op)->getOffset(); |
1164 | |
1165 | const LanaiTargetObjectFile *TLOF = |
1166 | static_cast<const LanaiTargetObjectFile *>( |
1167 | getTargetMachine().getObjFileLowering()); |
1168 | |
1169 | // If the code model is small or global variable will be placed in the small |
1170 | // section, then assume address will fit in 21-bits. |
1171 | const GlobalObject *GO = GV->getAliaseeObject(); |
1172 | if (TLOF->isGlobalInSmallSection(GO, TM: getTargetMachine())) { |
1173 | SDValue Small = DAG.getTargetGlobalAddress( |
1174 | GV, DL, VT: getPointerTy(DL: DAG.getDataLayout()), offset: Offset, TargetFlags: LanaiII::MO_NO_FLAG); |
1175 | return DAG.getNode(Opcode: ISD::OR, DL, VT: MVT::i32, |
1176 | N1: DAG.getRegister(Reg: Lanai::R0, VT: MVT::i32), |
1177 | N2: DAG.getNode(Opcode: LanaiISD::SMALL, DL, VT: MVT::i32, Operand: Small)); |
1178 | } else { |
1179 | uint8_t OpFlagHi = LanaiII::MO_ABS_HI; |
1180 | uint8_t OpFlagLo = LanaiII::MO_ABS_LO; |
1181 | |
1182 | // Create the TargetGlobalAddress node, folding in the constant offset. |
1183 | SDValue Hi = DAG.getTargetGlobalAddress( |
1184 | GV, DL, VT: getPointerTy(DL: DAG.getDataLayout()), offset: Offset, TargetFlags: OpFlagHi); |
1185 | SDValue Lo = DAG.getTargetGlobalAddress( |
1186 | GV, DL, VT: getPointerTy(DL: DAG.getDataLayout()), offset: Offset, TargetFlags: OpFlagLo); |
1187 | Hi = DAG.getNode(Opcode: LanaiISD::HI, DL, VT: MVT::i32, Operand: Hi); |
1188 | Lo = DAG.getNode(Opcode: LanaiISD::LO, DL, VT: MVT::i32, Operand: Lo); |
1189 | return DAG.getNode(Opcode: ISD::OR, DL, VT: MVT::i32, N1: Hi, N2: Lo); |
1190 | } |
1191 | } |
1192 | |
1193 | SDValue LanaiTargetLowering::LowerBlockAddress(SDValue Op, |
1194 | SelectionDAG &DAG) const { |
1195 | SDLoc DL(Op); |
1196 | const BlockAddress *BA = cast<BlockAddressSDNode>(Val&: Op)->getBlockAddress(); |
1197 | |
1198 | uint8_t OpFlagHi = LanaiII::MO_ABS_HI; |
1199 | uint8_t OpFlagLo = LanaiII::MO_ABS_LO; |
1200 | |
1201 | SDValue Hi = DAG.getBlockAddress(BA, VT: MVT::i32, Offset: true, isTarget: OpFlagHi); |
1202 | SDValue Lo = DAG.getBlockAddress(BA, VT: MVT::i32, Offset: true, isTarget: OpFlagLo); |
1203 | Hi = DAG.getNode(Opcode: LanaiISD::HI, DL, VT: MVT::i32, Operand: Hi); |
1204 | Lo = DAG.getNode(Opcode: LanaiISD::LO, DL, VT: MVT::i32, Operand: Lo); |
1205 | SDValue Result = DAG.getNode(Opcode: ISD::OR, DL, VT: MVT::i32, N1: Hi, N2: Lo); |
1206 | return Result; |
1207 | } |
1208 | |
1209 | SDValue LanaiTargetLowering::LowerJumpTable(SDValue Op, |
1210 | SelectionDAG &DAG) const { |
1211 | SDLoc DL(Op); |
1212 | JumpTableSDNode *JT = cast<JumpTableSDNode>(Val&: Op); |
1213 | |
1214 | // If the code model is small assume address will fit in 21-bits. |
1215 | if (getTargetMachine().getCodeModel() == CodeModel::Small) { |
1216 | SDValue Small = DAG.getTargetJumpTable( |
1217 | JTI: JT->getIndex(), VT: getPointerTy(DL: DAG.getDataLayout()), TargetFlags: LanaiII::MO_NO_FLAG); |
1218 | return DAG.getNode(Opcode: ISD::OR, DL, VT: MVT::i32, |
1219 | N1: DAG.getRegister(Reg: Lanai::R0, VT: MVT::i32), |
1220 | N2: DAG.getNode(Opcode: LanaiISD::SMALL, DL, VT: MVT::i32, Operand: Small)); |
1221 | } else { |
1222 | uint8_t OpFlagHi = LanaiII::MO_ABS_HI; |
1223 | uint8_t OpFlagLo = LanaiII::MO_ABS_LO; |
1224 | |
1225 | SDValue Hi = DAG.getTargetJumpTable( |
1226 | JTI: JT->getIndex(), VT: getPointerTy(DL: DAG.getDataLayout()), TargetFlags: OpFlagHi); |
1227 | SDValue Lo = DAG.getTargetJumpTable( |
1228 | JTI: JT->getIndex(), VT: getPointerTy(DL: DAG.getDataLayout()), TargetFlags: OpFlagLo); |
1229 | Hi = DAG.getNode(Opcode: LanaiISD::HI, DL, VT: MVT::i32, Operand: Hi); |
1230 | Lo = DAG.getNode(Opcode: LanaiISD::LO, DL, VT: MVT::i32, Operand: Lo); |
1231 | SDValue Result = DAG.getNode(Opcode: ISD::OR, DL, VT: MVT::i32, N1: Hi, N2: Lo); |
1232 | return Result; |
1233 | } |
1234 | } |
1235 | |
1236 | SDValue LanaiTargetLowering::LowerSHL_PARTS(SDValue Op, |
1237 | SelectionDAG &DAG) const { |
1238 | EVT VT = Op.getValueType(); |
1239 | unsigned VTBits = VT.getSizeInBits(); |
1240 | SDLoc dl(Op); |
1241 | assert(Op.getNumOperands() == 3 && "Unexpected SHL!" ); |
1242 | SDValue ShOpLo = Op.getOperand(i: 0); |
1243 | SDValue ShOpHi = Op.getOperand(i: 1); |
1244 | SDValue ShAmt = Op.getOperand(i: 2); |
1245 | |
1246 | // Performs the following for (ShOpLo + (ShOpHi << 32)) << ShAmt: |
1247 | // LoBitsForHi = (ShAmt == 0) ? 0 : (ShOpLo >> (32-ShAmt)) |
1248 | // HiBitsForHi = ShOpHi << ShAmt |
1249 | // Hi = (ShAmt >= 32) ? (ShOpLo << (ShAmt-32)) : (LoBitsForHi | HiBitsForHi) |
1250 | // Lo = (ShAmt >= 32) ? 0 : (ShOpLo << ShAmt) |
1251 | // return (Hi << 32) | Lo; |
1252 | |
1253 | SDValue RevShAmt = DAG.getNode(Opcode: ISD::SUB, DL: dl, VT: MVT::i32, |
1254 | N1: DAG.getConstant(Val: VTBits, DL: dl, VT: MVT::i32), N2: ShAmt); |
1255 | SDValue LoBitsForHi = DAG.getNode(Opcode: ISD::SRL, DL: dl, VT, N1: ShOpLo, N2: RevShAmt); |
1256 | |
1257 | // If ShAmt == 0, we just calculated "(SRL ShOpLo, 32)" which is "undef". We |
1258 | // wanted 0, so CSEL it directly. |
1259 | SDValue Zero = DAG.getConstant(Val: 0, DL: dl, VT: MVT::i32); |
1260 | SDValue SetCC = DAG.getSetCC(DL: dl, VT: MVT::i32, LHS: ShAmt, RHS: Zero, Cond: ISD::SETEQ); |
1261 | LoBitsForHi = DAG.getSelect(DL: dl, VT: MVT::i32, Cond: SetCC, LHS: Zero, RHS: LoBitsForHi); |
1262 | |
1263 | SDValue = DAG.getNode(Opcode: ISD::SUB, DL: dl, VT: MVT::i32, N1: ShAmt, |
1264 | N2: DAG.getConstant(Val: VTBits, DL: dl, VT: MVT::i32)); |
1265 | SDValue HiBitsForHi = DAG.getNode(Opcode: ISD::SHL, DL: dl, VT, N1: ShOpHi, N2: ShAmt); |
1266 | SDValue HiForNormalShift = |
1267 | DAG.getNode(Opcode: ISD::OR, DL: dl, VT, N1: LoBitsForHi, N2: HiBitsForHi); |
1268 | |
1269 | SDValue HiForBigShift = DAG.getNode(Opcode: ISD::SHL, DL: dl, VT, N1: ShOpLo, N2: ExtraShAmt); |
1270 | |
1271 | SetCC = DAG.getSetCC(DL: dl, VT: MVT::i32, LHS: ExtraShAmt, RHS: Zero, Cond: ISD::SETGE); |
1272 | SDValue Hi = |
1273 | DAG.getSelect(DL: dl, VT: MVT::i32, Cond: SetCC, LHS: HiForBigShift, RHS: HiForNormalShift); |
1274 | |
1275 | // Lanai shifts of larger than register sizes are wrapped rather than |
1276 | // clamped, so we can't just emit "lo << b" if b is too big. |
1277 | SDValue LoForNormalShift = DAG.getNode(Opcode: ISD::SHL, DL: dl, VT, N1: ShOpLo, N2: ShAmt); |
1278 | SDValue Lo = DAG.getSelect( |
1279 | DL: dl, VT: MVT::i32, Cond: SetCC, LHS: DAG.getConstant(Val: 0, DL: dl, VT: MVT::i32), RHS: LoForNormalShift); |
1280 | |
1281 | SDValue Ops[2] = {Lo, Hi}; |
1282 | return DAG.getMergeValues(Ops, dl); |
1283 | } |
1284 | |
1285 | SDValue LanaiTargetLowering::LowerSRL_PARTS(SDValue Op, |
1286 | SelectionDAG &DAG) const { |
1287 | MVT VT = Op.getSimpleValueType(); |
1288 | unsigned VTBits = VT.getSizeInBits(); |
1289 | SDLoc dl(Op); |
1290 | SDValue ShOpLo = Op.getOperand(i: 0); |
1291 | SDValue ShOpHi = Op.getOperand(i: 1); |
1292 | SDValue ShAmt = Op.getOperand(i: 2); |
1293 | |
1294 | // Performs the following for a >> b: |
1295 | // unsigned r_high = a_high >> b; |
1296 | // r_high = (32 - b <= 0) ? 0 : r_high; |
1297 | // |
1298 | // unsigned r_low = a_low >> b; |
1299 | // r_low = (32 - b <= 0) ? r_high : r_low; |
1300 | // r_low = (b == 0) ? r_low : r_low | (a_high << (32 - b)); |
1301 | // return (unsigned long long)r_high << 32 | r_low; |
1302 | // Note: This takes advantage of Lanai's shift behavior to avoid needing to |
1303 | // mask the shift amount. |
1304 | |
1305 | SDValue Zero = DAG.getConstant(Val: 0, DL: dl, VT: MVT::i32); |
1306 | SDValue NegatedPlus32 = DAG.getNode( |
1307 | Opcode: ISD::SUB, DL: dl, VT: MVT::i32, N1: DAG.getConstant(Val: VTBits, DL: dl, VT: MVT::i32), N2: ShAmt); |
1308 | SDValue SetCC = DAG.getSetCC(DL: dl, VT: MVT::i32, LHS: NegatedPlus32, RHS: Zero, Cond: ISD::SETLE); |
1309 | |
1310 | SDValue Hi = DAG.getNode(Opcode: ISD::SRL, DL: dl, VT: MVT::i32, N1: ShOpHi, N2: ShAmt); |
1311 | Hi = DAG.getSelect(DL: dl, VT: MVT::i32, Cond: SetCC, LHS: Zero, RHS: Hi); |
1312 | |
1313 | SDValue Lo = DAG.getNode(Opcode: ISD::SRL, DL: dl, VT: MVT::i32, N1: ShOpLo, N2: ShAmt); |
1314 | Lo = DAG.getSelect(DL: dl, VT: MVT::i32, Cond: SetCC, LHS: Hi, RHS: Lo); |
1315 | SDValue CarryBits = |
1316 | DAG.getNode(Opcode: ISD::SHL, DL: dl, VT: MVT::i32, N1: ShOpHi, N2: NegatedPlus32); |
1317 | SDValue ShiftIsZero = DAG.getSetCC(DL: dl, VT: MVT::i32, LHS: ShAmt, RHS: Zero, Cond: ISD::SETEQ); |
1318 | Lo = DAG.getSelect(DL: dl, VT: MVT::i32, Cond: ShiftIsZero, LHS: Lo, |
1319 | RHS: DAG.getNode(Opcode: ISD::OR, DL: dl, VT: MVT::i32, N1: Lo, N2: CarryBits)); |
1320 | |
1321 | SDValue Ops[2] = {Lo, Hi}; |
1322 | return DAG.getMergeValues(Ops, dl); |
1323 | } |
1324 | |
1325 | // Helper function that checks if N is a null or all ones constant. |
1326 | static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) { |
1327 | return AllOnes ? isAllOnesConstant(V: N) : isNullConstant(V: N); |
1328 | } |
1329 | |
1330 | // Return true if N is conditionally 0 or all ones. |
1331 | // Detects these expressions where cc is an i1 value: |
1332 | // |
1333 | // (select cc 0, y) [AllOnes=0] |
1334 | // (select cc y, 0) [AllOnes=0] |
1335 | // (zext cc) [AllOnes=0] |
1336 | // (sext cc) [AllOnes=0/1] |
1337 | // (select cc -1, y) [AllOnes=1] |
1338 | // (select cc y, -1) [AllOnes=1] |
1339 | // |
1340 | // * AllOnes determines whether to check for an all zero (AllOnes false) or an |
1341 | // all ones operand (AllOnes true). |
1342 | // * Invert is set when N is the all zero/ones constant when CC is false. |
1343 | // * OtherOp is set to the alternative value of N. |
1344 | // |
1345 | // For example, for (select cc X, Y) and AllOnes = 0 if: |
1346 | // * X = 0, Invert = False and OtherOp = Y |
1347 | // * Y = 0, Invert = True and OtherOp = X |
1348 | static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes, SDValue &CC, |
1349 | bool &Invert, SDValue &OtherOp, |
1350 | SelectionDAG &DAG) { |
1351 | switch (N->getOpcode()) { |
1352 | default: |
1353 | return false; |
1354 | case ISD::SELECT: { |
1355 | CC = N->getOperand(Num: 0); |
1356 | SDValue N1 = N->getOperand(Num: 1); |
1357 | SDValue N2 = N->getOperand(Num: 2); |
1358 | if (isZeroOrAllOnes(N: N1, AllOnes)) { |
1359 | Invert = false; |
1360 | OtherOp = N2; |
1361 | return true; |
1362 | } |
1363 | if (isZeroOrAllOnes(N: N2, AllOnes)) { |
1364 | Invert = true; |
1365 | OtherOp = N1; |
1366 | return true; |
1367 | } |
1368 | return false; |
1369 | } |
1370 | case ISD::ZERO_EXTEND: { |
1371 | // (zext cc) can never be the all ones value. |
1372 | if (AllOnes) |
1373 | return false; |
1374 | CC = N->getOperand(Num: 0); |
1375 | if (CC.getValueType() != MVT::i1) |
1376 | return false; |
1377 | SDLoc dl(N); |
1378 | EVT VT = N->getValueType(ResNo: 0); |
1379 | OtherOp = DAG.getConstant(Val: 1, DL: dl, VT); |
1380 | Invert = true; |
1381 | return true; |
1382 | } |
1383 | case ISD::SIGN_EXTEND: { |
1384 | CC = N->getOperand(Num: 0); |
1385 | if (CC.getValueType() != MVT::i1) |
1386 | return false; |
1387 | SDLoc dl(N); |
1388 | EVT VT = N->getValueType(ResNo: 0); |
1389 | Invert = !AllOnes; |
1390 | if (AllOnes) |
1391 | // When looking for an AllOnes constant, N is an sext, and the 'other' |
1392 | // value is 0. |
1393 | OtherOp = DAG.getConstant(Val: 0, DL: dl, VT); |
1394 | else |
1395 | OtherOp = DAG.getAllOnesConstant(DL: dl, VT); |
1396 | return true; |
1397 | } |
1398 | } |
1399 | } |
1400 | |
1401 | // Combine a constant select operand into its use: |
1402 | // |
1403 | // (add (select cc, 0, c), x) -> (select cc, x, (add, x, c)) |
1404 | // (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) |
1405 | // (and (select cc, -1, c), x) -> (select cc, x, (and, x, c)) [AllOnes=1] |
1406 | // (or (select cc, 0, c), x) -> (select cc, x, (or, x, c)) |
1407 | // (xor (select cc, 0, c), x) -> (select cc, x, (xor, x, c)) |
1408 | // |
1409 | // The transform is rejected if the select doesn't have a constant operand that |
1410 | // is null, or all ones when AllOnes is set. |
1411 | // |
1412 | // Also recognize sext/zext from i1: |
1413 | // |
1414 | // (add (zext cc), x) -> (select cc (add x, 1), x) |
1415 | // (add (sext cc), x) -> (select cc (add x, -1), x) |
1416 | // |
1417 | // These transformations eventually create predicated instructions. |
1418 | static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, |
1419 | TargetLowering::DAGCombinerInfo &DCI, |
1420 | bool AllOnes) { |
1421 | SelectionDAG &DAG = DCI.DAG; |
1422 | EVT VT = N->getValueType(ResNo: 0); |
1423 | SDValue NonConstantVal; |
1424 | SDValue CCOp; |
1425 | bool SwapSelectOps; |
1426 | if (!isConditionalZeroOrAllOnes(N: Slct.getNode(), AllOnes, CC&: CCOp, Invert&: SwapSelectOps, |
1427 | OtherOp&: NonConstantVal, DAG)) |
1428 | return SDValue(); |
1429 | |
1430 | // Slct is now know to be the desired identity constant when CC is true. |
1431 | SDValue TrueVal = OtherOp; |
1432 | SDValue FalseVal = |
1433 | DAG.getNode(Opcode: N->getOpcode(), DL: SDLoc(N), VT, N1: OtherOp, N2: NonConstantVal); |
1434 | // Unless SwapSelectOps says CC should be false. |
1435 | if (SwapSelectOps) |
1436 | std::swap(a&: TrueVal, b&: FalseVal); |
1437 | |
1438 | return DAG.getNode(Opcode: ISD::SELECT, DL: SDLoc(N), VT, N1: CCOp, N2: TrueVal, N3: FalseVal); |
1439 | } |
1440 | |
1441 | // Attempt combineSelectAndUse on each operand of a commutative operator N. |
1442 | static SDValue |
1443 | combineSelectAndUseCommutative(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, |
1444 | bool AllOnes) { |
1445 | SDValue N0 = N->getOperand(Num: 0); |
1446 | SDValue N1 = N->getOperand(Num: 1); |
1447 | if (N0.getNode()->hasOneUse()) |
1448 | if (SDValue Result = combineSelectAndUse(N, Slct: N0, OtherOp: N1, DCI, AllOnes)) |
1449 | return Result; |
1450 | if (N1.getNode()->hasOneUse()) |
1451 | if (SDValue Result = combineSelectAndUse(N, Slct: N1, OtherOp: N0, DCI, AllOnes)) |
1452 | return Result; |
1453 | return SDValue(); |
1454 | } |
1455 | |
1456 | // PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB. |
1457 | static SDValue PerformSUBCombine(SDNode *N, |
1458 | TargetLowering::DAGCombinerInfo &DCI) { |
1459 | SDValue N0 = N->getOperand(Num: 0); |
1460 | SDValue N1 = N->getOperand(Num: 1); |
1461 | |
1462 | // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) |
1463 | if (N1.getNode()->hasOneUse()) |
1464 | if (SDValue Result = combineSelectAndUse(N, Slct: N1, OtherOp: N0, DCI, /*AllOnes=*/false)) |
1465 | return Result; |
1466 | |
1467 | return SDValue(); |
1468 | } |
1469 | |
1470 | SDValue LanaiTargetLowering::PerformDAGCombine(SDNode *N, |
1471 | DAGCombinerInfo &DCI) const { |
1472 | switch (N->getOpcode()) { |
1473 | default: |
1474 | break; |
1475 | case ISD::ADD: |
1476 | case ISD::OR: |
1477 | case ISD::XOR: |
1478 | return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/false); |
1479 | case ISD::AND: |
1480 | return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/true); |
1481 | case ISD::SUB: |
1482 | return PerformSUBCombine(N, DCI); |
1483 | } |
1484 | |
1485 | return SDValue(); |
1486 | } |
1487 | |
1488 | void LanaiTargetLowering::computeKnownBitsForTargetNode( |
1489 | const SDValue Op, KnownBits &Known, const APInt &DemandedElts, |
1490 | const SelectionDAG &DAG, unsigned Depth) const { |
1491 | unsigned BitWidth = Known.getBitWidth(); |
1492 | switch (Op.getOpcode()) { |
1493 | default: |
1494 | break; |
1495 | case LanaiISD::SETCC: |
1496 | Known = KnownBits(BitWidth); |
1497 | Known.Zero.setBits(loBit: 1, hiBit: BitWidth); |
1498 | break; |
1499 | case LanaiISD::SELECT_CC: |
1500 | KnownBits Known2; |
1501 | Known = DAG.computeKnownBits(Op: Op->getOperand(Num: 0), Depth: Depth + 1); |
1502 | Known2 = DAG.computeKnownBits(Op: Op->getOperand(Num: 1), Depth: Depth + 1); |
1503 | Known = Known.intersectWith(RHS: Known2); |
1504 | break; |
1505 | } |
1506 | } |
1507 | |