Files
clang-p2996/llvm/test/CodeGen/X86/tailcall-3regparm.ll
Tong Zhang 2fe315162e [X86] TCRETURNmi fix for 32bit platform
This fix is similar to 3cf3ffce240e("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 3cf3ffce240e("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
2022-02-09 20:34:04 +08:00

31 lines
1.3 KiB
LLVM

; RUN: llc < %s -mtriple=i686-linux-gnu -mcpu=pentium | FileCheck %s
; Tail call should not make register allocation fail (x86-32)
%struct.anon = type { i32 (%struct.BIG_PARM*, i8*)*, i32 ()*, i32 ()*, i32 ()*, i32 ()*, i32 ()*, i32 ()* }
%struct.BIG_PARM = type { i32 }
@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
; Function Attrs: nounwind uwtable
define dso_local i32 @something(%struct.BIG_PARM* inreg noundef %a, i8* inreg noundef %b) local_unnamed_addr #0 {
entry:
; CHECK: movl (%eax), %ecx
; CHECK-NEXT: leal (%ecx,%ecx,8), %esi
; CHECK-NEXT: leal (%esi,%esi,2), %esi
; CHECK-NEXT: movl vtable(%ecx,%esi), %ecx
; CHECK-NEXT: popl %esi
; CHECK: jmpl *%ecx
%ver = getelementptr inbounds %struct.BIG_PARM, %struct.BIG_PARM* %a, i32 0, i32 0
%0 = load i32, i32* %ver, align 4
%foo = getelementptr [1 x %struct.anon], [1 x %struct.anon]* @vtable, i32 0, i32 %0, i32 0
%1 = load i32 (%struct.BIG_PARM*, i8*)*, i32 (%struct.BIG_PARM*, i8*)** %foo, align 4
%call = tail call i32 %1(%struct.BIG_PARM* inreg noundef %a, i8* inreg noundef %b) #1
ret i32 %call
}
!llvm.module.flags = !{!0}
!0 = !{i32 1, !"NumRegisterParameters", i32 3}