Bug Summary

File:build/source/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
Warning:line 1044, column 10
Although the value stored to 'CN' is used in the enclosing expression, the value is never actually read from 'CN'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name LoongArchISelLowering.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I lib/Target/LoongArch -I /build/source/llvm/lib/Target/LoongArch -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
1//=- LoongArchISelLowering.cpp - LoongArch 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 defines the interfaces that LoongArch uses to lower LLVM code into
10// a selection DAG.
11//
12//===----------------------------------------------------------------------===//
13
14#include "LoongArchISelLowering.h"
15#include "LoongArch.h"
16#include "LoongArchMachineFunctionInfo.h"
17#include "LoongArchRegisterInfo.h"
18#include "LoongArchSubtarget.h"
19#include "LoongArchTargetMachine.h"
20#include "MCTargetDesc/LoongArchBaseInfo.h"
21#include "MCTargetDesc/LoongArchMCTargetDesc.h"
22#include "llvm/ADT/Statistic.h"
23#include "llvm/CodeGen/ISDOpcodes.h"
24#include "llvm/CodeGen/RuntimeLibcalls.h"
25#include "llvm/IR/IRBuilder.h"
26#include "llvm/IR/IntrinsicsLoongArch.h"
27#include "llvm/Support/Debug.h"
28#include "llvm/Support/KnownBits.h"
29#include "llvm/Support/MathExtras.h"
30
31using namespace llvm;
32
33#define DEBUG_TYPE"loongarch-isel-lowering" "loongarch-isel-lowering"
34
35STATISTIC(NumTailCalls, "Number of tail calls")static llvm::Statistic NumTailCalls = {"loongarch-isel-lowering"
, "NumTailCalls", "Number of tail calls"}
;
36
37static cl::opt<bool> ZeroDivCheck(
38 "loongarch-check-zero-division", cl::Hidden,
39 cl::desc("Trap on integer division by zero."),
40 cl::init(false));
41
42LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
43 const LoongArchSubtarget &STI)
44 : TargetLowering(TM), Subtarget(STI) {
45
46 MVT GRLenVT = Subtarget.getGRLenVT();
47 // Set up the register classes.
48 addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
49 if (Subtarget.hasBasicF())
50 addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
51 if (Subtarget.hasBasicD())
52 addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
53
54 setLoadExtAction({ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}, GRLenVT,
55 MVT::i1, Promote);
56
57 // TODO: add necessary setOperationAction calls later.
58 setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom);
59 setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom);
60 setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom);
61 setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom);
62 setOperationAction(ISD::ROTL, GRLenVT, Expand);
63 setOperationAction(ISD::CTPOP, GRLenVT, Expand);
64 setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
65 setOperationAction(ISD::TRAP, MVT::Other, Legal);
66 setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
67 setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
68
69 setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool,
70 ISD::JumpTable},
71 GRLenVT, Custom);
72
73 setOperationAction(ISD::GlobalTLSAddress, GRLenVT, Custom);
74
75 setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
76
77 setOperationAction(ISD::EH_DWARF_CFA, MVT::i32, Custom);
78 if (Subtarget.is64Bit())
79 setOperationAction(ISD::EH_DWARF_CFA, MVT::i64, Custom);
80
81 setOperationAction(ISD::DYNAMIC_STACKALLOC, GRLenVT, Expand);
82 setOperationAction({ISD::STACKSAVE, ISD::STACKRESTORE}, MVT::Other, Expand);
83 setOperationAction(ISD::VASTART, MVT::Other, Custom);
84 setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand);
85
86 if (Subtarget.is64Bit()) {
87 setOperationAction(ISD::SHL, MVT::i32, Custom);
88 setOperationAction(ISD::SRA, MVT::i32, Custom);
89 setOperationAction(ISD::SRL, MVT::i32, Custom);
90 setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
91 setOperationAction(ISD::BITCAST, MVT::i32, Custom);
92 setOperationAction(ISD::ROTR, MVT::i32, Custom);
93 setOperationAction(ISD::ROTL, MVT::i32, Custom);
94 setOperationAction(ISD::CTTZ, MVT::i32, Custom);
95 setOperationAction(ISD::CTLZ, MVT::i32, Custom);
96 setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom);
97 setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom);
98 setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
99 setOperationAction(ISD::READ_REGISTER, MVT::i32, Custom);
100 setOperationAction(ISD::WRITE_REGISTER, MVT::i32, Custom);
101 if (Subtarget.hasBasicF() && !Subtarget.hasBasicD())
102 setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
103 if (Subtarget.hasBasicF())
104 setOperationAction(ISD::FRINT, MVT::f32, Legal);
105 if (Subtarget.hasBasicD())
106 setOperationAction(ISD::FRINT, MVT::f64, Legal);
107 }
108
109 // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
110 // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
111 // and i32 could still be byte-swapped relatively cheaply.
112 setOperationAction(ISD::BSWAP, MVT::i16, Custom);
113 if (Subtarget.is64Bit()) {
114 setOperationAction(ISD::BSWAP, MVT::i32, Custom);
115 }
116
117 // Expand bitreverse.i16 with native-width bitrev and shift for now, before
118 // we get to know which of sll and revb.2h is faster.
119 setOperationAction(ISD::BITREVERSE, MVT::i8, Custom);
120 if (Subtarget.is64Bit()) {
121 setOperationAction(ISD::BITREVERSE, MVT::i32, Custom);
122 setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
123 } else {
124 setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
125 setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom);
126 setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom);
127 setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom);
128 setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
129 setOperationAction(ISD::INTRINSIC_VOID, MVT::i64, Custom);
130 }
131
132 static const ISD::CondCode FPCCToExpand[] = {
133 ISD::SETOGT, ISD::SETOGE, ISD::SETUGT, ISD::SETUGE,
134 ISD::SETGE, ISD::SETNE, ISD::SETGT};
135
136 if (Subtarget.hasBasicF()) {
137 setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
138 setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
139 setOperationAction(ISD::BR_CC, MVT::f32, Expand);
140 setOperationAction(ISD::FMA, MVT::f32, Legal);
141 setOperationAction(ISD::FMINNUM_IEEE, MVT::f32, Legal);
142 setOperationAction(ISD::FMAXNUM_IEEE, MVT::f32, Legal);
143 setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Legal);
144 setOperationAction(ISD::STRICT_FSETCC, MVT::f32, Legal);
145 setOperationAction(ISD::FSIN, MVT::f32, Expand);
146 setOperationAction(ISD::FCOS, MVT::f32, Expand);
147 setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
148 setOperationAction(ISD::FPOW, MVT::f32, Expand);
149 setOperationAction(ISD::FREM, MVT::f32, Expand);
150 }
151 if (Subtarget.hasBasicD()) {
152 setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
153 setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
154 setOperationAction(ISD::BR_CC, MVT::f64, Expand);
155 setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Legal);
156 setOperationAction(ISD::STRICT_FSETCC, MVT::f64, Legal);
157 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
158 setOperationAction(ISD::FMA, MVT::f64, Legal);
159 setOperationAction(ISD::FMINNUM_IEEE, MVT::f64, Legal);
160 setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal);
161 setOperationAction(ISD::FSIN, MVT::f64, Expand);
162 setOperationAction(ISD::FCOS, MVT::f64, Expand);
163 setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
164 setOperationAction(ISD::FPOW, MVT::f64, Expand);
165 setOperationAction(ISD::FREM, MVT::f64, Expand);
166 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
167 }
168
169 setOperationAction(ISD::BR_JT, MVT::Other, Expand);
170
171 setOperationAction(ISD::BR_CC, GRLenVT, Expand);
172 setOperationAction(ISD::SELECT_CC, GRLenVT, Expand);
173 setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
174 setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, GRLenVT, Expand);
175 if (!Subtarget.is64Bit())
176 setLibcallName(RTLIB::MUL_I128, nullptr);
177
178 setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom);
179 setOperationAction(ISD::UINT_TO_FP, GRLenVT, Expand);
180 if ((Subtarget.is64Bit() && Subtarget.hasBasicF() &&
181 !Subtarget.hasBasicD())) {
182 setOperationAction(ISD::SINT_TO_FP, GRLenVT, Custom);
183 setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom);
184 }
185
186 // Compute derived properties from the register classes.
187 computeRegisterProperties(STI.getRegisterInfo());
188
189 setStackPointerRegisterToSaveRestore(LoongArch::R3);
190
191 setBooleanContents(ZeroOrOneBooleanContent);
192
193 setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
194
195 setMinCmpXchgSizeInBits(32);
196
197 // Function alignments.
198 setMinFunctionAlignment(Align(4));
199
200 setTargetDAGCombine(ISD::AND);
201 setTargetDAGCombine(ISD::OR);
202 setTargetDAGCombine(ISD::SRL);
203}
204
205bool LoongArchTargetLowering::isOffsetFoldingLegal(
206 const GlobalAddressSDNode *GA) const {
207 // In order to maximise the opportunity for common subexpression elimination,
208 // keep a separate ADD node for the global address offset instead of folding
209 // it in the global address node. Later peephole optimisations may choose to
210 // fold it back in when profitable.
211 return false;
212}
213
214SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
215 SelectionDAG &DAG) const {
216 switch (Op.getOpcode()) {
217 case ISD::EH_DWARF_CFA:
218 return lowerEH_DWARF_CFA(Op, DAG);
219 case ISD::GlobalAddress:
220 return lowerGlobalAddress(Op, DAG);
221 case ISD::GlobalTLSAddress:
222 return lowerGlobalTLSAddress(Op, DAG);
223 case ISD::INTRINSIC_WO_CHAIN:
224 return lowerINTRINSIC_WO_CHAIN(Op, DAG);
225 case ISD::INTRINSIC_W_CHAIN:
226 return lowerINTRINSIC_W_CHAIN(Op, DAG);
227 case ISD::INTRINSIC_VOID:
228 return lowerINTRINSIC_VOID(Op, DAG);
229 case ISD::BlockAddress:
230 return lowerBlockAddress(Op, DAG);
231 case ISD::JumpTable:
232 return lowerJumpTable(Op, DAG);
233 case ISD::SHL_PARTS:
234 return lowerShiftLeftParts(Op, DAG);
235 case ISD::SRA_PARTS:
236 return lowerShiftRightParts(Op, DAG, true);
237 case ISD::SRL_PARTS:
238 return lowerShiftRightParts(Op, DAG, false);
239 case ISD::ConstantPool:
240 return lowerConstantPool(Op, DAG);
241 case ISD::FP_TO_SINT:
242 return lowerFP_TO_SINT(Op, DAG);
243 case ISD::BITCAST:
244 return lowerBITCAST(Op, DAG);
245 case ISD::UINT_TO_FP:
246 return lowerUINT_TO_FP(Op, DAG);
247 case ISD::SINT_TO_FP:
248 return lowerSINT_TO_FP(Op, DAG);
249 case ISD::VASTART:
250 return lowerVASTART(Op, DAG);
251 case ISD::FRAMEADDR:
252 return lowerFRAMEADDR(Op, DAG);
253 case ISD::RETURNADDR:
254 return lowerRETURNADDR(Op, DAG);
255 case ISD::WRITE_REGISTER:
256 return lowerWRITE_REGISTER(Op, DAG);
257 }
258 return SDValue();
259}
260
261SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
262 SelectionDAG &DAG) const {
263
264 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
265 DAG.getContext()->emitError(
266 "On LA64, only 64-bit registers can be written.");
267 return Op.getOperand(0);
268 }
269
270 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
271 DAG.getContext()->emitError(
272 "On LA32, only 32-bit registers can be written.");
273 return Op.getOperand(0);
274 }
275
276 return Op;
277}
278
279SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
280 SelectionDAG &DAG) const {
281 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
282 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
283 "be a constant integer");
284 return SDValue();
285 }
286
287 MachineFunction &MF = DAG.getMachineFunction();
288 MF.getFrameInfo().setFrameAddressIsTaken(true);
289 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
290 EVT VT = Op.getValueType();
291 SDLoc DL(Op);
292 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
293 unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
294 int GRLenInBytes = Subtarget.getGRLen() / 8;
295
296 while (Depth--) {
297 int Offset = -(GRLenInBytes * 2);
298 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
299 DAG.getIntPtrConstant(Offset, DL));
300 FrameAddr =
301 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
302 }
303 return FrameAddr;
304}
305
306SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
307 SelectionDAG &DAG) const {
308 if (verifyReturnAddressArgumentIsConstant(Op, DAG))
309 return SDValue();
310
311 // Currently only support lowering return address for current frame.
312 if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() != 0) {
313 DAG.getContext()->emitError(
314 "return address can only be determined for the current frame");
315 return SDValue();
316 }
317
318 MachineFunction &MF = DAG.getMachineFunction();
319 MF.getFrameInfo().setReturnAddressIsTaken(true);
320 MVT GRLenVT = Subtarget.getGRLenVT();
321
322 // Return the value of the return address register, marking it an implicit
323 // live-in.
324 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
325 getRegClassFor(GRLenVT));
326 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
327}
328
329SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
330 SelectionDAG &DAG) const {
331 MachineFunction &MF = DAG.getMachineFunction();
332 auto Size = Subtarget.getGRLen() / 8;
333 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
334 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
335}
336
337SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
338 SelectionDAG &DAG) const {
339 MachineFunction &MF = DAG.getMachineFunction();
340 auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
341
342 SDLoc DL(Op);
343 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
344 getPointerTy(MF.getDataLayout()));
345
346 // vastart just stores the address of the VarArgsFrameIndex slot into the
347 // memory location argument.
348 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
349 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
350 MachinePointerInfo(SV));
351}
352
353SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
354 SelectionDAG &DAG) const {
355 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&(static_cast <bool> (Subtarget.is64Bit() && Subtarget
.hasBasicF() && !Subtarget.hasBasicD() && "unexpected target features"
) ? void (0) : __assert_fail ("Subtarget.is64Bit() && Subtarget.hasBasicF() && !Subtarget.hasBasicD() && \"unexpected target features\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 356,
__extension__ __PRETTY_FUNCTION__))
356 !Subtarget.hasBasicD() && "unexpected target features")(static_cast <bool> (Subtarget.is64Bit() && Subtarget
.hasBasicF() && !Subtarget.hasBasicD() && "unexpected target features"
) ? void (0) : __assert_fail ("Subtarget.is64Bit() && Subtarget.hasBasicF() && !Subtarget.hasBasicD() && \"unexpected target features\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 356,
__extension__ __PRETTY_FUNCTION__))
;
357
358 SDLoc DL(Op);
359 SDValue Op0 = Op.getOperand(0);
360 if (Op0->getOpcode() == ISD::AND) {
361 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
362 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF)0xFFFFFFFFUL)
363 return Op;
364 }
365
366 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
367 Op0.getConstantOperandVal(1) < UINT64_C(0X1F)0X1FUL &&
368 Op0.getConstantOperandVal(2) == UINT64_C(0)0UL)
369 return Op;
370
371 if (Op0.getOpcode() == ISD::AssertZext &&
372 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
373 return Op;
374
375 EVT OpVT = Op0.getValueType();
376 EVT RetVT = Op.getValueType();
377 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
378 MakeLibCallOptions CallOptions;
379 CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
380 SDValue Chain = SDValue();
381 SDValue Result;
382 std::tie(Result, Chain) =
383 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
384 return Result;
385}
386
387SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
388 SelectionDAG &DAG) const {
389 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&(static_cast <bool> (Subtarget.is64Bit() && Subtarget
.hasBasicF() && !Subtarget.hasBasicD() && "unexpected target features"
) ? void (0) : __assert_fail ("Subtarget.is64Bit() && Subtarget.hasBasicF() && !Subtarget.hasBasicD() && \"unexpected target features\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 390,
__extension__ __PRETTY_FUNCTION__))
390 !Subtarget.hasBasicD() && "unexpected target features")(static_cast <bool> (Subtarget.is64Bit() && Subtarget
.hasBasicF() && !Subtarget.hasBasicD() && "unexpected target features"
) ? void (0) : __assert_fail ("Subtarget.is64Bit() && Subtarget.hasBasicF() && !Subtarget.hasBasicD() && \"unexpected target features\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 390,
__extension__ __PRETTY_FUNCTION__))
;
391
392 SDLoc DL(Op);
393 SDValue Op0 = Op.getOperand(0);
394
395 if ((Op0.getOpcode() == ISD::AssertSext ||
396 Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) &&
397 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
398 return Op;
399
400 EVT OpVT = Op0.getValueType();
401 EVT RetVT = Op.getValueType();
402 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
403 MakeLibCallOptions CallOptions;
404 CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
405 SDValue Chain = SDValue();
406 SDValue Result;
407 std::tie(Result, Chain) =
408 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
409 return Result;
410}
411
412SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
413 SelectionDAG &DAG) const {
414
415 SDLoc DL(Op);
416 SDValue Op0 = Op.getOperand(0);
417
418 if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
419 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
420 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
421 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
422 }
423 return Op;
424}
425
426SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
427 SelectionDAG &DAG) const {
428
429 SDLoc DL(Op);
430
431 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
432 !Subtarget.hasBasicD()) {
433 SDValue Dst =
434 DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
435 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
436 }
437
438 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
439 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
440 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
441}
442
443static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
444 SelectionDAG &DAG, unsigned Flags) {
445 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
446}
447
448static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
449 SelectionDAG &DAG, unsigned Flags) {
450 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
451 Flags);
452}
453
454static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty,
455 SelectionDAG &DAG, unsigned Flags) {
456 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
457 N->getOffset(), Flags);
458}
459
460static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty,
461 SelectionDAG &DAG, unsigned Flags) {
462 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
463}
464
465template <class NodeTy>
466SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
467 bool IsLocal) const {
468 SDLoc DL(N);
469 EVT Ty = getPointerTy(DAG.getDataLayout());
470 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
471 // TODO: Check CodeModel.
472 if (IsLocal)
473 // This generates the pattern (PseudoLA_PCREL sym), which expands to
474 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
475 return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr),
476 0);
477
478 // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d
479 // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
480 return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
481}
482
483SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
484 SelectionDAG &DAG) const {
485 return getAddr(cast<BlockAddressSDNode>(Op), DAG);
486}
487
488SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
489 SelectionDAG &DAG) const {
490 return getAddr(cast<JumpTableSDNode>(Op), DAG);
491}
492
493SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
494 SelectionDAG &DAG) const {
495 return getAddr(cast<ConstantPoolSDNode>(Op), DAG);
496}
497
498SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
499 SelectionDAG &DAG) const {
500 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
501 assert(N->getOffset() == 0 && "unexpected offset in global node")(static_cast <bool> (N->getOffset() == 0 && "unexpected offset in global node"
) ? void (0) : __assert_fail ("N->getOffset() == 0 && \"unexpected offset in global node\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 501,
__extension__ __PRETTY_FUNCTION__))
;
502 return getAddr(N, DAG, N->getGlobal()->isDSOLocal());
503}
504
505SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
506 SelectionDAG &DAG,
507 unsigned Opc) const {
508 SDLoc DL(N);
509 EVT Ty = getPointerTy(DAG.getDataLayout());
510 MVT GRLenVT = Subtarget.getGRLenVT();
511
512 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
513 SDValue Offset = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
514
515 // Add the thread pointer.
516 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
517 DAG.getRegister(LoongArch::R2, GRLenVT));
518}
519
520SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
521 SelectionDAG &DAG,
522 unsigned Opc) const {
523 SDLoc DL(N);
524 EVT Ty = getPointerTy(DAG.getDataLayout());
525 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
526
527 // Use a PC-relative addressing mode to access the dynamic GOT address.
528 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
529 SDValue Load = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
530
531 // Prepare argument list to generate call.
532 ArgListTy Args;
533 ArgListEntry Entry;
534 Entry.Node = Load;
535 Entry.Ty = CallTy;
536 Args.push_back(Entry);
537
538 // Setup call to __tls_get_addr.
539 TargetLowering::CallLoweringInfo CLI(DAG);
540 CLI.setDebugLoc(DL)
541 .setChain(DAG.getEntryNode())
542 .setLibCallee(CallingConv::C, CallTy,
543 DAG.getExternalSymbol("__tls_get_addr", Ty),
544 std::move(Args));
545
546 return LowerCallTo(CLI).first;
547}
548
549SDValue
550LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
551 SelectionDAG &DAG) const {
552 if (DAG.getMachineFunction().getFunction().getCallingConv() ==
553 CallingConv::GHC)
554 report_fatal_error("In GHC calling convention TLS is not supported");
555
556 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
557 assert(N->getOffset() == 0 && "unexpected offset in global node")(static_cast <bool> (N->getOffset() == 0 && "unexpected offset in global node"
) ? void (0) : __assert_fail ("N->getOffset() == 0 && \"unexpected offset in global node\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 557,
__extension__ __PRETTY_FUNCTION__))
;
558
559 SDValue Addr;
560 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
561 case TLSModel::GeneralDynamic:
562 // In this model, application code calls the dynamic linker function
563 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
564 // runtime.
565 Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_GD);
566 break;
567 case TLSModel::LocalDynamic:
568 // Same as GeneralDynamic, except for assembly modifiers and relocation
569 // records.
570 Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LD);
571 break;
572 case TLSModel::InitialExec:
573 // This model uses the GOT to resolve TLS offsets.
574 Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_IE);
575 break;
576 case TLSModel::LocalExec:
577 // This model is used when static linking as the TLS offsets are resolved
578 // during program linking.
579 Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE);
580 break;
581 }
582
583 return Addr;
584}
585
586SDValue
587LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
588 SelectionDAG &DAG) const {
589 switch (Op.getConstantOperandVal(0)) {
590 default:
591 return SDValue(); // Don't custom lower most intrinsics.
592 case Intrinsic::thread_pointer: {
593 EVT PtrVT = getPointerTy(DAG.getDataLayout());
594 return DAG.getRegister(LoongArch::R2, PtrVT);
595 }
596 }
597}
598
599// Helper function that emits error message for intrinsics with chain.
600static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op,
601 StringRef ErrorMsg,
602 SelectionDAG &DAG) {
603
604 DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " +
605 ErrorMsg);
606 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
607 SDLoc(Op));
608}
609
610SDValue
611LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
612 SelectionDAG &DAG) const {
613 SDLoc DL(Op);
614 MVT GRLenVT = Subtarget.getGRLenVT();
615 SDValue Op0 = Op.getOperand(0);
616 std::string Name = Op->getOperationName(0);
617 const StringRef ErrorMsgOOR = "out of range";
618
619 switch (Op.getConstantOperandVal(1)) {
620 default:
621 return Op;
622 case Intrinsic::loongarch_crc_w_b_w:
623 case Intrinsic::loongarch_crc_w_h_w:
624 case Intrinsic::loongarch_crc_w_w_w:
625 case Intrinsic::loongarch_crc_w_d_w:
626 case Intrinsic::loongarch_crcc_w_b_w:
627 case Intrinsic::loongarch_crcc_w_h_w:
628 case Intrinsic::loongarch_crcc_w_w_w:
629 case Intrinsic::loongarch_crcc_w_d_w: {
630 std::string Name = Op->getOperationName(0);
631 DAG.getContext()->emitError(Name + " requires target: loongarch64");
632 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
633 }
634 case Intrinsic::loongarch_csrrd_w:
635 case Intrinsic::loongarch_csrrd_d: {
636 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
637 if (!isUInt<14>(Imm))
638 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
639 return DAG.getMergeValues(
640 {DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
641 DAG.getConstant(Imm, DL, GRLenVT)),
642 Op0},
643 DL);
644 }
645 case Intrinsic::loongarch_csrwr_w:
646 case Intrinsic::loongarch_csrwr_d: {
647 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
648 if (!isUInt<14>(Imm))
649 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
650 return DAG.getMergeValues(
651 {DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0, Op.getOperand(2),
652 DAG.getConstant(Imm, DL, GRLenVT)),
653 Op0},
654 DL);
655 }
656 case Intrinsic::loongarch_csrxchg_w:
657 case Intrinsic::loongarch_csrxchg_d: {
658 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue();
659 if (!isUInt<14>(Imm))
660 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
661 return DAG.getMergeValues(
662 {DAG.getNode(LoongArchISD::CSRXCHG, DL, GRLenVT, Op0, Op.getOperand(2),
663 Op.getOperand(3), DAG.getConstant(Imm, DL, GRLenVT)),
664 Op0},
665 DL);
666 }
667 case Intrinsic::loongarch_iocsrrd_d: {
668 if (Subtarget.is64Bit())
669 return DAG.getMergeValues(
670 {DAG.getNode(
671 LoongArchISD::IOCSRRD_D, DL, GRLenVT, Op0,
672 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))),
673 Op0},
674 DL);
675 else {
676 DAG.getContext()->emitError(
677 "llvm.loongarch.crc.w.d.w requires target: loongarch64");
678 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
679 }
680 }
681#define IOCSRRD_CASE(NAME, NODE) \
682 case Intrinsic::loongarch_##NAME: { \
683 return DAG.getMergeValues( \
684 {DAG.getNode(LoongArchISD::NODE, DL, GRLenVT, Op0, Op.getOperand(2)), \
685 Op0}, \
686 DL); \
687 }
688 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
689 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
690 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
691#undef IOCSRRD_CASE
692 case Intrinsic::loongarch_cpucfg: {
693 return DAG.getMergeValues(
694 {DAG.getNode(LoongArchISD::CPUCFG, DL, GRLenVT, Op0, Op.getOperand(2)),
695 Op0},
696 DL);
697 }
698 case Intrinsic::loongarch_lddir_d: {
699 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
700 if (!isUInt<8>(Imm)) {
701 DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) +
702 "' out of range");
703 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
704 }
705
706 return Op;
707 }
708 case Intrinsic::loongarch_movfcsr2gr: {
709 if (!Subtarget.hasBasicF()) {
710 DAG.getContext()->emitError(
711 "llvm.loongarch.movfcsr2gr expects basic f target feature");
712 return DAG.getMergeValues(
713 {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
714 }
715 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
716 if (!isUInt<2>(Imm)) {
717 DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) +
718 "' " + ErrorMsgOOR);
719 return DAG.getMergeValues(
720 {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
721 }
722 return DAG.getMergeValues(
723 {DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, Op.getValueType(),
724 DAG.getConstant(Imm, DL, GRLenVT)),
725 Op.getOperand(0)},
726 DL);
727 }
728 }
729}
730
731// Helper function that emits error message for intrinsics with void return
732// value.
733static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg,
734 SelectionDAG &DAG) {
735
736 DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " +
737 ErrorMsg);
738 return Op.getOperand(0);
739}
740
741SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
742 SelectionDAG &DAG) const {
743 SDLoc DL(Op);
744 MVT GRLenVT = Subtarget.getGRLenVT();
745 SDValue Op0 = Op.getOperand(0);
746 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
747 SDValue Op2 = Op.getOperand(2);
748 const StringRef ErrorMsgOOR = "out of range";
749
750 switch (IntrinsicEnum) {
751 default:
752 // TODO: Add more Intrinsics.
753 return SDValue();
754 case Intrinsic::loongarch_cacop_d:
755 case Intrinsic::loongarch_cacop_w: {
756 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit()) {
757 DAG.getContext()->emitError(
758 "llvm.loongarch.cacop.d requires target: loongarch64");
759 return Op.getOperand(0);
760 }
761 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit()) {
762 DAG.getContext()->emitError(
763 "llvm.loongarch.cacop.w requires target: loongarch32");
764 return Op.getOperand(0);
765 }
766 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
767 unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue();
768 if (!isUInt<5>(Imm1))
769 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
770 SDValue Op4 = Op.getOperand(4);
771 int Imm2 = cast<ConstantSDNode>(Op4)->getSExtValue();
772 if (!isInt<12>(Imm2))
773 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
774
775 return Op;
776 }
777
778 case Intrinsic::loongarch_dbar: {
779 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
780 if (!isUInt<15>(Imm))
781 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
782
783 return DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Op0,
784 DAG.getConstant(Imm, DL, GRLenVT));
785 }
786 case Intrinsic::loongarch_ibar: {
787 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
788 if (!isUInt<15>(Imm))
789 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
790
791 return DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Op0,
792 DAG.getConstant(Imm, DL, GRLenVT));
793 }
794 case Intrinsic::loongarch_break: {
795 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
796 if (!isUInt<15>(Imm))
797 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
798
799 return DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Op0,
800 DAG.getConstant(Imm, DL, GRLenVT));
801 }
802 case Intrinsic::loongarch_movgr2fcsr: {
803 if (!Subtarget.hasBasicF()) {
804 DAG.getContext()->emitError(
805 "llvm.loongarch.movgr2fcsr expects basic f target feature");
806 return Op0;
807 }
808 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
809 if (!isUInt<2>(Imm))
810 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
811
812 return DAG.getNode(
813 LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Op0,
814 DAG.getConstant(Imm, DL, GRLenVT),
815 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Op.getOperand(3)));
816 }
817 case Intrinsic::loongarch_syscall: {
818 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
819 if (!isUInt<15>(Imm))
820 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
821
822 return DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Op0,
823 DAG.getConstant(Imm, DL, GRLenVT));
824 }
825#define IOCSRWR_CASE(NAME, NODE) \
826 case Intrinsic::loongarch_##NAME: { \
827 SDValue Op3 = Op.getOperand(3); \
828 if (Subtarget.is64Bit()) \
829 return DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Op0, \
830 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
831 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)); \
832 else \
833 return DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Op0, Op2, Op3); \
834 }
835 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
836 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
837 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
838#undef IOCSRWR_CASE
839 case Intrinsic::loongarch_iocsrwr_d: {
840 if (Subtarget.is64Bit())
841 return DAG.getNode(
842 LoongArchISD::IOCSRWR_D, DL, MVT::Other, Op0, Op2,
843 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(3)));
844 else {
845 DAG.getContext()->emitError(
846 "llvm.loongarch.iocsrwr.d requires target: loongarch64");
847 return Op.getOperand(0);
848 }
849 }
850#define ASRT_LE_GT_CASE(NAME) \
851 case Intrinsic::loongarch_##NAME: { \
852 if (!Subtarget.is64Bit()) { \
853 DAG.getContext()->emitError(Op->getOperationName(0) + \
854 " requires target: loongarch64"); \
855 return Op.getOperand(0); \
856 } \
857 return Op; \
858 }
859 ASRT_LE_GT_CASE(asrtle_d)
860 ASRT_LE_GT_CASE(asrtgt_d)
861#undef ASRT_LE_GT_CASE
862 case Intrinsic::loongarch_ldpte_d: {
863 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
864 if (!isUInt<8>(Imm))
865 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
866 if (!Subtarget.is64Bit()) {
867 DAG.getContext()->emitError(Op->getOperationName(0) +
868 " requires target: loongarch64");
869 return Op.getOperand(0);
870 }
871 return Op;
872 }
873 }
874}
875
876SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
877 SelectionDAG &DAG) const {
878 SDLoc DL(Op);
879 SDValue Lo = Op.getOperand(0);
880 SDValue Hi = Op.getOperand(1);
881 SDValue Shamt = Op.getOperand(2);
882 EVT VT = Lo.getValueType();
883
884 // if Shamt-GRLen < 0: // Shamt < GRLen
885 // Lo = Lo << Shamt
886 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
887 // else:
888 // Lo = 0
889 // Hi = Lo << (Shamt-GRLen)
890
891 SDValue Zero = DAG.getConstant(0, DL, VT);
892 SDValue One = DAG.getConstant(1, DL, VT);
893 SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
894 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
895 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
896 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
897
898 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
899 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
900 SDValue ShiftRightLo =
901 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
902 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
903 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
904 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
905
906 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
907
908 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
909 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
910
911 SDValue Parts[2] = {Lo, Hi};
912 return DAG.getMergeValues(Parts, DL);
913}
914
915SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
916 SelectionDAG &DAG,
917 bool IsSRA) const {
918 SDLoc DL(Op);
919 SDValue Lo = Op.getOperand(0);
920 SDValue Hi = Op.getOperand(1);
921 SDValue Shamt = Op.getOperand(2);
922 EVT VT = Lo.getValueType();
923
924 // SRA expansion:
925 // if Shamt-GRLen < 0: // Shamt < GRLen
926 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
927 // Hi = Hi >>s Shamt
928 // else:
929 // Lo = Hi >>s (Shamt-GRLen);
930 // Hi = Hi >>s (GRLen-1)
931 //
932 // SRL expansion:
933 // if Shamt-GRLen < 0: // Shamt < GRLen
934 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
935 // Hi = Hi >>u Shamt
936 // else:
937 // Lo = Hi >>u (Shamt-GRLen);
938 // Hi = 0;
939
940 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
941
942 SDValue Zero = DAG.getConstant(0, DL, VT);
943 SDValue One = DAG.getConstant(1, DL, VT);
944 SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
945 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
946 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
947 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
948
949 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
950 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
951 SDValue ShiftLeftHi =
952 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
953 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
954 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
955 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
956 SDValue HiFalse =
957 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
958
959 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
960
961 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
962 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
963
964 SDValue Parts[2] = {Lo, Hi};
965 return DAG.getMergeValues(Parts, DL);
966}
967
968// Returns the opcode of the target-specific SDNode that implements the 32-bit
969// form of the given Opcode.
970static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode) {
971 switch (Opcode) {
972 default:
973 llvm_unreachable("Unexpected opcode")::llvm::llvm_unreachable_internal("Unexpected opcode", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 973)
;
974 case ISD::SHL:
975 return LoongArchISD::SLL_W;
976 case ISD::SRA:
977 return LoongArchISD::SRA_W;
978 case ISD::SRL:
979 return LoongArchISD::SRL_W;
980 case ISD::ROTR:
981 return LoongArchISD::ROTR_W;
982 case ISD::ROTL:
983 return LoongArchISD::ROTL_W;
984 case ISD::CTTZ:
985 return LoongArchISD::CTZ_W;
986 case ISD::CTLZ:
987 return LoongArchISD::CLZ_W;
988 }
989}
990
991// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
992// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
993// otherwise be promoted to i64, making it difficult to select the
994// SLL_W/.../*W later one because the fact the operation was originally of
995// type i8/i16/i32 is lost.
996static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp,
997 unsigned ExtOpc = ISD::ANY_EXTEND) {
998 SDLoc DL(N);
999 LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode());
1000 SDValue NewOp0, NewRes;
1001
1002 switch (NumOp) {
1003 default:
1004 llvm_unreachable("Unexpected NumOp")::llvm::llvm_unreachable_internal("Unexpected NumOp", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 1004)
;
1005 case 1: {
1006 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1007 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
1008 break;
1009 }
1010 case 2: {
1011 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1012 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
1013 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
1014 break;
1015 }
1016 // TODO:Handle more NumOp.
1017 }
1018
1019 // ReplaceNodeResults requires we maintain the same type for the return
1020 // value.
1021 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
1022}
1023
1024void LoongArchTargetLowering::ReplaceNodeResults(
1025 SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
1026 SDLoc DL(N);
1027 EVT VT = N->getValueType(0);
1028 switch (N->getOpcode()) {
1029 default:
1030 llvm_unreachable("Don't know how to legalize this operation")::llvm::llvm_unreachable_internal("Don't know how to legalize this operation"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1030
)
;
1031 case ISD::SHL:
1032 case ISD::SRA:
1033 case ISD::SRL:
1034 case ISD::ROTR:
1035 assert(VT == MVT::i32 && Subtarget.is64Bit() &&(static_cast <bool> (VT == MVT::i32 && Subtarget
.is64Bit() && "Unexpected custom legalisation") ? void
(0) : __assert_fail ("VT == MVT::i32 && Subtarget.is64Bit() && \"Unexpected custom legalisation\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1036
, __extension__ __PRETTY_FUNCTION__))
1036 "Unexpected custom legalisation")(static_cast <bool> (VT == MVT::i32 && Subtarget
.is64Bit() && "Unexpected custom legalisation") ? void
(0) : __assert_fail ("VT == MVT::i32 && Subtarget.is64Bit() && \"Unexpected custom legalisation\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1036
, __extension__ __PRETTY_FUNCTION__))
;
1037 if (N->getOperand(1).getOpcode() != ISD::Constant) {
1038 Results.push_back(customLegalizeToWOp(N, DAG, 2));
1039 break;
1040 }
1041 break;
1042 case ISD::ROTL:
1043 ConstantSDNode *CN;
1044 if ((CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) {
Although the value stored to 'CN' is used in the enclosing expression, the value is never actually read from 'CN'
1045 Results.push_back(customLegalizeToWOp(N, DAG, 2));
1046 break;
1047 }
1048 break;
1049 case ISD::FP_TO_SINT: {
1050 assert(VT == MVT::i32 && Subtarget.is64Bit() &&(static_cast <bool> (VT == MVT::i32 && Subtarget
.is64Bit() && "Unexpected custom legalisation") ? void
(0) : __assert_fail ("VT == MVT::i32 && Subtarget.is64Bit() && \"Unexpected custom legalisation\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1051
, __extension__ __PRETTY_FUNCTION__))
1051 "Unexpected custom legalisation")(static_cast <bool> (VT == MVT::i32 && Subtarget
.is64Bit() && "Unexpected custom legalisation") ? void
(0) : __assert_fail ("VT == MVT::i32 && Subtarget.is64Bit() && \"Unexpected custom legalisation\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1051
, __extension__ __PRETTY_FUNCTION__))
;
1052 SDValue Src = N->getOperand(0);
1053 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
1054 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
1055 TargetLowering::TypeSoftenFloat) {
1056 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
1057 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
1058 return;
1059 }
1060 // If the FP type needs to be softened, emit a library call using the 'si'
1061 // version. If we left it to default legalization we'd end up with 'di'.
1062 RTLIB::Libcall LC;
1063 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
1064 MakeLibCallOptions CallOptions;
1065 EVT OpVT = Src.getValueType();
1066 CallOptions.setTypeListBeforeSoften(OpVT, VT, true);
1067 SDValue Chain = SDValue();
1068 SDValue Result;
1069 std::tie(Result, Chain) =
1070 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
1071 Results.push_back(Result);
1072 break;
1073 }
1074 case ISD::BITCAST: {
1075 SDValue Src = N->getOperand(0);
1076 EVT SrcVT = Src.getValueType();
1077 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
1078 Subtarget.hasBasicF()) {
1079 SDValue Dst =
1080 DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
1081 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
1082 }
1083 break;
1084 }
1085 case ISD::FP_TO_UINT: {
1086 assert(VT == MVT::i32 && Subtarget.is64Bit() &&(static_cast <bool> (VT == MVT::i32 && Subtarget
.is64Bit() && "Unexpected custom legalisation") ? void
(0) : __assert_fail ("VT == MVT::i32 && Subtarget.is64Bit() && \"Unexpected custom legalisation\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1087
, __extension__ __PRETTY_FUNCTION__))
1087 "Unexpected custom legalisation")(static_cast <bool> (VT == MVT::i32 && Subtarget
.is64Bit() && "Unexpected custom legalisation") ? void
(0) : __assert_fail ("VT == MVT::i32 && Subtarget.is64Bit() && \"Unexpected custom legalisation\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1087
, __extension__ __PRETTY_FUNCTION__))
;
1088 auto &TLI = DAG.getTargetLoweringInfo();
1089 SDValue Tmp1, Tmp2;
1090 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
1091 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
1092 break;
1093 }
1094 case ISD::BSWAP: {
1095 SDValue Src = N->getOperand(0);
1096 assert((VT == MVT::i16 || VT == MVT::i32) &&(static_cast <bool> ((VT == MVT::i16 || VT == MVT::i32)
&& "Unexpected custom legalization") ? void (0) : __assert_fail
("(VT == MVT::i16 || VT == MVT::i32) && \"Unexpected custom legalization\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1097
, __extension__ __PRETTY_FUNCTION__))
1097 "Unexpected custom legalization")(static_cast <bool> ((VT == MVT::i16 || VT == MVT::i32)
&& "Unexpected custom legalization") ? void (0) : __assert_fail
("(VT == MVT::i16 || VT == MVT::i32) && \"Unexpected custom legalization\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1097
, __extension__ __PRETTY_FUNCTION__))
;
1098 MVT GRLenVT = Subtarget.getGRLenVT();
1099 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1100 SDValue Tmp;
1101 switch (VT.getSizeInBits()) {
1102 default:
1103 llvm_unreachable("Unexpected operand width")::llvm::llvm_unreachable_internal("Unexpected operand width",
"llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1103)
;
1104 case 16:
1105 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
1106 break;
1107 case 32:
1108 // Only LA64 will get to here due to the size mismatch between VT and
1109 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
1110 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
1111 break;
1112 }
1113 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1114 break;
1115 }
1116 case ISD::BITREVERSE: {
1117 SDValue Src = N->getOperand(0);
1118 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&(static_cast <bool> ((VT == MVT::i8 || (VT == MVT::i32 &&
Subtarget.is64Bit())) && "Unexpected custom legalization"
) ? void (0) : __assert_fail ("(VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) && \"Unexpected custom legalization\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1119
, __extension__ __PRETTY_FUNCTION__))
1119 "Unexpected custom legalization")(static_cast <bool> ((VT == MVT::i8 || (VT == MVT::i32 &&
Subtarget.is64Bit())) && "Unexpected custom legalization"
) ? void (0) : __assert_fail ("(VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) && \"Unexpected custom legalization\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1119
, __extension__ __PRETTY_FUNCTION__))
;
1120 MVT GRLenVT = Subtarget.getGRLenVT();
1121 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1122 SDValue Tmp;
1123 switch (VT.getSizeInBits()) {
1124 default:
1125 llvm_unreachable("Unexpected operand width")::llvm::llvm_unreachable_internal("Unexpected operand width",
"llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1125)
;
1126 case 8:
1127 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
1128 break;
1129 case 32:
1130 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
1131 break;
1132 }
1133 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1134 break;
1135 }
1136 case ISD::CTLZ:
1137 case ISD::CTTZ: {
1138 assert(VT == MVT::i32 && Subtarget.is64Bit() &&(static_cast <bool> (VT == MVT::i32 && Subtarget
.is64Bit() && "Unexpected custom legalisation") ? void
(0) : __assert_fail ("VT == MVT::i32 && Subtarget.is64Bit() && \"Unexpected custom legalisation\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1139
, __extension__ __PRETTY_FUNCTION__))
1139 "Unexpected custom legalisation")(static_cast <bool> (VT == MVT::i32 && Subtarget
.is64Bit() && "Unexpected custom legalisation") ? void
(0) : __assert_fail ("VT == MVT::i32 && Subtarget.is64Bit() && \"Unexpected custom legalisation\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1139
, __extension__ __PRETTY_FUNCTION__))
;
1140 Results.push_back(customLegalizeToWOp(N, DAG, 1));
1141 break;
1142 }
1143 case ISD::INTRINSIC_W_CHAIN: {
1144 SDValue Op0 = N->getOperand(0);
1145 EVT VT = N->getValueType(0);
1146 uint64_t Op1 = N->getConstantOperandVal(1);
1147 MVT GRLenVT = Subtarget.getGRLenVT();
1148 if (Op1 == Intrinsic::loongarch_movfcsr2gr) {
1149 if (!Subtarget.hasBasicF()) {
1150 DAG.getContext()->emitError(
1151 "llvm.loongarch.movfcsr2gr expects basic f target feature");
1152 Results.push_back(DAG.getMergeValues(
1153 {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N)));
1154 Results.push_back(N->getOperand(0));
1155 return;
1156 }
1157 unsigned Imm = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue();
1158 if (!isUInt<2>(Imm)) {
1159 DAG.getContext()->emitError("argument to '" + N->getOperationName(0) +
1160 "' " + "out of range");
1161 Results.push_back(DAG.getMergeValues(
1162 {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N)));
1163 Results.push_back(N->getOperand(0));
1164 return;
1165 }
1166 Results.push_back(
1167 DAG.getNode(ISD::TRUNCATE, DL, VT,
1168 DAG.getNode(LoongArchISD::MOVFCSR2GR, SDLoc(N), MVT::i64,
1169 DAG.getConstant(Imm, DL, GRLenVT))));
1170 Results.push_back(N->getOperand(0));
1171 return;
1172 }
1173 SDValue Op2 = N->getOperand(2);
1174 std::string Name = N->getOperationName(0);
1175
1176 switch (Op1) {
1177 default:
1178 llvm_unreachable("Unexpected Intrinsic.")::llvm::llvm_unreachable_internal("Unexpected Intrinsic.", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 1178)
;
1179#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
1180 case Intrinsic::loongarch_##NAME: { \
1181 Results.push_back(DAG.getNode( \
1182 ISD::TRUNCATE, DL, VT, \
1183 DAG.getNode( \
1184 LoongArchISD::NODE, DL, MVT::i64, \
1185 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
1186 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))))); \
1187 Results.push_back(N->getOperand(0)); \
1188 break; \
1189 }
1190 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
1191 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
1192 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
1193 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
1194 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
1195 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
1196#undef CRC_CASE_EXT_BINARYOP
1197
1198#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
1199 case Intrinsic::loongarch_##NAME: { \
1200 Results.push_back( \
1201 DAG.getNode(ISD::TRUNCATE, DL, VT, \
1202 DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op2, \
1203 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, \
1204 N->getOperand(3))))); \
1205 Results.push_back(N->getOperand(0)); \
1206 break; \
1207 }
1208 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
1209 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
1210#undef CRC_CASE_EXT_UNARYOP
1211#define CSR_CASE(ID) \
1212 case Intrinsic::loongarch_##ID: { \
1213 if (!Subtarget.is64Bit()) { \
1214 DAG.getContext()->emitError(Name + " requires target: loongarch64"); \
1215 Results.push_back(DAG.getUNDEF(VT)); \
1216 Results.push_back(N->getOperand(0)); \
1217 } \
1218 break; \
1219 }
1220 CSR_CASE(csrrd_d);
1221 CSR_CASE(csrwr_d);
1222 CSR_CASE(csrxchg_d);
1223 CSR_CASE(iocsrrd_d);
1224#undef CSR_CASE
1225 case Intrinsic::loongarch_csrrd_w: {
1226 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
1227 if (!isUInt<14>(Imm)) {
1228 DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1229 Results.push_back(DAG.getUNDEF(VT));
1230 Results.push_back(N->getOperand(0));
1231 break;
1232 }
1233
1234 Results.push_back(
1235 DAG.getNode(ISD::TRUNCATE, DL, VT,
1236 DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
1237 DAG.getConstant(Imm, DL, GRLenVT))));
1238 Results.push_back(N->getOperand(0));
1239 break;
1240 }
1241 case Intrinsic::loongarch_csrwr_w: {
1242 unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();
1243 if (!isUInt<14>(Imm)) {
1244 DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1245 Results.push_back(DAG.getUNDEF(VT));
1246 Results.push_back(N->getOperand(0));
1247 break;
1248 }
1249
1250 Results.push_back(DAG.getNode(
1251 ISD::TRUNCATE, DL, VT,
1252 DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0,
1253 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
1254 DAG.getConstant(Imm, DL, GRLenVT))));
1255 Results.push_back(N->getOperand(0));
1256 break;
1257 }
1258 case Intrinsic::loongarch_csrxchg_w: {
1259 unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();
1260 if (!isUInt<14>(Imm)) {
1261 DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1262 Results.push_back(DAG.getUNDEF(VT));
1263 Results.push_back(N->getOperand(0));
1264 break;
1265 }
1266
1267 Results.push_back(DAG.getNode(
1268 ISD::TRUNCATE, DL, VT,
1269 DAG.getNode(
1270 LoongArchISD::CSRXCHG, DL, GRLenVT, Op0,
1271 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
1272 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
1273 DAG.getConstant(Imm, DL, GRLenVT))));
1274 Results.push_back(N->getOperand(0));
1275 break;
1276 }
1277#define IOCSRRD_CASE(NAME, NODE) \
1278 case Intrinsic::loongarch_##NAME: { \
1279 Results.push_back(DAG.getNode( \
1280 ISD::TRUNCATE, DL, N->getValueType(0), \
1281 DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op0, \
1282 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)))); \
1283 Results.push_back(N->getOperand(0)); \
1284 break; \
1285 }
1286 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
1287 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
1288 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
1289#undef IOCSRRD_CASE
1290 case Intrinsic::loongarch_cpucfg: {
1291 Results.push_back(DAG.getNode(
1292 ISD::TRUNCATE, DL, VT,
1293 DAG.getNode(LoongArchISD::CPUCFG, DL, GRLenVT, Op0,
1294 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2))));
1295 Results.push_back(Op0);
1296 break;
1297 }
1298 case Intrinsic::loongarch_lddir_d: {
1299 if (!Subtarget.is64Bit()) {
1300 DAG.getContext()->emitError(N->getOperationName(0) +
1301 " requires target: loongarch64");
1302 Results.push_back(DAG.getUNDEF(VT));
1303 Results.push_back(Op0);
1304 break;
1305 }
1306 break;
1307 }
1308 }
1309 break;
1310 }
1311 case ISD::READ_REGISTER: {
1312 if (Subtarget.is64Bit())
1313 DAG.getContext()->emitError(
1314 "On LA64, only 64-bit registers can be read.");
1315 else
1316 DAG.getContext()->emitError(
1317 "On LA32, only 32-bit registers can be read.");
1318 Results.push_back(DAG.getUNDEF(VT));
1319 Results.push_back(N->getOperand(0));
1320 break;
1321 }
1322 }
1323}
1324
1325static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
1326 TargetLowering::DAGCombinerInfo &DCI,
1327 const LoongArchSubtarget &Subtarget) {
1328 if (DCI.isBeforeLegalizeOps())
1329 return SDValue();
1330
1331 SDValue FirstOperand = N->getOperand(0);
1332 SDValue SecondOperand = N->getOperand(1);
1333 unsigned FirstOperandOpc = FirstOperand.getOpcode();
1334 EVT ValTy = N->getValueType(0);
1335 SDLoc DL(N);
1336 uint64_t lsb, msb;
1337 unsigned SMIdx, SMLen;
1338 ConstantSDNode *CN;
1339 SDValue NewOperand;
1340 MVT GRLenVT = Subtarget.getGRLenVT();
1341
1342 // Op's second operand must be a shifted mask.
1343 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
1344 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
1345 return SDValue();
1346
1347 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
1348 // Pattern match BSTRPICK.
1349 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
1350 // => BSTRPICK $dst, $src, msb, lsb
1351 // where msb = lsb + len - 1
1352
1353 // The second operand of the shift must be an immediate.
1354 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
1355 return SDValue();
1356
1357 lsb = CN->getZExtValue();
1358
1359 // Return if the shifted mask does not start at bit 0 or the sum of its
1360 // length and lsb exceeds the word's size.
1361 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
1362 return SDValue();
1363
1364 NewOperand = FirstOperand.getOperand(0);
1365 } else {
1366 // Pattern match BSTRPICK.
1367 // $dst = and $src, (2**len- 1) , if len > 12
1368 // => BSTRPICK $dst, $src, msb, lsb
1369 // where lsb = 0 and msb = len - 1
1370
1371 // If the mask is <= 0xfff, andi can be used instead.
1372 if (CN->getZExtValue() <= 0xfff)
1373 return SDValue();
1374
1375 // Return if the MSB exceeds.
1376 if (SMIdx + SMLen > ValTy.getSizeInBits())
1377 return SDValue();
1378
1379 if (SMIdx > 0) {
1380 // Omit if the constant has more than 2 uses. This a conservative
1381 // decision. Whether it is a win depends on the HW microarchitecture.
1382 // However it should always be better for 1 and 2 uses.
1383 if (CN->use_size() > 2)
1384 return SDValue();
1385 // Return if the constant can be composed by a single LU12I.W.
1386 if ((CN->getZExtValue() & 0xfff) == 0)
1387 return SDValue();
1388 // Return if the constand can be composed by a single ADDI with
1389 // the zero register.
1390 if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
1391 return SDValue();
1392 }
1393
1394 lsb = SMIdx;
1395 NewOperand = FirstOperand;
1396 }
1397
1398 msb = lsb + SMLen - 1;
1399 SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
1400 DAG.getConstant(msb, DL, GRLenVT),
1401 DAG.getConstant(lsb, DL, GRLenVT));
1402 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
1403 return NR0;
1404 // Try to optimize to
1405 // bstrpick $Rd, $Rs, msb, lsb
1406 // slli $Rd, $Rd, lsb
1407 return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
1408 DAG.getConstant(lsb, DL, GRLenVT));
1409}
1410
1411static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
1412 TargetLowering::DAGCombinerInfo &DCI,
1413 const LoongArchSubtarget &Subtarget) {
1414 if (DCI.isBeforeLegalizeOps())
1415 return SDValue();
1416
1417 // $dst = srl (and $src, Mask), Shamt
1418 // =>
1419 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
1420 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
1421 //
1422
1423 SDValue FirstOperand = N->getOperand(0);
1424 ConstantSDNode *CN;
1425 EVT ValTy = N->getValueType(0);
1426 SDLoc DL(N);
1427 MVT GRLenVT = Subtarget.getGRLenVT();
1428 unsigned MaskIdx, MaskLen;
1429 uint64_t Shamt;
1430
1431 // The first operand must be an AND and the second operand of the AND must be
1432 // a shifted mask.
1433 if (FirstOperand.getOpcode() != ISD::AND ||
1434 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
1435 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
1436 return SDValue();
1437
1438 // The second operand (shift amount) must be an immediate.
1439 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
1440 return SDValue();
1441
1442 Shamt = CN->getZExtValue();
1443 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
1444 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
1445 FirstOperand->getOperand(0),
1446 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1447 DAG.getConstant(Shamt, DL, GRLenVT));
1448
1449 return SDValue();
1450}
1451
1452static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
1453 TargetLowering::DAGCombinerInfo &DCI,
1454 const LoongArchSubtarget &Subtarget) {
1455 MVT GRLenVT = Subtarget.getGRLenVT();
1456 EVT ValTy = N->getValueType(0);
1457 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
1458 ConstantSDNode *CN0, *CN1;
1459 SDLoc DL(N);
1460 unsigned ValBits = ValTy.getSizeInBits();
1461 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
1462 unsigned Shamt;
1463 bool SwapAndRetried = false;
1464
1465 if (DCI.isBeforeLegalizeOps())
1466 return SDValue();
1467
1468 if (ValBits != 32 && ValBits != 64)
1469 return SDValue();
1470
1471Retry:
1472 // 1st pattern to match BSTRINS:
1473 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
1474 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
1475 // =>
1476 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1477 if (N0.getOpcode() == ISD::AND &&
1478 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1479 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1480 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
1481 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1482 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1483 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
1484 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1485 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1486 (MaskIdx0 + MaskLen0 <= ValBits)) {
1487 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "Perform OR combine: match pattern 1\n"
; } } while (false)
;
1488 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1489 N1.getOperand(0).getOperand(0),
1490 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1491 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1492 }
1493
1494 // 2nd pattern to match BSTRINS:
1495 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
1496 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
1497 // =>
1498 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1499 if (N0.getOpcode() == ISD::AND &&
1500 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1501 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1502 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1503 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1504 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1505 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1506 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1507 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
1508 (MaskIdx0 + MaskLen0 <= ValBits)) {
1509 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "Perform OR combine: match pattern 2\n"
; } } while (false)
;
1510 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1511 N1.getOperand(0).getOperand(0),
1512 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1513 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1514 }
1515
1516 // 3rd pattern to match BSTRINS:
1517 // R = or (and X, mask0), (and Y, mask1)
1518 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
1519 // =>
1520 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
1521 // where msb = lsb + size - 1
1522 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
1523 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1524 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1525 (MaskIdx0 + MaskLen0 <= 64) &&
1526 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
1527 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1528 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "Perform OR combine: match pattern 3\n"
; } } while (false)
;
1529 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1530 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
1531 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
1532 DAG.getConstant(ValBits == 32
1533 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
1534 : (MaskIdx0 + MaskLen0 - 1),
1535 DL, GRLenVT),
1536 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1537 }
1538
1539 // 4th pattern to match BSTRINS:
1540 // R = or (and X, mask), (shl Y, shamt)
1541 // where mask = (2**shamt - 1)
1542 // =>
1543 // R = BSTRINS X, Y, ValBits - 1, shamt
1544 // where ValBits = 32 or 64
1545 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
1546 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1547 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
1548 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1549 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
1550 (MaskIdx0 + MaskLen0 <= ValBits)) {
1551 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "Perform OR combine: match pattern 4\n"
; } } while (false)
;
1552 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1553 N1.getOperand(0),
1554 DAG.getConstant((ValBits - 1), DL, GRLenVT),
1555 DAG.getConstant(Shamt, DL, GRLenVT));
1556 }
1557
1558 // 5th pattern to match BSTRINS:
1559 // R = or (and X, mask), const
1560 // where ~mask = (2**size - 1) << lsb, mask & const = 0
1561 // =>
1562 // R = BSTRINS X, (const >> lsb), msb, lsb
1563 // where msb = lsb + size - 1
1564 if (N0.getOpcode() == ISD::AND &&
1565 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1566 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1567 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
1568 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1569 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "Perform OR combine: match pattern 5\n"
; } } while (false)
;
1570 return DAG.getNode(
1571 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1572 DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
1573 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1574 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1575 }
1576
1577 // 6th pattern.
1578 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
1579 // by the incoming bits are known to be zero.
1580 // =>
1581 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
1582 //
1583 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
1584 // pattern is more common than the 1st. So we put the 1st before the 6th in
1585 // order to match as many nodes as possible.
1586 ConstantSDNode *CNMask, *CNShamt;
1587 unsigned MaskIdx, MaskLen;
1588 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1589 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1590 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1591 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1592 CNShamt->getZExtValue() + MaskLen <= ValBits) {
1593 Shamt = CNShamt->getZExtValue();
1594 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
1595 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1596 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "Perform OR combine: match pattern 6\n"
; } } while (false)
;
1597 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1598 N1.getOperand(0).getOperand(0),
1599 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
1600 DAG.getConstant(Shamt, DL, GRLenVT));
1601 }
1602 }
1603
1604 // 7th pattern.
1605 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
1606 // overwritten by the incoming bits are known to be zero.
1607 // =>
1608 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
1609 //
1610 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
1611 // before the 7th in order to match as many nodes as possible.
1612 if (N1.getOpcode() == ISD::AND &&
1613 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1614 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1615 N1.getOperand(0).getOpcode() == ISD::SHL &&
1616 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1617 CNShamt->getZExtValue() == MaskIdx) {
1618 APInt ShMask(ValBits, CNMask->getZExtValue());
1619 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1620 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "Perform OR combine: match pattern 7\n"
; } } while (false)
;
1621 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1622 N1.getOperand(0).getOperand(0),
1623 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1624 DAG.getConstant(MaskIdx, DL, GRLenVT));
1625 }
1626 }
1627
1628 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
1629 if (!SwapAndRetried) {
1630 std::swap(N0, N1);
1631 SwapAndRetried = true;
1632 goto Retry;
1633 }
1634
1635 SwapAndRetried = false;
1636Retry2:
1637 // 8th pattern.
1638 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
1639 // the incoming bits are known to be zero.
1640 // =>
1641 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
1642 //
1643 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
1644 // we put it here in order to match as many nodes as possible or generate less
1645 // instructions.
1646 if (N1.getOpcode() == ISD::AND &&
1647 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1648 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
1649 APInt ShMask(ValBits, CNMask->getZExtValue());
1650 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1651 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "Perform OR combine: match pattern 8\n"
; } } while (false)
;
1652 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1653 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
1654 N1->getOperand(0),
1655 DAG.getConstant(MaskIdx, DL, GRLenVT)),
1656 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1657 DAG.getConstant(MaskIdx, DL, GRLenVT));
1658 }
1659 }
1660 // Swap N0/N1 and retry.
1661 if (!SwapAndRetried) {
1662 std::swap(N0, N1);
1663 SwapAndRetried = true;
1664 goto Retry2;
1665 }
1666
1667 return SDValue();
1668}
1669
1670// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
1671static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG,
1672 TargetLowering::DAGCombinerInfo &DCI,
1673 const LoongArchSubtarget &Subtarget) {
1674 if (DCI.isBeforeLegalizeOps())
1675 return SDValue();
1676
1677 SDValue Src = N->getOperand(0);
1678 if (Src.getOpcode() != LoongArchISD::REVB_2W)
1679 return SDValue();
1680
1681 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
1682 Src.getOperand(0));
1683}
1684
1685SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
1686 DAGCombinerInfo &DCI) const {
1687 SelectionDAG &DAG = DCI.DAG;
1688 switch (N->getOpcode()) {
1689 default:
1690 break;
1691 case ISD::AND:
1692 return performANDCombine(N, DAG, DCI, Subtarget);
1693 case ISD::OR:
1694 return performORCombine(N, DAG, DCI, Subtarget);
1695 case ISD::SRL:
1696 return performSRLCombine(N, DAG, DCI, Subtarget);
1697 case LoongArchISD::BITREV_W:
1698 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
1699 }
1700 return SDValue();
1701}
1702
1703static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI,
1704 MachineBasicBlock *MBB) {
1705 if (!ZeroDivCheck)
1706 return MBB;
1707
1708 // Build instructions:
1709 // MBB:
1710 // div(or mod) $dst, $dividend, $divisor
1711 // bnez $divisor, SinkMBB
1712 // BreakMBB:
1713 // break 7 // BRK_DIVZERO
1714 // SinkMBB:
1715 // fallthrough
1716 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
1717 MachineFunction::iterator It = ++MBB->getIterator();
1718 MachineFunction *MF = MBB->getParent();
1719 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1720 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1721 MF->insert(It, BreakMBB);
1722 MF->insert(It, SinkMBB);
1723
1724 // Transfer the remainder of MBB and its successor edges to SinkMBB.
1725 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
1726 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
1727
1728 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
1729 DebugLoc DL = MI.getDebugLoc();
1730 MachineOperand &Divisor = MI.getOperand(2);
1731 Register DivisorReg = Divisor.getReg();
1732
1733 // MBB:
1734 BuildMI(MBB, DL, TII.get(LoongArch::BNEZ))
1735 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
1736 .addMBB(SinkMBB);
1737 MBB->addSuccessor(BreakMBB);
1738 MBB->addSuccessor(SinkMBB);
1739
1740 // BreakMBB:
1741 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
1742 // definition of BRK_DIVZERO.
1743 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
1744 BreakMBB->addSuccessor(SinkMBB);
1745
1746 // Clear Divisor's kill flag.
1747 Divisor.setIsKill(false);
1748
1749 return SinkMBB;
1750}
1751
1752MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
1753 MachineInstr &MI, MachineBasicBlock *BB) const {
1754 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
1755 DebugLoc DL = MI.getDebugLoc();
1756
1757 switch (MI.getOpcode()) {
1758 default:
1759 llvm_unreachable("Unexpected instr type to insert")::llvm::llvm_unreachable_internal("Unexpected instr type to insert"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1759
)
;
1760 case LoongArch::DIV_W:
1761 case LoongArch::DIV_WU:
1762 case LoongArch::MOD_W:
1763 case LoongArch::MOD_WU:
1764 case LoongArch::DIV_D:
1765 case LoongArch::DIV_DU:
1766 case LoongArch::MOD_D:
1767 case LoongArch::MOD_DU:
1768 return insertDivByZeroTrap(MI, BB);
1769 break;
1770 case LoongArch::WRFCSR: {
1771 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
1772 LoongArch::FCSR0 + MI.getOperand(0).getImm())
1773 .addReg(MI.getOperand(1).getReg());
1774 MI.eraseFromParent();
1775 return BB;
1776 }
1777 case LoongArch::RDFCSR: {
1778 MachineInstr *ReadFCSR =
1779 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
1780 MI.getOperand(0).getReg())
1781 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
1782 ReadFCSR->getOperand(1).setIsUndef();
1783 MI.eraseFromParent();
1784 return BB;
1785 }
1786 }
1787}
1788
1789const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
1790 switch ((LoongArchISD::NodeType)Opcode) {
1791 case LoongArchISD::FIRST_NUMBER:
1792 break;
1793
1794#define NODE_NAME_CASE(node) \
1795 case LoongArchISD::node: \
1796 return "LoongArchISD::" #node;
1797
1798 // TODO: Add more target-dependent nodes later.
1799 NODE_NAME_CASE(CALL)
1800 NODE_NAME_CASE(RET)
1801 NODE_NAME_CASE(TAIL)
1802 NODE_NAME_CASE(SLL_W)
1803 NODE_NAME_CASE(SRA_W)
1804 NODE_NAME_CASE(SRL_W)
1805 NODE_NAME_CASE(BSTRINS)
1806 NODE_NAME_CASE(BSTRPICK)
1807 NODE_NAME_CASE(MOVGR2FR_W_LA64)
1808 NODE_NAME_CASE(MOVFR2GR_S_LA64)
1809 NODE_NAME_CASE(FTINT)
1810 NODE_NAME_CASE(REVB_2H)
1811 NODE_NAME_CASE(REVB_2W)
1812 NODE_NAME_CASE(BITREV_4B)
1813 NODE_NAME_CASE(BITREV_W)
1814 NODE_NAME_CASE(ROTR_W)
1815 NODE_NAME_CASE(ROTL_W)
1816 NODE_NAME_CASE(CLZ_W)
1817 NODE_NAME_CASE(CTZ_W)
1818 NODE_NAME_CASE(DBAR)
1819 NODE_NAME_CASE(IBAR)
1820 NODE_NAME_CASE(BREAK)
1821 NODE_NAME_CASE(SYSCALL)
1822 NODE_NAME_CASE(CRC_W_B_W)
1823 NODE_NAME_CASE(CRC_W_H_W)
1824 NODE_NAME_CASE(CRC_W_W_W)
1825 NODE_NAME_CASE(CRC_W_D_W)
1826 NODE_NAME_CASE(CRCC_W_B_W)
1827 NODE_NAME_CASE(CRCC_W_H_W)
1828 NODE_NAME_CASE(CRCC_W_W_W)
1829 NODE_NAME_CASE(CRCC_W_D_W)
1830 NODE_NAME_CASE(CSRRD)
1831 NODE_NAME_CASE(CSRWR)
1832 NODE_NAME_CASE(CSRXCHG)
1833 NODE_NAME_CASE(IOCSRRD_B)
1834 NODE_NAME_CASE(IOCSRRD_H)
1835 NODE_NAME_CASE(IOCSRRD_W)
1836 NODE_NAME_CASE(IOCSRRD_D)
1837 NODE_NAME_CASE(IOCSRWR_B)
1838 NODE_NAME_CASE(IOCSRWR_H)
1839 NODE_NAME_CASE(IOCSRWR_W)
1840 NODE_NAME_CASE(IOCSRWR_D)
1841 NODE_NAME_CASE(CPUCFG)
1842 NODE_NAME_CASE(MOVGR2FCSR)
1843 NODE_NAME_CASE(MOVFCSR2GR)
1844 NODE_NAME_CASE(CACOP_D)
1845 NODE_NAME_CASE(CACOP_W)
1846 }
1847#undef NODE_NAME_CASE
1848 return nullptr;
1849}
1850
1851//===----------------------------------------------------------------------===//
1852// Calling Convention Implementation
1853//===----------------------------------------------------------------------===//
1854
1855// Eight general-purpose registers a0-a7 used for passing integer arguments,
1856// with a0-a1 reused to return values. Generally, the GPRs are used to pass
1857// fixed-point arguments, and floating-point arguments when no FPR is available
1858// or with soft float ABI.
1859const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
1860 LoongArch::R7, LoongArch::R8, LoongArch::R9,
1861 LoongArch::R10, LoongArch::R11};
1862// Eight floating-point registers fa0-fa7 used for passing floating-point
1863// arguments, and fa0-fa1 are also used to return values.
1864const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
1865 LoongArch::F3, LoongArch::F4, LoongArch::F5,
1866 LoongArch::F6, LoongArch::F7};
1867// FPR32 and FPR64 alias each other.
1868const MCPhysReg ArgFPR64s[] = {
1869 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
1870 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
1871
1872// Pass a 2*GRLen argument that has been split into two GRLen values through
1873// registers or the stack as necessary.
1874static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
1875 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
1876 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
1877 ISD::ArgFlagsTy ArgFlags2) {
1878 unsigned GRLenInBytes = GRLen / 8;
1879 if (Register Reg = State.AllocateReg(ArgGPRs)) {
1880 // At least one half can be passed via register.
1881 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
1882 VA1.getLocVT(), CCValAssign::Full));
1883 } else {
1884 // Both halves must be passed on the stack, with proper alignment.
1885 Align StackAlign =
1886 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
1887 State.addLoc(
1888 CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(),
1889 State.AllocateStack(GRLenInBytes, StackAlign),
1890 VA1.getLocVT(), CCValAssign::Full));
1891 State.addLoc(CCValAssign::getMem(
1892 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1893 LocVT2, CCValAssign::Full));
1894 return false;
1895 }
1896 if (Register Reg = State.AllocateReg(ArgGPRs)) {
1897 // The second half can also be passed via register.
1898 State.addLoc(
1899 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
1900 } else {
1901 // The second half is passed via the stack, without additional alignment.
1902 State.addLoc(CCValAssign::getMem(
1903 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1904 LocVT2, CCValAssign::Full));
1905 }
1906 return false;
1907}
1908
1909// Implements the LoongArch calling convention. Returns true upon failure.
1910static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI,
1911 unsigned ValNo, MVT ValVT,
1912 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
1913 CCState &State, bool IsFixed, bool IsRet,
1914 Type *OrigTy) {
1915 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
1916 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen")(static_cast <bool> ((GRLen == 32 || GRLen == 64) &&
"Unspport GRLen") ? void (0) : __assert_fail ("(GRLen == 32 || GRLen == 64) && \"Unspport GRLen\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1916
, __extension__ __PRETTY_FUNCTION__))
;
1917 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
1918 MVT LocVT = ValVT;
1919
1920 // Any return value split into more than two values can't be returned
1921 // directly.
1922 if (IsRet && ValNo > 1)
1923 return true;
1924
1925 // If passing a variadic argument, or if no FPR is available.
1926 bool UseGPRForFloat = true;
1927
1928 switch (ABI) {
1929 default:
1930 llvm_unreachable("Unexpected ABI")::llvm::llvm_unreachable_internal("Unexpected ABI", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 1930)
;
1931 case LoongArchABI::ABI_ILP32S:
1932 case LoongArchABI::ABI_LP64S:
1933 case LoongArchABI::ABI_ILP32F:
1934 case LoongArchABI::ABI_LP64F:
1935 report_fatal_error("Unimplemented ABI");
1936 break;
1937 case LoongArchABI::ABI_ILP32D:
1938 case LoongArchABI::ABI_LP64D:
1939 UseGPRForFloat = !IsFixed;
1940 break;
1941 }
1942
1943 // FPR32 and FPR64 alias each other.
1944 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
1945 UseGPRForFloat = true;
1946
1947 if (UseGPRForFloat && ValVT == MVT::f32) {
1948 LocVT = GRLenVT;
1949 LocInfo = CCValAssign::BCvt;
1950 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
1951 LocVT = MVT::i64;
1952 LocInfo = CCValAssign::BCvt;
1953 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
1954 // TODO: Handle passing f64 on LA32 with D feature.
1955 report_fatal_error("Passing f64 with GPR on LA32 is undefined");
1956 }
1957
1958 // If this is a variadic argument, the LoongArch calling convention requires
1959 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
1960 // byte alignment. An aligned register should be used regardless of whether
1961 // the original argument was split during legalisation or not. The argument
1962 // will not be passed by registers if the original type is larger than
1963 // 2*GRLen, so the register alignment rule does not apply.
1964 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
1965 if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
1966 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
1967 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
1968 // Skip 'odd' register if necessary.
1969 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
1970 State.AllocateReg(ArgGPRs);
1971 }
1972
1973 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
1974 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
1975 State.getPendingArgFlags();
1976
1977 assert(PendingLocs.size() == PendingArgFlags.size() &&(static_cast <bool> (PendingLocs.size() == PendingArgFlags
.size() && "PendingLocs and PendingArgFlags out of sync"
) ? void (0) : __assert_fail ("PendingLocs.size() == PendingArgFlags.size() && \"PendingLocs and PendingArgFlags out of sync\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1978
, __extension__ __PRETTY_FUNCTION__))
1978 "PendingLocs and PendingArgFlags out of sync")(static_cast <bool> (PendingLocs.size() == PendingArgFlags
.size() && "PendingLocs and PendingArgFlags out of sync"
) ? void (0) : __assert_fail ("PendingLocs.size() == PendingArgFlags.size() && \"PendingLocs and PendingArgFlags out of sync\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1978
, __extension__ __PRETTY_FUNCTION__))
;
1979
1980 // Split arguments might be passed indirectly, so keep track of the pending
1981 // values.
1982 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
1983 LocVT = GRLenVT;
1984 LocInfo = CCValAssign::Indirect;
1985 PendingLocs.push_back(
1986 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
1987 PendingArgFlags.push_back(ArgFlags);
1988 if (!ArgFlags.isSplitEnd()) {
1989 return false;
1990 }
1991 }
1992
1993 // If the split argument only had two elements, it should be passed directly
1994 // in registers or on the stack.
1995 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
1996 PendingLocs.size() <= 2) {
1997 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()")(static_cast <bool> (PendingLocs.size() == 2 &&
"Unexpected PendingLocs.size()") ? void (0) : __assert_fail (
"PendingLocs.size() == 2 && \"Unexpected PendingLocs.size()\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1997
, __extension__ __PRETTY_FUNCTION__))
;
1998 // Apply the normal calling convention rules to the first half of the
1999 // split argument.
2000 CCValAssign VA = PendingLocs[0];
2001 ISD::ArgFlagsTy AF = PendingArgFlags[0];
2002 PendingLocs.clear();
2003 PendingArgFlags.clear();
2004 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
2005 ArgFlags);
2006 }
2007
2008 // Allocate to a register if possible, or else a stack slot.
2009 Register Reg;
2010 unsigned StoreSizeBytes = GRLen / 8;
2011 Align StackAlign = Align(GRLen / 8);
2012
2013 if (ValVT == MVT::f32 && !UseGPRForFloat)
2014 Reg = State.AllocateReg(ArgFPR32s);
2015 else if (ValVT == MVT::f64 && !UseGPRForFloat)
2016 Reg = State.AllocateReg(ArgFPR64s);
2017 else
2018 Reg = State.AllocateReg(ArgGPRs);
2019
2020 unsigned StackOffset =
2021 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
2022
2023 // If we reach this point and PendingLocs is non-empty, we must be at the
2024 // end of a split argument that must be passed indirectly.
2025 if (!PendingLocs.empty()) {
2026 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()")(static_cast <bool> (ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()"
) ? void (0) : __assert_fail ("ArgFlags.isSplitEnd() && \"Expected ArgFlags.isSplitEnd()\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2026
, __extension__ __PRETTY_FUNCTION__))
;
2027 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()")(static_cast <bool> (PendingLocs.size() > 2 &&
"Unexpected PendingLocs.size()") ? void (0) : __assert_fail (
"PendingLocs.size() > 2 && \"Unexpected PendingLocs.size()\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2027
, __extension__ __PRETTY_FUNCTION__))
;
2028 for (auto &It : PendingLocs) {
2029 if (Reg)
2030 It.convertToReg(Reg);
2031 else
2032 It.convertToMem(StackOffset);
2033 State.addLoc(It);
2034 }
2035 PendingLocs.clear();
2036 PendingArgFlags.clear();
2037 return false;
2038 }
2039 assert((!UseGPRForFloat || LocVT == GRLenVT) &&(static_cast <bool> ((!UseGPRForFloat || LocVT == GRLenVT
) && "Expected an GRLenVT at this stage") ? void (0) :
__assert_fail ("(!UseGPRForFloat || LocVT == GRLenVT) && \"Expected an GRLenVT at this stage\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2040
, __extension__ __PRETTY_FUNCTION__))
2040 "Expected an GRLenVT at this stage")(static_cast <bool> ((!UseGPRForFloat || LocVT == GRLenVT
) && "Expected an GRLenVT at this stage") ? void (0) :
__assert_fail ("(!UseGPRForFloat || LocVT == GRLenVT) && \"Expected an GRLenVT at this stage\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2040
, __extension__ __PRETTY_FUNCTION__))
;
2041
2042 if (Reg) {
2043 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2044 return false;
2045 }
2046
2047 // When a floating-point value is passed on the stack, no bit-cast is needed.
2048 if (ValVT.isFloatingPoint()) {
2049 LocVT = ValVT;
2050 LocInfo = CCValAssign::Full;
2051 }
2052
2053 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
2054 return false;
2055}
2056
2057void LoongArchTargetLowering::analyzeInputArgs(
2058 MachineFunction &MF, CCState &CCInfo,
2059 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
2060 LoongArchCCAssignFn Fn) const {
2061 FunctionType *FType = MF.getFunction().getFunctionType();
2062 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
2063 MVT ArgVT = Ins[i].VT;
2064 Type *ArgTy = nullptr;
2065 if (IsRet)
2066 ArgTy = FType->getReturnType();
2067 else if (Ins[i].isOrigArg())
2068 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
2069 LoongArchABI::ABI ABI =
2070 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2071 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
2072 CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) {
2073 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "InputArg #" <<
i << " has unhandled type " << ArgVT << '\n'
; } } while (false)
2074 << ArgVT << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "InputArg #" <<
i << " has unhandled type " << ArgVT << '\n'
; } } while (false)
;
2075 llvm_unreachable("")::llvm::llvm_unreachable_internal("", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2075)
;
2076 }
2077 }
2078}
2079
2080void LoongArchTargetLowering::analyzeOutputArgs(
2081 MachineFunction &MF, CCState &CCInfo,
2082 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
2083 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
2084 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2085 MVT ArgVT = Outs[i].VT;
2086 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
2087 LoongArchABI::ABI ABI =
2088 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2089 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
2090 CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
2091 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "OutputArg #" <<
i << " has unhandled type " << ArgVT << "\n"
; } } while (false)
2092 << ArgVT << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "OutputArg #" <<
i << " has unhandled type " << ArgVT << "\n"
; } } while (false)
;
2093 llvm_unreachable("")::llvm::llvm_unreachable_internal("", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2093)
;
2094 }
2095 }
2096}
2097
2098// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
2099// values.
2100static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
2101 const CCValAssign &VA, const SDLoc &DL) {
2102 switch (VA.getLocInfo()) {
2103 default:
2104 llvm_unreachable("Unexpected CCValAssign::LocInfo")::llvm::llvm_unreachable_internal("Unexpected CCValAssign::LocInfo"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2104
)
;
2105 case CCValAssign::Full:
2106 case CCValAssign::Indirect:
2107 break;
2108 case CCValAssign::BCvt:
2109 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2110 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
2111 else
2112 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
2113 break;
2114 }
2115 return Val;
2116}
2117
2118static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
2119 const CCValAssign &VA, const SDLoc &DL,
2120 const LoongArchTargetLowering &TLI) {
2121 MachineFunction &MF = DAG.getMachineFunction();
2122 MachineRegisterInfo &RegInfo = MF.getRegInfo();
2123 EVT LocVT = VA.getLocVT();
2124 SDValue Val;
2125 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
2126 Register VReg = RegInfo.createVirtualRegister(RC);
2127 RegInfo.addLiveIn(VA.getLocReg(), VReg);
2128 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
2129
2130 return convertLocVTToValVT(DAG, Val, VA, DL);
2131}
2132
2133// The caller is responsible for loading the full value if the argument is
2134// passed with CCValAssign::Indirect.
2135static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
2136 const CCValAssign &VA, const SDLoc &DL) {
2137 MachineFunction &MF = DAG.getMachineFunction();
2138 MachineFrameInfo &MFI = MF.getFrameInfo();
2139 EVT ValVT = VA.getValVT();
2140 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
2141 /*IsImmutable=*/true);
2142 SDValue FIN = DAG.getFrameIndex(
2143 FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)));
2144
2145 ISD::LoadExtType ExtType;
2146 switch (VA.getLocInfo()) {
2147 default:
2148 llvm_unreachable("Unexpected CCValAssign::LocInfo")::llvm::llvm_unreachable_internal("Unexpected CCValAssign::LocInfo"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2148
)
;
2149 case CCValAssign::Full:
2150 case CCValAssign::Indirect:
2151 case CCValAssign::BCvt:
2152 ExtType = ISD::NON_EXTLOAD;
2153 break;
2154 }
2155 return DAG.getExtLoad(
2156 ExtType, DL, VA.getLocVT(), Chain, FIN,
2157 MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
2158}
2159
2160static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
2161 const CCValAssign &VA, const SDLoc &DL) {
2162 EVT LocVT = VA.getLocVT();
2163
2164 switch (VA.getLocInfo()) {
2165 default:
2166 llvm_unreachable("Unexpected CCValAssign::LocInfo")::llvm::llvm_unreachable_internal("Unexpected CCValAssign::LocInfo"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2166
)
;
2167 case CCValAssign::Full:
2168 break;
2169 case CCValAssign::BCvt:
2170 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2171 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
2172 else
2173 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
2174 break;
2175 }
2176 return Val;
2177}
2178
2179static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
2180 CCValAssign::LocInfo LocInfo,
2181 ISD::ArgFlagsTy ArgFlags, CCState &State) {
2182 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
2183 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
2184 // s0 s1 s2 s3 s4 s5 s6 s7 s8
2185 static const MCPhysReg GPRList[] = {
2186 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26, LoongArch::R27,
2187 LoongArch::R28, LoongArch::R29, LoongArch::R30, LoongArch::R31};
2188 if (unsigned Reg = State.AllocateReg(GPRList)) {
2189 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2190 return false;
2191 }
2192 }
2193
2194 if (LocVT == MVT::f32) {
2195 // Pass in STG registers: F1, F2, F3, F4
2196 // fs0,fs1,fs2,fs3
2197 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
2198 LoongArch::F26, LoongArch::F27};
2199 if (unsigned Reg = State.AllocateReg(FPR32List)) {
2200 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2201 return false;
2202 }
2203 }
2204
2205 if (LocVT == MVT::f64) {
2206 // Pass in STG registers: D1, D2, D3, D4
2207 // fs4,fs5,fs6,fs7
2208 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
2209 LoongArch::F30_64, LoongArch::F31_64};
2210 if (unsigned Reg = State.AllocateReg(FPR64List)) {
2211 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2212 return false;
2213 }
2214 }
2215
2216 report_fatal_error("No registers left in GHC calling convention");
2217 return true;
2218}
2219
2220// Transform physical registers into virtual registers.
2221SDValue LoongArchTargetLowering::LowerFormalArguments(
2222 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
2223 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
2224 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
2225
2226 MachineFunction &MF = DAG.getMachineFunction();
2227
2228 switch (CallConv) {
2229 default:
2230 llvm_unreachable("Unsupported calling convention")::llvm::llvm_unreachable_internal("Unsupported calling convention"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2230
)
;
2231 case CallingConv::C:
2232 case CallingConv::Fast:
2233 break;
2234 case CallingConv::GHC:
2235 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
2236 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
2237 report_fatal_error(
2238 "GHC calling convention requires the F and D extensions");
2239 }
2240
2241 EVT PtrVT = getPointerTy(DAG.getDataLayout());
2242 MVT GRLenVT = Subtarget.getGRLenVT();
2243 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
2244 // Used with varargs to acumulate store chains.
2245 std::vector<SDValue> OutChains;
2246
2247 // Assign locations to all of the incoming arguments.
2248 SmallVector<CCValAssign> ArgLocs;
2249 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
2250
2251 if (CallConv == CallingConv::GHC)
2252 CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC);
2253 else
2254 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
2255
2256 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
2257 CCValAssign &VA = ArgLocs[i];
2258 SDValue ArgValue;
2259 if (VA.isRegLoc())
2260 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, *this);
2261 else
2262 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
2263 if (VA.getLocInfo() == CCValAssign::Indirect) {
2264 // If the original argument was split and passed by reference, we need to
2265 // load all parts of it here (using the same address).
2266 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
2267 MachinePointerInfo()));
2268 unsigned ArgIndex = Ins[i].OrigArgIndex;
2269 unsigned ArgPartOffset = Ins[i].PartOffset;
2270 assert(ArgPartOffset == 0)(static_cast <bool> (ArgPartOffset == 0) ? void (0) : __assert_fail
("ArgPartOffset == 0", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2270, __extension__ __PRETTY_FUNCTION__))
;
2271 while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) {
2272 CCValAssign &PartVA = ArgLocs[i + 1];
2273 unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset;
2274 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2275 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
2276 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
2277 MachinePointerInfo()));
2278 ++i;
2279 }
2280 continue;
2281 }
2282 InVals.push_back(ArgValue);
2283 }
2284
2285 if (IsVarArg) {
2286 ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs);
2287 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
2288 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
2289 MachineFrameInfo &MFI = MF.getFrameInfo();
2290 MachineRegisterInfo &RegInfo = MF.getRegInfo();
2291 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
2292
2293 // Offset of the first variable argument from stack pointer, and size of
2294 // the vararg save area. For now, the varargs save area is either zero or
2295 // large enough to hold a0-a7.
2296 int VaArgOffset, VarArgsSaveSize;
2297
2298 // If all registers are allocated, then all varargs must be passed on the
2299 // stack and we don't need to save any argregs.
2300 if (ArgRegs.size() == Idx) {
2301 VaArgOffset = CCInfo.getNextStackOffset();
2302 VarArgsSaveSize = 0;
2303 } else {
2304 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
2305 VaArgOffset = -VarArgsSaveSize;
2306 }
2307
2308 // Record the frame index of the first variable argument
2309 // which is a value necessary to VASTART.
2310 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2311 LoongArchFI->setVarArgsFrameIndex(FI);
2312
2313 // If saving an odd number of registers then create an extra stack slot to
2314 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
2315 // offsets to even-numbered registered remain 2*GRLen-aligned.
2316 if (Idx % 2) {
2317 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
2318 true);
2319 VarArgsSaveSize += GRLenInBytes;
2320 }
2321
2322 // Copy the integer registers that may have been used for passing varargs
2323 // to the vararg save area.
2324 for (unsigned I = Idx; I < ArgRegs.size();
2325 ++I, VaArgOffset += GRLenInBytes) {
2326 const Register Reg = RegInfo.createVirtualRegister(RC);
2327 RegInfo.addLiveIn(ArgRegs[I], Reg);
2328 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
2329 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2330 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2331 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
2332 MachinePointerInfo::getFixedStack(MF, FI));
2333 cast<StoreSDNode>(Store.getNode())
2334 ->getMemOperand()
2335 ->setValue((Value *)nullptr);
2336 OutChains.push_back(Store);
2337 }
2338 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
2339 }
2340
2341 // All stores are grouped in one node to allow the matching between
2342 // the size of Ins and InVals. This only happens for vararg functions.
2343 if (!OutChains.empty()) {
2344 OutChains.push_back(Chain);
2345 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
2346 }
2347
2348 return Chain;
2349}
2350
2351bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
2352 return CI->isTailCall();
2353}
2354
2355// Check if the return value is used as only a return value, as otherwise
2356// we can't perform a tail-call.
2357bool LoongArchTargetLowering::isUsedByReturnOnly(SDNode *N,
2358 SDValue &Chain) const {
2359 if (N->getNumValues() != 1)
2360 return false;
2361 if (!N->hasNUsesOfValue(1, 0))
2362 return false;
2363
2364 SDNode *Copy = *N->use_begin();
2365 if (Copy->getOpcode() != ISD::CopyToReg)
2366 return false;
2367
2368 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
2369 // isn't safe to perform a tail call.
2370 if (Copy->getGluedNode())
2371 return false;
2372
2373 // The copy must be used by a LoongArchISD::RET, and nothing else.
2374 bool HasRet = false;
2375 for (SDNode *Node : Copy->uses()) {
2376 if (Node->getOpcode() != LoongArchISD::RET)
2377 return false;
2378 HasRet = true;
2379 }
2380
2381 if (!HasRet)
2382 return false;
2383
2384 Chain = Copy->getOperand(0);
2385 return true;
2386}
2387
2388// Check whether the call is eligible for tail call optimization.
2389bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
2390 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
2391 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
2392
2393 auto CalleeCC = CLI.CallConv;
2394 auto &Outs = CLI.Outs;
2395 auto &Caller = MF.getFunction();
2396 auto CallerCC = Caller.getCallingConv();
2397
2398 // Do not tail call opt if the stack is used to pass parameters.
2399 if (CCInfo.getNextStackOffset() != 0)
2400 return false;
2401
2402 // Do not tail call opt if any parameters need to be passed indirectly.
2403 for (auto &VA : ArgLocs)
2404 if (VA.getLocInfo() == CCValAssign::Indirect)
2405 return false;
2406
2407 // Do not tail call opt if either caller or callee uses struct return
2408 // semantics.
2409 auto IsCallerStructRet = Caller.hasStructRetAttr();
2410 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
2411 if (IsCallerStructRet || IsCalleeStructRet)
2412 return false;
2413
2414 // Do not tail call opt if either the callee or caller has a byval argument.
2415 for (auto &Arg : Outs)
2416 if (Arg.Flags.isByVal())
2417 return false;
2418
2419 // The callee has to preserve all registers the caller needs to preserve.
2420 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
2421 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
2422 if (CalleeCC != CallerCC) {
2423 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
2424 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
2425 return false;
2426 }
2427 return true;
2428}
2429
2430static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) {
2431 return DAG.getDataLayout().getPrefTypeAlign(
2432 VT.getTypeForEVT(*DAG.getContext()));
2433}
2434
2435// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
2436// and output parameter nodes.
2437SDValue
2438LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
2439 SmallVectorImpl<SDValue> &InVals) const {
2440 SelectionDAG &DAG = CLI.DAG;
2441 SDLoc &DL = CLI.DL;
2442 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
2443 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
2444 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
2445 SDValue Chain = CLI.Chain;
2446 SDValue Callee = CLI.Callee;
2447 CallingConv::ID CallConv = CLI.CallConv;
2448 bool IsVarArg = CLI.IsVarArg;
2449 EVT PtrVT = getPointerTy(DAG.getDataLayout());
2450 MVT GRLenVT = Subtarget.getGRLenVT();
2451 bool &IsTailCall = CLI.IsTailCall;
2452
2453 MachineFunction &MF = DAG.getMachineFunction();
2454
2455 // Analyze the operands of the call, assigning locations to each operand.
2456 SmallVector<CCValAssign> ArgLocs;
2457 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
2458
2459 if (CallConv == CallingConv::GHC)
2460 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
2461 else
2462 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
2463
2464 // Check if it's really possible to do a tail call.
2465 if (IsTailCall)
2466 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
2467
2468 if (IsTailCall)
2469 ++NumTailCalls;
2470 else if (CLI.CB && CLI.CB->isMustTailCall())
2471 report_fatal_error("failed to perform tail call elimination on a call "
2472 "site marked musttail");
2473
2474 // Get a count of how many bytes are to be pushed on the stack.
2475 unsigned NumBytes = ArgCCInfo.getNextStackOffset();
2476
2477 // Create local copies for byval args.
2478 SmallVector<SDValue> ByValArgs;
2479 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2480 ISD::ArgFlagsTy Flags = Outs[i].Flags;
2481 if (!Flags.isByVal())
2482 continue;
2483
2484 SDValue Arg = OutVals[i];
2485 unsigned Size = Flags.getByValSize();
2486 Align Alignment = Flags.getNonZeroByValAlign();
2487
2488 int FI =
2489 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
2490 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2491 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
2492
2493 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
2494 /*IsVolatile=*/false,
2495 /*AlwaysInline=*/false, /*isTailCall=*/IsTailCall,
2496 MachinePointerInfo(), MachinePointerInfo());
2497 ByValArgs.push_back(FIPtr);
2498 }
2499
2500 if (!IsTailCall)
2501 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
2502
2503 // Copy argument values to their designated locations.
2504 SmallVector<std::pair<Register, SDValue>> RegsToPass;
2505 SmallVector<SDValue> MemOpChains;
2506 SDValue StackPtr;
2507 for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
2508 CCValAssign &VA = ArgLocs[i];
2509 SDValue ArgValue = OutVals[i];
2510 ISD::ArgFlagsTy Flags = Outs[i].Flags;
2511
2512 // Promote the value if needed.
2513 // For now, only handle fully promoted and indirect arguments.
2514 if (VA.getLocInfo() == CCValAssign::Indirect) {
2515 // Store the argument in a stack slot and pass its address.
2516 Align StackAlign =
2517 std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG),
2518 getPrefTypeAlign(ArgValue.getValueType(), DAG));
2519 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
2520 // If the original argument was split and passed by reference, we need to
2521 // store the required parts of it here (and pass just one address).
2522 unsigned ArgIndex = Outs[i].OrigArgIndex;
2523 unsigned ArgPartOffset = Outs[i].PartOffset;
2524 assert(ArgPartOffset == 0)(static_cast <bool> (ArgPartOffset == 0) ? void (0) : __assert_fail
("ArgPartOffset == 0", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2524, __extension__ __PRETTY_FUNCTION__))
;
2525 // Calculate the total size to store. We don't have access to what we're
2526 // actually storing other than performing the loop and collecting the
2527 // info.
2528 SmallVector<std::pair<SDValue, SDValue>> Parts;
2529 while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) {
2530 SDValue PartValue = OutVals[i + 1];
2531 unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset;
2532 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2533 EVT PartVT = PartValue.getValueType();
2534
2535 StoredSize += PartVT.getStoreSize();
2536 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
2537 Parts.push_back(std::make_pair(PartValue, Offset));
2538 ++i;
2539 }
2540 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
2541 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
2542 MemOpChains.push_back(
2543 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
2544 MachinePointerInfo::getFixedStack(MF, FI)));
2545 for (const auto &Part : Parts) {
2546 SDValue PartValue = Part.first;
2547 SDValue PartOffset = Part.second;
2548 SDValue Address =
2549 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
2550 MemOpChains.push_back(
2551 DAG.getStore(Chain, DL, PartValue, Address,
2552 MachinePointerInfo::getFixedStack(MF, FI)));
2553 }
2554 ArgValue = SpillSlot;
2555 } else {
2556 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
2557 }
2558
2559 // Use local copy if it is a byval arg.
2560 if (Flags.isByVal())
2561 ArgValue = ByValArgs[j++];
2562
2563 if (VA.isRegLoc()) {
2564 // Queue up the argument copies and emit them at the end.
2565 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
2566 } else {
2567 assert(VA.isMemLoc() && "Argument not register or memory")(static_cast <bool> (VA.isMemLoc() && "Argument not register or memory"
) ? void (0) : __assert_fail ("VA.isMemLoc() && \"Argument not register or memory\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2567
, __extension__ __PRETTY_FUNCTION__))
;
2568 assert(!IsTailCall && "Tail call not allowed if stack is used "(static_cast <bool> (!IsTailCall && "Tail call not allowed if stack is used "
"for passing parameters") ? void (0) : __assert_fail ("!IsTailCall && \"Tail call not allowed if stack is used \" \"for passing parameters\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2569
, __extension__ __PRETTY_FUNCTION__))
2569 "for passing parameters")(static_cast <bool> (!IsTailCall && "Tail call not allowed if stack is used "
"for passing parameters") ? void (0) : __assert_fail ("!IsTailCall && \"Tail call not allowed if stack is used \" \"for passing parameters\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2569
, __extension__ __PRETTY_FUNCTION__))
;
2570
2571 // Work out the address of the stack slot.
2572 if (!StackPtr.getNode())
2573 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
2574 SDValue Address =
2575 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
2576 DAG.getIntPtrConstant(VA.getLocMemOffset(), DL));
2577
2578 // Emit the store.
2579 MemOpChains.push_back(
2580 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
2581 }
2582 }
2583
2584 // Join the stores, which are independent of one another.
2585 if (!MemOpChains.empty())
2586 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
2587
2588 SDValue Glue;
2589
2590 // Build a sequence of copy-to-reg nodes, chained and glued together.
2591 for (auto &Reg : RegsToPass) {
2592 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
2593 Glue = Chain.getValue(1);
2594 }
2595
2596 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
2597 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
2598 // split it and then direct call can be matched by PseudoCALL.
2599 if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
2600 const GlobalValue *GV = S->getGlobal();
2601 unsigned OpFlags =
2602 getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)
2603 ? LoongArchII::MO_CALL
2604 : LoongArchII::MO_CALL_PLT;
2605 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
2606 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
2607 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(
2608 *MF.getFunction().getParent(), nullptr)
2609 ? LoongArchII::MO_CALL
2610 : LoongArchII::MO_CALL_PLT;
2611 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
2612 }
2613
2614 // The first call operand is the chain and the second is the target address.
2615 SmallVector<SDValue> Ops;
2616 Ops.push_back(Chain);
2617 Ops.push_back(Callee);
2618
2619 // Add argument registers to the end of the list so that they are
2620 // known live into the call.
2621 for (auto &Reg : RegsToPass)
2622 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
2623
2624 if (!IsTailCall) {
2625 // Add a register mask operand representing the call-preserved registers.
2626 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
2627 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
2628 assert(Mask && "Missing call preserved mask for calling convention")(static_cast <bool> (Mask && "Missing call preserved mask for calling convention"
) ? void (0) : __assert_fail ("Mask && \"Missing call preserved mask for calling convention\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2628
, __extension__ __PRETTY_FUNCTION__))
;
2629 Ops.push_back(DAG.getRegisterMask(Mask));
2630 }
2631
2632 // Glue the call to the argument copies, if any.
2633 if (Glue.getNode())
2634 Ops.push_back(Glue);
2635
2636 // Emit the call.
2637 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
2638
2639 if (IsTailCall) {
2640 MF.getFrameInfo().setHasTailCall();
2641 return DAG.getNode(LoongArchISD::TAIL, DL, NodeTys, Ops);
2642 }
2643
2644 Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops);
2645 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
2646 Glue = Chain.getValue(1);
2647
2648 // Mark the end of the call, which is glued to the call itself.
2649 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
2650 Glue = Chain.getValue(1);
2651
2652 // Assign locations to each value returned by this call.
2653 SmallVector<CCValAssign> RVLocs;
2654 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
2655 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
2656
2657 // Copy all of the result registers out of their specified physreg.
2658 for (auto &VA : RVLocs) {
2659 // Copy the value out.
2660 SDValue RetValue =
2661 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
2662 // Glue the RetValue to the end of the call sequence.
2663 Chain = RetValue.getValue(1);
2664 Glue = RetValue.getValue(2);
2665
2666 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
2667
2668 InVals.push_back(RetValue);
2669 }
2670
2671 return Chain;
2672}
2673
2674bool LoongArchTargetLowering::CanLowerReturn(
2675 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
2676 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
2677 SmallVector<CCValAssign> RVLocs;
2678 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
2679
2680 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2681 LoongArchABI::ABI ABI =
2682 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2683 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
2684 Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true,
2685 nullptr))
2686 return false;
2687 }
2688 return true;
2689}
2690
2691SDValue LoongArchTargetLowering::LowerReturn(
2692 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
2693 const SmallVectorImpl<ISD::OutputArg> &Outs,
2694 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
2695 SelectionDAG &DAG) const {
2696 // Stores the assignment of the return value to a location.
2697 SmallVector<CCValAssign> RVLocs;
2698
2699 // Info about the registers and stack slot.
2700 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
2701 *DAG.getContext());
2702
2703 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
2704 nullptr, CC_LoongArch);
2705 if (CallConv == CallingConv::GHC && !RVLocs.empty())
2706 report_fatal_error("GHC functions return void only");
2707 SDValue Glue;
2708 SmallVector<SDValue, 4> RetOps(1, Chain);
2709
2710 // Copy the result values into the output registers.
2711 for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
2712 CCValAssign &VA = RVLocs[i];
2713 assert(VA.isRegLoc() && "Can only return in registers!")(static_cast <bool> (VA.isRegLoc() && "Can only return in registers!"
) ? void (0) : __assert_fail ("VA.isRegLoc() && \"Can only return in registers!\""
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2713
, __extension__ __PRETTY_FUNCTION__))
;
2714
2715 // Handle a 'normal' return.
2716 SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL);
2717 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
2718
2719 // Guarantee that all emitted copies are stuck together.
2720 Glue = Chain.getValue(1);
2721 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
2722 }
2723
2724 RetOps[0] = Chain; // Update chain.
2725
2726 // Add the glue node if we have it.
2727 if (Glue.getNode())
2728 RetOps.push_back(Glue);
2729
2730 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
2731}
2732
2733bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
2734 bool ForCodeSize) const {
2735 // TODO: Maybe need more checks here after vector extension is supported.
2736 if (VT == MVT::f32 && !Subtarget.hasBasicF())
2737 return false;
2738 if (VT == MVT::f64 && !Subtarget.hasBasicD())
2739 return false;
2740 return (Imm.isZero() || Imm.isExactlyValue(+1.0));
2741}
2742
2743bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const {
2744 return true;
2745}
2746
2747bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const {
2748 return true;
2749}
2750
2751bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
2752 const Instruction *I) const {
2753 if (!Subtarget.is64Bit())
2754 return isa<LoadInst>(I) || isa<StoreInst>(I);
2755
2756 if (isa<LoadInst>(I))
2757 return true;
2758
2759 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
2760 // require fences beacuse we can use amswap_db.[w/d].
2761 if (isa<StoreInst>(I)) {
2762 unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth();
2763 return (Size == 8 || Size == 16);
2764 }
2765
2766 return false;
2767}
2768
2769EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL,
2770 LLVMContext &Context,
2771 EVT VT) const {
2772 if (!VT.isVector())
2773 return getPointerTy(DL);
2774 return VT.changeVectorElementTypeToInteger();
2775}
2776
2777bool LoongArchTargetLowering::hasAndNot(SDValue Y) const {
2778 // TODO: Support vectors.
2779 return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y);
2780}
2781
2782bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
2783 const CallInst &I,
2784 MachineFunction &MF,
2785 unsigned Intrinsic) const {
2786 switch (Intrinsic) {
2787 default:
2788 return false;
2789 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
2790 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
2791 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
2792 case Intrinsic::loongarch_masked_atomicrmw_nand_i32:
2793 Info.opc = ISD::INTRINSIC_W_CHAIN;
2794 Info.memVT = MVT::i32;
2795 Info.ptrVal = I.getArgOperand(0);
2796 Info.offset = 0;
2797 Info.align = Align(4);
2798 Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore |
2799 MachineMemOperand::MOVolatile;
2800 return true;
2801 // TODO: Add more Intrinsics later.
2802 }
2803}
2804
2805TargetLowering::AtomicExpansionKind
2806LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
2807 // TODO: Add more AtomicRMWInst that needs to be extended.
2808
2809 // Since floating-point operation requires a non-trivial set of data
2810 // operations, use CmpXChg to expand.
2811 if (AI->isFloatingPointOperation() ||
2812 AI->getOperation() == AtomicRMWInst::UIncWrap ||
2813 AI->getOperation() == AtomicRMWInst::UDecWrap)
2814 return AtomicExpansionKind::CmpXChg;
2815
2816 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
2817 if (Size == 8 || Size == 16)
2818 return AtomicExpansionKind::MaskedIntrinsic;
2819 return AtomicExpansionKind::None;
2820}
2821
2822static Intrinsic::ID
2823getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen,
2824 AtomicRMWInst::BinOp BinOp) {
2825 if (GRLen == 64) {
2826 switch (BinOp) {
2827 default:
2828 llvm_unreachable("Unexpected AtomicRMW BinOp")::llvm::llvm_unreachable_internal("Unexpected AtomicRMW BinOp"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2828
)
;
2829 case AtomicRMWInst::Xchg:
2830 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
2831 case AtomicRMWInst::Add:
2832 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
2833 case AtomicRMWInst::Sub:
2834 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
2835 case AtomicRMWInst::Nand:
2836 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
2837 case AtomicRMWInst::UMax:
2838 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
2839 case AtomicRMWInst::UMin:
2840 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
2841 case AtomicRMWInst::Max:
2842 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
2843 case AtomicRMWInst::Min:
2844 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
2845 // TODO: support other AtomicRMWInst.
2846 }
2847 }
2848
2849 if (GRLen == 32) {
2850 switch (BinOp) {
2851 default:
2852 llvm_unreachable("Unexpected AtomicRMW BinOp")::llvm::llvm_unreachable_internal("Unexpected AtomicRMW BinOp"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2852
)
;
2853 case AtomicRMWInst::Xchg:
2854 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
2855 case AtomicRMWInst::Add:
2856 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
2857 case AtomicRMWInst::Sub:
2858 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
2859 case AtomicRMWInst::Nand:
2860 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
2861 // TODO: support other AtomicRMWInst.
2862 }
2863 }
2864
2865 llvm_unreachable("Unexpected GRLen\n")::llvm::llvm_unreachable_internal("Unexpected GRLen\n", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2865)
;
2866}
2867
2868TargetLowering::AtomicExpansionKind
2869LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR(
2870 AtomicCmpXchgInst *CI) const {
2871 unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits();
2872 if (Size == 8 || Size == 16)
2873 return AtomicExpansionKind::MaskedIntrinsic;
2874 return AtomicExpansionKind::None;
2875}
2876
2877Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
2878 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
2879 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
2880 Value *Ordering =
2881 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(Ord));
2882
2883 // TODO: Support cmpxchg on LA32.
2884 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
2885 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
2886 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
2887 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2888 Type *Tys[] = {AlignedAddr->getType()};
2889 Function *MaskedCmpXchg =
2890 Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys);
2891 Value *Result = Builder.CreateCall(
2892 MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering});
2893 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2894 return Result;
2895}
2896
2897Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic(
2898 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
2899 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
2900 unsigned GRLen = Subtarget.getGRLen();
2901 Value *Ordering =
2902 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
2903 Type *Tys[] = {AlignedAddr->getType()};
2904 Function *LlwOpScwLoop = Intrinsic::getDeclaration(
2905 AI->getModule(),
2906 getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys);
2907
2908 if (GRLen == 64) {
2909 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
2910 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2911 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
2912 }
2913
2914 Value *Result;
2915
2916 // Must pass the shift amount needed to sign extend the loaded value prior
2917 // to performing a signed comparison for min/max. ShiftAmt is the number of
2918 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
2919 // is the number of bits to left+right shift the value in order to
2920 // sign-extend.
2921 if (AI->getOperation() == AtomicRMWInst::Min ||
2922 AI->getOperation() == AtomicRMWInst::Max) {
2923 const DataLayout &DL = AI->getModule()->getDataLayout();
2924 unsigned ValWidth =
2925 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
2926 Value *SextShamt =
2927 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
2928 Result = Builder.CreateCall(LlwOpScwLoop,
2929 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
2930 } else {
2931 Result =
2932 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
2933 }
2934
2935 if (GRLen == 64)
2936 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2937 return Result;
2938}
2939
2940bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd(
2941 const MachineFunction &MF, EVT VT) const {
2942 VT = VT.getScalarType();
2943
2944 if (!VT.isSimple())
2945 return false;
2946
2947 switch (VT.getSimpleVT().SimpleTy) {
2948 case MVT::f32:
2949 case MVT::f64:
2950 return true;
2951 default:
2952 break;
2953 }
2954
2955 return false;
2956}
2957
2958Register LoongArchTargetLowering::getExceptionPointerRegister(
2959 const Constant *PersonalityFn) const {
2960 return LoongArch::R4;
2961}
2962
2963Register LoongArchTargetLowering::getExceptionSelectorRegister(
2964 const Constant *PersonalityFn) const {
2965 return LoongArch::R5;
2966}
2967
2968//===----------------------------------------------------------------------===//
2969// LoongArch Inline Assembly Support
2970//===----------------------------------------------------------------------===//
2971
2972LoongArchTargetLowering::ConstraintType
2973LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
2974 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
2975 //
2976 // 'f': A floating-point register (if available).
2977 // 'k': A memory operand whose address is formed by a base register and
2978 // (optionally scaled) index register.
2979 // 'l': A signed 16-bit constant.
2980 // 'm': A memory operand whose address is formed by a base register and
2981 // offset that is suitable for use in instructions with the same
2982 // addressing mode as st.w and ld.w.
2983 // 'I': A signed 12-bit constant (for arithmetic instructions).
2984 // 'J': Integer zero.
2985 // 'K': An unsigned 12-bit constant (for logic instructions).
2986 // "ZB": An address that is held in a general-purpose register. The offset is
2987 // zero.
2988 // "ZC": A memory operand whose address is formed by a base register and
2989 // offset that is suitable for use in instructions with the same
2990 // addressing mode as ll.w and sc.w.
2991 if (Constraint.size() == 1) {
2992 switch (Constraint[0]) {
2993 default:
2994 break;
2995 case 'f':
2996 return C_RegisterClass;
2997 case 'l':
2998 case 'I':
2999 case 'J':
3000 case 'K':
3001 return C_Immediate;
3002 case 'k':
3003 return C_Memory;
3004 }
3005 }
3006
3007 if (Constraint == "ZC" || Constraint == "ZB")
3008 return C_Memory;
3009
3010 // 'm' is handled here.
3011 return TargetLowering::getConstraintType(Constraint);
3012}
3013
3014unsigned LoongArchTargetLowering::getInlineAsmMemConstraint(
3015 StringRef ConstraintCode) const {
3016 return StringSwitch<unsigned>(ConstraintCode)
3017 .Case("k", InlineAsm::Constraint_k)
3018 .Case("ZB", InlineAsm::Constraint_ZB)
3019 .Case("ZC", InlineAsm::Constraint_ZC)
3020 .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
3021}
3022
3023std::pair<unsigned, const TargetRegisterClass *>
3024LoongArchTargetLowering::getRegForInlineAsmConstraint(
3025 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
3026 // First, see if this is a constraint that directly corresponds to a LoongArch
3027 // register class.
3028 if (Constraint.size() == 1) {
3029 switch (Constraint[0]) {
3030 case 'r':
3031 // TODO: Support fixed vectors up to GRLen?
3032 if (VT.isVector())
3033 break;
3034 return std::make_pair(0U, &LoongArch::GPRRegClass);
3035 case 'f':
3036 if (Subtarget.hasBasicF() && VT == MVT::f32)
3037 return std::make_pair(0U, &LoongArch::FPR32RegClass);
3038 if (Subtarget.hasBasicD() && VT == MVT::f64)
3039 return std::make_pair(0U, &LoongArch::FPR64RegClass);
3040 break;
3041 default:
3042 break;
3043 }
3044 }
3045
3046 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
3047 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
3048 // constraints while the official register name is prefixed with a '$'. So we
3049 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
3050 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
3051 // case insensitive, so no need to convert the constraint to upper case here.
3052 //
3053 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
3054 // decode the usage of register name aliases into their official names. And
3055 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
3056 // official register names.
3057 if (Constraint.startswith("{$r") || Constraint.startswith("{$f")) {
3058 bool IsFP = Constraint[2] == 'f';
3059 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
3060 std::pair<unsigned, const TargetRegisterClass *> R;
3061 R = TargetLowering::getRegForInlineAsmConstraint(
3062 TRI, join_items("", Temp.first, Temp.second), VT);
3063 // Match those names to the widest floating point register type available.
3064 if (IsFP) {
3065 unsigned RegNo = R.first;
3066 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
3067 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
3068 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
3069 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
3070 }
3071 }
3072 }
3073 return R;
3074 }
3075
3076 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
3077}
3078
3079void LoongArchTargetLowering::LowerAsmOperandForConstraint(
3080 SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
3081 SelectionDAG &DAG) const {
3082 // Currently only support length 1 constraints.
3083 if (Constraint.length() == 1) {
3084 switch (Constraint[0]) {
3085 case 'l':
3086 // Validate & create a 16-bit signed immediate operand.
3087 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3088 uint64_t CVal = C->getSExtValue();
3089 if (isInt<16>(CVal))
3090 Ops.push_back(
3091 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3092 }
3093 return;
3094 case 'I':
3095 // Validate & create a 12-bit signed immediate operand.
3096 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3097 uint64_t CVal = C->getSExtValue();
3098 if (isInt<12>(CVal))
3099 Ops.push_back(
3100 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3101 }
3102 return;
3103 case 'J':
3104 // Validate & create an integer zero operand.
3105 if (auto *C = dyn_cast<ConstantSDNode>(Op))
3106 if (C->getZExtValue() == 0)
3107 Ops.push_back(
3108 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
3109 return;
3110 case 'K':
3111 // Validate & create a 12-bit unsigned immediate operand.
3112 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3113 uint64_t CVal = C->getZExtValue();
3114 if (isUInt<12>(CVal))
3115 Ops.push_back(
3116 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3117 }
3118 return;
3119 default:
3120 break;
3121 }
3122 }
3123 TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
3124}
3125
3126#define GET_REGISTER_MATCHER
3127#include "LoongArchGenAsmMatcher.inc"
3128
3129Register
3130LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT,
3131 const MachineFunction &MF) const {
3132 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
3133 std::string NewRegName = Name.second.str();
3134 Register Reg = MatchRegisterAltName(NewRegName);
3135 if (Reg == LoongArch::NoRegister)
3136 Reg = MatchRegisterName(NewRegName);
3137 if (Reg == LoongArch::NoRegister)
3138 report_fatal_error(
3139 Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
3140 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
3141 if (!ReservedRegs.test(Reg))
3142 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
3143 StringRef(RegName) + "\"."));
3144 return Reg;
3145}
3146
3147bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context,
3148 EVT VT, SDValue C) const {
3149 // TODO: Support vectors.
3150 if (!VT.isScalarInteger())
3151 return false;
3152
3153 // Omit the optimization if the data size exceeds GRLen.
3154 if (VT.getSizeInBits() > Subtarget.getGRLen())
3155 return false;
3156
3157 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
3158 const APInt &Imm = ConstNode->getAPIntValue();
3159 // Break MUL into (SLLI + ADD/SUB) or ALSL.
3160 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
3161 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
3162 return true;
3163 // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
3164 if (ConstNode->hasOneUse() &&
3165 ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
3166 (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
3167 return true;
3168 // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
3169 // in which the immediate has two set bits. Or Break (MUL x, imm)
3170 // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
3171 // equals to (1 << s0) - (1 << s1).
3172 if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
3173 unsigned Shifts = Imm.countr_zero();
3174 // Reject immediates which can be composed via a single LUI.
3175 if (Shifts >= 12)
3176 return false;
3177 // Reject multiplications can be optimized to
3178 // (SLLI (ALSL x, x, 1/2/3/4), s).
3179 APInt ImmPop = Imm.ashr(Shifts);
3180 if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
3181 return false;
3182 // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
3183 // since it needs one more instruction than other 3 cases.
3184 APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
3185 if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
3186 (ImmSmall - Imm).isPowerOf2())
3187 return true;
3188 }
3189 }
3190
3191 return false;
3192}
3193
3194bool LoongArchTargetLowering::isLegalAddressingMode(const DataLayout &DL,
3195 const AddrMode &AM,
3196 Type *Ty, unsigned AS,
3197 Instruction *I) const {
3198 // LoongArch has four basic addressing modes:
3199 // 1. reg
3200 // 2. reg + 12-bit signed offset
3201 // 3. reg + 14-bit signed offset left-shifted by 2
3202 // 4. reg1 + reg2
3203 // TODO: Add more checks after support vector extension.
3204
3205 // No global is ever allowed as a base.
3206 if (AM.BaseGV)
3207 return false;
3208
3209 // Require a 12 or 14 bit signed offset.
3210 if (!isInt<12>(AM.BaseOffs) || !isShiftedInt<14, 2>(AM.BaseOffs))
3211 return false;
3212
3213 switch (AM.Scale) {
3214 case 0:
3215 // "i" is not allowed.
3216 if (!AM.HasBaseReg)
3217 return false;
3218 // Otherwise we have "r+i".
3219 break;
3220 case 1:
3221 // "r+r+i" is not allowed.
3222 if (AM.HasBaseReg && AM.BaseOffs != 0)
3223 return false;
3224 // Otherwise we have "r+r" or "r+i".
3225 break;
3226 case 2:
3227 // "2*r+r" or "2*r+i" is not allowed.
3228 if (AM.HasBaseReg || AM.BaseOffs)
3229 return false;
3230 // Otherwise we have "r+r".
3231 break;
3232 default:
3233 return false;
3234 }
3235
3236 return true;
3237}
3238
3239bool LoongArchTargetLowering::hasAndNotCompare(SDValue Y) const {
3240 // TODO: Support vectors.
3241 if (Y.getValueType().isVector())
3242 return false;
3243
3244 return !isa<ConstantSDNode>(Y);
3245}