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 1679915782 -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-03-27-130437-16335-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 mask doesn't start at position 0.
1376 if (SMIdx)
1377 return SDValue();
1378
1379 lsb = 0;
1380 NewOperand = FirstOperand;
1381 }
1382 msb = lsb + SMLen - 1;
1383 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
1384 DAG.getConstant(msb, DL, GRLenVT),
1385 DAG.getConstant(lsb, DL, GRLenVT));
1386}
1387
1388static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
1389 TargetLowering::DAGCombinerInfo &DCI,
1390 const LoongArchSubtarget &Subtarget) {
1391 if (DCI.isBeforeLegalizeOps())
1392 return SDValue();
1393
1394 // $dst = srl (and $src, Mask), Shamt
1395 // =>
1396 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
1397 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
1398 //
1399
1400 SDValue FirstOperand = N->getOperand(0);
1401 ConstantSDNode *CN;
1402 EVT ValTy = N->getValueType(0);
1403 SDLoc DL(N);
1404 MVT GRLenVT = Subtarget.getGRLenVT();
1405 unsigned MaskIdx, MaskLen;
1406 uint64_t Shamt;
1407
1408 // The first operand must be an AND and the second operand of the AND must be
1409 // a shifted mask.
1410 if (FirstOperand.getOpcode() != ISD::AND ||
1411 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
1412 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
1413 return SDValue();
1414
1415 // The second operand (shift amount) must be an immediate.
1416 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
1417 return SDValue();
1418
1419 Shamt = CN->getZExtValue();
1420 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
1421 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
1422 FirstOperand->getOperand(0),
1423 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1424 DAG.getConstant(Shamt, DL, GRLenVT));
1425
1426 return SDValue();
1427}
1428
1429static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
1430 TargetLowering::DAGCombinerInfo &DCI,
1431 const LoongArchSubtarget &Subtarget) {
1432 MVT GRLenVT = Subtarget.getGRLenVT();
1433 EVT ValTy = N->getValueType(0);
1434 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
1435 ConstantSDNode *CN0, *CN1;
1436 SDLoc DL(N);
1437 unsigned ValBits = ValTy.getSizeInBits();
1438 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
1439 unsigned Shamt;
1440 bool SwapAndRetried = false;
1441
1442 if (DCI.isBeforeLegalizeOps())
1443 return SDValue();
1444
1445 if (ValBits != 32 && ValBits != 64)
1446 return SDValue();
1447
1448Retry:
1449 // 1st pattern to match BSTRINS:
1450 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
1451 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
1452 // =>
1453 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1454 if (N0.getOpcode() == ISD::AND &&
1455 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1456 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1457 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
1458 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1459 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1460 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
1461 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1462 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1463 (MaskIdx0 + MaskLen0 <= ValBits)) {
1464 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)
;
1465 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1466 N1.getOperand(0).getOperand(0),
1467 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1468 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1469 }
1470
1471 // 2nd pattern to match BSTRINS:
1472 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
1473 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
1474 // =>
1475 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1476 if (N0.getOpcode() == ISD::AND &&
1477 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1478 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1479 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1480 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1481 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1482 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1483 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1484 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
1485 (MaskIdx0 + MaskLen0 <= ValBits)) {
1486 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)
;
1487 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1488 N1.getOperand(0).getOperand(0),
1489 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1490 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1491 }
1492
1493 // 3rd pattern to match BSTRINS:
1494 // R = or (and X, mask0), (and Y, mask1)
1495 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
1496 // =>
1497 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
1498 // where msb = lsb + size - 1
1499 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
1500 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1501 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1502 (MaskIdx0 + MaskLen0 <= 64) &&
1503 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
1504 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1505 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)
;
1506 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1507 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
1508 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
1509 DAG.getConstant(ValBits == 32
1510 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
1511 : (MaskIdx0 + MaskLen0 - 1),
1512 DL, GRLenVT),
1513 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1514 }
1515
1516 // 4th pattern to match BSTRINS:
1517 // R = or (and X, mask), (shl Y, shamt)
1518 // where mask = (2**shamt - 1)
1519 // =>
1520 // R = BSTRINS X, Y, ValBits - 1, shamt
1521 // where ValBits = 32 or 64
1522 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
1523 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1524 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
1525 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1526 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
1527 (MaskIdx0 + MaskLen0 <= ValBits)) {
1528 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)
;
1529 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1530 N1.getOperand(0),
1531 DAG.getConstant((ValBits - 1), DL, GRLenVT),
1532 DAG.getConstant(Shamt, DL, GRLenVT));
1533 }
1534
1535 // 5th pattern to match BSTRINS:
1536 // R = or (and X, mask), const
1537 // where ~mask = (2**size - 1) << lsb, mask & const = 0
1538 // =>
1539 // R = BSTRINS X, (const >> lsb), msb, lsb
1540 // where msb = lsb + size - 1
1541 if (N0.getOpcode() == ISD::AND &&
1542 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1543 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1544 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
1545 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1546 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)
;
1547 return DAG.getNode(
1548 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1549 DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
1550 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1551 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1552 }
1553
1554 // 6th pattern.
1555 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
1556 // by the incoming bits are known to be zero.
1557 // =>
1558 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
1559 //
1560 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
1561 // pattern is more common than the 1st. So we put the 1st before the 6th in
1562 // order to match as many nodes as possible.
1563 ConstantSDNode *CNMask, *CNShamt;
1564 unsigned MaskIdx, MaskLen;
1565 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1566 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1567 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1568 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1569 CNShamt->getZExtValue() + MaskLen <= ValBits) {
1570 Shamt = CNShamt->getZExtValue();
1571 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
1572 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1573 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)
;
1574 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1575 N1.getOperand(0).getOperand(0),
1576 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
1577 DAG.getConstant(Shamt, DL, GRLenVT));
1578 }
1579 }
1580
1581 // 7th pattern.
1582 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
1583 // overwritten by the incoming bits are known to be zero.
1584 // =>
1585 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
1586 //
1587 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
1588 // before the 7th in order to match as many nodes as possible.
1589 if (N1.getOpcode() == ISD::AND &&
1590 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1591 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1592 N1.getOperand(0).getOpcode() == ISD::SHL &&
1593 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1594 CNShamt->getZExtValue() == MaskIdx) {
1595 APInt ShMask(ValBits, CNMask->getZExtValue());
1596 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1597 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)
;
1598 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1599 N1.getOperand(0).getOperand(0),
1600 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1601 DAG.getConstant(MaskIdx, DL, GRLenVT));
1602 }
1603 }
1604
1605 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
1606 if (!SwapAndRetried) {
1607 std::swap(N0, N1);
1608 SwapAndRetried = true;
1609 goto Retry;
1610 }
1611
1612 SwapAndRetried = false;
1613Retry2:
1614 // 8th pattern.
1615 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
1616 // the incoming bits are known to be zero.
1617 // =>
1618 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
1619 //
1620 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
1621 // we put it here in order to match as many nodes as possible or generate less
1622 // instructions.
1623 if (N1.getOpcode() == ISD::AND &&
1624 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1625 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
1626 APInt ShMask(ValBits, CNMask->getZExtValue());
1627 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1628 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)
;
1629 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1630 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
1631 N1->getOperand(0),
1632 DAG.getConstant(MaskIdx, DL, GRLenVT)),
1633 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1634 DAG.getConstant(MaskIdx, DL, GRLenVT));
1635 }
1636 }
1637 // Swap N0/N1 and retry.
1638 if (!SwapAndRetried) {
1639 std::swap(N0, N1);
1640 SwapAndRetried = true;
1641 goto Retry2;
1642 }
1643
1644 return SDValue();
1645}
1646
1647// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
1648static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG,
1649 TargetLowering::DAGCombinerInfo &DCI,
1650 const LoongArchSubtarget &Subtarget) {
1651 if (DCI.isBeforeLegalizeOps())
1652 return SDValue();
1653
1654 SDValue Src = N->getOperand(0);
1655 if (Src.getOpcode() != LoongArchISD::REVB_2W)
1656 return SDValue();
1657
1658 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
1659 Src.getOperand(0));
1660}
1661
1662SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
1663 DAGCombinerInfo &DCI) const {
1664 SelectionDAG &DAG = DCI.DAG;
1665 switch (N->getOpcode()) {
1666 default:
1667 break;
1668 case ISD::AND:
1669 return performANDCombine(N, DAG, DCI, Subtarget);
1670 case ISD::OR:
1671 return performORCombine(N, DAG, DCI, Subtarget);
1672 case ISD::SRL:
1673 return performSRLCombine(N, DAG, DCI, Subtarget);
1674 case LoongArchISD::BITREV_W:
1675 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
1676 }
1677 return SDValue();
1678}
1679
1680static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI,
1681 MachineBasicBlock *MBB) {
1682 if (!ZeroDivCheck)
1683 return MBB;
1684
1685 // Build instructions:
1686 // MBB:
1687 // div(or mod) $dst, $dividend, $divisor
1688 // bnez $divisor, SinkMBB
1689 // BreakMBB:
1690 // break 7 // BRK_DIVZERO
1691 // SinkMBB:
1692 // fallthrough
1693 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
1694 MachineFunction::iterator It = ++MBB->getIterator();
1695 MachineFunction *MF = MBB->getParent();
1696 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1697 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1698 MF->insert(It, BreakMBB);
1699 MF->insert(It, SinkMBB);
1700
1701 // Transfer the remainder of MBB and its successor edges to SinkMBB.
1702 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
1703 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
1704
1705 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
1706 DebugLoc DL = MI.getDebugLoc();
1707 MachineOperand &Divisor = MI.getOperand(2);
1708 Register DivisorReg = Divisor.getReg();
1709
1710 // MBB:
1711 BuildMI(MBB, DL, TII.get(LoongArch::BNEZ))
1712 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
1713 .addMBB(SinkMBB);
1714 MBB->addSuccessor(BreakMBB);
1715 MBB->addSuccessor(SinkMBB);
1716
1717 // BreakMBB:
1718 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
1719 // definition of BRK_DIVZERO.
1720 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
1721 BreakMBB->addSuccessor(SinkMBB);
1722
1723 // Clear Divisor's kill flag.
1724 Divisor.setIsKill(false);
1725
1726 return SinkMBB;
1727}
1728
1729MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
1730 MachineInstr &MI, MachineBasicBlock *BB) const {
1731 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
1732 DebugLoc DL = MI.getDebugLoc();
1733
1734 switch (MI.getOpcode()) {
1735 default:
1736 llvm_unreachable("Unexpected instr type to insert")::llvm::llvm_unreachable_internal("Unexpected instr type to insert"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 1736
)
;
1737 case LoongArch::DIV_W:
1738 case LoongArch::DIV_WU:
1739 case LoongArch::MOD_W:
1740 case LoongArch::MOD_WU:
1741 case LoongArch::DIV_D:
1742 case LoongArch::DIV_DU:
1743 case LoongArch::MOD_D:
1744 case LoongArch::MOD_DU:
1745 return insertDivByZeroTrap(MI, BB);
1746 break;
1747 case LoongArch::WRFCSR: {
1748 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
1749 LoongArch::FCSR0 + MI.getOperand(0).getImm())
1750 .addReg(MI.getOperand(1).getReg());
1751 MI.eraseFromParent();
1752 return BB;
1753 }
1754 case LoongArch::RDFCSR: {
1755 MachineInstr *ReadFCSR =
1756 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
1757 MI.getOperand(0).getReg())
1758 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
1759 ReadFCSR->getOperand(1).setIsUndef();
1760 MI.eraseFromParent();
1761 return BB;
1762 }
1763 }
1764}
1765
1766const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
1767 switch ((LoongArchISD::NodeType)Opcode) {
1768 case LoongArchISD::FIRST_NUMBER:
1769 break;
1770
1771#define NODE_NAME_CASE(node) \
1772 case LoongArchISD::node: \
1773 return "LoongArchISD::" #node;
1774
1775 // TODO: Add more target-dependent nodes later.
1776 NODE_NAME_CASE(CALL)
1777 NODE_NAME_CASE(RET)
1778 NODE_NAME_CASE(TAIL)
1779 NODE_NAME_CASE(SLL_W)
1780 NODE_NAME_CASE(SRA_W)
1781 NODE_NAME_CASE(SRL_W)
1782 NODE_NAME_CASE(BSTRINS)
1783 NODE_NAME_CASE(BSTRPICK)
1784 NODE_NAME_CASE(MOVGR2FR_W_LA64)
1785 NODE_NAME_CASE(MOVFR2GR_S_LA64)
1786 NODE_NAME_CASE(FTINT)
1787 NODE_NAME_CASE(REVB_2H)
1788 NODE_NAME_CASE(REVB_2W)
1789 NODE_NAME_CASE(BITREV_4B)
1790 NODE_NAME_CASE(BITREV_W)
1791 NODE_NAME_CASE(ROTR_W)
1792 NODE_NAME_CASE(ROTL_W)
1793 NODE_NAME_CASE(CLZ_W)
1794 NODE_NAME_CASE(CTZ_W)
1795 NODE_NAME_CASE(DBAR)
1796 NODE_NAME_CASE(IBAR)
1797 NODE_NAME_CASE(BREAK)
1798 NODE_NAME_CASE(SYSCALL)
1799 NODE_NAME_CASE(CRC_W_B_W)
1800 NODE_NAME_CASE(CRC_W_H_W)
1801 NODE_NAME_CASE(CRC_W_W_W)
1802 NODE_NAME_CASE(CRC_W_D_W)
1803 NODE_NAME_CASE(CRCC_W_B_W)
1804 NODE_NAME_CASE(CRCC_W_H_W)
1805 NODE_NAME_CASE(CRCC_W_W_W)
1806 NODE_NAME_CASE(CRCC_W_D_W)
1807 NODE_NAME_CASE(CSRRD)
1808 NODE_NAME_CASE(CSRWR)
1809 NODE_NAME_CASE(CSRXCHG)
1810 NODE_NAME_CASE(IOCSRRD_B)
1811 NODE_NAME_CASE(IOCSRRD_H)
1812 NODE_NAME_CASE(IOCSRRD_W)
1813 NODE_NAME_CASE(IOCSRRD_D)
1814 NODE_NAME_CASE(IOCSRWR_B)
1815 NODE_NAME_CASE(IOCSRWR_H)
1816 NODE_NAME_CASE(IOCSRWR_W)
1817 NODE_NAME_CASE(IOCSRWR_D)
1818 NODE_NAME_CASE(CPUCFG)
1819 NODE_NAME_CASE(MOVGR2FCSR)
1820 NODE_NAME_CASE(MOVFCSR2GR)
1821 NODE_NAME_CASE(CACOP_D)
1822 NODE_NAME_CASE(CACOP_W)
1823 }
1824#undef NODE_NAME_CASE
1825 return nullptr;
1826}
1827
1828//===----------------------------------------------------------------------===//
1829// Calling Convention Implementation
1830//===----------------------------------------------------------------------===//
1831
1832// Eight general-purpose registers a0-a7 used for passing integer arguments,
1833// with a0-a1 reused to return values. Generally, the GPRs are used to pass
1834// fixed-point arguments, and floating-point arguments when no FPR is available
1835// or with soft float ABI.
1836const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
1837 LoongArch::R7, LoongArch::R8, LoongArch::R9,
1838 LoongArch::R10, LoongArch::R11};
1839// Eight floating-point registers fa0-fa7 used for passing floating-point
1840// arguments, and fa0-fa1 are also used to return values.
1841const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
1842 LoongArch::F3, LoongArch::F4, LoongArch::F5,
1843 LoongArch::F6, LoongArch::F7};
1844// FPR32 and FPR64 alias each other.
1845const MCPhysReg ArgFPR64s[] = {
1846 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
1847 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
1848
1849// Pass a 2*GRLen argument that has been split into two GRLen values through
1850// registers or the stack as necessary.
1851static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
1852 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
1853 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
1854 ISD::ArgFlagsTy ArgFlags2) {
1855 unsigned GRLenInBytes = GRLen / 8;
1856 if (Register Reg = State.AllocateReg(ArgGPRs)) {
1857 // At least one half can be passed via register.
1858 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
1859 VA1.getLocVT(), CCValAssign::Full));
1860 } else {
1861 // Both halves must be passed on the stack, with proper alignment.
1862 Align StackAlign =
1863 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
1864 State.addLoc(
1865 CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(),
1866 State.AllocateStack(GRLenInBytes, StackAlign),
1867 VA1.getLocVT(), CCValAssign::Full));
1868 State.addLoc(CCValAssign::getMem(
1869 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1870 LocVT2, CCValAssign::Full));
1871 return false;
1872 }
1873 if (Register Reg = State.AllocateReg(ArgGPRs)) {
1874 // The second half can also be passed via register.
1875 State.addLoc(
1876 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
1877 } else {
1878 // The second half is passed via the stack, without additional alignment.
1879 State.addLoc(CCValAssign::getMem(
1880 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1881 LocVT2, CCValAssign::Full));
1882 }
1883 return false;
1884}
1885
1886// Implements the LoongArch calling convention. Returns true upon failure.
1887static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI,
1888 unsigned ValNo, MVT ValVT,
1889 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
1890 CCState &State, bool IsFixed, bool IsRet,
1891 Type *OrigTy) {
1892 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
1893 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", 1893
, __extension__ __PRETTY_FUNCTION__))
;
1894 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
1895 MVT LocVT = ValVT;
1896
1897 // Any return value split into more than two values can't be returned
1898 // directly.
1899 if (IsRet && ValNo > 1)
1900 return true;
1901
1902 // If passing a variadic argument, or if no FPR is available.
1903 bool UseGPRForFloat = true;
1904
1905 switch (ABI) {
1906 default:
1907 llvm_unreachable("Unexpected ABI")::llvm::llvm_unreachable_internal("Unexpected ABI", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 1907)
;
1908 case LoongArchABI::ABI_ILP32S:
1909 case LoongArchABI::ABI_LP64S:
1910 case LoongArchABI::ABI_ILP32F:
1911 case LoongArchABI::ABI_LP64F:
1912 report_fatal_error("Unimplemented ABI");
1913 break;
1914 case LoongArchABI::ABI_ILP32D:
1915 case LoongArchABI::ABI_LP64D:
1916 UseGPRForFloat = !IsFixed;
1917 break;
1918 }
1919
1920 // FPR32 and FPR64 alias each other.
1921 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
1922 UseGPRForFloat = true;
1923
1924 if (UseGPRForFloat && ValVT == MVT::f32) {
1925 LocVT = GRLenVT;
1926 LocInfo = CCValAssign::BCvt;
1927 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
1928 LocVT = MVT::i64;
1929 LocInfo = CCValAssign::BCvt;
1930 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
1931 // TODO: Handle passing f64 on LA32 with D feature.
1932 report_fatal_error("Passing f64 with GPR on LA32 is undefined");
1933 }
1934
1935 // If this is a variadic argument, the LoongArch calling convention requires
1936 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
1937 // byte alignment. An aligned register should be used regardless of whether
1938 // the original argument was split during legalisation or not. The argument
1939 // will not be passed by registers if the original type is larger than
1940 // 2*GRLen, so the register alignment rule does not apply.
1941 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
1942 if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
1943 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
1944 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
1945 // Skip 'odd' register if necessary.
1946 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
1947 State.AllocateReg(ArgGPRs);
1948 }
1949
1950 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
1951 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
1952 State.getPendingArgFlags();
1953
1954 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", 1955
, __extension__ __PRETTY_FUNCTION__))
1955 "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", 1955
, __extension__ __PRETTY_FUNCTION__))
;
1956
1957 // Split arguments might be passed indirectly, so keep track of the pending
1958 // values.
1959 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
1960 LocVT = GRLenVT;
1961 LocInfo = CCValAssign::Indirect;
1962 PendingLocs.push_back(
1963 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
1964 PendingArgFlags.push_back(ArgFlags);
1965 if (!ArgFlags.isSplitEnd()) {
1966 return false;
1967 }
1968 }
1969
1970 // If the split argument only had two elements, it should be passed directly
1971 // in registers or on the stack.
1972 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
1973 PendingLocs.size() <= 2) {
1974 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", 1974
, __extension__ __PRETTY_FUNCTION__))
;
1975 // Apply the normal calling convention rules to the first half of the
1976 // split argument.
1977 CCValAssign VA = PendingLocs[0];
1978 ISD::ArgFlagsTy AF = PendingArgFlags[0];
1979 PendingLocs.clear();
1980 PendingArgFlags.clear();
1981 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
1982 ArgFlags);
1983 }
1984
1985 // Allocate to a register if possible, or else a stack slot.
1986 Register Reg;
1987 unsigned StoreSizeBytes = GRLen / 8;
1988 Align StackAlign = Align(GRLen / 8);
1989
1990 if (ValVT == MVT::f32 && !UseGPRForFloat)
1991 Reg = State.AllocateReg(ArgFPR32s);
1992 else if (ValVT == MVT::f64 && !UseGPRForFloat)
1993 Reg = State.AllocateReg(ArgFPR64s);
1994 else
1995 Reg = State.AllocateReg(ArgGPRs);
1996
1997 unsigned StackOffset =
1998 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
1999
2000 // If we reach this point and PendingLocs is non-empty, we must be at the
2001 // end of a split argument that must be passed indirectly.
2002 if (!PendingLocs.empty()) {
2003 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", 2003
, __extension__ __PRETTY_FUNCTION__))
;
2004 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", 2004
, __extension__ __PRETTY_FUNCTION__))
;
2005 for (auto &It : PendingLocs) {
2006 if (Reg)
2007 It.convertToReg(Reg);
2008 else
2009 It.convertToMem(StackOffset);
2010 State.addLoc(It);
2011 }
2012 PendingLocs.clear();
2013 PendingArgFlags.clear();
2014 return false;
2015 }
2016 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", 2017
, __extension__ __PRETTY_FUNCTION__))
2017 "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", 2017
, __extension__ __PRETTY_FUNCTION__))
;
2018
2019 if (Reg) {
2020 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2021 return false;
2022 }
2023
2024 // When a floating-point value is passed on the stack, no bit-cast is needed.
2025 if (ValVT.isFloatingPoint()) {
2026 LocVT = ValVT;
2027 LocInfo = CCValAssign::Full;
2028 }
2029
2030 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
2031 return false;
2032}
2033
2034void LoongArchTargetLowering::analyzeInputArgs(
2035 MachineFunction &MF, CCState &CCInfo,
2036 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
2037 LoongArchCCAssignFn Fn) const {
2038 FunctionType *FType = MF.getFunction().getFunctionType();
2039 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
2040 MVT ArgVT = Ins[i].VT;
2041 Type *ArgTy = nullptr;
2042 if (IsRet)
2043 ArgTy = FType->getReturnType();
2044 else if (Ins[i].isOrigArg())
2045 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
2046 LoongArchABI::ABI ABI =
2047 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2048 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
2049 CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) {
2050 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)
2051 << ArgVT << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "InputArg #" <<
i << " has unhandled type " << ArgVT << '\n'
; } } while (false)
;
2052 llvm_unreachable("")::llvm::llvm_unreachable_internal("", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2052)
;
2053 }
2054 }
2055}
2056
2057void LoongArchTargetLowering::analyzeOutputArgs(
2058 MachineFunction &MF, CCState &CCInfo,
2059 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
2060 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
2061 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2062 MVT ArgVT = Outs[i].VT;
2063 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
2064 LoongArchABI::ABI ABI =
2065 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2066 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
2067 CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
2068 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)
2069 << ArgVT << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("loongarch-isel-lowering")) { dbgs() << "OutputArg #" <<
i << " has unhandled type " << ArgVT << "\n"
; } } while (false)
;
2070 llvm_unreachable("")::llvm::llvm_unreachable_internal("", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2070)
;
2071 }
2072 }
2073}
2074
2075// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
2076// values.
2077static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val,
2078 const CCValAssign &VA, const SDLoc &DL) {
2079 switch (VA.getLocInfo()) {
2080 default:
2081 llvm_unreachable("Unexpected CCValAssign::LocInfo")::llvm::llvm_unreachable_internal("Unexpected CCValAssign::LocInfo"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2081
)
;
2082 case CCValAssign::Full:
2083 case CCValAssign::Indirect:
2084 break;
2085 case CCValAssign::BCvt:
2086 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2087 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
2088 else
2089 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
2090 break;
2091 }
2092 return Val;
2093}
2094
2095static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
2096 const CCValAssign &VA, const SDLoc &DL,
2097 const LoongArchTargetLowering &TLI) {
2098 MachineFunction &MF = DAG.getMachineFunction();
2099 MachineRegisterInfo &RegInfo = MF.getRegInfo();
2100 EVT LocVT = VA.getLocVT();
2101 SDValue Val;
2102 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
2103 Register VReg = RegInfo.createVirtualRegister(RC);
2104 RegInfo.addLiveIn(VA.getLocReg(), VReg);
2105 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
2106
2107 return convertLocVTToValVT(DAG, Val, VA, DL);
2108}
2109
2110// The caller is responsible for loading the full value if the argument is
2111// passed with CCValAssign::Indirect.
2112static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain,
2113 const CCValAssign &VA, const SDLoc &DL) {
2114 MachineFunction &MF = DAG.getMachineFunction();
2115 MachineFrameInfo &MFI = MF.getFrameInfo();
2116 EVT ValVT = VA.getValVT();
2117 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
2118 /*IsImmutable=*/true);
2119 SDValue FIN = DAG.getFrameIndex(
2120 FI, MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)));
2121
2122 ISD::LoadExtType ExtType;
2123 switch (VA.getLocInfo()) {
2124 default:
2125 llvm_unreachable("Unexpected CCValAssign::LocInfo")::llvm::llvm_unreachable_internal("Unexpected CCValAssign::LocInfo"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2125
)
;
2126 case CCValAssign::Full:
2127 case CCValAssign::Indirect:
2128 case CCValAssign::BCvt:
2129 ExtType = ISD::NON_EXTLOAD;
2130 break;
2131 }
2132 return DAG.getExtLoad(
2133 ExtType, DL, VA.getLocVT(), Chain, FIN,
2134 MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
2135}
2136
2137static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val,
2138 const CCValAssign &VA, const SDLoc &DL) {
2139 EVT LocVT = VA.getLocVT();
2140
2141 switch (VA.getLocInfo()) {
2142 default:
2143 llvm_unreachable("Unexpected CCValAssign::LocInfo")::llvm::llvm_unreachable_internal("Unexpected CCValAssign::LocInfo"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2143
)
;
2144 case CCValAssign::Full:
2145 break;
2146 case CCValAssign::BCvt:
2147 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2148 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
2149 else
2150 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
2151 break;
2152 }
2153 return Val;
2154}
2155
2156static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
2157 CCValAssign::LocInfo LocInfo,
2158 ISD::ArgFlagsTy ArgFlags, CCState &State) {
2159 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
2160 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
2161 // s0 s1 s2 s3 s4 s5 s6 s7 s8
2162 static const MCPhysReg GPRList[] = {
2163 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26, LoongArch::R27,
2164 LoongArch::R28, LoongArch::R29, LoongArch::R30, LoongArch::R31};
2165 if (unsigned Reg = State.AllocateReg(GPRList)) {
2166 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2167 return false;
2168 }
2169 }
2170
2171 if (LocVT == MVT::f32) {
2172 // Pass in STG registers: F1, F2, F3, F4
2173 // fs0,fs1,fs2,fs3
2174 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
2175 LoongArch::F26, LoongArch::F27};
2176 if (unsigned Reg = State.AllocateReg(FPR32List)) {
2177 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2178 return false;
2179 }
2180 }
2181
2182 if (LocVT == MVT::f64) {
2183 // Pass in STG registers: D1, D2, D3, D4
2184 // fs4,fs5,fs6,fs7
2185 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
2186 LoongArch::F30_64, LoongArch::F31_64};
2187 if (unsigned Reg = State.AllocateReg(FPR64List)) {
2188 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2189 return false;
2190 }
2191 }
2192
2193 report_fatal_error("No registers left in GHC calling convention");
2194 return true;
2195}
2196
2197// Transform physical registers into virtual registers.
2198SDValue LoongArchTargetLowering::LowerFormalArguments(
2199 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
2200 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
2201 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
2202
2203 MachineFunction &MF = DAG.getMachineFunction();
2204
2205 switch (CallConv) {
2206 default:
2207 llvm_unreachable("Unsupported calling convention")::llvm::llvm_unreachable_internal("Unsupported calling convention"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2207
)
;
2208 case CallingConv::C:
2209 case CallingConv::Fast:
2210 break;
2211 case CallingConv::GHC:
2212 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
2213 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
2214 report_fatal_error(
2215 "GHC calling convention requires the F and D extensions");
2216 }
2217
2218 EVT PtrVT = getPointerTy(DAG.getDataLayout());
2219 MVT GRLenVT = Subtarget.getGRLenVT();
2220 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
2221 // Used with varargs to acumulate store chains.
2222 std::vector<SDValue> OutChains;
2223
2224 // Assign locations to all of the incoming arguments.
2225 SmallVector<CCValAssign> ArgLocs;
2226 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
2227
2228 if (CallConv == CallingConv::GHC)
2229 CCInfo.AnalyzeFormalArguments(Ins, CC_LoongArch_GHC);
2230 else
2231 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
2232
2233 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
2234 CCValAssign &VA = ArgLocs[i];
2235 SDValue ArgValue;
2236 if (VA.isRegLoc())
2237 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, *this);
2238 else
2239 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
2240 if (VA.getLocInfo() == CCValAssign::Indirect) {
2241 // If the original argument was split and passed by reference, we need to
2242 // load all parts of it here (using the same address).
2243 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
2244 MachinePointerInfo()));
2245 unsigned ArgIndex = Ins[i].OrigArgIndex;
2246 unsigned ArgPartOffset = Ins[i].PartOffset;
2247 assert(ArgPartOffset == 0)(static_cast <bool> (ArgPartOffset == 0) ? void (0) : __assert_fail
("ArgPartOffset == 0", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2247, __extension__ __PRETTY_FUNCTION__))
;
2248 while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) {
2249 CCValAssign &PartVA = ArgLocs[i + 1];
2250 unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset;
2251 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2252 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
2253 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
2254 MachinePointerInfo()));
2255 ++i;
2256 }
2257 continue;
2258 }
2259 InVals.push_back(ArgValue);
2260 }
2261
2262 if (IsVarArg) {
2263 ArrayRef<MCPhysReg> ArgRegs = ArrayRef(ArgGPRs);
2264 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
2265 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
2266 MachineFrameInfo &MFI = MF.getFrameInfo();
2267 MachineRegisterInfo &RegInfo = MF.getRegInfo();
2268 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
2269
2270 // Offset of the first variable argument from stack pointer, and size of
2271 // the vararg save area. For now, the varargs save area is either zero or
2272 // large enough to hold a0-a7.
2273 int VaArgOffset, VarArgsSaveSize;
2274
2275 // If all registers are allocated, then all varargs must be passed on the
2276 // stack and we don't need to save any argregs.
2277 if (ArgRegs.size() == Idx) {
2278 VaArgOffset = CCInfo.getNextStackOffset();
2279 VarArgsSaveSize = 0;
2280 } else {
2281 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
2282 VaArgOffset = -VarArgsSaveSize;
2283 }
2284
2285 // Record the frame index of the first variable argument
2286 // which is a value necessary to VASTART.
2287 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2288 LoongArchFI->setVarArgsFrameIndex(FI);
2289
2290 // If saving an odd number of registers then create an extra stack slot to
2291 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
2292 // offsets to even-numbered registered remain 2*GRLen-aligned.
2293 if (Idx % 2) {
2294 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
2295 true);
2296 VarArgsSaveSize += GRLenInBytes;
2297 }
2298
2299 // Copy the integer registers that may have been used for passing varargs
2300 // to the vararg save area.
2301 for (unsigned I = Idx; I < ArgRegs.size();
2302 ++I, VaArgOffset += GRLenInBytes) {
2303 const Register Reg = RegInfo.createVirtualRegister(RC);
2304 RegInfo.addLiveIn(ArgRegs[I], Reg);
2305 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
2306 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2307 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2308 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
2309 MachinePointerInfo::getFixedStack(MF, FI));
2310 cast<StoreSDNode>(Store.getNode())
2311 ->getMemOperand()
2312 ->setValue((Value *)nullptr);
2313 OutChains.push_back(Store);
2314 }
2315 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
2316 }
2317
2318 // All stores are grouped in one node to allow the matching between
2319 // the size of Ins and InVals. This only happens for vararg functions.
2320 if (!OutChains.empty()) {
2321 OutChains.push_back(Chain);
2322 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
2323 }
2324
2325 return Chain;
2326}
2327
2328bool LoongArchTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
2329 return CI->isTailCall();
2330}
2331
2332// Check if the return value is used as only a return value, as otherwise
2333// we can't perform a tail-call.
2334bool LoongArchTargetLowering::isUsedByReturnOnly(SDNode *N,
2335 SDValue &Chain) const {
2336 if (N->getNumValues() != 1)
2337 return false;
2338 if (!N->hasNUsesOfValue(1, 0))
2339 return false;
2340
2341 SDNode *Copy = *N->use_begin();
2342 if (Copy->getOpcode() != ISD::CopyToReg)
2343 return false;
2344
2345 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
2346 // isn't safe to perform a tail call.
2347 if (Copy->getGluedNode())
2348 return false;
2349
2350 // The copy must be used by a LoongArchISD::RET, and nothing else.
2351 bool HasRet = false;
2352 for (SDNode *Node : Copy->uses()) {
2353 if (Node->getOpcode() != LoongArchISD::RET)
2354 return false;
2355 HasRet = true;
2356 }
2357
2358 if (!HasRet)
2359 return false;
2360
2361 Chain = Copy->getOperand(0);
2362 return true;
2363}
2364
2365// Check whether the call is eligible for tail call optimization.
2366bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
2367 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
2368 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
2369
2370 auto CalleeCC = CLI.CallConv;
2371 auto &Outs = CLI.Outs;
2372 auto &Caller = MF.getFunction();
2373 auto CallerCC = Caller.getCallingConv();
2374
2375 // Do not tail call opt if the stack is used to pass parameters.
2376 if (CCInfo.getNextStackOffset() != 0)
2377 return false;
2378
2379 // Do not tail call opt if any parameters need to be passed indirectly.
2380 for (auto &VA : ArgLocs)
2381 if (VA.getLocInfo() == CCValAssign::Indirect)
2382 return false;
2383
2384 // Do not tail call opt if either caller or callee uses struct return
2385 // semantics.
2386 auto IsCallerStructRet = Caller.hasStructRetAttr();
2387 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
2388 if (IsCallerStructRet || IsCalleeStructRet)
2389 return false;
2390
2391 // Do not tail call opt if either the callee or caller has a byval argument.
2392 for (auto &Arg : Outs)
2393 if (Arg.Flags.isByVal())
2394 return false;
2395
2396 // The callee has to preserve all registers the caller needs to preserve.
2397 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
2398 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
2399 if (CalleeCC != CallerCC) {
2400 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
2401 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
2402 return false;
2403 }
2404 return true;
2405}
2406
2407static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG) {
2408 return DAG.getDataLayout().getPrefTypeAlign(
2409 VT.getTypeForEVT(*DAG.getContext()));
2410}
2411
2412// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
2413// and output parameter nodes.
2414SDValue
2415LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
2416 SmallVectorImpl<SDValue> &InVals) const {
2417 SelectionDAG &DAG = CLI.DAG;
2418 SDLoc &DL = CLI.DL;
2419 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
2420 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
2421 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
2422 SDValue Chain = CLI.Chain;
2423 SDValue Callee = CLI.Callee;
2424 CallingConv::ID CallConv = CLI.CallConv;
2425 bool IsVarArg = CLI.IsVarArg;
2426 EVT PtrVT = getPointerTy(DAG.getDataLayout());
2427 MVT GRLenVT = Subtarget.getGRLenVT();
2428 bool &IsTailCall = CLI.IsTailCall;
2429
2430 MachineFunction &MF = DAG.getMachineFunction();
2431
2432 // Analyze the operands of the call, assigning locations to each operand.
2433 SmallVector<CCValAssign> ArgLocs;
2434 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
2435
2436 if (CallConv == CallingConv::GHC)
2437 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
2438 else
2439 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
2440
2441 // Check if it's really possible to do a tail call.
2442 if (IsTailCall)
2443 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
2444
2445 if (IsTailCall)
2446 ++NumTailCalls;
2447 else if (CLI.CB && CLI.CB->isMustTailCall())
2448 report_fatal_error("failed to perform tail call elimination on a call "
2449 "site marked musttail");
2450
2451 // Get a count of how many bytes are to be pushed on the stack.
2452 unsigned NumBytes = ArgCCInfo.getNextStackOffset();
2453
2454 // Create local copies for byval args.
2455 SmallVector<SDValue> ByValArgs;
2456 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2457 ISD::ArgFlagsTy Flags = Outs[i].Flags;
2458 if (!Flags.isByVal())
2459 continue;
2460
2461 SDValue Arg = OutVals[i];
2462 unsigned Size = Flags.getByValSize();
2463 Align Alignment = Flags.getNonZeroByValAlign();
2464
2465 int FI =
2466 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
2467 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2468 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
2469
2470 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
2471 /*IsVolatile=*/false,
2472 /*AlwaysInline=*/false, /*isTailCall=*/IsTailCall,
2473 MachinePointerInfo(), MachinePointerInfo());
2474 ByValArgs.push_back(FIPtr);
2475 }
2476
2477 if (!IsTailCall)
2478 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
2479
2480 // Copy argument values to their designated locations.
2481 SmallVector<std::pair<Register, SDValue>> RegsToPass;
2482 SmallVector<SDValue> MemOpChains;
2483 SDValue StackPtr;
2484 for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
2485 CCValAssign &VA = ArgLocs[i];
2486 SDValue ArgValue = OutVals[i];
2487 ISD::ArgFlagsTy Flags = Outs[i].Flags;
2488
2489 // Promote the value if needed.
2490 // For now, only handle fully promoted and indirect arguments.
2491 if (VA.getLocInfo() == CCValAssign::Indirect) {
2492 // Store the argument in a stack slot and pass its address.
2493 Align StackAlign =
2494 std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG),
2495 getPrefTypeAlign(ArgValue.getValueType(), DAG));
2496 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
2497 // If the original argument was split and passed by reference, we need to
2498 // store the required parts of it here (and pass just one address).
2499 unsigned ArgIndex = Outs[i].OrigArgIndex;
2500 unsigned ArgPartOffset = Outs[i].PartOffset;
2501 assert(ArgPartOffset == 0)(static_cast <bool> (ArgPartOffset == 0) ? void (0) : __assert_fail
("ArgPartOffset == 0", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2501, __extension__ __PRETTY_FUNCTION__))
;
2502 // Calculate the total size to store. We don't have access to what we're
2503 // actually storing other than performing the loop and collecting the
2504 // info.
2505 SmallVector<std::pair<SDValue, SDValue>> Parts;
2506 while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) {
2507 SDValue PartValue = OutVals[i + 1];
2508 unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset;
2509 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2510 EVT PartVT = PartValue.getValueType();
2511
2512 StoredSize += PartVT.getStoreSize();
2513 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
2514 Parts.push_back(std::make_pair(PartValue, Offset));
2515 ++i;
2516 }
2517 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
2518 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
2519 MemOpChains.push_back(
2520 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
2521 MachinePointerInfo::getFixedStack(MF, FI)));
2522 for (const auto &Part : Parts) {
2523 SDValue PartValue = Part.first;
2524 SDValue PartOffset = Part.second;
2525 SDValue Address =
2526 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
2527 MemOpChains.push_back(
2528 DAG.getStore(Chain, DL, PartValue, Address,
2529 MachinePointerInfo::getFixedStack(MF, FI)));
2530 }
2531 ArgValue = SpillSlot;
2532 } else {
2533 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
2534 }
2535
2536 // Use local copy if it is a byval arg.
2537 if (Flags.isByVal())
2538 ArgValue = ByValArgs[j++];
2539
2540 if (VA.isRegLoc()) {
2541 // Queue up the argument copies and emit them at the end.
2542 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
2543 } else {
2544 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", 2544
, __extension__ __PRETTY_FUNCTION__))
;
2545 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", 2546
, __extension__ __PRETTY_FUNCTION__))
2546 "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", 2546
, __extension__ __PRETTY_FUNCTION__))
;
2547
2548 // Work out the address of the stack slot.
2549 if (!StackPtr.getNode())
2550 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
2551 SDValue Address =
2552 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
2553 DAG.getIntPtrConstant(VA.getLocMemOffset(), DL));
2554
2555 // Emit the store.
2556 MemOpChains.push_back(
2557 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
2558 }
2559 }
2560
2561 // Join the stores, which are independent of one another.
2562 if (!MemOpChains.empty())
2563 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
2564
2565 SDValue Glue;
2566
2567 // Build a sequence of copy-to-reg nodes, chained and glued together.
2568 for (auto &Reg : RegsToPass) {
2569 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
2570 Glue = Chain.getValue(1);
2571 }
2572
2573 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
2574 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
2575 // split it and then direct call can be matched by PseudoCALL.
2576 if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
2577 const GlobalValue *GV = S->getGlobal();
2578 unsigned OpFlags =
2579 getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)
2580 ? LoongArchII::MO_CALL
2581 : LoongArchII::MO_CALL_PLT;
2582 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
2583 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
2584 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(
2585 *MF.getFunction().getParent(), nullptr)
2586 ? LoongArchII::MO_CALL
2587 : LoongArchII::MO_CALL_PLT;
2588 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
2589 }
2590
2591 // The first call operand is the chain and the second is the target address.
2592 SmallVector<SDValue> Ops;
2593 Ops.push_back(Chain);
2594 Ops.push_back(Callee);
2595
2596 // Add argument registers to the end of the list so that they are
2597 // known live into the call.
2598 for (auto &Reg : RegsToPass)
2599 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
2600
2601 if (!IsTailCall) {
2602 // Add a register mask operand representing the call-preserved registers.
2603 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
2604 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
2605 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", 2605
, __extension__ __PRETTY_FUNCTION__))
;
2606 Ops.push_back(DAG.getRegisterMask(Mask));
2607 }
2608
2609 // Glue the call to the argument copies, if any.
2610 if (Glue.getNode())
2611 Ops.push_back(Glue);
2612
2613 // Emit the call.
2614 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
2615
2616 if (IsTailCall) {
2617 MF.getFrameInfo().setHasTailCall();
2618 return DAG.getNode(LoongArchISD::TAIL, DL, NodeTys, Ops);
2619 }
2620
2621 Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops);
2622 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
2623 Glue = Chain.getValue(1);
2624
2625 // Mark the end of the call, which is glued to the call itself.
2626 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
2627 Glue = Chain.getValue(1);
2628
2629 // Assign locations to each value returned by this call.
2630 SmallVector<CCValAssign> RVLocs;
2631 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
2632 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
2633
2634 // Copy all of the result registers out of their specified physreg.
2635 for (auto &VA : RVLocs) {
2636 // Copy the value out.
2637 SDValue RetValue =
2638 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
2639 // Glue the RetValue to the end of the call sequence.
2640 Chain = RetValue.getValue(1);
2641 Glue = RetValue.getValue(2);
2642
2643 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
2644
2645 InVals.push_back(RetValue);
2646 }
2647
2648 return Chain;
2649}
2650
2651bool LoongArchTargetLowering::CanLowerReturn(
2652 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
2653 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
2654 SmallVector<CCValAssign> RVLocs;
2655 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
2656
2657 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2658 LoongArchABI::ABI ABI =
2659 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2660 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
2661 Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true,
2662 nullptr))
2663 return false;
2664 }
2665 return true;
2666}
2667
2668SDValue LoongArchTargetLowering::LowerReturn(
2669 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
2670 const SmallVectorImpl<ISD::OutputArg> &Outs,
2671 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
2672 SelectionDAG &DAG) const {
2673 // Stores the assignment of the return value to a location.
2674 SmallVector<CCValAssign> RVLocs;
2675
2676 // Info about the registers and stack slot.
2677 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
2678 *DAG.getContext());
2679
2680 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
2681 nullptr, CC_LoongArch);
2682 if (CallConv == CallingConv::GHC && !RVLocs.empty())
2683 report_fatal_error("GHC functions return void only");
2684 SDValue Glue;
2685 SmallVector<SDValue, 4> RetOps(1, Chain);
2686
2687 // Copy the result values into the output registers.
2688 for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
2689 CCValAssign &VA = RVLocs[i];
2690 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", 2690
, __extension__ __PRETTY_FUNCTION__))
;
2691
2692 // Handle a 'normal' return.
2693 SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL);
2694 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
2695
2696 // Guarantee that all emitted copies are stuck together.
2697 Glue = Chain.getValue(1);
2698 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
2699 }
2700
2701 RetOps[0] = Chain; // Update chain.
2702
2703 // Add the glue node if we have it.
2704 if (Glue.getNode())
2705 RetOps.push_back(Glue);
2706
2707 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
2708}
2709
2710bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
2711 bool ForCodeSize) const {
2712 // TODO: Maybe need more checks here after vector extension is supported.
2713 if (VT == MVT::f32 && !Subtarget.hasBasicF())
2714 return false;
2715 if (VT == MVT::f64 && !Subtarget.hasBasicD())
2716 return false;
2717 return (Imm.isZero() || Imm.isExactlyValue(+1.0));
2718}
2719
2720bool LoongArchTargetLowering::isCheapToSpeculateCttz(Type *) const {
2721 return true;
2722}
2723
2724bool LoongArchTargetLowering::isCheapToSpeculateCtlz(Type *) const {
2725 return true;
2726}
2727
2728bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
2729 const Instruction *I) const {
2730 if (!Subtarget.is64Bit())
2731 return isa<LoadInst>(I) || isa<StoreInst>(I);
2732
2733 if (isa<LoadInst>(I))
2734 return true;
2735
2736 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
2737 // require fences beacuse we can use amswap_db.[w/d].
2738 if (isa<StoreInst>(I)) {
2739 unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth();
2740 return (Size == 8 || Size == 16);
2741 }
2742
2743 return false;
2744}
2745
2746EVT LoongArchTargetLowering::getSetCCResultType(const DataLayout &DL,
2747 LLVMContext &Context,
2748 EVT VT) const {
2749 if (!VT.isVector())
2750 return getPointerTy(DL);
2751 return VT.changeVectorElementTypeToInteger();
2752}
2753
2754bool LoongArchTargetLowering::hasAndNot(SDValue Y) const {
2755 // TODO: Support vectors.
2756 return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y);
2757}
2758
2759bool LoongArchTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
2760 const CallInst &I,
2761 MachineFunction &MF,
2762 unsigned Intrinsic) const {
2763 switch (Intrinsic) {
2764 default:
2765 return false;
2766 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
2767 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
2768 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
2769 case Intrinsic::loongarch_masked_atomicrmw_nand_i32:
2770 Info.opc = ISD::INTRINSIC_W_CHAIN;
2771 Info.memVT = MVT::i32;
2772 Info.ptrVal = I.getArgOperand(0);
2773 Info.offset = 0;
2774 Info.align = Align(4);
2775 Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore |
2776 MachineMemOperand::MOVolatile;
2777 return true;
2778 // TODO: Add more Intrinsics later.
2779 }
2780}
2781
2782TargetLowering::AtomicExpansionKind
2783LoongArchTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
2784 // TODO: Add more AtomicRMWInst that needs to be extended.
2785
2786 // Since floating-point operation requires a non-trivial set of data
2787 // operations, use CmpXChg to expand.
2788 if (AI->isFloatingPointOperation() ||
2789 AI->getOperation() == AtomicRMWInst::UIncWrap ||
2790 AI->getOperation() == AtomicRMWInst::UDecWrap)
2791 return AtomicExpansionKind::CmpXChg;
2792
2793 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
2794 if (Size == 8 || Size == 16)
2795 return AtomicExpansionKind::MaskedIntrinsic;
2796 return AtomicExpansionKind::None;
2797}
2798
2799static Intrinsic::ID
2800getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen,
2801 AtomicRMWInst::BinOp BinOp) {
2802 if (GRLen == 64) {
2803 switch (BinOp) {
2804 default:
2805 llvm_unreachable("Unexpected AtomicRMW BinOp")::llvm::llvm_unreachable_internal("Unexpected AtomicRMW BinOp"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2805
)
;
2806 case AtomicRMWInst::Xchg:
2807 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
2808 case AtomicRMWInst::Add:
2809 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
2810 case AtomicRMWInst::Sub:
2811 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
2812 case AtomicRMWInst::Nand:
2813 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
2814 case AtomicRMWInst::UMax:
2815 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
2816 case AtomicRMWInst::UMin:
2817 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
2818 case AtomicRMWInst::Max:
2819 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
2820 case AtomicRMWInst::Min:
2821 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
2822 // TODO: support other AtomicRMWInst.
2823 }
2824 }
2825
2826 if (GRLen == 32) {
2827 switch (BinOp) {
2828 default:
2829 llvm_unreachable("Unexpected AtomicRMW BinOp")::llvm::llvm_unreachable_internal("Unexpected AtomicRMW BinOp"
, "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp", 2829
)
;
2830 case AtomicRMWInst::Xchg:
2831 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
2832 case AtomicRMWInst::Add:
2833 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
2834 case AtomicRMWInst::Sub:
2835 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
2836 case AtomicRMWInst::Nand:
2837 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
2838 // TODO: support other AtomicRMWInst.
2839 }
2840 }
2841
2842 llvm_unreachable("Unexpected GRLen\n")::llvm::llvm_unreachable_internal("Unexpected GRLen\n", "llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp"
, 2842)
;
2843}
2844
2845TargetLowering::AtomicExpansionKind
2846LoongArchTargetLowering::shouldExpandAtomicCmpXchgInIR(
2847 AtomicCmpXchgInst *CI) const {
2848 unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits();
2849 if (Size == 8 || Size == 16)
2850 return AtomicExpansionKind::MaskedIntrinsic;
2851 return AtomicExpansionKind::None;
2852}
2853
2854Value *LoongArchTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
2855 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
2856 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
2857 Value *Ordering =
2858 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(Ord));
2859
2860 // TODO: Support cmpxchg on LA32.
2861 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
2862 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
2863 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
2864 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2865 Type *Tys[] = {AlignedAddr->getType()};
2866 Function *MaskedCmpXchg =
2867 Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys);
2868 Value *Result = Builder.CreateCall(
2869 MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering});
2870 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2871 return Result;
2872}
2873
2874Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic(
2875 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
2876 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
2877 unsigned GRLen = Subtarget.getGRLen();
2878 Value *Ordering =
2879 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
2880 Type *Tys[] = {AlignedAddr->getType()};
2881 Function *LlwOpScwLoop = Intrinsic::getDeclaration(
2882 AI->getModule(),
2883 getIntrinsicForMaskedAtomicRMWBinOp(GRLen, AI->getOperation()), Tys);
2884
2885 if (GRLen == 64) {
2886 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
2887 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2888 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
2889 }
2890
2891 Value *Result;
2892
2893 // Must pass the shift amount needed to sign extend the loaded value prior
2894 // to performing a signed comparison for min/max. ShiftAmt is the number of
2895 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
2896 // is the number of bits to left+right shift the value in order to
2897 // sign-extend.
2898 if (AI->getOperation() == AtomicRMWInst::Min ||
2899 AI->getOperation() == AtomicRMWInst::Max) {
2900 const DataLayout &DL = AI->getModule()->getDataLayout();
2901 unsigned ValWidth =
2902 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
2903 Value *SextShamt =
2904 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
2905 Result = Builder.CreateCall(LlwOpScwLoop,
2906 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
2907 } else {
2908 Result =
2909 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
2910 }
2911
2912 if (GRLen == 64)
2913 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2914 return Result;
2915}
2916
2917bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd(
2918 const MachineFunction &MF, EVT VT) const {
2919 VT = VT.getScalarType();
2920
2921 if (!VT.isSimple())
2922 return false;
2923
2924 switch (VT.getSimpleVT().SimpleTy) {
2925 case MVT::f32:
2926 case MVT::f64:
2927 return true;
2928 default:
2929 break;
2930 }
2931
2932 return false;
2933}
2934
2935Register LoongArchTargetLowering::getExceptionPointerRegister(
2936 const Constant *PersonalityFn) const {
2937 return LoongArch::R4;
2938}
2939
2940Register LoongArchTargetLowering::getExceptionSelectorRegister(
2941 const Constant *PersonalityFn) const {
2942 return LoongArch::R5;
2943}
2944
2945//===----------------------------------------------------------------------===//
2946// LoongArch Inline Assembly Support
2947//===----------------------------------------------------------------------===//
2948
2949LoongArchTargetLowering::ConstraintType
2950LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
2951 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
2952 //
2953 // 'f': A floating-point register (if available).
2954 // 'k': A memory operand whose address is formed by a base register and
2955 // (optionally scaled) index register.
2956 // 'l': A signed 16-bit constant.
2957 // 'm': A memory operand whose address is formed by a base register and
2958 // offset that is suitable for use in instructions with the same
2959 // addressing mode as st.w and ld.w.
2960 // 'I': A signed 12-bit constant (for arithmetic instructions).
2961 // 'J': Integer zero.
2962 // 'K': An unsigned 12-bit constant (for logic instructions).
2963 // "ZB": An address that is held in a general-purpose register. The offset is
2964 // zero.
2965 // "ZC": A memory operand whose address is formed by a base register and
2966 // offset that is suitable for use in instructions with the same
2967 // addressing mode as ll.w and sc.w.
2968 if (Constraint.size() == 1) {
2969 switch (Constraint[0]) {
2970 default:
2971 break;
2972 case 'f':
2973 return C_RegisterClass;
2974 case 'l':
2975 case 'I':
2976 case 'J':
2977 case 'K':
2978 return C_Immediate;
2979 case 'k':
2980 return C_Memory;
2981 }
2982 }
2983
2984 if (Constraint == "ZC" || Constraint == "ZB")
2985 return C_Memory;
2986
2987 // 'm' is handled here.
2988 return TargetLowering::getConstraintType(Constraint);
2989}
2990
2991unsigned LoongArchTargetLowering::getInlineAsmMemConstraint(
2992 StringRef ConstraintCode) const {
2993 return StringSwitch<unsigned>(ConstraintCode)
2994 .Case("k", InlineAsm::Constraint_k)
2995 .Case("ZB", InlineAsm::Constraint_ZB)
2996 .Case("ZC", InlineAsm::Constraint_ZC)
2997 .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
2998}
2999
3000std::pair<unsigned, const TargetRegisterClass *>
3001LoongArchTargetLowering::getRegForInlineAsmConstraint(
3002 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
3003 // First, see if this is a constraint that directly corresponds to a LoongArch
3004 // register class.
3005 if (Constraint.size() == 1) {
3006 switch (Constraint[0]) {
3007 case 'r':
3008 // TODO: Support fixed vectors up to GRLen?
3009 if (VT.isVector())
3010 break;
3011 return std::make_pair(0U, &LoongArch::GPRRegClass);
3012 case 'f':
3013 if (Subtarget.hasBasicF() && VT == MVT::f32)
3014 return std::make_pair(0U, &LoongArch::FPR32RegClass);
3015 if (Subtarget.hasBasicD() && VT == MVT::f64)
3016 return std::make_pair(0U, &LoongArch::FPR64RegClass);
3017 break;
3018 default:
3019 break;
3020 }
3021 }
3022
3023 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
3024 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
3025 // constraints while the official register name is prefixed with a '$'. So we
3026 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
3027 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
3028 // case insensitive, so no need to convert the constraint to upper case here.
3029 //
3030 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
3031 // decode the usage of register name aliases into their official names. And
3032 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
3033 // official register names.
3034 if (Constraint.startswith("{$r") || Constraint.startswith("{$f")) {
3035 bool IsFP = Constraint[2] == 'f';
3036 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
3037 std::pair<unsigned, const TargetRegisterClass *> R;
3038 R = TargetLowering::getRegForInlineAsmConstraint(
3039 TRI, join_items("", Temp.first, Temp.second), VT);
3040 // Match those names to the widest floating point register type available.
3041 if (IsFP) {
3042 unsigned RegNo = R.first;
3043 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
3044 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
3045 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
3046 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
3047 }
3048 }
3049 }
3050 return R;
3051 }
3052
3053 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
3054}
3055
3056void LoongArchTargetLowering::LowerAsmOperandForConstraint(
3057 SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
3058 SelectionDAG &DAG) const {
3059 // Currently only support length 1 constraints.
3060 if (Constraint.length() == 1) {
3061 switch (Constraint[0]) {
3062 case 'l':
3063 // Validate & create a 16-bit signed immediate operand.
3064 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3065 uint64_t CVal = C->getSExtValue();
3066 if (isInt<16>(CVal))
3067 Ops.push_back(
3068 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3069 }
3070 return;
3071 case 'I':
3072 // Validate & create a 12-bit signed immediate operand.
3073 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3074 uint64_t CVal = C->getSExtValue();
3075 if (isInt<12>(CVal))
3076 Ops.push_back(
3077 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3078 }
3079 return;
3080 case 'J':
3081 // Validate & create an integer zero operand.
3082 if (auto *C = dyn_cast<ConstantSDNode>(Op))
3083 if (C->getZExtValue() == 0)
3084 Ops.push_back(
3085 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
3086 return;
3087 case 'K':
3088 // Validate & create a 12-bit unsigned immediate operand.
3089 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3090 uint64_t CVal = C->getZExtValue();
3091 if (isUInt<12>(CVal))
3092 Ops.push_back(
3093 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3094 }
3095 return;
3096 default:
3097 break;
3098 }
3099 }
3100 TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
3101}
3102
3103#define GET_REGISTER_MATCHER
3104#include "LoongArchGenAsmMatcher.inc"
3105
3106Register
3107LoongArchTargetLowering::getRegisterByName(const char *RegName, LLT VT,
3108 const MachineFunction &MF) const {
3109 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
3110 std::string NewRegName = Name.second.str();
3111 Register Reg = MatchRegisterAltName(NewRegName);
3112 if (Reg == LoongArch::NoRegister)
3113 Reg = MatchRegisterName(NewRegName);
3114 if (Reg == LoongArch::NoRegister)
3115 report_fatal_error(
3116 Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
3117 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
3118 if (!ReservedRegs.test(Reg))
3119 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
3120 StringRef(RegName) + "\"."));
3121 return Reg;
3122}
3123
3124bool LoongArchTargetLowering::decomposeMulByConstant(LLVMContext &Context,
3125 EVT VT, SDValue C) const {
3126 // TODO: Support vectors.
3127 if (!VT.isScalarInteger())
3128 return false;
3129
3130 // Omit the optimization if the data size exceeds GRLen.
3131 if (VT.getSizeInBits() > Subtarget.getGRLen())
3132 return false;
3133
3134 // Break MUL into (SLLI + ADD/SUB) or ALSL.
3135 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
3136 const APInt &Imm = ConstNode->getAPIntValue();
3137 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
3138 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
3139 return true;
3140 }
3141
3142 return false;
3143}
3144
3145bool LoongArchTargetLowering::isLegalAddressingMode(const DataLayout &DL,
3146 const AddrMode &AM,
3147 Type *Ty, unsigned AS,
3148 Instruction *I) const {
3149 // LoongArch has four basic addressing modes:
3150 // 1. reg
3151 // 2. reg + 12-bit signed offset
3152 // 3. reg + 14-bit signed offset left-shifted by 2
3153 // 4. reg1 + reg2
3154 // TODO: Add more checks after support vector extension.
3155
3156 // No global is ever allowed as a base.
3157 if (AM.BaseGV)
3158 return false;
3159
3160 // Require a 12 or 14 bit signed offset.
3161 if (!isInt<12>(AM.BaseOffs) || !isShiftedInt<14, 2>(AM.BaseOffs))
3162 return false;
3163
3164 switch (AM.Scale) {
3165 case 0:
3166 // "i" is not allowed.
3167 if (!AM.HasBaseReg)
3168 return false;
3169 // Otherwise we have "r+i".
3170 break;
3171 case 1:
3172 // "r+r+i" is not allowed.
3173 if (AM.HasBaseReg && AM.BaseOffs != 0)
3174 return false;
3175 // Otherwise we have "r+r" or "r+i".
3176 break;
3177 case 2:
3178 // "2*r+r" or "2*r+i" is not allowed.
3179 if (AM.HasBaseReg || AM.BaseOffs)
3180 return false;
3181 // Otherwise we have "r+r".
3182 break;
3183 default:
3184 return false;
3185 }
3186
3187 return true;
3188}
3189
3190bool LoongArchTargetLowering::hasAndNotCompare(SDValue Y) const {
3191 // TODO: Support vectors.
3192 if (Y.getValueType().isVector())
3193 return false;
3194
3195 return !isa<ConstantSDNode>(Y);
3196}