Skip to content

Commit ffcebcd

Browse files
authored
[LoongArch] Implement Statepoint lowering (llvm#108212)
The functionality has been validated in OpenHarmony's arkcompiler.
1 parent 59731ee commit ffcebcd

File tree

7 files changed

+335
-1
lines changed

7 files changed

+335
-1
lines changed

llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ void LoongArchAsmPrinter::emitInstruction(const MachineInstr *MI) {
4040
}
4141

4242
switch (MI->getOpcode()) {
43+
case TargetOpcode::STATEPOINT:
44+
LowerSTATEPOINT(*MI);
45+
return;
4346
case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
4447
LowerPATCHABLE_FUNCTION_ENTER(*MI);
4548
return;
@@ -146,6 +149,46 @@ bool LoongArchAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
146149
return false;
147150
}
148151

152+
void LoongArchAsmPrinter::LowerSTATEPOINT(const MachineInstr &MI) {
153+
StatepointOpers SOpers(&MI);
154+
if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
155+
assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
156+
emitNops(PatchBytes / 4);
157+
} else {
158+
// Lower call target and choose correct opcode.
159+
const MachineOperand &CallTarget = SOpers.getCallTarget();
160+
MCOperand CallTargetMCOp;
161+
switch (CallTarget.getType()) {
162+
case MachineOperand::MO_GlobalAddress:
163+
case MachineOperand::MO_ExternalSymbol:
164+
lowerOperand(CallTarget, CallTargetMCOp);
165+
EmitToStreamer(*OutStreamer,
166+
MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));
167+
break;
168+
case MachineOperand::MO_Immediate:
169+
CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
170+
EmitToStreamer(*OutStreamer,
171+
MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));
172+
break;
173+
case MachineOperand::MO_Register:
174+
CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
175+
EmitToStreamer(*OutStreamer, MCInstBuilder(LoongArch::JIRL)
176+
.addReg(LoongArch::R1)
177+
.addOperand(CallTargetMCOp)
178+
.addImm(0));
179+
break;
180+
default:
181+
llvm_unreachable("Unsupported operand type in statepoint call target");
182+
break;
183+
}
184+
}
185+
186+
auto &Ctx = OutStreamer->getContext();
187+
MCSymbol *MILabel = Ctx.createTempSymbol();
188+
OutStreamer->emitLabel(MILabel);
189+
SM.recordStatepoint(*MILabel, MI);
190+
}
191+
149192
void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
150193
const MachineInstr &MI) {
151194
const Function &F = MF->getFunction();

llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "LoongArchSubtarget.h"
1717
#include "llvm/CodeGen/AsmPrinter.h"
18+
#include "llvm/CodeGen/StackMaps.h"
1819
#include "llvm/MC/MCStreamer.h"
1920
#include "llvm/Support/Compiler.h"
2021

@@ -41,6 +42,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchAsmPrinter : public AsmPrinter {
4142
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
4243
const char *ExtraCode, raw_ostream &OS) override;
4344

45+
void LowerSTATEPOINT(const MachineInstr &MI);
4446
void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
4547
void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
4648
void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);

llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4588,6 +4588,20 @@ MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
45884588
return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
45894589
case LoongArch::PseudoCTPOP:
45904590
return emitPseudoCTPOP(MI, BB, Subtarget);
4591+
case TargetOpcode::STATEPOINT:
4592+
// STATEPOINT is a pseudo instruction which has no implicit defs/uses
4593+
// while bl call instruction (where statepoint will be lowered at the
4594+
// end) has implicit def. This def is early-clobber as it will be set at
4595+
// the moment of the call and earlier than any use is read.
4596+
// Add this implicit dead def here as a workaround.
4597+
MI.addOperand(*MI.getMF(),
4598+
MachineOperand::CreateReg(
4599+
LoongArch::R1, /*isDef*/ true,
4600+
/*isImp*/ true, /*isKill*/ false, /*isDead*/ true,
4601+
/*isUndef*/ false, /*isEarlyClobber*/ true));
4602+
if (!Subtarget.is64Bit())
4603+
report_fatal_error("STATEPOINT is only supported on 64-bit targets");
4604+
return emitPatchPoint(MI, BB);
45914605
}
45924606
}
45934607

llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
1818
#include "MCTargetDesc/LoongArchMatInt.h"
1919
#include "llvm/CodeGen/RegisterScavenging.h"
20+
#include "llvm/CodeGen/StackMaps.h"
2021
#include "llvm/MC/MCInstBuilder.h"
2122

2223
using namespace llvm;
@@ -236,7 +237,25 @@ unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
236237
const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
237238
return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
238239
}
239-
return MI.getDesc().getSize();
240+
241+
unsigned NumBytes = 0;
242+
const MCInstrDesc &Desc = MI.getDesc();
243+
244+
// Size should be preferably set in
245+
// llvm/lib/Target/LoongArch/LoongArch*InstrInfo.td (default case).
246+
// Specific cases handle instructions of variable sizes.
247+
switch (Desc.getOpcode()) {
248+
default:
249+
return Desc.getSize();
250+
case TargetOpcode::STATEPOINT:
251+
NumBytes = StatepointOpers(&MI).getNumPatchBytes();
252+
assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
253+
// No patch bytes means a normal call inst (i.e. `bl`) is emitted.
254+
if (NumBytes == 0)
255+
NumBytes = 4;
256+
break;
257+
}
258+
return NumBytes;
240259
}
241260

242261
bool LoongArchInstrInfo::isAsCheapAsAMove(const MachineInstr &MI) const {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; RUN: llc --mtriple=loongarch64 --verify-machineinstrs --stop-after=prologepilog < %s | FileCheck %s
2+
3+
;; Check that STATEPOINT instruction has an early clobber implicit def for R1.
4+
5+
define void @test() gc "statepoint-example" {
6+
entry:
7+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" ()]
8+
; CHECK: STATEPOINT 0, 0, 0, target-flags(loongarch-call-plt) @return_i1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, csr_ilp32s_lp64s, implicit-def $r3, implicit-def dead early-clobber $r1
9+
ret void
10+
}
11+
12+
declare void @return_i1()
13+
declare token @llvm.experimental.gc.statepoint.p0(i64, i32, ptr, i32, i32, ...)
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc --mtriple=loongarch64 -verify-machineinstrs < %s | FileCheck %s
3+
;; A collection of basic functionality tests for statepoint lowering - most
4+
;; interesting cornercases are exercised through the x86 tests.
5+
6+
%struct = type { i64, i64 }
7+
8+
declare zeroext i1 @return_i1()
9+
declare zeroext i32 @return_i32()
10+
declare ptr @return_i32ptr()
11+
declare float @return_float()
12+
declare %struct @return_struct()
13+
declare void @varargf(i32, ...)
14+
15+
define i1 @test_i1_return() nounwind gc "statepoint-example" {
16+
;; This is just checking that a i1 gets lowered normally when there's no extra
17+
;; state arguments to the statepoint
18+
; CHECK-LABEL: test_i1_return:
19+
; CHECK: # %bb.0: # %entry
20+
; CHECK-NEXT: addi.d $sp, $sp, -16
21+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
22+
; CHECK-NEXT: bl %plt(return_i1)
23+
; CHECK-NEXT: .Ltmp0:
24+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
25+
; CHECK-NEXT: addi.d $sp, $sp, 16
26+
; CHECK-NEXT: ret
27+
entry:
28+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0)
29+
%call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
30+
ret i1 %call1
31+
}
32+
33+
define i32 @test_i32_return() nounwind gc "statepoint-example" {
34+
; CHECK-LABEL: test_i32_return:
35+
; CHECK: # %bb.0: # %entry
36+
; CHECK-NEXT: addi.d $sp, $sp, -16
37+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
38+
; CHECK-NEXT: bl %plt(return_i32)
39+
; CHECK-NEXT: .Ltmp1:
40+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
41+
; CHECK-NEXT: addi.d $sp, $sp, 16
42+
; CHECK-NEXT: ret
43+
entry:
44+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i32 ()) @return_i32, i32 0, i32 0, i32 0, i32 0)
45+
%call1 = call zeroext i32 @llvm.experimental.gc.result.i32(token %safepoint_token)
46+
ret i32 %call1
47+
}
48+
49+
define ptr @test_i32ptr_return() nounwind gc "statepoint-example" {
50+
; CHECK-LABEL: test_i32ptr_return:
51+
; CHECK: # %bb.0: # %entry
52+
; CHECK-NEXT: addi.d $sp, $sp, -16
53+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
54+
; CHECK-NEXT: bl %plt(return_i32ptr)
55+
; CHECK-NEXT: .Ltmp2:
56+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
57+
; CHECK-NEXT: addi.d $sp, $sp, 16
58+
; CHECK-NEXT: ret
59+
entry:
60+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(ptr ()) @return_i32ptr, i32 0, i32 0, i32 0, i32 0)
61+
%call1 = call ptr @llvm.experimental.gc.result.p0(token %safepoint_token)
62+
ret ptr %call1
63+
}
64+
65+
define float @test_float_return() nounwind gc "statepoint-example" {
66+
; CHECK-LABEL: test_float_return:
67+
; CHECK: # %bb.0: # %entry
68+
; CHECK-NEXT: addi.d $sp, $sp, -16
69+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
70+
; CHECK-NEXT: bl %plt(return_float)
71+
; CHECK-NEXT: .Ltmp3:
72+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
73+
; CHECK-NEXT: addi.d $sp, $sp, 16
74+
; CHECK-NEXT: ret
75+
entry:
76+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(float ()) @return_float, i32 0, i32 0, i32 0, i32 0)
77+
%call1 = call float @llvm.experimental.gc.result.f32(token %safepoint_token)
78+
ret float %call1
79+
}
80+
81+
define %struct @test_struct_return() nounwind gc "statepoint-example" {
82+
; CHECK-LABEL: test_struct_return:
83+
; CHECK: # %bb.0: # %entry
84+
; CHECK-NEXT: addi.d $sp, $sp, -16
85+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
86+
; CHECK-NEXT: bl %plt(return_struct)
87+
; CHECK-NEXT: .Ltmp4:
88+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
89+
; CHECK-NEXT: addi.d $sp, $sp, 16
90+
; CHECK-NEXT: ret
91+
entry:
92+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(%struct ()) @return_struct, i32 0, i32 0, i32 0, i32 0)
93+
%call1 = call %struct @llvm.experimental.gc.result.struct(token %safepoint_token)
94+
ret %struct %call1
95+
}
96+
97+
define i1 @test_relocate(ptr addrspace(1) %a) nounwind gc "statepoint-example" {
98+
; CHECK-LABEL: test_relocate:
99+
; CHECK: # %bb.0: # %entry
100+
; CHECK-NEXT: addi.d $sp, $sp, -16
101+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
102+
; CHECK-NEXT: st.d $a0, $sp, 0
103+
; CHECK-NEXT: bl %plt(return_i1)
104+
; CHECK-NEXT: .Ltmp5:
105+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
106+
; CHECK-NEXT: addi.d $sp, $sp, 16
107+
; CHECK-NEXT: ret
108+
entry:
109+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a)]
110+
%call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0)
111+
%call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
112+
ret i1 %call2
113+
}
114+
115+
define void @test_void_vararg() nounwind gc "statepoint-example" {
116+
; CHECK-LABEL: test_void_vararg:
117+
; CHECK: # %bb.0: # %entry
118+
; CHECK-NEXT: addi.d $sp, $sp, -16
119+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
120+
; CHECK-NEXT: ori $a0, $zero, 42
121+
; CHECK-NEXT: ori $a1, $zero, 43
122+
; CHECK-NEXT: bl %plt(varargf)
123+
; CHECK-NEXT: .Ltmp6:
124+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
125+
; CHECK-NEXT: addi.d $sp, $sp, 16
126+
; CHECK-NEXT: ret
127+
entry:
128+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void (i32, ...)) @varargf, i32 2, i32 0, i32 42, i32 43, i32 0, i32 0)
129+
;; if we try to use the result from a statepoint wrapping a
130+
;; non-void-returning varargf, we will experience a crash.
131+
ret void
132+
}
133+
134+
define i1 @test_i1_return_patchable() nounwind gc "statepoint-example" {
135+
;; A patchable variant of test_i1_return
136+
; CHECK-LABEL: test_i1_return_patchable:
137+
; CHECK: # %bb.0: # %entry
138+
; CHECK-NEXT: addi.d $sp, $sp, -16
139+
; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
140+
; CHECK-NEXT: nop
141+
; CHECK-NEXT: .Ltmp7:
142+
; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
143+
; CHECK-NEXT: addi.d $sp, $sp, 16
144+
; CHECK-NEXT: ret
145+
entry:
146+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 4, ptr elementtype(i1 ()) null, i32 0, i32 0, i32 0, i32 0)
147+
%call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
148+
ret i1 %call1
149+
}
150+
151+
declare void @consume(ptr addrspace(1) %obj)
152+
153+
define i1 @test_cross_bb(ptr addrspace(1) %a, i1 %external_cond) nounwind gc "statepoint-example" {
154+
; CHECK-LABEL: test_cross_bb:
155+
; CHECK: # %bb.0: # %entry
156+
; CHECK-NEXT: addi.d $sp, $sp, -32
157+
; CHECK-NEXT: st.d $ra, $sp, 24 # 8-byte Folded Spill
158+
; CHECK-NEXT: st.d $fp, $sp, 16 # 8-byte Folded Spill
159+
; CHECK-NEXT: andi $fp, $a1, 1
160+
; CHECK-NEXT: st.d $a0, $sp, 8
161+
; CHECK-NEXT: bl %plt(return_i1)
162+
; CHECK-NEXT: .Ltmp8:
163+
; CHECK-NEXT: beqz $fp, .LBB8_2
164+
; CHECK-NEXT: # %bb.1: # %left
165+
; CHECK-NEXT: ld.d $a1, $sp, 8
166+
; CHECK-NEXT: move $fp, $a0
167+
; CHECK-NEXT: move $a0, $a1
168+
; CHECK-NEXT: bl %plt(consume)
169+
; CHECK-NEXT: move $a0, $fp
170+
; CHECK-NEXT: b .LBB8_3
171+
; CHECK-NEXT: .LBB8_2: # %right
172+
; CHECK-NEXT: ori $a0, $zero, 1
173+
; CHECK-NEXT: .LBB8_3: # %right
174+
; CHECK-NEXT: ld.d $fp, $sp, 16 # 8-byte Folded Reload
175+
; CHECK-NEXT: ld.d $ra, $sp, 24 # 8-byte Folded Reload
176+
; CHECK-NEXT: addi.d $sp, $sp, 32
177+
; CHECK-NEXT: ret
178+
entry:
179+
%safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a)]
180+
br i1 %external_cond, label %left, label %right
181+
182+
left:
183+
%call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0)
184+
%call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
185+
call void @consume(ptr addrspace(1) %call1)
186+
ret i1 %call2
187+
188+
right:
189+
ret i1 true
190+
}
191+
192+
%struct2 = type { i64, i64, i64 }
193+
194+
declare void @consume_attributes(i32, ptr nest, i32, ptr byval(%struct2))
195+
196+
define void @test_attributes(ptr byval(%struct2) %s) nounwind gc "statepoint-example" {
197+
; CHECK-LABEL: test_attributes:
198+
; CHECK: # %bb.0: # %entry
199+
; CHECK-NEXT: addi.d $sp, $sp, -32
200+
; CHECK-NEXT: st.d $ra, $sp, 24 # 8-byte Folded Spill
201+
; CHECK-NEXT: ld.d $a1, $a0, 16
202+
; CHECK-NEXT: st.d $a1, $sp, 16
203+
; CHECK-NEXT: ld.d $a1, $a0, 8
204+
; CHECK-NEXT: st.d $a1, $sp, 8
205+
; CHECK-NEXT: ld.d $a0, $a0, 0
206+
; CHECK-NEXT: st.d $a0, $sp, 0
207+
; CHECK-NEXT: ori $a0, $zero, 42
208+
; CHECK-NEXT: ori $a2, $zero, 17
209+
; CHECK-NEXT: addi.d $a3, $sp, 0
210+
; CHECK-NEXT: move $a1, $zero
211+
; CHECK-NEXT: bl %plt(consume_attributes)
212+
; CHECK-NEXT: .Ltmp9:
213+
; CHECK-NEXT: ld.d $ra, $sp, 24 # 8-byte Folded Reload
214+
; CHECK-NEXT: addi.d $sp, $sp, 32
215+
; CHECK-NEXT: ret
216+
entry:
217+
;; We call a function that has a nest argument and a byval argument.
218+
%statepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void (i32, ptr, i32, ptr)) @consume_attributes, i32 4, i32 0, i32 42, ptr nest null, i32 17, ptr byval(%struct2) %s, i32 0, i32 0)
219+
ret void
220+
}
221+
222+
declare token @llvm.experimental.gc.statepoint.p0(i64, i32, ptr, i32, i32, ...)
223+
declare i1 @llvm.experimental.gc.result.i1(token)
224+
declare i32 @llvm.experimental.gc.result.i32(token)
225+
declare ptr @llvm.experimental.gc.result.p0(token)
226+
declare float @llvm.experimental.gc.result.f32(token)
227+
declare %struct @llvm.experimental.gc.result.struct(token)
228+
declare ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token, i32, i32)

llvm/unittests/Target/LoongArch/InstSizes.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,18 @@ TEST(InstSizes, AtomicPseudo) {
140140
EXPECT_EQ(44u, II.getInstSizeInBytes(*I));
141141
});
142142
}
143+
144+
TEST(InstSizes, StatePoint) {
145+
std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
146+
std::unique_ptr<LoongArchInstrInfo> II = createInstrInfo(TM.get());
147+
148+
runChecks(
149+
TM.get(), II.get(), " declare zeroext i1 @return_i1()\n",
150+
// clang-format off
151+
" STATEPOINT 0, 0, 0, target-flags(loongarch-call-plt) @return_i1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, implicit-def $r3, implicit-def $r4\n",
152+
// clang-format on
153+
[](LoongArchInstrInfo &II, MachineFunction &MF) {
154+
auto I = MF.begin()->begin();
155+
EXPECT_EQ(4u, II.getInstSizeInBytes(*I));
156+
});
157+
}

0 commit comments

Comments
 (0)