| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | |
| ; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp < %s | FileCheck %s --check-prefixes=CHECK,RV32 | |
| ; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp < %s | FileCheck %s --check-prefixes=CHECK,RV64 | |
| ; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp \ | |
| ; RUN: -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=FIXED-ONE,FIXED-ONE-RV32 | |
| ; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp \ | |
| ; RUN: -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=FIXED-ONE,FIXED-ONE-RV64 | |
| ; Check indirectbr. | |
| @__const.indirctbr.addr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirctbr, %labelA), ptr blockaddress(@indirctbr, %labelB)], align 8 | |
| define void @indirctbr(i32 %i, ptr %p) { | |
| ; RV32-LABEL: indirctbr: | |
| ; RV32: # %bb.0: # %entry | |
| ; RV32-NEXT: lpad 0 | |
| ; RV32-NEXT: lui a2, %hi(.L__const.indirctbr.addr) | |
| ; RV32-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) | |
| ; RV32-NEXT: slli a0, a0, 2 | |
| ; RV32-NEXT: add a0, a2, a0 | |
| ; RV32-NEXT: lw a0, 0(a0) | |
| ; RV32-NEXT: jr a0 | |
| ; RV32-NEXT: .p2align 2 | |
| ; RV32-NEXT: .Ltmp3: # Block address taken | |
| ; RV32-NEXT: .LBB0_1: # %labelA | |
| ; RV32-NEXT: lpad 0 | |
| ; RV32-NEXT: li a0, 1 | |
| ; RV32-NEXT: sw a0, 0(a1) | |
| ; RV32-NEXT: .p2align 2 | |
| ; RV32-NEXT: .Ltmp4: # Block address taken | |
| ; RV32-NEXT: .LBB0_2: # %labelB | |
| ; RV32-NEXT: lpad 0 | |
| ; RV32-NEXT: li a0, 2 | |
| ; RV32-NEXT: sw a0, 0(a1) | |
| ; RV32-NEXT: ret | |
| ; | |
| ; RV64-LABEL: indirctbr: | |
| ; RV64: # %bb.0: # %entry | |
| ; RV64-NEXT: lpad 0 | |
| ; RV64-NEXT: lui a2, %hi(.L__const.indirctbr.addr) | |
| ; RV64-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) | |
| ; RV64-NEXT: sext.w a0, a0 | |
| ; RV64-NEXT: slli a0, a0, 3 | |
| ; RV64-NEXT: add a0, a2, a0 | |
| ; RV64-NEXT: ld a0, 0(a0) | |
| ; RV64-NEXT: jr a0 | |
| ; RV64-NEXT: .p2align 2 | |
| ; RV64-NEXT: .Ltmp3: # Block address taken | |
| ; RV64-NEXT: .LBB0_1: # %labelA | |
| ; RV64-NEXT: lpad 0 | |
| ; RV64-NEXT: li a0, 1 | |
| ; RV64-NEXT: sw a0, 0(a1) | |
| ; RV64-NEXT: .p2align 2 | |
| ; RV64-NEXT: .Ltmp4: # Block address taken | |
| ; RV64-NEXT: .LBB0_2: # %labelB | |
| ; RV64-NEXT: lpad 0 | |
| ; RV64-NEXT: li a0, 2 | |
| ; RV64-NEXT: sw a0, 0(a1) | |
| ; RV64-NEXT: ret | |
| ; | |
| ; FIXED-ONE-RV32-LABEL: indirctbr: | |
| ; FIXED-ONE-RV32: # %bb.0: # %entry | |
| ; FIXED-ONE-RV32-NEXT: lpad 1 | |
| ; FIXED-ONE-RV32-NEXT: lui a2, %hi(.L__const.indirctbr.addr) | |
| ; FIXED-ONE-RV32-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) | |
| ; FIXED-ONE-RV32-NEXT: slli a0, a0, 2 | |
| ; FIXED-ONE-RV32-NEXT: add a0, a2, a0 | |
| ; FIXED-ONE-RV32-NEXT: lw a0, 0(a0) | |
| ; FIXED-ONE-RV32-NEXT: lui t2, 1 | |
| ; FIXED-ONE-RV32-NEXT: jr a0 | |
| ; FIXED-ONE-RV32-NEXT: .p2align 2 | |
| ; FIXED-ONE-RV32-NEXT: .Ltmp3: # Block address taken | |
| ; FIXED-ONE-RV32-NEXT: .LBB0_1: # %labelA | |
| ; FIXED-ONE-RV32-NEXT: lpad 1 | |
| ; FIXED-ONE-RV32-NEXT: li a0, 1 | |
| ; FIXED-ONE-RV32-NEXT: sw a0, 0(a1) | |
| ; FIXED-ONE-RV32-NEXT: .p2align 2 | |
| ; FIXED-ONE-RV32-NEXT: .Ltmp4: # Block address taken | |
| ; FIXED-ONE-RV32-NEXT: .LBB0_2: # %labelB | |
| ; FIXED-ONE-RV32-NEXT: lpad 1 | |
| ; FIXED-ONE-RV32-NEXT: li a0, 2 | |
| ; FIXED-ONE-RV32-NEXT: sw a0, 0(a1) | |
| ; FIXED-ONE-RV32-NEXT: ret | |
| ; | |
| ; FIXED-ONE-RV64-LABEL: indirctbr: | |
| ; FIXED-ONE-RV64: # %bb.0: # %entry | |
| ; FIXED-ONE-RV64-NEXT: lpad 1 | |
| ; FIXED-ONE-RV64-NEXT: lui a2, %hi(.L__const.indirctbr.addr) | |
| ; FIXED-ONE-RV64-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) | |
| ; FIXED-ONE-RV64-NEXT: sext.w a0, a0 | |
| ; FIXED-ONE-RV64-NEXT: slli a0, a0, 3 | |
| ; FIXED-ONE-RV64-NEXT: add a0, a2, a0 | |
| ; FIXED-ONE-RV64-NEXT: ld a0, 0(a0) | |
| ; FIXED-ONE-RV64-NEXT: lui t2, 1 | |
| ; FIXED-ONE-RV64-NEXT: jr a0 | |
| ; FIXED-ONE-RV64-NEXT: .p2align 2 | |
| ; FIXED-ONE-RV64-NEXT: .Ltmp3: # Block address taken | |
| ; FIXED-ONE-RV64-NEXT: .LBB0_1: # %labelA | |
| ; FIXED-ONE-RV64-NEXT: lpad 1 | |
| ; FIXED-ONE-RV64-NEXT: li a0, 1 | |
| ; FIXED-ONE-RV64-NEXT: sw a0, 0(a1) | |
| ; FIXED-ONE-RV64-NEXT: .p2align 2 | |
| ; FIXED-ONE-RV64-NEXT: .Ltmp4: # Block address taken | |
| ; FIXED-ONE-RV64-NEXT: .LBB0_2: # %labelB | |
| ; FIXED-ONE-RV64-NEXT: lpad 1 | |
| ; FIXED-ONE-RV64-NEXT: li a0, 2 | |
| ; FIXED-ONE-RV64-NEXT: sw a0, 0(a1) | |
| ; FIXED-ONE-RV64-NEXT: ret | |
| entry: | |
| %arrayidx = getelementptr inbounds [2 x ptr], ptr @__const.indirctbr.addr, i64 0, i32 %i | |
| %0 = load ptr, ptr %arrayidx | |
| indirectbr ptr %0, [label %labelA, label %labelB] | |
| labelA: ; preds = %entry | |
| store volatile i32 1, ptr %p | |
| br label %labelB | |
| labelB: ; preds = %labelA, %entry | |
| store volatile i32 2, ptr %p | |
| ret void | |
| } | |
| ; Check indirect call. | |
| define void @call(ptr %0) { | |
| ; CHECK-LABEL: call: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: lpad 0 | |
| ; CHECK-NEXT: jr a0 | |
| ; | |
| ; FIXED-ONE-LABEL: call: | |
| ; FIXED-ONE: # %bb.0: | |
| ; FIXED-ONE-NEXT: lpad 1 | |
| ; FIXED-ONE-NEXT: lui t2, 1 | |
| ; FIXED-ONE-NEXT: jr a0 | |
| tail call void %0() | |
| ret void | |
| } | |
| ; Check invoke. | |
| declare dso_local i32 @__gxx_personality_v0(...) | |
| define void @invoke(ptr %f) personality ptr @__gxx_personality_v0 { | |
| ; RV32-LABEL: invoke: | |
| ; RV32: # %bb.0: # %entry | |
| ; RV32-NEXT: lpad 0 | |
| ; RV32-NEXT: addi sp, sp, -16 | |
| ; RV32-NEXT: .cfi_def_cfa_offset 16 | |
| ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; RV32-NEXT: .cfi_offset ra, -4 | |
| ; RV32-NEXT: .cfi_remember_state | |
| ; RV32-NEXT: .Ltmp0: # EH_LABEL | |
| ; RV32-NEXT: jalr a0 | |
| ; RV32-NEXT: .Ltmp1: # EH_LABEL | |
| ; RV32-NEXT: .LBB2_1: # %try.cont | |
| ; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; RV32-NEXT: .cfi_restore ra | |
| ; RV32-NEXT: addi sp, sp, 16 | |
| ; RV32-NEXT: .cfi_def_cfa_offset 0 | |
| ; RV32-NEXT: ret | |
| ; RV32-NEXT: .LBB2_2: # %lpad | |
| ; RV32-NEXT: .cfi_restore_state | |
| ; RV32-NEXT: .Ltmp2: # EH_LABEL | |
| ; RV32-NEXT: j .LBB2_1 | |
| ; | |
| ; RV64-LABEL: invoke: | |
| ; RV64: # %bb.0: # %entry | |
| ; RV64-NEXT: lpad 0 | |
| ; RV64-NEXT: addi sp, sp, -16 | |
| ; RV64-NEXT: .cfi_def_cfa_offset 16 | |
| ; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; RV64-NEXT: .cfi_offset ra, -8 | |
| ; RV64-NEXT: .cfi_remember_state | |
| ; RV64-NEXT: .Ltmp0: # EH_LABEL | |
| ; RV64-NEXT: jalr a0 | |
| ; RV64-NEXT: .Ltmp1: # EH_LABEL | |
| ; RV64-NEXT: .LBB2_1: # %try.cont | |
| ; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; RV64-NEXT: .cfi_restore ra | |
| ; RV64-NEXT: addi sp, sp, 16 | |
| ; RV64-NEXT: .cfi_def_cfa_offset 0 | |
| ; RV64-NEXT: ret | |
| ; RV64-NEXT: .LBB2_2: # %lpad | |
| ; RV64-NEXT: .cfi_restore_state | |
| ; RV64-NEXT: .Ltmp2: # EH_LABEL | |
| ; RV64-NEXT: j .LBB2_1 | |
| ; | |
| ; FIXED-ONE-RV32-LABEL: invoke: | |
| ; FIXED-ONE-RV32: # %bb.0: # %entry | |
| ; FIXED-ONE-RV32-NEXT: lpad 1 | |
| ; FIXED-ONE-RV32-NEXT: addi sp, sp, -16 | |
| ; FIXED-ONE-RV32-NEXT: .cfi_def_cfa_offset 16 | |
| ; FIXED-ONE-RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; FIXED-ONE-RV32-NEXT: .cfi_offset ra, -4 | |
| ; FIXED-ONE-RV32-NEXT: .cfi_remember_state | |
| ; FIXED-ONE-RV32-NEXT: .Ltmp0: # EH_LABEL | |
| ; FIXED-ONE-RV32-NEXT: lui t2, 1 | |
| ; FIXED-ONE-RV32-NEXT: jalr a0 | |
| ; FIXED-ONE-RV32-NEXT: .Ltmp1: # EH_LABEL | |
| ; FIXED-ONE-RV32-NEXT: .LBB2_1: # %try.cont | |
| ; FIXED-ONE-RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; FIXED-ONE-RV32-NEXT: .cfi_restore ra | |
| ; FIXED-ONE-RV32-NEXT: addi sp, sp, 16 | |
| ; FIXED-ONE-RV32-NEXT: .cfi_def_cfa_offset 0 | |
| ; FIXED-ONE-RV32-NEXT: ret | |
| ; FIXED-ONE-RV32-NEXT: .LBB2_2: # %lpad | |
| ; FIXED-ONE-RV32-NEXT: .cfi_restore_state | |
| ; FIXED-ONE-RV32-NEXT: .Ltmp2: # EH_LABEL | |
| ; FIXED-ONE-RV32-NEXT: j .LBB2_1 | |
| ; | |
| ; FIXED-ONE-RV64-LABEL: invoke: | |
| ; FIXED-ONE-RV64: # %bb.0: # %entry | |
| ; FIXED-ONE-RV64-NEXT: lpad 1 | |
| ; FIXED-ONE-RV64-NEXT: addi sp, sp, -16 | |
| ; FIXED-ONE-RV64-NEXT: .cfi_def_cfa_offset 16 | |
| ; FIXED-ONE-RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; FIXED-ONE-RV64-NEXT: .cfi_offset ra, -8 | |
| ; FIXED-ONE-RV64-NEXT: .cfi_remember_state | |
| ; FIXED-ONE-RV64-NEXT: .Ltmp0: # EH_LABEL | |
| ; FIXED-ONE-RV64-NEXT: lui t2, 1 | |
| ; FIXED-ONE-RV64-NEXT: jalr a0 | |
| ; FIXED-ONE-RV64-NEXT: .Ltmp1: # EH_LABEL | |
| ; FIXED-ONE-RV64-NEXT: .LBB2_1: # %try.cont | |
| ; FIXED-ONE-RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; FIXED-ONE-RV64-NEXT: .cfi_restore ra | |
| ; FIXED-ONE-RV64-NEXT: addi sp, sp, 16 | |
| ; FIXED-ONE-RV64-NEXT: .cfi_def_cfa_offset 0 | |
| ; FIXED-ONE-RV64-NEXT: ret | |
| ; FIXED-ONE-RV64-NEXT: .LBB2_2: # %lpad | |
| ; FIXED-ONE-RV64-NEXT: .cfi_restore_state | |
| ; FIXED-ONE-RV64-NEXT: .Ltmp2: # EH_LABEL | |
| ; FIXED-ONE-RV64-NEXT: j .LBB2_1 | |
| entry: | |
| invoke void %f() to label %try.cont unwind label %lpad | |
| lpad: | |
| %0 = landingpad { ptr, i32 } cleanup | |
| br label %try.cont | |
| try.cont: | |
| ret void | |
| } | |
| ; Check external linkage function. | |
| define void @external() { | |
| ; CHECK-LABEL: external: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: lpad 0 | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; FIXED-ONE-LABEL: external: | |
| ; FIXED-ONE: # %bb.0: | |
| ; FIXED-ONE-NEXT: lpad 1 | |
| ; FIXED-ONE-NEXT: ret | |
| ret void | |
| } | |
| ; Check internal linkage function. | |
| define internal void @internal() { | |
| ; CHECK-LABEL: internal: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; FIXED-ONE-LABEL: internal: | |
| ; FIXED-ONE: # %bb.0: | |
| ; FIXED-ONE-NEXT: ret | |
| ret void | |
| } | |
| ; Check internal linkage function with taken address. | |
| @foo = constant ptr @internal2 | |
| define internal void @internal2() { | |
| ; CHECK-LABEL: internal2: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: lpad 0 | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; FIXED-ONE-LABEL: internal2: | |
| ; FIXED-ONE: # %bb.0: | |
| ; FIXED-ONE-NEXT: lpad 1 | |
| ; FIXED-ONE-NEXT: ret | |
| ret void | |
| } | |
| ; Check interrupt function does not need landing pad. | |
| define void @interrupt() "interrupt"="machine" { | |
| ; CHECK-LABEL: interrupt: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mret | |
| ; | |
| ; FIXED-ONE-LABEL: interrupt: | |
| ; FIXED-ONE: # %bb.0: | |
| ; FIXED-ONE-NEXT: mret | |
| ret void | |
| } | |
| declare i32 @setjmp(ptr) returns_twice | |
| ; Note: This test doesn't have +c or +relax, so no .p2align 2 or .option exact | |
| ; is emitted before the setjmp call. See lpad-setjmp.ll for tests with those | |
| ; attributes enabled. | |
| define i32 @test_returns_twice() { | |
| ; RV32-LABEL: test_returns_twice: | |
| ; RV32: # %bb.0: | |
| ; RV32-NEXT: lpad 0 | |
| ; RV32-NEXT: addi sp, sp, -16 | |
| ; RV32-NEXT: .cfi_def_cfa_offset 16 | |
| ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; RV32-NEXT: .cfi_offset ra, -4 | |
| ; RV32-NEXT: addi a0, sp, 8 | |
| ; RV32-NEXT: call setjmp | |
| ; RV32-NEXT: lpad 0 | |
| ; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; RV32-NEXT: .cfi_restore ra | |
| ; RV32-NEXT: addi sp, sp, 16 | |
| ; RV32-NEXT: .cfi_def_cfa_offset 0 | |
| ; RV32-NEXT: ret | |
| ; | |
| ; RV64-LABEL: test_returns_twice: | |
| ; RV64: # %bb.0: | |
| ; RV64-NEXT: lpad 0 | |
| ; RV64-NEXT: addi sp, sp, -16 | |
| ; RV64-NEXT: .cfi_def_cfa_offset 16 | |
| ; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; RV64-NEXT: .cfi_offset ra, -8 | |
| ; RV64-NEXT: addi a0, sp, 4 | |
| ; RV64-NEXT: call setjmp | |
| ; RV64-NEXT: lpad 0 | |
| ; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; RV64-NEXT: .cfi_restore ra | |
| ; RV64-NEXT: addi sp, sp, 16 | |
| ; RV64-NEXT: .cfi_def_cfa_offset 0 | |
| ; RV64-NEXT: ret | |
| ; | |
| ; FIXED-ONE-RV32-LABEL: test_returns_twice: | |
| ; FIXED-ONE-RV32: # %bb.0: | |
| ; FIXED-ONE-RV32-NEXT: lpad 1 | |
| ; FIXED-ONE-RV32-NEXT: addi sp, sp, -16 | |
| ; FIXED-ONE-RV32-NEXT: .cfi_def_cfa_offset 16 | |
| ; FIXED-ONE-RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; FIXED-ONE-RV32-NEXT: .cfi_offset ra, -4 | |
| ; FIXED-ONE-RV32-NEXT: addi a0, sp, 8 | |
| ; FIXED-ONE-RV32-NEXT: call setjmp | |
| ; FIXED-ONE-RV32-NEXT: lpad 1 | |
| ; FIXED-ONE-RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; FIXED-ONE-RV32-NEXT: .cfi_restore ra | |
| ; FIXED-ONE-RV32-NEXT: addi sp, sp, 16 | |
| ; FIXED-ONE-RV32-NEXT: .cfi_def_cfa_offset 0 | |
| ; FIXED-ONE-RV32-NEXT: ret | |
| ; | |
| ; FIXED-ONE-RV64-LABEL: test_returns_twice: | |
| ; FIXED-ONE-RV64: # %bb.0: | |
| ; FIXED-ONE-RV64-NEXT: lpad 1 | |
| ; FIXED-ONE-RV64-NEXT: addi sp, sp, -16 | |
| ; FIXED-ONE-RV64-NEXT: .cfi_def_cfa_offset 16 | |
| ; FIXED-ONE-RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; FIXED-ONE-RV64-NEXT: .cfi_offset ra, -8 | |
| ; FIXED-ONE-RV64-NEXT: addi a0, sp, 4 | |
| ; FIXED-ONE-RV64-NEXT: call setjmp | |
| ; FIXED-ONE-RV64-NEXT: lpad 1 | |
| ; FIXED-ONE-RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; FIXED-ONE-RV64-NEXT: .cfi_restore ra | |
| ; FIXED-ONE-RV64-NEXT: addi sp, sp, 16 | |
| ; FIXED-ONE-RV64-NEXT: .cfi_def_cfa_offset 0 | |
| ; FIXED-ONE-RV64-NEXT: ret | |
| %buf = alloca [1 x i32], align 4 | |
| %call = call i32 @setjmp(ptr %buf) | |
| ret i32 %call | |
| } | |
| !llvm.module.flags = !{!0, !1} | |
| !0 = !{i32 8, !"cf-protection-branch", i32 1} | |
| !1 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"} |