[llvm] [X86] Fix RegAlloc issue by implementing TRI::getCustomEHPadPreservedMask (PR #135518)
Sergei Barannikov via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 12 22:03:07 PDT 2025
https://github.com/s-barannikov created https://github.com/llvm/llvm-project/pull/135518
This method needs to be implemented so that the register allocator can
correctly split live ranges of loop invariant virtual registers.
This default return value is correct for DWARF unwinder, which preserves
all registers (except exception pointer/selector), but not for SjLj,
which only preserves sp/fp and possibly bp (they should be reserved).
In the added test `rcx` on the entry to the loop contains the argument
to `foo`. It survives the call due to `preserve_allcc`, but not the
unwind edge entering LBB0_3, and so must be recomputed before going to
the next iteration.
Similarly, `rdx` holds the address of a jump table and is recomputed on
every iteration rather than once before the loop.
>From 46745b042906b80948ec34ad603234e6f912fedb Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 13 Apr 2025 07:13:54 +0300
Subject: [PATCH 1/2] Add a test
---
llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll | 74 ++++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100644 llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll
diff --git a/llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll b/llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll
new file mode 100644
index 0000000000000..3a4dc8f652eb4
--- /dev/null
+++ b/llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll
@@ -0,0 +1,74 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=x86_64 -exception-model=sjlj -o - %s | FileCheck %s
+
+declare dso_local i32 @__gxx_personality_sj0(...)
+declare dso_local preserve_allcc void @foo(ptr)
+
+define void @test() personality ptr @__gxx_personality_sj0 {
+; CHECK-LABEL: test:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: pushq %rbp
+; CHECK-NEXT: movq %rsp, %rbp
+; CHECK-NEXT: pushq %r15
+; CHECK-NEXT: pushq %r14
+; CHECK-NEXT: pushq %r13
+; CHECK-NEXT: pushq %r12
+; CHECK-NEXT: pushq %rbx
+; CHECK-NEXT: subq $104, %rsp
+; CHECK-NEXT: movq $__gxx_personality_sj0, -104(%rbp)
+; CHECK-NEXT: movq $GCC_except_table0, -96(%rbp)
+; CHECK-NEXT: movq %rbp, -88(%rbp)
+; CHECK-NEXT: movq %rsp, -72(%rbp)
+; CHECK-NEXT: movq $.LBB0_3, -80(%rbp)
+; CHECK-NEXT: leaq -136(%rbp), %rdi
+; CHECK-NEXT: callq _Unwind_SjLj_Register at PLT
+; CHECK-NEXT: leaq -44(%rbp), %rdi
+; CHECK-NEXT: leaq .LJTI0_0(%rip), %rax
+; CHECK-NEXT: .LBB0_1: # %while.cond
+; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT: movl $1, -128(%rbp)
+; CHECK-NEXT: .Ltmp0:
+; CHECK-NEXT: callq foo
+; CHECK-NEXT: .Ltmp1:
+; CHECK-NEXT: jmp .LBB0_2
+; CHECK-NEXT: .LBB0_3: # in Loop: Header=BB0_1 Depth=1
+; CHECK-NEXT: movl -128(%rbp), %ecx
+; CHECK-NEXT: cmpl $1, %ecx
+; CHECK-NEXT: jae .LBB0_5
+; CHECK-NEXT: # %bb.4: # in Loop: Header=BB0_1 Depth=1
+; CHECK-NEXT: jmpq *(%rax,%rcx,8)
+; CHECK-NEXT: .LBB0_6: # %lpad
+; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1
+; CHECK-NEXT: .Ltmp2:
+; CHECK-NEXT: movl -124(%rbp), %ecx
+; CHECK-NEXT: movl -120(%rbp), %ecx
+; CHECK-NEXT: jmp .LBB0_1
+; CHECK-NEXT: .LBB0_2: # %while.end
+; CHECK-NEXT: leaq -136(%rbp), %rdi
+; CHECK-NEXT: callq _Unwind_SjLj_Unregister at PLT
+; CHECK-NEXT: addq $104, %rsp
+; CHECK-NEXT: popq %rbx
+; CHECK-NEXT: popq %r12
+; CHECK-NEXT: popq %r13
+; CHECK-NEXT: popq %r14
+; CHECK-NEXT: popq %r15
+; CHECK-NEXT: popq %rbp
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB0_5:
+; CHECK-NEXT: ud2
+entry:
+ %ptr = alloca i32, align 4
+ br label %while.cond
+
+while.cond:
+ invoke preserve_allcc void @foo(ptr %ptr)
+ to label %while.end unwind label %lpad
+
+lpad:
+ %lp = landingpad { ptr, i32 }
+ catch ptr null
+ br label %while.cond
+
+while.end:
+ ret void
+}
>From b5f35ecfcd7c653f61ee67e2fc25a9273ae776a6 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 13 Apr 2025 07:18:26 +0300
Subject: [PATCH 2/2] [X86] Implement
TargetRegisterInfo::getCustomEHPadPreservedMask
This method needs to be implemented so that the register allocator can
correctly split live ranges of loop invariant virtual registers.
This default return value is correct for DWARF unwinder, which preserves
all registers (except exception pointer/selector), but not for SjLj,
which only preserves sp/fp and possibly bp (they should be reserved).
In the added test `rcx` on the entry to the loop contains the argument
to `foo`. It survives the call due to `preserve_allcc`, but not the
unwind edge entering LBB0_3, and so must be recomputed before going to
the next iteration.
Similarly, `rdx` holds the address of a jump table and is recomputed on
every iteration rather than once before the loop.
---
llvm/lib/Target/X86/X86RegisterInfo.cpp | 7 +++++++
llvm/lib/Target/X86/X86RegisterInfo.h | 2 ++
llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll | 16 +++++++++-------
3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/X86/X86RegisterInfo.cpp b/llvm/lib/Target/X86/X86RegisterInfo.cpp
index 1c4114f8cc9c6..68c227cb987de 100644
--- a/llvm/lib/Target/X86/X86RegisterInfo.cpp
+++ b/llvm/lib/Target/X86/X86RegisterInfo.cpp
@@ -525,6 +525,13 @@ X86RegisterInfo::getNoPreservedMask() const {
return CSR_NoRegs_RegMask;
}
+const uint32_t *
+X86RegisterInfo::getCustomEHPadPreservedMask(const MachineFunction &MF) const {
+ if (MF.getTarget().Options.ExceptionModel == ExceptionHandling::SjLj)
+ return getNoPreservedMask();
+ return TargetRegisterInfo::getCustomEHPadPreservedMask(MF);
+}
+
const uint32_t *X86RegisterInfo::getDarwinTLSCallPreservedMask() const {
return CSR_64_TLS_Darwin_RegMask;
}
diff --git a/llvm/lib/Target/X86/X86RegisterInfo.h b/llvm/lib/Target/X86/X86RegisterInfo.h
index 5b6ac3c5da019..d9491cd225827 100644
--- a/llvm/lib/Target/X86/X86RegisterInfo.h
+++ b/llvm/lib/Target/X86/X86RegisterInfo.h
@@ -102,6 +102,8 @@ class X86RegisterInfo final : public X86GenRegisterInfo {
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID) const override;
const uint32_t *getNoPreservedMask() const override;
+ const uint32_t *
+ getCustomEHPadPreservedMask(const MachineFunction &MF) const override;
// Calls involved in thread-local variable lookup save more registers than
// normal calls, so they need a different mask to represent this.
diff --git a/llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll b/llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll
index 3a4dc8f652eb4..c1d718a9f7031 100644
--- a/llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll
+++ b/llvm/test/CodeGen/X86/sjlj-unwind-clobber.ll
@@ -22,26 +22,28 @@ define void @test() personality ptr @__gxx_personality_sj0 {
; CHECK-NEXT: movq $.LBB0_3, -80(%rbp)
; CHECK-NEXT: leaq -136(%rbp), %rdi
; CHECK-NEXT: callq _Unwind_SjLj_Register at PLT
-; CHECK-NEXT: leaq -44(%rbp), %rdi
-; CHECK-NEXT: leaq .LJTI0_0(%rip), %rax
+; CHECK-NEXT: leaq -44(%rbp), %rcx
; CHECK-NEXT: .LBB0_1: # %while.cond
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: movl $1, -128(%rbp)
; CHECK-NEXT: .Ltmp0:
+; CHECK-NEXT: movq %rcx, %rdi
; CHECK-NEXT: callq foo
; CHECK-NEXT: .Ltmp1:
; CHECK-NEXT: jmp .LBB0_2
; CHECK-NEXT: .LBB0_3: # in Loop: Header=BB0_1 Depth=1
-; CHECK-NEXT: movl -128(%rbp), %ecx
-; CHECK-NEXT: cmpl $1, %ecx
+; CHECK-NEXT: leaq -44(%rbp), %rcx
+; CHECK-NEXT: movl -128(%rbp), %eax
+; CHECK-NEXT: cmpl $1, %eax
; CHECK-NEXT: jae .LBB0_5
; CHECK-NEXT: # %bb.4: # in Loop: Header=BB0_1 Depth=1
-; CHECK-NEXT: jmpq *(%rax,%rcx,8)
+; CHECK-NEXT: leaq .LJTI0_0(%rip), %rdx
+; CHECK-NEXT: jmpq *(%rdx,%rax,8)
; CHECK-NEXT: .LBB0_6: # %lpad
; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1
; CHECK-NEXT: .Ltmp2:
-; CHECK-NEXT: movl -124(%rbp), %ecx
-; CHECK-NEXT: movl -120(%rbp), %ecx
+; CHECK-NEXT: movl -124(%rbp), %eax
+; CHECK-NEXT: movl -120(%rbp), %eax
; CHECK-NEXT: jmp .LBB0_1
; CHECK-NEXT: .LBB0_2: # %while.end
; CHECK-NEXT: leaq -136(%rbp), %rdi
More information about the llvm-commits
mailing list