| ; 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: slli a0, a0, 2 |
| ; RV32-NEXT: lui a2, %hi(.L__const.indirctbr.addr) |
| ; RV32-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) |
| ; 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: sext.w a0, a0 |
| ; RV64-NEXT: slli a0, a0, 3 |
| ; RV64-NEXT: lui a2, %hi(.L__const.indirctbr.addr) |
| ; RV64-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) |
| ; 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: slli a0, a0, 2 |
| ; 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: 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: sext.w a0, a0 |
| ; FIXED-ONE-RV64-NEXT: slli a0, a0, 3 |
| ; 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: 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: |
| ; RV32-NEXT: jalr a0 |
| ; RV32-NEXT: .Ltmp1: |
| ; 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: |
| ; 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: |
| ; RV64-NEXT: jalr a0 |
| ; RV64-NEXT: .Ltmp1: |
| ; 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: |
| ; 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: |
| ; FIXED-ONE-RV32-NEXT: lui t2, 1 |
| ; FIXED-ONE-RV32-NEXT: jalr a0 |
| ; FIXED-ONE-RV32-NEXT: .Ltmp1: |
| ; 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: |
| ; 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: |
| ; FIXED-ONE-RV64-NEXT: lui t2, 1 |
| ; FIXED-ONE-RV64-NEXT: jalr a0 |
| ; FIXED-ONE-RV64-NEXT: .Ltmp1: |
| ; 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: |
| ; 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 |
| } |