Skip to content

Commit 407143c

Browse files
committed
[BPF] fix sub-register handling for bpf_fastcall
bpf_fastcall induced spill/fill pairs should be generated for sub-register as well as for sub-registers. At the moment this is not the case, e.g.: $ cat t.c extern int foo(void) __attribute__((bpf_fastcall)); int bar(int a) { foo(); return a; } $ clang --target=bpf -mcpu=v3 -O2 -S t.c -o - ... call foo w0 = w1 exit Modify BPFMIPeephole.cpp:collectBPFFastCalls() to check sub-registers liveness and thus produce correct code for example above: *(u64 *)(r10 - 8) = r1 call foo r1 = *(u64 *)(r10 - 8) w0 = w1 exit
1 parent 7883b02 commit 407143c

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

llvm/lib/Target/BPF/BPFMIPeephole.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,11 +614,20 @@ static void collectBPFFastCalls(const TargetRegisterInfo *TRI,
614614
LiveRegs.init(*TRI);
615615
LiveRegs.addLiveOuts(BB);
616616
Calls.clear();
617+
618+
auto IsLiveBeforeInsn = [&](MCRegister R, MachineInstr &MI) {
619+
return !MI.definesRegister(R, TRI) && LiveRegs.contains(R);
620+
};
621+
617622
for (MachineInstr &MI : llvm::reverse(BB)) {
618623
if (MI.isCall()) {
619624
unsigned LiveCallerSavedRegs = 0;
620625
for (MCRegister R : CallerSavedRegs) {
621-
bool DoSpillFill = !MI.definesRegister(R, TRI) && LiveRegs.contains(R);
626+
bool DoSpillFill = IsLiveBeforeInsn(R, MI);
627+
for (MCSubRegIndexIterator SRI(R, TRI); SRI.isValid(); ++SRI) {
628+
MCRegister SR = SRI.getSubReg();
629+
DoSpillFill |= IsLiveBeforeInsn(SR, MI);
630+
}
622631
if (!DoSpillFill)
623632
continue;
624633
LiveCallerSavedRegs |= 1 << R;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
; RUN: llc -O2 --march=bpfel %s -o - | FileCheck %s
2+
3+
; Generated from the following C code:
4+
;
5+
; extern int foo(void) __attribute__((bpf_fastcall));
6+
;
7+
; int bar(int a) {
8+
; foo();
9+
; return a;
10+
; }
11+
;
12+
; Using the following command:
13+
;
14+
; clang --target=bpf -emit-llvm -O2 -S -o - t.c
15+
;
16+
; (unnecessary attrs removed maually)
17+
18+
; Check that function marked with bpf_fastcall does not clobber W1-W5.
19+
20+
define dso_local i32 @bar(i32 %a) {
21+
entry:
22+
%call = tail call i32 @foo() #0
23+
ret i32 %a
24+
}
25+
26+
; CHECK: # %bb.0:
27+
; CHECK-NEXT: *(u64 *)(r10 - 8) = r1
28+
; CHECK-NEXT: call foo
29+
; CHECK-NEXT: r1 = *(u64 *)(r10 - 8)
30+
; CHECK-NEXT: w0 = w1
31+
; CHECK-NEXT: exit
32+
33+
declare dso_local i32 @foo() #0
34+
35+
attributes #0 = { "bpf_fastcall" }
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
; RUN: llc -O2 --march=bpfel %s -o - | FileCheck %s
2+
3+
; Generated from the following C code:
4+
;
5+
; extern int foo(void) __attribute__((bpf_fastcall));
6+
;
7+
; int bar(int a, int b, int c, int d, int e) {
8+
; foo();
9+
; return e;
10+
; }
11+
;
12+
; Using the following command:
13+
;
14+
; clang --target=bpf -emit-llvm -O2 -S -o - t.c
15+
;
16+
; (unnecessary attrs removed maually)
17+
18+
; Check that function marked with bpf_fastcall does not clobber W1-W5.
19+
20+
define dso_local i32 @bar(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
21+
entry:
22+
%call = tail call i32 @foo() #0
23+
ret i32 %e
24+
}
25+
26+
; CHECK: # %bb.0:
27+
; CHECK-NEXT: *(u64 *)(r10 - 8) = r5
28+
; CHECK-NEXT: call foo
29+
; CHECK-NEXT: r5 = *(u64 *)(r10 - 8)
30+
; CHECK-NEXT: w0 = w5
31+
; CHECK-NEXT: exit
32+
33+
declare dso_local i32 @foo() #0
34+
35+
attributes #0 = { "bpf_fastcall" }

0 commit comments

Comments
 (0)