Skip to content

Commit 2fe3151

Browse files
lztophoebewang
authored andcommitted
[X86] TCRETURNmi fix for 32bit platform
This fix is similar to 3cf3ffc("Fix the TCRETURNmi64 bug differently.") after allocating register for index+base, we will only have one register left This bug affects linux kernel compilation for x86 target. Error happens when compiling kmod_si476x_core. clang complains: error: ran out of registers during register allocation The full command is: clang -Wp,-MMD,drivers/mfd/.si476x-cmd.o.d -nostdinc -isystem /opt/toolchain/main/lib/clang/14.0.0/include -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/compiler-version.h -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -Qunused-arguments -fmacro-prefix-map=./= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -std=gnu89 -no-integrated-as --prefix=/usr/bin/ -Werror=unknown-warning-option -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m32 -msoft-float -mregparm=3 -freg-struct-return -fno-pic -mstack-alignment=4 -march=atom -mtune=atom -mtune=generic -Wa,-mtune=generic32 -ffreestanding -Wno-sign-compare -fno-asynchronous-unwind-tables -fno-delete-null-pointer-checks -Wno-frame-address -Wno-address-of-packed-member -O2 -Wframe-larger-than=1024 -fno-stack-protector -Wno-format-invalid-specifier -Wno-gnu -mno-global-merge -Wno-unused-but-set-variable -Wno-unused-const-variable -fomit-frame-pointer -ftrivial-auto-var-init=pattern -fno-stack-clash-protection -falign-functions=32 -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wno-array-bounds -fno-strict-overflow -fno-stack-check -Werror=date-time -Werror=incompatible-pointer-types -Wno-initializer-overrides -Wno-format -Wno-sign-compare -Wno-format-zero-length -Wno-pointer-to-enum-cast -Wno-tautological-constant-out-of-range-compare -DKBUILD_MODFILE='"drivers/mfd/si476x-core"' -DKBUILD_BASENAME='"si476x_cmd"' -DKBUILD_MODNAME='"si476x_core"' -D__KBUILD_MODNAME=kmod_si476x_core -c -o drivers/mfd/si476x-cmd.o drivers/mfd/si476x-cmd.c ------------- LLVM cannot compile the following code for x86 32bit target, the reason is tail call(TCRETURNmi) is using 2 registers for index+base and we want to use more than one registers for passing function args and that is impossible. This fix is similar to 3cf3ffc("Fix the TCRETURNmi64 bug differently."). We will only use tail call when it is using <=1 registers for passing args. ``` struct BIG_PARM { int ver; }; static struct { int (*foo) (struct BIG_PARM* a, void *b); int (*bar) (struct BIG_PARM* a); int (*zoo0) (void); int (*zoo1) (void); int (*zoo2) (void); int (*zoo3) (void); int (*zoo4) (void); } vtable[] = { [0] = { .foo = (int (*)(struct BIG_PARM* a, void *b))0xdeadbeef, }, }; int something(struct BIG_PARM *a, void* b) { return vtable[a->ver].foo(a,b); } ``` ``` $ clang -std=gnu89 -m32 -mregparm=3 -mtune=generic -fno-strict-overflow -O2 -c t0.c -o t0.c.o error: ran out of registers during register allocation 1 error generated. ``` Reviewed By: pengfei Differential Revision: https://reviews.llvm.org/D118312
1 parent 8366e18 commit 2fe3151

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

llvm/lib/Target/X86/X86InstrCompiler.td

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1235,14 +1235,31 @@ def X86tcret_6regs : PatFrag<(ops node:$ptr, node:$off),
12351235
return true;
12361236
}]>;
12371237

1238+
def X86tcret_1reg : PatFrag<(ops node:$ptr, node:$off),
1239+
(X86tcret node:$ptr, node:$off), [{
1240+
// X86tcret args: (*chain, ptr, imm, regs..., glue)
1241+
unsigned NumRegs = 1;
1242+
LoadSDNode* ld = dyn_cast<LoadSDNode>(N->getOperand(1));
1243+
const SDValue& BasePtr = ld->getBasePtr();
1244+
if (isa<FrameIndexSDNode>(BasePtr))
1245+
NumRegs = 3;
1246+
else if (BasePtr->getNumOperands() && isa<GlobalAddressSDNode>(BasePtr->getOperand(0)))
1247+
NumRegs = 3;
1248+
for (unsigned i = 3, e = N->getNumOperands(); i != e; ++i)
1249+
if (isa<RegisterSDNode>(N->getOperand(i)) && ( NumRegs-- == 0))
1250+
return false;
1251+
return true;
1252+
}]>;
1253+
12381254
def : Pat<(X86tcret ptr_rc_tailcall:$dst, timm:$off),
12391255
(TCRETURNri ptr_rc_tailcall:$dst, timm:$off)>,
12401256
Requires<[Not64BitMode, NotUseIndirectThunkCalls]>;
12411257

12421258
// FIXME: This is disabled for 32-bit PIC mode because the global base
12431259
// register which is part of the address mode may be assigned a
12441260
// callee-saved register.
1245-
def : Pat<(X86tcret (load addr:$dst), timm:$off),
1261+
// Similar to X86tcret_6regs, here we only have 1 register left
1262+
def : Pat<(X86tcret_1reg (load addr:$dst), timm:$off),
12461263
(TCRETURNmi addr:$dst, timm:$off)>,
12471264
Requires<[Not64BitMode, IsNotPIC, NotUseIndirectThunkCalls]>;
12481265

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
; RUN: llc < %s -mtriple=i686-linux-gnu -mcpu=pentium | FileCheck %s
2+
3+
; Tail call should not make register allocation fail (x86-32)
4+
5+
%struct.anon = type { i32 (%struct.BIG_PARM*, i8*)*, i32 ()*, i32 ()*, i32 ()*, i32 ()*, i32 ()*, i32 ()* }
6+
%struct.BIG_PARM = type { i32 }
7+
8+
@vtable = internal unnamed_addr constant [1 x %struct.anon] [%struct.anon { i32 (%struct.BIG_PARM*, i8*)* inttoptr (i32 -559038737 to i32 (%struct.BIG_PARM*, i8*)*), i32 ()* null, i32 ()* null, i32 ()* null, i32 ()* null, i32 ()* null, i32 ()* null }], align 4
9+
10+
; Function Attrs: nounwind uwtable
11+
define dso_local i32 @something(%struct.BIG_PARM* inreg noundef %a, i8* inreg noundef %b) local_unnamed_addr #0 {
12+
entry:
13+
; CHECK: movl (%eax), %ecx
14+
; CHECK-NEXT: leal (%ecx,%ecx,8), %esi
15+
; CHECK-NEXT: leal (%esi,%esi,2), %esi
16+
; CHECK-NEXT: movl vtable(%ecx,%esi), %ecx
17+
; CHECK-NEXT: popl %esi
18+
; CHECK: jmpl *%ecx
19+
%ver = getelementptr inbounds %struct.BIG_PARM, %struct.BIG_PARM* %a, i32 0, i32 0
20+
%0 = load i32, i32* %ver, align 4
21+
%foo = getelementptr [1 x %struct.anon], [1 x %struct.anon]* @vtable, i32 0, i32 %0, i32 0
22+
%1 = load i32 (%struct.BIG_PARM*, i8*)*, i32 (%struct.BIG_PARM*, i8*)** %foo, align 4
23+
%call = tail call i32 %1(%struct.BIG_PARM* inreg noundef %a, i8* inreg noundef %b) #1
24+
ret i32 %call
25+
}
26+
27+
!llvm.module.flags = !{!0}
28+
29+
!0 = !{i32 1, !"NumRegisterParameters", i32 3}
30+

0 commit comments

Comments
 (0)