| ; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp,+relax,+c \ | |
| ; RUN: < %s | FileCheck %s --check-prefixes=CHECK | |
| ; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp,+relax,+c \ | |
| ; RUN: < %s | FileCheck %s --check-prefixes=CHECK | |
| ; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp,+relax,+zcmt \ | |
| ; RUN: < %s | FileCheck %s --check-prefixes=CHECK | |
| ; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp,-relax,+c \ | |
| ; RUN: < %s | FileCheck %s --check-prefixes=NORELAX | |
| ; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp,+relax,-c \ | |
| ; RUN: < %s | FileCheck %s --check-prefixes=NOZCA | |
| ; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp,+relax,+c \ | |
| ; RUN: -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=LABEL1 | |
| ; Verify that object file output does not have R_RISCV_RELAX on the setjmp call. | |
| ; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp,+relax,+c \ | |
| ; RUN: -filetype=obj -o - < %s | llvm-readobj -r - | FileCheck %s --check-prefix=RELOC | |
| ; setjmp call: R_RISCV_CALL_PLT followed by regular_func (no R_RISCV_RELAX in between) | |
| ; regular_func call: R_RISCV_CALL_PLT followed by R_RISCV_RELAX | |
| ; RELOC: R_RISCV_CALL_PLT setjmp | |
| ; RELOC-NEXT: R_RISCV_CALL_PLT regular_func | |
| ; RELOC-NEXT: R_RISCV_RELAX | |
| ; Test that returns_twice calls (e.g., setjmp) are wrapped with .option push/exact/pop | |
| ; when Zicfilp + relax are enabled, to prevent LPAD misalignment. | |
| declare i32 @setjmp(ptr) returns_twice | |
| declare i32 @regular_func(ptr) | |
| define i32 @test_setjmp() { | |
| ; CHECK-LABEL: test_setjmp: | |
| ; CHECK: .p2align 2 | |
| ; CHECK-NEXT: .option push | |
| ; CHECK-NEXT: .option exact | |
| ; CHECK-NEXT: call setjmp | |
| ; CHECK-NEXT: .option pop | |
| ; CHECK-NEXT: lpad 0 | |
| ; | |
| ; Without relax, only .p2align 2 is needed. | |
| ; NORELAX-LABEL: test_setjmp: | |
| ; NORELAX-NOT: .option push | |
| ; NORELAX-NOT: .option exact | |
| ; NORELAX: .p2align 2 | |
| ; NORELAX-NEXT: call setjmp | |
| ; NORELAX-NEXT: lpad 0 | |
| ; | |
| ; Without Zca, no .p2align or .option push/exact needed (no compressed calls). | |
| ; NOZCA-LABEL: test_setjmp: | |
| ; NOZCA-NOT: .p2align 2 | |
| ; NOZCA-NOT: .option push | |
| ; NOZCA-NOT: .option exact | |
| ; NOZCA: call setjmp | |
| ; NOZCA-NEXT: lpad 0 | |
| ; | |
| ; With -riscv-landing-pad-label=1, lpad uses label 1. | |
| ; LABEL1-LABEL: test_setjmp: | |
| ; LABEL1: call setjmp | |
| ; LABEL1: lpad 1 | |
| %buf = alloca [1 x i32], align 4 | |
| %call = call i32 @setjmp(ptr %buf) | |
| ret i32 %call | |
| } | |
| ; Regular calls should not be affected. | |
| define i32 @test_regular_call() { | |
| ; CHECK-LABEL: test_regular_call: | |
| ; CHECK-NOT: .option exact | |
| ; CHECK: call regular_func | |
| %buf = alloca [1 x i32], align 4 | |
| %call = call i32 @regular_func(ptr %buf) | |
| ret i32 %call | |
| } | |
| ; Indirect calls with returns_twice attribute also get the same treatment. | |
| define i32 @test_indirect_returns_twice(ptr %fptr) { | |
| ; CHECK-LABEL: test_indirect_returns_twice: | |
| ; CHECK: .p2align 2 | |
| ; CHECK-NEXT: .option push | |
| ; CHECK-NEXT: .option exact | |
| ; CHECK-NEXT: jalr | |
| ; CHECK-NEXT: .option pop | |
| ; CHECK-NEXT: lpad 0 | |
| ; | |
| ; Without relax, only .p2align 2 is needed (no .option push/exact). | |
| ; NORELAX-LABEL: test_indirect_returns_twice: | |
| ; NORELAX-NOT: .option push | |
| ; NORELAX-NOT: .option exact | |
| ; NORELAX: .p2align 2 | |
| ; NORELAX-NEXT: jalr | |
| ; NORELAX-NEXT: lpad 0 | |
| ; | |
| ; Without Zca, no .p2align or .option push/exact needed. | |
| ; NOZCA-LABEL: test_indirect_returns_twice: | |
| ; NOZCA-NOT: .p2align 2 | |
| ; NOZCA-NOT: .option push | |
| ; NOZCA-NOT: .option exact | |
| ; NOZCA: jalr | |
| ; NOZCA-NEXT: lpad 0 | |
| ; | |
| ; With -riscv-landing-pad-label=1, lpad uses label 1. | |
| ; LABEL1-LABEL: test_indirect_returns_twice: | |
| ; LABEL1: jalr | |
| ; LABEL1: lpad 1 | |
| %buf = alloca [1 x i32], align 4 | |
| %call = call i32 %fptr(ptr %buf) #0 | |
| ret i32 %call | |
| } | |
| attributes #0 = { returns_twice } | |
| !llvm.module.flags = !{!0, !1} | |
| !0 = !{i32 8, !"cf-protection-branch", i32 1} | |
| !1 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"} |