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