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/RuntimeLibcalls.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(MVT::i32, &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(ISD::BR_CC, MVT::i32, Custom); |
86 | setOperationAction(ISD::BR_JT, MVT::Other, Expand); |
87 | setOperationAction(ISD::BRCOND, MVT::Other, Expand); |
88 | setOperationAction(ISD::SETCC, MVT::i32, Custom); |
89 | setOperationAction(ISD::SELECT, MVT::i32, Expand); |
90 | setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); |
91 | |
92 | setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); |
93 | setOperationAction(ISD::BlockAddress, MVT::i32, Custom); |
94 | setOperationAction(ISD::JumpTable, MVT::i32, Custom); |
95 | setOperationAction(ISD::ConstantPool, MVT::i32, Custom); |
96 | |
97 | setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom); |
98 | setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); |
99 | setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); |
100 | |
101 | setOperationAction(ISD::VASTART, MVT::Other, Custom); |
102 | setOperationAction(ISD::VAARG, MVT::Other, Expand); |
103 | setOperationAction(ISD::VACOPY, MVT::Other, Expand); |
104 | setOperationAction(ISD::VAEND, MVT::Other, Expand); |
105 | |
106 | setOperationAction(ISD::SDIV, MVT::i32, Expand); |
107 | setOperationAction(ISD::UDIV, MVT::i32, Expand); |
108 | setOperationAction(ISD::SDIVREM, MVT::i32, Expand); |
109 | setOperationAction(ISD::UDIVREM, MVT::i32, Expand); |
110 | setOperationAction(ISD::SREM, MVT::i32, Expand); |
111 | setOperationAction(ISD::UREM, MVT::i32, Expand); |
112 | |
113 | setOperationAction(ISD::MUL, MVT::i32, Custom); |
114 | setOperationAction(ISD::MULHU, MVT::i32, Expand); |
115 | setOperationAction(ISD::MULHS, MVT::i32, Expand); |
116 | setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); |
117 | setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); |
118 | |
119 | setOperationAction(ISD::ROTR, MVT::i32, Expand); |
120 | setOperationAction(ISD::ROTL, MVT::i32, Expand); |
121 | setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom); |
122 | setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); |
123 | setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); |
124 | |
125 | setOperationAction(ISD::BSWAP, MVT::i32, Expand); |
126 | setOperationAction(ISD::CTPOP, MVT::i32, Legal); |
127 | setOperationAction(ISD::CTLZ, MVT::i32, Legal); |
128 | setOperationAction(ISD::CTTZ, MVT::i32, Legal); |
129 | |
130 | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); |
131 | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); |
132 | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); |
133 | |
134 | // Extended load operations for i1 types must be promoted |
135 | for (MVT VT : MVT::integer_valuetypes()) { |
136 | setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); |
137 | setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); |
138 | setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, 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("pc" , Lanai::PC) |
219 | .Case("sp" , Lanai::SP) |
220 | .Case("fp" , Lanai::FP) |
221 | .Case("rr1" , Lanai::RR1) |
222 | .Case("r10" , Lanai::R10) |
223 | .Case("rr2" , Lanai::RR2) |
224 | .Case("r11" , Lanai::R11) |
225 | .Case("rca" , Lanai::RCA) |
226 | .Default(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(0U, &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, CC_Lanai32_Fast); |
450 | } else { |
451 | CCInfo.AnalyzeFormalArguments(Ins, CC_Lanai32); |
452 | } |
453 | |
454 | for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { |
455 | CCValAssign &VA = ArgLocs[i]; |
456 | if (VA.isRegLoc()) { |
457 | // Arguments passed in registers |
458 | EVT RegVT = VA.getLocVT(); |
459 | switch (RegVT.getSimpleVT().SimpleTy) { |
460 | case MVT::i32: { |
461 | Register VReg = RegInfo.createVirtualRegister(&Lanai::GPRRegClass); |
462 | RegInfo.addLiveIn(Reg: VA.getLocReg(), vreg: VReg); |
463 | SDValue ArgValue = DAG.getCopyFromReg(Chain, dl: DL, Reg: VReg, VT: RegVT); |
464 | |
465 | // If this is an 8/16-bit value, it is really passed promoted to 32 |
466 | // bits. Insert an assert[sz]ext to capture this, then truncate to the |
467 | // right size. |
468 | if (VA.getLocInfo() == CCValAssign::SExt) |
469 | ArgValue = DAG.getNode(Opcode: ISD::AssertSext, DL, VT: RegVT, N1: ArgValue, |
470 | N2: DAG.getValueType(VA.getValVT())); |
471 | else if (VA.getLocInfo() == CCValAssign::ZExt) |
472 | ArgValue = DAG.getNode(Opcode: ISD::AssertZext, DL, VT: RegVT, N1: ArgValue, |
473 | N2: DAG.getValueType(VA.getValVT())); |
474 | |
475 | if (VA.getLocInfo() != CCValAssign::Full) |
476 | ArgValue = DAG.getNode(Opcode: ISD::TRUNCATE, DL, VT: VA.getValVT(), Operand: ArgValue); |
477 | |
478 | InVals.push_back(Elt: ArgValue); |
479 | break; |
480 | } |
481 | default: |
482 | LLVM_DEBUG(dbgs() << "LowerFormalArguments Unhandled argument type: " |
483 | << RegVT << "\n" ); |
484 | llvm_unreachable("unhandled argument type" ); |
485 | } |
486 | } else { |
487 | // Only arguments passed on the stack should make it here. |
488 | assert(VA.isMemLoc()); |
489 | // Load the argument to a virtual register |
490 | unsigned ObjSize = VA.getLocVT().getSizeInBits() / 8; |
491 | // Check that the argument fits in stack slot |
492 | if (ObjSize > 4) { |
493 | errs() << "LowerFormalArguments Unhandled argument type: " |
494 | << VA.getLocVT() << "\n" ; |
495 | } |
496 | // Create the frame index object for this incoming parameter... |
497 | int FI = MFI.CreateFixedObject(Size: ObjSize, SPOffset: VA.getLocMemOffset(), IsImmutable: true); |
498 | |
499 | // Create the SelectionDAG nodes corresponding to a load |
500 | // from this parameter |
501 | SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); |
502 | InVals.push_back(Elt: DAG.getLoad( |
503 | VT: VA.getLocVT(), dl: DL, Chain, Ptr: FIN, |
504 | PtrInfo: MachinePointerInfo::getFixedStack(MF&: DAG.getMachineFunction(), FI))); |
505 | } |
506 | } |
507 | |
508 | // The Lanai ABI for returning structs by value requires that we copy |
509 | // the sret argument into rv for the return. Save the argument into |
510 | // a virtual register so that we can access it from the return points. |
511 | if (MF.getFunction().hasStructRetAttr()) { |
512 | Register Reg = LanaiMFI->getSRetReturnReg(); |
513 | if (!Reg) { |
514 | Reg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i32)); |
515 | LanaiMFI->setSRetReturnReg(Reg); |
516 | } |
517 | SDValue Copy = DAG.getCopyToReg(Chain: DAG.getEntryNode(), dl: DL, Reg, N: InVals[0]); |
518 | Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Copy, Chain); |
519 | } |
520 | |
521 | if (IsVarArg) { |
522 | // Record the frame index of the first variable argument |
523 | // which is a value necessary to VASTART. |
524 | int FI = MFI.CreateFixedObject(Size: 4, SPOffset: CCInfo.getStackSize(), IsImmutable: true); |
525 | LanaiMFI->setVarArgsFrameIndex(FI); |
526 | } |
527 | |
528 | return Chain; |
529 | } |
530 | |
531 | bool LanaiTargetLowering::CanLowerReturn( |
532 | CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, |
533 | const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { |
534 | SmallVector<CCValAssign, 16> RVLocs; |
535 | CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); |
536 | |
537 | return CCInfo.CheckReturn(Outs, RetCC_Lanai32); |
538 | } |
539 | |
540 | SDValue |
541 | LanaiTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, |
542 | bool IsVarArg, |
543 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
544 | const SmallVectorImpl<SDValue> &OutVals, |
545 | const SDLoc &DL, SelectionDAG &DAG) const { |
546 | // CCValAssign - represent the assignment of the return value to a location |
547 | SmallVector<CCValAssign, 16> RVLocs; |
548 | |
549 | // CCState - Info about the registers and stack slot. |
550 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, |
551 | *DAG.getContext()); |
552 | |
553 | // Analize return values. |
554 | CCInfo.AnalyzeReturn(Outs, RetCC_Lanai32); |
555 | |
556 | SDValue Glue; |
557 | SmallVector<SDValue, 4> RetOps(1, Chain); |
558 | |
559 | // Copy the result values into the output registers. |
560 | for (unsigned i = 0; i != RVLocs.size(); ++i) { |
561 | CCValAssign &VA = RVLocs[i]; |
562 | assert(VA.isRegLoc() && "Can only return in registers!" ); |
563 | |
564 | Chain = DAG.getCopyToReg(Chain, dl: DL, Reg: VA.getLocReg(), N: OutVals[i], Glue); |
565 | |
566 | // Guarantee that all emitted copies are stuck together with flags. |
567 | Glue = Chain.getValue(R: 1); |
568 | RetOps.push_back(Elt: DAG.getRegister(Reg: VA.getLocReg(), VT: VA.getLocVT())); |
569 | } |
570 | |
571 | // The Lanai ABI for returning structs by value requires that we copy |
572 | // the sret argument into rv for the return. We saved the argument into |
573 | // a virtual register in the entry block, so now we copy the value out |
574 | // and into rv. |
575 | if (DAG.getMachineFunction().getFunction().hasStructRetAttr()) { |
576 | MachineFunction &MF = DAG.getMachineFunction(); |
577 | LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo<LanaiMachineFunctionInfo>(); |
578 | Register Reg = LanaiMFI->getSRetReturnReg(); |
579 | assert(Reg && |
580 | "SRetReturnReg should have been set in LowerFormalArguments()." ); |
581 | SDValue Val = |
582 | DAG.getCopyFromReg(Chain, dl: DL, Reg, VT: getPointerTy(DL: DAG.getDataLayout())); |
583 | |
584 | Chain = DAG.getCopyToReg(Chain, DL, Lanai::RV, Val, Glue); |
585 | Glue = Chain.getValue(R: 1); |
586 | RetOps.push_back( |
587 | DAG.getRegister(Lanai::RV, getPointerTy(DAG.getDataLayout()))); |
588 | } |
589 | |
590 | RetOps[0] = Chain; // Update chain |
591 | |
592 | unsigned Opc = LanaiISD::RET_GLUE; |
593 | if (Glue.getNode()) |
594 | RetOps.push_back(Elt: Glue); |
595 | |
596 | // Return Void |
597 | return DAG.getNode(Opc, DL, MVT::Other, |
598 | ArrayRef<SDValue>(&RetOps[0], RetOps.size())); |
599 | } |
600 | |
601 | // LowerCCCCallTo - functions arguments are copied from virtual regs to |
602 | // (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. |
603 | SDValue LanaiTargetLowering::LowerCCCCallTo( |
604 | SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool IsVarArg, |
605 | bool /*IsTailCall*/, const SmallVectorImpl<ISD::OutputArg> &Outs, |
606 | const SmallVectorImpl<SDValue> &OutVals, |
607 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, |
608 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { |
609 | // Analyze operands of the call, assigning locations to each operand. |
610 | SmallVector<CCValAssign, 16> ArgLocs; |
611 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, |
612 | *DAG.getContext()); |
613 | GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Val&: Callee); |
614 | MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); |
615 | |
616 | NumFixedArgs = 0; |
617 | if (IsVarArg && G) { |
618 | const Function *CalleeFn = dyn_cast<Function>(Val: G->getGlobal()); |
619 | if (CalleeFn) |
620 | NumFixedArgs = CalleeFn->getFunctionType()->getNumParams(); |
621 | } |
622 | if (NumFixedArgs) |
623 | CCInfo.AnalyzeCallOperands(Outs, Fn: CC_Lanai32_VarArg); |
624 | else { |
625 | if (CallConv == CallingConv::Fast) |
626 | CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32_Fast); |
627 | else |
628 | CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32); |
629 | } |
630 | |
631 | // Get a count of how many bytes are to be pushed on the stack. |
632 | unsigned NumBytes = CCInfo.getStackSize(); |
633 | |
634 | // Create local copies for byval args. |
635 | SmallVector<SDValue, 8> ByValArgs; |
636 | for (unsigned I = 0, E = Outs.size(); I != E; ++I) { |
637 | ISD::ArgFlagsTy Flags = Outs[I].Flags; |
638 | if (!Flags.isByVal()) |
639 | continue; |
640 | |
641 | SDValue Arg = OutVals[I]; |
642 | unsigned Size = Flags.getByValSize(); |
643 | Align Alignment = Flags.getNonZeroByValAlign(); |
644 | |
645 | int FI = MFI.CreateStackObject(Size, Alignment, isSpillSlot: false); |
646 | SDValue FIPtr = DAG.getFrameIndex(FI, VT: getPointerTy(DL: DAG.getDataLayout())); |
647 | SDValue SizeNode = DAG.getConstant(Size, DL, MVT::i32); |
648 | |
649 | Chain = DAG.getMemcpy(Chain, dl: DL, Dst: FIPtr, Src: Arg, Size: SizeNode, Alignment, |
650 | /*IsVolatile=*/isVol: false, |
651 | /*AlwaysInline=*/false, |
652 | /*isTailCall=*/false, DstPtrInfo: MachinePointerInfo(), |
653 | SrcPtrInfo: MachinePointerInfo()); |
654 | ByValArgs.push_back(Elt: FIPtr); |
655 | } |
656 | |
657 | Chain = DAG.getCALLSEQ_START(Chain, InSize: NumBytes, OutSize: 0, DL); |
658 | |
659 | SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; |
660 | SmallVector<SDValue, 12> MemOpChains; |
661 | SDValue StackPtr; |
662 | |
663 | // Walk the register/memloc assignments, inserting copies/loads. |
664 | for (unsigned I = 0, J = 0, E = ArgLocs.size(); I != E; ++I) { |
665 | CCValAssign &VA = ArgLocs[I]; |
666 | SDValue Arg = OutVals[I]; |
667 | ISD::ArgFlagsTy Flags = Outs[I].Flags; |
668 | |
669 | // Promote the value if needed. |
670 | switch (VA.getLocInfo()) { |
671 | case CCValAssign::Full: |
672 | break; |
673 | case CCValAssign::SExt: |
674 | Arg = DAG.getNode(Opcode: ISD::SIGN_EXTEND, DL, VT: VA.getLocVT(), Operand: Arg); |
675 | break; |
676 | case CCValAssign::ZExt: |
677 | Arg = DAG.getNode(Opcode: ISD::ZERO_EXTEND, DL, VT: VA.getLocVT(), Operand: Arg); |
678 | break; |
679 | case CCValAssign::AExt: |
680 | Arg = DAG.getNode(Opcode: ISD::ANY_EXTEND, DL, VT: VA.getLocVT(), Operand: Arg); |
681 | break; |
682 | default: |
683 | llvm_unreachable("Unknown loc info!" ); |
684 | } |
685 | |
686 | // Use local copy if it is a byval arg. |
687 | if (Flags.isByVal()) |
688 | Arg = ByValArgs[J++]; |
689 | |
690 | // Arguments that can be passed on register must be kept at RegsToPass |
691 | // vector |
692 | if (VA.isRegLoc()) { |
693 | RegsToPass.push_back(Elt: std::make_pair(x: VA.getLocReg(), y&: Arg)); |
694 | } else { |
695 | assert(VA.isMemLoc()); |
696 | |
697 | if (StackPtr.getNode() == nullptr) |
698 | StackPtr = DAG.getCopyFromReg(Chain, DL, Lanai::SP, |
699 | getPointerTy(DAG.getDataLayout())); |
700 | |
701 | SDValue PtrOff = |
702 | DAG.getNode(Opcode: ISD::ADD, DL, VT: getPointerTy(DL: DAG.getDataLayout()), N1: StackPtr, |
703 | N2: DAG.getIntPtrConstant(Val: VA.getLocMemOffset(), DL)); |
704 | |
705 | MemOpChains.push_back( |
706 | Elt: DAG.getStore(Chain, dl: DL, Val: Arg, Ptr: PtrOff, PtrInfo: MachinePointerInfo())); |
707 | } |
708 | } |
709 | |
710 | // Transform all store nodes into one single node because all store nodes are |
711 | // independent of each other. |
712 | if (!MemOpChains.empty()) |
713 | Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, |
714 | ArrayRef<SDValue>(&MemOpChains[0], MemOpChains.size())); |
715 | |
716 | SDValue InGlue; |
717 | |
718 | // Build a sequence of copy-to-reg nodes chained together with token chain and |
719 | // flag operands which copy the outgoing args into registers. The InGlue in |
720 | // necessary since all emitted instructions must be stuck together. |
721 | for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { |
722 | Chain = DAG.getCopyToReg(Chain, dl: DL, Reg: RegsToPass[I].first, |
723 | N: RegsToPass[I].second, Glue: InGlue); |
724 | InGlue = Chain.getValue(R: 1); |
725 | } |
726 | |
727 | // If the callee is a GlobalAddress node (quite common, every direct call is) |
728 | // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. |
729 | // Likewise ExternalSymbol -> TargetExternalSymbol. |
730 | uint8_t OpFlag = LanaiII::MO_NO_FLAG; |
731 | if (G) { |
732 | Callee = DAG.getTargetGlobalAddress( |
733 | GV: G->getGlobal(), DL, VT: getPointerTy(DL: DAG.getDataLayout()), offset: 0, TargetFlags: OpFlag); |
734 | } else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Val&: Callee)) { |
735 | Callee = DAG.getTargetExternalSymbol( |
736 | Sym: E->getSymbol(), VT: getPointerTy(DL: DAG.getDataLayout()), TargetFlags: OpFlag); |
737 | } |
738 | |
739 | // Returns a chain & a flag for retval copy to use. |
740 | SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); |
741 | SmallVector<SDValue, 8> Ops; |
742 | Ops.push_back(Elt: Chain); |
743 | Ops.push_back(Elt: Callee); |
744 | |
745 | // Add a register mask operand representing the call-preserved registers. |
746 | // TODO: Should return-twice functions be handled? |
747 | const uint32_t *Mask = |
748 | TRI->getCallPreservedMask(MF: DAG.getMachineFunction(), CallConv); |
749 | assert(Mask && "Missing call preserved mask for calling convention" ); |
750 | Ops.push_back(Elt: DAG.getRegisterMask(RegMask: Mask)); |
751 | |
752 | // Add argument registers to the end of the list so that they are |
753 | // known live into the call. |
754 | for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) |
755 | Ops.push_back(Elt: DAG.getRegister(Reg: RegsToPass[I].first, |
756 | VT: RegsToPass[I].second.getValueType())); |
757 | |
758 | if (InGlue.getNode()) |
759 | Ops.push_back(Elt: InGlue); |
760 | |
761 | Chain = DAG.getNode(Opcode: LanaiISD::CALL, DL, VTList: NodeTys, |
762 | Ops: ArrayRef<SDValue>(&Ops[0], Ops.size())); |
763 | InGlue = Chain.getValue(R: 1); |
764 | |
765 | // Create the CALLSEQ_END node. |
766 | Chain = DAG.getCALLSEQ_END(Chain, Size1: NumBytes, Size2: 0, Glue: InGlue, DL); |
767 | InGlue = Chain.getValue(R: 1); |
768 | |
769 | // Handle result values, copying them out of physregs into vregs that we |
770 | // return. |
771 | return LowerCallResult(Chain, InGlue, CallConv, IsVarArg, Ins, DL, DAG, |
772 | InVals); |
773 | } |
774 | |
775 | // LowerCallResult - Lower the result values of a call into the |
776 | // appropriate copies out of appropriate physical registers. |
777 | SDValue LanaiTargetLowering::LowerCallResult( |
778 | SDValue Chain, SDValue InGlue, CallingConv::ID CallConv, bool IsVarArg, |
779 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, |
780 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { |
781 | // Assign locations to each value returned by this call. |
782 | SmallVector<CCValAssign, 16> RVLocs; |
783 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, |
784 | *DAG.getContext()); |
785 | |
786 | CCInfo.AnalyzeCallResult(Ins, RetCC_Lanai32); |
787 | |
788 | // Copy all of the result registers out of their specified physreg. |
789 | for (unsigned I = 0; I != RVLocs.size(); ++I) { |
790 | Chain = DAG.getCopyFromReg(Chain, dl: DL, Reg: RVLocs[I].getLocReg(), |
791 | VT: RVLocs[I].getValVT(), Glue: InGlue) |
792 | .getValue(R: 1); |
793 | InGlue = Chain.getValue(R: 2); |
794 | InVals.push_back(Elt: Chain.getValue(R: 0)); |
795 | } |
796 | |
797 | return Chain; |
798 | } |
799 | |
800 | //===----------------------------------------------------------------------===// |
801 | // Custom Lowerings |
802 | //===----------------------------------------------------------------------===// |
803 | |
804 | static LPCC::CondCode IntCondCCodeToICC(SDValue CC, const SDLoc &DL, |
805 | SDValue &RHS, SelectionDAG &DAG) { |
806 | ISD::CondCode SetCCOpcode = cast<CondCodeSDNode>(Val&: CC)->get(); |
807 | |
808 | // For integer, only the SETEQ, SETNE, SETLT, SETLE, SETGT, SETGE, SETULT, |
809 | // SETULE, SETUGT, and SETUGE opcodes are used (see CodeGen/ISDOpcodes.h) |
810 | // and Lanai only supports integer comparisons, so only provide definitions |
811 | // for them. |
812 | switch (SetCCOpcode) { |
813 | case ISD::SETEQ: |
814 | return LPCC::ICC_EQ; |
815 | case ISD::SETGT: |
816 | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Val&: RHS)) |
817 | if (RHSC->getZExtValue() == 0xFFFFFFFF) { |
818 | // X > -1 -> X >= 0 -> is_plus(X) |
819 | RHS = DAG.getConstant(Val: 0, DL, VT: RHS.getValueType()); |
820 | return LPCC::ICC_PL; |
821 | } |
822 | return LPCC::ICC_GT; |
823 | case ISD::SETUGT: |
824 | return LPCC::ICC_UGT; |
825 | case ISD::SETLT: |
826 | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Val&: RHS)) |
827 | if (RHSC->getZExtValue() == 0) |
828 | // X < 0 -> is_minus(X) |
829 | return LPCC::ICC_MI; |
830 | return LPCC::ICC_LT; |
831 | case ISD::SETULT: |
832 | return LPCC::ICC_ULT; |
833 | case ISD::SETLE: |
834 | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Val&: RHS)) |
835 | if (RHSC->getZExtValue() == 0xFFFFFFFF) { |
836 | // X <= -1 -> X < 0 -> is_minus(X) |
837 | RHS = DAG.getConstant(Val: 0, DL, VT: RHS.getValueType()); |
838 | return LPCC::ICC_MI; |
839 | } |
840 | return LPCC::ICC_LE; |
841 | case ISD::SETULE: |
842 | return LPCC::ICC_ULE; |
843 | case ISD::SETGE: |
844 | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(Val&: RHS)) |
845 | if (RHSC->getZExtValue() == 0) |
846 | // X >= 0 -> is_plus(X) |
847 | return LPCC::ICC_PL; |
848 | return LPCC::ICC_GE; |
849 | case ISD::SETUGE: |
850 | return LPCC::ICC_UGE; |
851 | case ISD::SETNE: |
852 | return LPCC::ICC_NE; |
853 | case ISD::SETONE: |
854 | case ISD::SETUNE: |
855 | case ISD::SETOGE: |
856 | case ISD::SETOLE: |
857 | case ISD::SETOLT: |
858 | case ISD::SETOGT: |
859 | case ISD::SETOEQ: |
860 | case ISD::SETUEQ: |
861 | case ISD::SETO: |
862 | case ISD::SETUO: |
863 | llvm_unreachable("Unsupported comparison." ); |
864 | default: |
865 | llvm_unreachable("Unknown integer condition code!" ); |
866 | } |
867 | } |
868 | |
869 | SDValue LanaiTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { |
870 | SDValue Chain = Op.getOperand(i: 0); |
871 | SDValue Cond = Op.getOperand(i: 1); |
872 | SDValue LHS = Op.getOperand(i: 2); |
873 | SDValue RHS = Op.getOperand(i: 3); |
874 | SDValue Dest = Op.getOperand(i: 4); |
875 | SDLoc DL(Op); |
876 | |
877 | LPCC::CondCode CC = IntCondCCodeToICC(CC: Cond, DL, RHS, DAG); |
878 | SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); |
879 | SDValue Glue = |
880 | DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); |
881 | |
882 | return DAG.getNode(Opcode: LanaiISD::BR_CC, DL, VT: Op.getValueType(), N1: Chain, N2: Dest, |
883 | N3: TargetCC, N4: Glue); |
884 | } |
885 | |
886 | SDValue LanaiTargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const { |
887 | EVT VT = Op->getValueType(ResNo: 0); |
888 | if (VT != MVT::i32) |
889 | return SDValue(); |
890 | |
891 | ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val: Op->getOperand(Num: 1)); |
892 | if (!C) |
893 | return SDValue(); |
894 | |
895 | int64_t MulAmt = C->getSExtValue(); |
896 | int32_t HighestOne = -1; |
897 | uint32_t NonzeroEntries = 0; |
898 | int SignedDigit[32] = {0}; |
899 | |
900 | // Convert to non-adjacent form (NAF) signed-digit representation. |
901 | // NAF is a signed-digit form where no adjacent digits are non-zero. It is the |
902 | // minimal Hamming weight representation of a number (on average 1/3 of the |
903 | // digits will be non-zero vs 1/2 for regular binary representation). And as |
904 | // the non-zero digits will be the only digits contributing to the instruction |
905 | // count, this is desirable. The next loop converts it to NAF (following the |
906 | // approach in 'Guide to Elliptic Curve Cryptography' [ISBN: 038795273X]) by |
907 | // choosing the non-zero coefficients such that the resulting quotient is |
908 | // divisible by 2 which will cause the next coefficient to be zero. |
909 | int64_t E = std::abs(i: MulAmt); |
910 | int S = (MulAmt < 0 ? -1 : 1); |
911 | int I = 0; |
912 | while (E > 0) { |
913 | int ZI = 0; |
914 | if (E % 2 == 1) { |
915 | ZI = 2 - (E % 4); |
916 | if (ZI != 0) |
917 | ++NonzeroEntries; |
918 | } |
919 | SignedDigit[I] = S * ZI; |
920 | if (SignedDigit[I] == 1) |
921 | HighestOne = I; |
922 | E = (E - ZI) / 2; |
923 | ++I; |
924 | } |
925 | |
926 | // Compute number of instructions required. Due to differences in lowering |
927 | // between the different processors this count is not exact. |
928 | // Start by assuming a shift and a add/sub for every non-zero entry (hence |
929 | // every non-zero entry requires 1 shift and 1 add/sub except for the first |
930 | // entry). |
931 | int32_t InstrRequired = 2 * NonzeroEntries - 1; |
932 | // Correct possible over-adding due to shift by 0 (which is not emitted). |
933 | if (std::abs(i: MulAmt) % 2 == 1) |
934 | --InstrRequired; |
935 | // Return if the form generated would exceed the instruction threshold. |
936 | if (InstrRequired > LanaiLowerConstantMulThreshold) |
937 | return SDValue(); |
938 | |
939 | SDValue Res; |
940 | SDLoc DL(Op); |
941 | SDValue V = Op->getOperand(Num: 0); |
942 | |
943 | // Initialize the running sum. Set the running sum to the maximal shifted |
944 | // positive value (i.e., largest i such that zi == 1 and MulAmt has V<<i as a |
945 | // term NAF). |
946 | if (HighestOne == -1) |
947 | Res = DAG.getConstant(0, DL, MVT::i32); |
948 | else { |
949 | Res = DAG.getNode(ISD::SHL, DL, VT, V, |
950 | DAG.getConstant(HighestOne, DL, MVT::i32)); |
951 | SignedDigit[HighestOne] = 0; |
952 | } |
953 | |
954 | // Assemble multiplication from shift, add, sub using NAF form and running |
955 | // sum. |
956 | for (unsigned int I = 0; I < std::size(SignedDigit); ++I) { |
957 | if (SignedDigit[I] == 0) |
958 | continue; |
959 | |
960 | // Shifted multiplicand (v<<i). |
961 | SDValue Op = |
962 | DAG.getNode(ISD::SHL, DL, VT, V, DAG.getConstant(I, DL, MVT::i32)); |
963 | if (SignedDigit[I] == 1) |
964 | Res = DAG.getNode(Opcode: ISD::ADD, DL, VT, N1: Res, N2: Op); |
965 | else if (SignedDigit[I] == -1) |
966 | Res = DAG.getNode(Opcode: ISD::SUB, DL, VT, N1: Res, N2: Op); |
967 | } |
968 | return Res; |
969 | } |
970 | |
971 | SDValue LanaiTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { |
972 | SDValue LHS = Op.getOperand(i: 0); |
973 | SDValue RHS = Op.getOperand(i: 1); |
974 | SDValue Cond = Op.getOperand(i: 2); |
975 | SDLoc DL(Op); |
976 | |
977 | LPCC::CondCode CC = IntCondCCodeToICC(CC: Cond, DL, RHS, DAG); |
978 | SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); |
979 | SDValue Glue = |
980 | DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); |
981 | |
982 | return DAG.getNode(Opcode: LanaiISD::SETCC, DL, VT: Op.getValueType(), N1: TargetCC, N2: Glue); |
983 | } |
984 | |
985 | SDValue LanaiTargetLowering::LowerSELECT_CC(SDValue Op, |
986 | SelectionDAG &DAG) const { |
987 | SDValue LHS = Op.getOperand(i: 0); |
988 | SDValue RHS = Op.getOperand(i: 1); |
989 | SDValue TrueV = Op.getOperand(i: 2); |
990 | SDValue FalseV = Op.getOperand(i: 3); |
991 | SDValue Cond = Op.getOperand(i: 4); |
992 | SDLoc DL(Op); |
993 | |
994 | LPCC::CondCode CC = IntCondCCodeToICC(CC: Cond, DL, RHS, DAG); |
995 | SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); |
996 | SDValue Glue = |
997 | DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); |
998 | |
999 | SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); |
1000 | return DAG.getNode(Opcode: LanaiISD::SELECT_CC, DL, VTList: VTs, N1: TrueV, N2: FalseV, N3: TargetCC, |
1001 | N4: Glue); |
1002 | } |
1003 | |
1004 | SDValue LanaiTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { |
1005 | MachineFunction &MF = DAG.getMachineFunction(); |
1006 | LanaiMachineFunctionInfo *FuncInfo = MF.getInfo<LanaiMachineFunctionInfo>(); |
1007 | |
1008 | SDLoc DL(Op); |
1009 | SDValue FI = DAG.getFrameIndex(FI: FuncInfo->getVarArgsFrameIndex(), |
1010 | VT: getPointerTy(DL: DAG.getDataLayout())); |
1011 | |
1012 | // vastart just stores the address of the VarArgsFrameIndex slot into the |
1013 | // memory location argument. |
1014 | const Value *SV = cast<SrcValueSDNode>(Val: Op.getOperand(i: 2))->getValue(); |
1015 | return DAG.getStore(Chain: Op.getOperand(i: 0), dl: DL, Val: FI, Ptr: Op.getOperand(i: 1), |
1016 | PtrInfo: MachinePointerInfo(SV)); |
1017 | } |
1018 | |
1019 | SDValue LanaiTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, |
1020 | SelectionDAG &DAG) const { |
1021 | SDValue Chain = Op.getOperand(i: 0); |
1022 | SDValue Size = Op.getOperand(i: 1); |
1023 | SDLoc DL(Op); |
1024 | |
1025 | Register SPReg = getStackPointerRegisterToSaveRestore(); |
1026 | |
1027 | // Get a reference to the stack pointer. |
1028 | SDValue StackPointer = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32); |
1029 | |
1030 | // Subtract the dynamic size from the actual stack size to |
1031 | // obtain the new stack size. |
1032 | SDValue Sub = DAG.getNode(ISD::SUB, DL, MVT::i32, StackPointer, Size); |
1033 | |
1034 | // For Lanai, the outgoing memory arguments area should be on top of the |
1035 | // alloca area on the stack i.e., the outgoing memory arguments should be |
1036 | // at a lower address than the alloca area. Move the alloca area down the |
1037 | // stack by adding back the space reserved for outgoing arguments to SP |
1038 | // here. |
1039 | // |
1040 | // We do not know what the size of the outgoing args is at this point. |
1041 | // So, we add a pseudo instruction ADJDYNALLOC that will adjust the |
1042 | // stack pointer. We replace this instruction with on that has the correct, |
1043 | // known offset in emitPrologue(). |
1044 | SDValue ArgAdjust = DAG.getNode(LanaiISD::ADJDYNALLOC, DL, MVT::i32, Sub); |
1045 | |
1046 | // The Sub result contains the new stack start address, so it |
1047 | // must be placed in the stack pointer register. |
1048 | SDValue CopyChain = DAG.getCopyToReg(Chain, dl: DL, Reg: SPReg, N: Sub); |
1049 | |
1050 | SDValue Ops[2] = {ArgAdjust, CopyChain}; |
1051 | return DAG.getMergeValues(Ops, dl: DL); |
1052 | } |
1053 | |
1054 | SDValue LanaiTargetLowering::LowerRETURNADDR(SDValue Op, |
1055 | SelectionDAG &DAG) const { |
1056 | MachineFunction &MF = DAG.getMachineFunction(); |
1057 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
1058 | MFI.setReturnAddressIsTaken(true); |
1059 | |
1060 | EVT VT = Op.getValueType(); |
1061 | SDLoc DL(Op); |
1062 | unsigned Depth = Op.getConstantOperandVal(i: 0); |
1063 | if (Depth) { |
1064 | SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); |
1065 | const unsigned Offset = -4; |
1066 | SDValue Ptr = DAG.getNode(Opcode: ISD::ADD, DL, VT, N1: FrameAddr, |
1067 | N2: DAG.getIntPtrConstant(Val: Offset, DL)); |
1068 | return DAG.getLoad(VT, dl: DL, Chain: DAG.getEntryNode(), Ptr, PtrInfo: MachinePointerInfo()); |
1069 | } |
1070 | |
1071 | // Return the link register, which contains the return address. |
1072 | // Mark it an implicit live-in. |
1073 | Register Reg = MF.addLiveIn(TRI->getRARegister(), getRegClassFor(MVT::i32)); |
1074 | return DAG.getCopyFromReg(Chain: DAG.getEntryNode(), dl: DL, Reg, VT); |
1075 | } |
1076 | |
1077 | SDValue LanaiTargetLowering::LowerFRAMEADDR(SDValue Op, |
1078 | SelectionDAG &DAG) const { |
1079 | MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); |
1080 | MFI.setFrameAddressIsTaken(true); |
1081 | |
1082 | EVT VT = Op.getValueType(); |
1083 | SDLoc DL(Op); |
1084 | SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, Lanai::FP, VT); |
1085 | unsigned Depth = Op.getConstantOperandVal(i: 0); |
1086 | while (Depth--) { |
1087 | const unsigned Offset = -8; |
1088 | SDValue Ptr = DAG.getNode(Opcode: ISD::ADD, DL, VT, N1: FrameAddr, |
1089 | N2: DAG.getIntPtrConstant(Val: Offset, DL)); |
1090 | FrameAddr = |
1091 | DAG.getLoad(VT, dl: DL, Chain: DAG.getEntryNode(), Ptr, PtrInfo: MachinePointerInfo()); |
1092 | } |
1093 | return FrameAddr; |
1094 | } |
1095 | |
1096 | const char *LanaiTargetLowering::getTargetNodeName(unsigned Opcode) const { |
1097 | switch (Opcode) { |
1098 | case LanaiISD::ADJDYNALLOC: |
1099 | return "LanaiISD::ADJDYNALLOC" ; |
1100 | case LanaiISD::RET_GLUE: |
1101 | return "LanaiISD::RET_GLUE" ; |
1102 | case LanaiISD::CALL: |
1103 | return "LanaiISD::CALL" ; |
1104 | case LanaiISD::SELECT_CC: |
1105 | return "LanaiISD::SELECT_CC" ; |
1106 | case LanaiISD::SETCC: |
1107 | return "LanaiISD::SETCC" ; |
1108 | case LanaiISD::SUBBF: |
1109 | return "LanaiISD::SUBBF" ; |
1110 | case LanaiISD::SET_FLAG: |
1111 | return "LanaiISD::SET_FLAG" ; |
1112 | case LanaiISD::BR_CC: |
1113 | return "LanaiISD::BR_CC" ; |
1114 | case LanaiISD::Wrapper: |
1115 | return "LanaiISD::Wrapper" ; |
1116 | case LanaiISD::HI: |
1117 | return "LanaiISD::HI" ; |
1118 | case LanaiISD::LO: |
1119 | return "LanaiISD::LO" ; |
1120 | case LanaiISD::SMALL: |
1121 | return "LanaiISD::SMALL" ; |
1122 | default: |
1123 | return nullptr; |
1124 | } |
1125 | } |
1126 | |
1127 | SDValue LanaiTargetLowering::LowerConstantPool(SDValue Op, |
1128 | SelectionDAG &DAG) const { |
1129 | SDLoc DL(Op); |
1130 | ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Val&: Op); |
1131 | const Constant *C = N->getConstVal(); |
1132 | const LanaiTargetObjectFile *TLOF = |
1133 | static_cast<const LanaiTargetObjectFile *>( |
1134 | getTargetMachine().getObjFileLowering()); |
1135 | |
1136 | // If the code model is small or constant will be placed in the small section, |
1137 | // then assume address will fit in 21-bits. |
1138 | if (getTargetMachine().getCodeModel() == CodeModel::Small || |
1139 | TLOF->isConstantInSmallSection(DL: DAG.getDataLayout(), CN: C)) { |
1140 | SDValue Small = DAG.getTargetConstantPool( |
1141 | C, MVT::i32, N->getAlign(), N->getOffset(), LanaiII::MO_NO_FLAG); |
1142 | return DAG.getNode(ISD::OR, DL, MVT::i32, |
1143 | DAG.getRegister(Lanai::R0, MVT::i32), |
1144 | DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); |
1145 | } else { |
1146 | uint8_t OpFlagHi = LanaiII::MO_ABS_HI; |
1147 | uint8_t OpFlagLo = LanaiII::MO_ABS_LO; |
1148 | |
1149 | SDValue Hi = DAG.getTargetConstantPool(C, MVT::i32, N->getAlign(), |
1150 | N->getOffset(), OpFlagHi); |
1151 | SDValue Lo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlign(), |
1152 | N->getOffset(), OpFlagLo); |
1153 | Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); |
1154 | Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); |
1155 | SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); |
1156 | return Result; |
1157 | } |
1158 | } |
1159 | |
1160 | SDValue LanaiTargetLowering::LowerGlobalAddress(SDValue Op, |
1161 | SelectionDAG &DAG) const { |
1162 | SDLoc DL(Op); |
1163 | const GlobalValue *GV = cast<GlobalAddressSDNode>(Val&: Op)->getGlobal(); |
1164 | int64_t Offset = cast<GlobalAddressSDNode>(Val&: Op)->getOffset(); |
1165 | |
1166 | const LanaiTargetObjectFile *TLOF = |
1167 | static_cast<const LanaiTargetObjectFile *>( |
1168 | getTargetMachine().getObjFileLowering()); |
1169 | |
1170 | // If the code model is small or global variable will be placed in the small |
1171 | // section, then assume address will fit in 21-bits. |
1172 | const GlobalObject *GO = GV->getAliaseeObject(); |
1173 | if (TLOF->isGlobalInSmallSection(GO, TM: getTargetMachine())) { |
1174 | SDValue Small = DAG.getTargetGlobalAddress( |
1175 | GV, DL, VT: getPointerTy(DL: DAG.getDataLayout()), offset: Offset, TargetFlags: LanaiII::MO_NO_FLAG); |
1176 | return DAG.getNode(ISD::OR, DL, MVT::i32, |
1177 | DAG.getRegister(Lanai::R0, MVT::i32), |
1178 | DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); |
1179 | } else { |
1180 | uint8_t OpFlagHi = LanaiII::MO_ABS_HI; |
1181 | uint8_t OpFlagLo = LanaiII::MO_ABS_LO; |
1182 | |
1183 | // Create the TargetGlobalAddress node, folding in the constant offset. |
1184 | SDValue Hi = DAG.getTargetGlobalAddress( |
1185 | GV, DL, VT: getPointerTy(DL: DAG.getDataLayout()), offset: Offset, TargetFlags: OpFlagHi); |
1186 | SDValue Lo = DAG.getTargetGlobalAddress( |
1187 | GV, DL, VT: getPointerTy(DL: DAG.getDataLayout()), offset: Offset, TargetFlags: OpFlagLo); |
1188 | Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); |
1189 | Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); |
1190 | return DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); |
1191 | } |
1192 | } |
1193 | |
1194 | SDValue LanaiTargetLowering::LowerBlockAddress(SDValue Op, |
1195 | SelectionDAG &DAG) const { |
1196 | SDLoc DL(Op); |
1197 | const BlockAddress *BA = cast<BlockAddressSDNode>(Val&: Op)->getBlockAddress(); |
1198 | |
1199 | uint8_t OpFlagHi = LanaiII::MO_ABS_HI; |
1200 | uint8_t OpFlagLo = LanaiII::MO_ABS_LO; |
1201 | |
1202 | SDValue Hi = DAG.getBlockAddress(BA, MVT::i32, true, OpFlagHi); |
1203 | SDValue Lo = DAG.getBlockAddress(BA, MVT::i32, true, OpFlagLo); |
1204 | Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); |
1205 | Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); |
1206 | SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); |
1207 | return Result; |
1208 | } |
1209 | |
1210 | SDValue LanaiTargetLowering::LowerJumpTable(SDValue Op, |
1211 | SelectionDAG &DAG) const { |
1212 | SDLoc DL(Op); |
1213 | JumpTableSDNode *JT = cast<JumpTableSDNode>(Val&: Op); |
1214 | |
1215 | // If the code model is small assume address will fit in 21-bits. |
1216 | if (getTargetMachine().getCodeModel() == CodeModel::Small) { |
1217 | SDValue Small = DAG.getTargetJumpTable( |
1218 | JTI: JT->getIndex(), VT: getPointerTy(DL: DAG.getDataLayout()), TargetFlags: LanaiII::MO_NO_FLAG); |
1219 | return DAG.getNode(ISD::OR, DL, MVT::i32, |
1220 | DAG.getRegister(Lanai::R0, MVT::i32), |
1221 | DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); |
1222 | } else { |
1223 | uint8_t OpFlagHi = LanaiII::MO_ABS_HI; |
1224 | uint8_t OpFlagLo = LanaiII::MO_ABS_LO; |
1225 | |
1226 | SDValue Hi = DAG.getTargetJumpTable( |
1227 | JTI: JT->getIndex(), VT: getPointerTy(DL: DAG.getDataLayout()), TargetFlags: OpFlagHi); |
1228 | SDValue Lo = DAG.getTargetJumpTable( |
1229 | JTI: JT->getIndex(), VT: getPointerTy(DL: DAG.getDataLayout()), TargetFlags: OpFlagLo); |
1230 | Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); |
1231 | Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); |
1232 | SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); |
1233 | return Result; |
1234 | } |
1235 | } |
1236 | |
1237 | SDValue LanaiTargetLowering::LowerSHL_PARTS(SDValue Op, |
1238 | SelectionDAG &DAG) const { |
1239 | EVT VT = Op.getValueType(); |
1240 | unsigned VTBits = VT.getSizeInBits(); |
1241 | SDLoc dl(Op); |
1242 | assert(Op.getNumOperands() == 3 && "Unexpected SHL!" ); |
1243 | SDValue ShOpLo = Op.getOperand(i: 0); |
1244 | SDValue ShOpHi = Op.getOperand(i: 1); |
1245 | SDValue ShAmt = Op.getOperand(i: 2); |
1246 | |
1247 | // Performs the following for (ShOpLo + (ShOpHi << 32)) << ShAmt: |
1248 | // LoBitsForHi = (ShAmt == 0) ? 0 : (ShOpLo >> (32-ShAmt)) |
1249 | // HiBitsForHi = ShOpHi << ShAmt |
1250 | // Hi = (ShAmt >= 32) ? (ShOpLo << (ShAmt-32)) : (LoBitsForHi | HiBitsForHi) |
1251 | // Lo = (ShAmt >= 32) ? 0 : (ShOpLo << ShAmt) |
1252 | // return (Hi << 32) | Lo; |
1253 | |
1254 | SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, |
1255 | DAG.getConstant(VTBits, dl, MVT::i32), ShAmt); |
1256 | SDValue LoBitsForHi = DAG.getNode(Opcode: ISD::SRL, DL: dl, VT, N1: ShOpLo, N2: RevShAmt); |
1257 | |
1258 | // If ShAmt == 0, we just calculated "(SRL ShOpLo, 32)" which is "undef". We |
1259 | // wanted 0, so CSEL it directly. |
1260 | SDValue Zero = DAG.getConstant(0, dl, MVT::i32); |
1261 | SDValue SetCC = DAG.getSetCC(dl, MVT::i32, ShAmt, Zero, ISD::SETEQ); |
1262 | LoBitsForHi = DAG.getSelect(dl, MVT::i32, SetCC, Zero, LoBitsForHi); |
1263 | |
1264 | SDValue = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt, |
1265 | DAG.getConstant(VTBits, dl, MVT::i32)); |
1266 | SDValue HiBitsForHi = DAG.getNode(Opcode: ISD::SHL, DL: dl, VT, N1: ShOpHi, N2: ShAmt); |
1267 | SDValue HiForNormalShift = |
1268 | DAG.getNode(Opcode: ISD::OR, DL: dl, VT, N1: LoBitsForHi, N2: HiBitsForHi); |
1269 | |
1270 | SDValue HiForBigShift = DAG.getNode(Opcode: ISD::SHL, DL: dl, VT, N1: ShOpLo, N2: ExtraShAmt); |
1271 | |
1272 | SetCC = DAG.getSetCC(dl, MVT::i32, ExtraShAmt, Zero, ISD::SETGE); |
1273 | SDValue Hi = |
1274 | DAG.getSelect(dl, MVT::i32, SetCC, HiForBigShift, HiForNormalShift); |
1275 | |
1276 | // Lanai shifts of larger than register sizes are wrapped rather than |
1277 | // clamped, so we can't just emit "lo << b" if b is too big. |
1278 | SDValue LoForNormalShift = DAG.getNode(Opcode: ISD::SHL, DL: dl, VT, N1: ShOpLo, N2: ShAmt); |
1279 | SDValue Lo = DAG.getSelect( |
1280 | dl, MVT::i32, SetCC, DAG.getConstant(0, dl, MVT::i32), LoForNormalShift); |
1281 | |
1282 | SDValue Ops[2] = {Lo, Hi}; |
1283 | return DAG.getMergeValues(Ops, dl); |
1284 | } |
1285 | |
1286 | SDValue LanaiTargetLowering::LowerSRL_PARTS(SDValue Op, |
1287 | SelectionDAG &DAG) const { |
1288 | MVT VT = Op.getSimpleValueType(); |
1289 | unsigned VTBits = VT.getSizeInBits(); |
1290 | SDLoc dl(Op); |
1291 | SDValue ShOpLo = Op.getOperand(i: 0); |
1292 | SDValue ShOpHi = Op.getOperand(i: 1); |
1293 | SDValue ShAmt = Op.getOperand(i: 2); |
1294 | |
1295 | // Performs the following for a >> b: |
1296 | // unsigned r_high = a_high >> b; |
1297 | // r_high = (32 - b <= 0) ? 0 : r_high; |
1298 | // |
1299 | // unsigned r_low = a_low >> b; |
1300 | // r_low = (32 - b <= 0) ? r_high : r_low; |
1301 | // r_low = (b == 0) ? r_low : r_low | (a_high << (32 - b)); |
1302 | // return (unsigned long long)r_high << 32 | r_low; |
1303 | // Note: This takes advantage of Lanai's shift behavior to avoid needing to |
1304 | // mask the shift amount. |
1305 | |
1306 | SDValue Zero = DAG.getConstant(0, dl, MVT::i32); |
1307 | SDValue NegatedPlus32 = DAG.getNode( |
1308 | ISD::SUB, dl, MVT::i32, DAG.getConstant(VTBits, dl, MVT::i32), ShAmt); |
1309 | SDValue SetCC = DAG.getSetCC(dl, MVT::i32, NegatedPlus32, Zero, ISD::SETLE); |
1310 | |
1311 | SDValue Hi = DAG.getNode(ISD::SRL, dl, MVT::i32, ShOpHi, ShAmt); |
1312 | Hi = DAG.getSelect(dl, MVT::i32, SetCC, Zero, Hi); |
1313 | |
1314 | SDValue Lo = DAG.getNode(ISD::SRL, dl, MVT::i32, ShOpLo, ShAmt); |
1315 | Lo = DAG.getSelect(dl, MVT::i32, SetCC, Hi, Lo); |
1316 | SDValue CarryBits = |
1317 | DAG.getNode(ISD::SHL, dl, MVT::i32, ShOpHi, NegatedPlus32); |
1318 | SDValue ShiftIsZero = DAG.getSetCC(dl, MVT::i32, ShAmt, Zero, ISD::SETEQ); |
1319 | Lo = DAG.getSelect(dl, MVT::i32, ShiftIsZero, Lo, |
1320 | DAG.getNode(ISD::OR, dl, MVT::i32, Lo, CarryBits)); |
1321 | |
1322 | SDValue Ops[2] = {Lo, Hi}; |
1323 | return DAG.getMergeValues(Ops, dl); |
1324 | } |
1325 | |
1326 | // Helper function that checks if N is a null or all ones constant. |
1327 | static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) { |
1328 | return AllOnes ? isAllOnesConstant(V: N) : isNullConstant(V: N); |
1329 | } |
1330 | |
1331 | // Return true if N is conditionally 0 or all ones. |
1332 | // Detects these expressions where cc is an i1 value: |
1333 | // |
1334 | // (select cc 0, y) [AllOnes=0] |
1335 | // (select cc y, 0) [AllOnes=0] |
1336 | // (zext cc) [AllOnes=0] |
1337 | // (sext cc) [AllOnes=0/1] |
1338 | // (select cc -1, y) [AllOnes=1] |
1339 | // (select cc y, -1) [AllOnes=1] |
1340 | // |
1341 | // * AllOnes determines whether to check for an all zero (AllOnes false) or an |
1342 | // all ones operand (AllOnes true). |
1343 | // * Invert is set when N is the all zero/ones constant when CC is false. |
1344 | // * OtherOp is set to the alternative value of N. |
1345 | // |
1346 | // For example, for (select cc X, Y) and AllOnes = 0 if: |
1347 | // * X = 0, Invert = False and OtherOp = Y |
1348 | // * Y = 0, Invert = True and OtherOp = X |
1349 | static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes, SDValue &CC, |
1350 | bool &Invert, SDValue &OtherOp, |
1351 | SelectionDAG &DAG) { |
1352 | switch (N->getOpcode()) { |
1353 | default: |
1354 | return false; |
1355 | case ISD::SELECT: { |
1356 | CC = N->getOperand(Num: 0); |
1357 | SDValue N1 = N->getOperand(Num: 1); |
1358 | SDValue N2 = N->getOperand(Num: 2); |
1359 | if (isZeroOrAllOnes(N: N1, AllOnes)) { |
1360 | Invert = false; |
1361 | OtherOp = N2; |
1362 | return true; |
1363 | } |
1364 | if (isZeroOrAllOnes(N: N2, AllOnes)) { |
1365 | Invert = true; |
1366 | OtherOp = N1; |
1367 | return true; |
1368 | } |
1369 | return false; |
1370 | } |
1371 | case ISD::ZERO_EXTEND: { |
1372 | // (zext cc) can never be the all ones value. |
1373 | if (AllOnes) |
1374 | return false; |
1375 | CC = N->getOperand(Num: 0); |
1376 | if (CC.getValueType() != MVT::i1) |
1377 | return false; |
1378 | SDLoc dl(N); |
1379 | EVT VT = N->getValueType(ResNo: 0); |
1380 | OtherOp = DAG.getConstant(Val: 1, DL: dl, VT); |
1381 | Invert = true; |
1382 | return true; |
1383 | } |
1384 | case ISD::SIGN_EXTEND: { |
1385 | CC = N->getOperand(Num: 0); |
1386 | if (CC.getValueType() != MVT::i1) |
1387 | return false; |
1388 | SDLoc dl(N); |
1389 | EVT VT = N->getValueType(ResNo: 0); |
1390 | Invert = !AllOnes; |
1391 | if (AllOnes) |
1392 | // When looking for an AllOnes constant, N is an sext, and the 'other' |
1393 | // value is 0. |
1394 | OtherOp = DAG.getConstant(Val: 0, DL: dl, VT); |
1395 | else |
1396 | OtherOp = DAG.getAllOnesConstant(DL: dl, VT); |
1397 | return true; |
1398 | } |
1399 | } |
1400 | } |
1401 | |
1402 | // Combine a constant select operand into its use: |
1403 | // |
1404 | // (add (select cc, 0, c), x) -> (select cc, x, (add, x, c)) |
1405 | // (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) |
1406 | // (and (select cc, -1, c), x) -> (select cc, x, (and, x, c)) [AllOnes=1] |
1407 | // (or (select cc, 0, c), x) -> (select cc, x, (or, x, c)) |
1408 | // (xor (select cc, 0, c), x) -> (select cc, x, (xor, x, c)) |
1409 | // |
1410 | // The transform is rejected if the select doesn't have a constant operand that |
1411 | // is null, or all ones when AllOnes is set. |
1412 | // |
1413 | // Also recognize sext/zext from i1: |
1414 | // |
1415 | // (add (zext cc), x) -> (select cc (add x, 1), x) |
1416 | // (add (sext cc), x) -> (select cc (add x, -1), x) |
1417 | // |
1418 | // These transformations eventually create predicated instructions. |
1419 | static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, |
1420 | TargetLowering::DAGCombinerInfo &DCI, |
1421 | bool AllOnes) { |
1422 | SelectionDAG &DAG = DCI.DAG; |
1423 | EVT VT = N->getValueType(ResNo: 0); |
1424 | SDValue NonConstantVal; |
1425 | SDValue CCOp; |
1426 | bool SwapSelectOps; |
1427 | if (!isConditionalZeroOrAllOnes(N: Slct.getNode(), AllOnes, CC&: CCOp, Invert&: SwapSelectOps, |
1428 | OtherOp&: NonConstantVal, DAG)) |
1429 | return SDValue(); |
1430 | |
1431 | // Slct is now know to be the desired identity constant when CC is true. |
1432 | SDValue TrueVal = OtherOp; |
1433 | SDValue FalseVal = |
1434 | DAG.getNode(Opcode: N->getOpcode(), DL: SDLoc(N), VT, N1: OtherOp, N2: NonConstantVal); |
1435 | // Unless SwapSelectOps says CC should be false. |
1436 | if (SwapSelectOps) |
1437 | std::swap(a&: TrueVal, b&: FalseVal); |
1438 | |
1439 | return DAG.getNode(Opcode: ISD::SELECT, DL: SDLoc(N), VT, N1: CCOp, N2: TrueVal, N3: FalseVal); |
1440 | } |
1441 | |
1442 | // Attempt combineSelectAndUse on each operand of a commutative operator N. |
1443 | static SDValue |
1444 | combineSelectAndUseCommutative(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, |
1445 | bool AllOnes) { |
1446 | SDValue N0 = N->getOperand(Num: 0); |
1447 | SDValue N1 = N->getOperand(Num: 1); |
1448 | if (N0.getNode()->hasOneUse()) |
1449 | if (SDValue Result = combineSelectAndUse(N, Slct: N0, OtherOp: N1, DCI, AllOnes)) |
1450 | return Result; |
1451 | if (N1.getNode()->hasOneUse()) |
1452 | if (SDValue Result = combineSelectAndUse(N, Slct: N1, OtherOp: N0, DCI, AllOnes)) |
1453 | return Result; |
1454 | return SDValue(); |
1455 | } |
1456 | |
1457 | // PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB. |
1458 | static SDValue PerformSUBCombine(SDNode *N, |
1459 | TargetLowering::DAGCombinerInfo &DCI) { |
1460 | SDValue N0 = N->getOperand(Num: 0); |
1461 | SDValue N1 = N->getOperand(Num: 1); |
1462 | |
1463 | // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) |
1464 | if (N1.getNode()->hasOneUse()) |
1465 | if (SDValue Result = combineSelectAndUse(N, Slct: N1, OtherOp: N0, DCI, /*AllOnes=*/false)) |
1466 | return Result; |
1467 | |
1468 | return SDValue(); |
1469 | } |
1470 | |
1471 | SDValue LanaiTargetLowering::PerformDAGCombine(SDNode *N, |
1472 | DAGCombinerInfo &DCI) const { |
1473 | switch (N->getOpcode()) { |
1474 | default: |
1475 | break; |
1476 | case ISD::ADD: |
1477 | case ISD::OR: |
1478 | case ISD::XOR: |
1479 | return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/false); |
1480 | case ISD::AND: |
1481 | return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/true); |
1482 | case ISD::SUB: |
1483 | return PerformSUBCombine(N, DCI); |
1484 | } |
1485 | |
1486 | return SDValue(); |
1487 | } |
1488 | |
1489 | void LanaiTargetLowering::computeKnownBitsForTargetNode( |
1490 | const SDValue Op, KnownBits &Known, const APInt &DemandedElts, |
1491 | const SelectionDAG &DAG, unsigned Depth) const { |
1492 | unsigned BitWidth = Known.getBitWidth(); |
1493 | switch (Op.getOpcode()) { |
1494 | default: |
1495 | break; |
1496 | case LanaiISD::SETCC: |
1497 | Known = KnownBits(BitWidth); |
1498 | Known.Zero.setBits(loBit: 1, hiBit: BitWidth); |
1499 | break; |
1500 | case LanaiISD::SELECT_CC: |
1501 | KnownBits Known2; |
1502 | Known = DAG.computeKnownBits(Op: Op->getOperand(Num: 0), Depth: Depth + 1); |
1503 | Known2 = DAG.computeKnownBits(Op: Op->getOperand(Num: 1), Depth: Depth + 1); |
1504 | Known = Known.intersectWith(RHS: Known2); |
1505 | break; |
1506 | } |
1507 | } |
1508 | |