llvm/llvm/test/Transforms/Inline/AArch64/sme-pstatesm-attrs.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt < %s -mtriple=aarch64-unknown-linux-gnu -mattr=+sme -S -passes=inline | FileCheck %s

declare i32 @llvm.vscale.i32()

; Define some functions that merely call llvm.vscale.i32(), which will be called
; by the other functions below. If we see the call to one of these functions
; being replaced by 'llvm.vscale()', then we know it has been inlined.

define i32 @normal_callee() {
; CHECK-LABEL: define i32 @normal_callee
; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @llvm.vscale.i32()
  ret i32 %res
}

define i32 @streaming_callee() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define i32 @streaming_callee
; CHECK-SAME: () #[[ATTR2:[0-9]+]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @llvm.vscale.i32()
  ret i32 %res
}

define i32 @locally_streaming_callee() "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @locally_streaming_callee
; CHECK-SAME: () #[[ATTR3:[0-9]+]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @llvm.vscale.i32()
  ret i32 %res
}

define i32 @streaming_compatible_callee() "aarch64_pstate_sm_compatible" {
; CHECK-LABEL: define i32 @streaming_compatible_callee
; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @llvm.vscale.i32()
  ret i32 %res
}

define i32 @streaming_compatible_locally_streaming_callee() "aarch64_pstate_sm_compatible" "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @streaming_compatible_locally_streaming_callee
; CHECK-SAME: () #[[ATTR4:[0-9]+]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @llvm.vscale()
  ret i32 %res
}

; Now test that inlining only happens when their streaming modes match.
; Test for a number of combinations, where:
; N       Normal-interface (PSTATE.SM=0 on entry/exit)
; S       Streaming-interface (PSTATE.SM=1 on entry/exit)
; SC      Streaming-compatible interface
;         (PSTATE.SM=0 or 1, unchanged on exit)
; N + B   Normal-interface, streaming body
;         (PSTATE.SM=0 on entry/exit, but 1 within the body of the function)
; SC + B  Streaming-compatible-interface, streaming body
;         (PSTATE.SM=0 or 1 on entry, unchanged on exit,
;          but guaranteed to be 1 within the body of the function)

; [x] N  -> N
; [ ] N  -> S
; [ ] N  -> SC
; [ ] N  -> N + B
; [ ] N  -> SC + B
define i32 @normal_caller_normal_callee_inline() {
; CHECK-LABEL: define i32 @normal_caller_normal_callee_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @normal_callee()
  ret i32 %res
}

; [ ] N  -> N
; [x] N  -> S
; [ ] N  -> SC
; [ ] N  -> N + B
; [ ] N  -> SC + B
define i32 @normal_caller_streaming_callee_dont_inline() {
; CHECK-LABEL: define i32 @normal_caller_streaming_callee_dont_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @streaming_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @streaming_callee()
  ret i32 %res
}

; [ ] N  -> N
; [ ] N  -> S
; [x] N  -> SC
; [ ] N  -> N + B
; [ ] N  -> SC + B
define i32 @normal_caller_streaming_compatible_callee_inline() {
; CHECK-LABEL: define i32 @normal_caller_streaming_compatible_callee_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_compatible_callee()
  ret i32 %res
}

; [ ] N  -> N
; [ ] N  -> S
; [ ] N  -> SC
; [x] N  -> N + B
; [ ] N  -> SC + B
define i32 @normal_caller_locally_streaming_callee_dont_inline() {
; CHECK-LABEL: define i32 @normal_caller_locally_streaming_callee_dont_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @locally_streaming_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @locally_streaming_callee()
  ret i32 %res
}

; [ ] N  -> N
; [ ] N  -> S
; [ ] N  -> SC
; [ ] N  -> N + B
; [x] N  -> SC + B
define i32 @normal_caller_streaming_compatible_locally_streaming_callee_dont_inline() {
; CHECK-LABEL: define i32 @normal_caller_streaming_compatible_locally_streaming_callee_dont_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @streaming_compatible_locally_streaming_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @streaming_compatible_locally_streaming_callee()
  ret i32 %res
}

; [x] S  -> N
; [ ] S  -> S
; [ ] S  -> SC
; [ ] S  -> N + B
; [ ] S  -> SC + B
define i32 @streaming_caller_normal_callee_dont_inline() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define i32 @streaming_caller_normal_callee_dont_inline
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @normal_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @normal_callee()
  ret i32 %res
}

; [ ] S  -> N
; [x] S  -> S
; [ ] S  -> SC
; [ ] S  -> N + B
; [ ] S  -> SC + B
define i32 @streaming_caller_streaming_callee_inline() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define i32 @streaming_caller_streaming_callee_inline
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_callee()
  ret i32 %res
}

; [ ] S  -> N
; [ ] S  -> S
; [x] S  -> SC
; [ ] S  -> N + B
; [ ] S  -> SC + B
define i32 @streaming_caller_streaming_compatible_callee_inline() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define i32 @streaming_caller_streaming_compatible_callee_inline
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_compatible_callee()
  ret i32 %res
}

; [ ] S  -> N
; [ ] S  -> S
; [ ] S  -> SC
; [x] S  -> N + B
; [ ] S  -> SC + B
define i32 @streaming_caller_locally_streaming_callee_inline() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define i32 @streaming_caller_locally_streaming_callee_inline
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @locally_streaming_callee()
  ret i32 %res
}

; [ ] S  -> N
; [ ] S  -> S
; [ ] S  -> SC
; [ ] S  -> N + B
; [x] S  -> SC + B
define i32 @streaming_caller_streaming_compatible_locally_streaming_callee_inline() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define i32 @streaming_caller_streaming_compatible_locally_streaming_callee_inline
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_compatible_locally_streaming_callee()
  ret i32 %res
}

; [x] N + B -> N
; [ ] N + B -> S
; [ ] N + B -> SC
; [ ] N + B -> N + B
; [ ] N + B -> SC + B
define i32 @locally_streaming_caller_normal_callee_dont_inline() "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @locally_streaming_caller_normal_callee_dont_inline
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @normal_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @normal_callee()
  ret i32 %res
}

; [ ] N + B -> N
; [x] N + B -> S
; [ ] N + B -> SC
; [ ] N + B -> N + B
; [ ] N + B -> SC + B
define i32 @locally_streaming_caller_streaming_callee_inline() "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @locally_streaming_caller_streaming_callee_inline
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_callee()
  ret i32 %res
}

; [ ] N + B -> N
; [ ] N + B -> S
; [x] N + B -> SC
; [ ] N + B -> N + B
; [ ] N + B -> SC + B
define i32 @locally_streaming_caller_streaming_compatible_callee_inline() "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @locally_streaming_caller_streaming_compatible_callee_inline
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_compatible_callee()
  ret i32 %res
}

; [ ] N + B -> N
; [ ] N + B -> S
; [ ] N + B -> SC
; [x] N + B -> N + B
; [ ] N + B -> SC + B
define i32 @locally_streaming_caller_locally_streaming_callee_inline() "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @locally_streaming_caller_locally_streaming_callee_inline
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @locally_streaming_callee()
  ret i32 %res
}

; [ ] N + B -> N
; [ ] N + B -> S
; [ ] N + B -> SC
; [ ] N + B -> N + B
; [x] N + B -> SC + B
define i32 @locally_streaming_caller_streaming_compatible_locally_streaming_callee_inline() "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @locally_streaming_caller_streaming_compatible_locally_streaming_callee_inline
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_compatible_locally_streaming_callee()
  ret i32 %res
}

; [x] SC -> N
; [ ] SC -> S
; [ ] SC -> SC
; [ ] SC -> N + B
; [ ] SC -> SC + B
define i32 @streaming_compatible_caller_normal_callee_dont_inline() "aarch64_pstate_sm_compatible" {
; CHECK-LABEL: define i32 @streaming_compatible_caller_normal_callee_dont_inline
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @normal_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @normal_callee()
  ret i32 %res
}

; [ ] SC -> N
; [x] SC -> S
; [ ] SC -> SC
; [ ] SC -> N + B
; [ ] SC -> SC + B
define i32 @streaming_compatible_caller_streaming_callee_dont_inline() "aarch64_pstate_sm_compatible" {
; CHECK-LABEL: define i32 @streaming_compatible_caller_streaming_callee_dont_inline
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @streaming_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @streaming_callee()
  ret i32 %res
}

; [ ] SC -> N
; [ ] SC -> S
; [x] SC -> SC
; [ ] SC -> N + B
; [ ] SC -> SC + B
define i32 @streaming_compatible_caller_streaming_compatible_callee_inline() "aarch64_pstate_sm_compatible" {
; CHECK-LABEL: define i32 @streaming_compatible_caller_streaming_compatible_callee_inline
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_compatible_callee()
  ret i32 %res
}

; [ ] SC -> N
; [ ] SC -> S
; [ ] SC -> SC
; [x] SC -> N + B
; [ ] SC -> SC + B
define i32 @streaming_compatible_caller_locally_streaming_callee_dont_inline() "aarch64_pstate_sm_compatible" {
; CHECK-LABEL: define i32 @streaming_compatible_caller_locally_streaming_callee_dont_inline
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @locally_streaming_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @locally_streaming_callee()
  ret i32 %res
}

; [ ] SC -> N
; [ ] SC -> S
; [ ] SC -> SC
; [ ] SC -> N + B
; [x] SC -> SC + B
define i32 @streaming_compatible_caller_streaming_compatible_locally_streaming_callee_dont_inline() "aarch64_pstate_sm_compatible" {
; CHECK-LABEL: define i32 @streaming_compatible_caller_streaming_compatible_locally_streaming_callee_dont_inline
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @streaming_compatible_locally_streaming_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @streaming_compatible_locally_streaming_callee()
  ret i32 %res
}
; [x] SC + B -> N
; [ ] SC + B -> S
; [ ] SC + B -> SC
; [ ] SC + B -> N + B
; [ ] SC + B -> SC + B
define i32 @streaming_compatible_locally_streaming_caller_normal_callee_dont_inline() "aarch64_pstate_sm_compatible" "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @streaming_compatible_locally_streaming_caller_normal_callee_dont_inline
; CHECK-SAME: () #[[ATTR4]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i32 @normal_callee()
; CHECK-NEXT:    ret i32 [[RES]]
;
entry:
  %res = call i32 @normal_callee()
  ret i32 %res
}

; [ ] SC + B -> N
; [x] SC + B -> S
; [ ] SC + B -> SC
; [ ] SC + B -> N + B
; [ ] SC + B -> SC + B
define i32 @streaming_compatible_locally_streaming_caller_streaming_callee_inline() "aarch64_pstate_sm_compatible" "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @streaming_compatible_locally_streaming_caller_streaming_callee_inline
; CHECK-SAME: () #[[ATTR4]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_callee()
  ret i32 %res
}

; [ ] SC + B -> N
; [ ] SC + B -> S
; [x] SC + B -> SC
; [ ] SC + B -> N + B
; [ ] SC + B -> SC + B
define i32 @streaming_compatible_locally_streaming_caller_streaming_compatible_callee_inline() "aarch64_pstate_sm_compatible" "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @streaming_compatible_locally_streaming_caller_streaming_compatible_callee_inline
; CHECK-SAME: () #[[ATTR4]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_compatible_callee()
  ret i32 %res
}

; [ ] SC + B -> N
; [ ] SC + B -> S
; [ ] SC + B -> SC
; [x] SC + B -> N + B
; [ ] SC + B -> SC + B
define i32 @streaming_compatible_locally_streaming_caller_locally_streaming_callee_inline() "aarch64_pstate_sm_compatible" "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @streaming_compatible_locally_streaming_caller_locally_streaming_callee_inline
; CHECK-SAME: () #[[ATTR4]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @locally_streaming_callee()
  ret i32 %res
}

; [ ] SC + B -> N
; [ ] SC + B -> S
; [ ] SC + B -> SC
; [ ] SC + B -> N + B
; [x] SC + B -> SC + B
define i32 @streaming_compatible_locally_streaming_caller_and_callee_inline() "aarch64_pstate_sm_compatible" "aarch64_pstate_sm_body" {
; CHECK-LABEL: define i32 @streaming_compatible_locally_streaming_caller_and_callee_inline
; CHECK-SAME: () #[[ATTR4]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES_I:%.*]] = call i32 @llvm.vscale.i32()
; CHECK-NEXT:    ret i32 [[RES_I]]
;
entry:
  %res = call i32 @streaming_compatible_locally_streaming_callee()
  ret i32 %res
}

define void @normal_callee_with_inlineasm() {
; CHECK-LABEL: define void @normal_callee_with_inlineasm
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    call void asm sideeffect "
; CHECK-NEXT:    ret void
;
entry:
  call void asm sideeffect "; inlineasm", ""()
  ret void
}

define void @streaming_caller_normal_callee_with_inlineasm_dont_inline() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define void @streaming_caller_normal_callee_with_inlineasm_dont_inline
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    call void @normal_callee_with_inlineasm()
; CHECK-NEXT:    ret void
;
entry:
  call void @normal_callee_with_inlineasm()
  ret void
}

define i64 @normal_callee_with_intrinsic_call() {
; CHECK-LABEL: define i64 @normal_callee_with_intrinsic_call
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i64 @llvm.aarch64.sve.cntb(i32 4)
; CHECK-NEXT:    ret i64 [[RES]]
;
entry:
  %res = call i64 @llvm.aarch64.sve.cntb(i32 4)
  ret i64 %res
}

define i64 @streaming_caller_normal_callee_with_intrinsic_call_dont_inline() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define i64 @streaming_caller_normal_callee_with_intrinsic_call_dont_inline
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i64 @normal_callee_with_intrinsic_call()
; CHECK-NEXT:    ret i64 [[RES]]
;
entry:
  %res = call i64 @normal_callee_with_intrinsic_call()
  ret i64 %res
}

declare i64 @llvm.aarch64.sve.cntb(i32)

define i64 @normal_callee_call_sme_state() {
; CHECK-LABEL: define i64 @normal_callee_call_sme_state
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call { i64, i64 } @__arm_sme_state()
; CHECK-NEXT:    [[RES_0:%.*]] = extractvalue { i64, i64 } [[RES]], 0
; CHECK-NEXT:    ret i64 [[RES_0]]
;
entry:
  %res = call {i64, i64} @__arm_sme_state()
  %res.0 = extractvalue {i64, i64} %res, 0
  ret i64 %res.0
}

declare {i64, i64} @__arm_sme_state()

define i64 @streaming_caller_normal_callee_call_sme_state_dont_inline() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define i64 @streaming_caller_normal_callee_call_sme_state_dont_inline
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RES:%.*]] = call i64 @normal_callee_call_sme_state()
; CHECK-NEXT:    ret i64 [[RES]]
;
entry:
  %res = call i64 @normal_callee_call_sme_state()
  ret i64 %res
}



declare void @streaming_body() "aarch64_pstate_sm_enabled"

define void @streaming_caller_single_streaming_callee() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define void @streaming_caller_single_streaming_callee
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:    call void @streaming_body()
; CHECK-NEXT:    ret void
;
  call void @streaming_body()
  ret void
}

define void @streaming_caller_multiple_streaming_callees() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define void @streaming_caller_multiple_streaming_callees
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:    call void @streaming_body()
; CHECK-NEXT:    call void @streaming_body()
; CHECK-NEXT:    ret void
;
  call void @streaming_body()
  call void @streaming_body()
  ret void
}

; Allow inlining, as inline it would not increase the number of streaming-mode changes.
define void @streaming_caller_single_streaming_callee_inline() {
; CHECK-LABEL: define void @streaming_caller_single_streaming_callee_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:    call void @streaming_body()
; CHECK-NEXT:    ret void
;
  call void @streaming_caller_single_streaming_callee()
  ret void
}

; Prevent inlining, as inline it would lead to multiple streaming-mode changes.
define void @streaming_caller_multiple_streaming_callees_dont_inline() {
; CHECK-LABEL: define void @streaming_caller_multiple_streaming_callees_dont_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:    call void @streaming_caller_multiple_streaming_callees()
; CHECK-NEXT:    ret void
;
  call void @streaming_caller_multiple_streaming_callees()
  ret void
}

declare void @streaming_compatible_body() "aarch64_pstate_sm_compatible"

define void @streaming_caller_single_streaming_compatible_callee() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define void @streaming_caller_single_streaming_compatible_callee
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:    call void @streaming_compatible_body()
; CHECK-NEXT:    ret void
;
  call void @streaming_compatible_body()
  ret void
}

define void @streaming_caller_multiple_streaming_compatible_callees() "aarch64_pstate_sm_enabled" {
; CHECK-LABEL: define void @streaming_caller_multiple_streaming_compatible_callees
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:    call void @streaming_compatible_body()
; CHECK-NEXT:    call void @streaming_compatible_body()
; CHECK-NEXT:    ret void
;
  call void @streaming_compatible_body()
  call void @streaming_compatible_body()
  ret void
}

; Allow inlining, as inline would remove a streaming-mode change.
define void @streaming_caller_single_streaming_compatible_callee_inline() {
; CHECK-LABEL: define void @streaming_caller_single_streaming_compatible_callee_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:    call void @streaming_compatible_body()
; CHECK-NEXT:    ret void
;
  call void @streaming_caller_single_streaming_compatible_callee()
  ret void
}

; Allow inlining, as inline would remove several stremaing-mode changes.
define void @streaming_caller_multiple_streaming_compatible_callees_inline() {
; CHECK-LABEL: define void @streaming_caller_multiple_streaming_compatible_callees_inline
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT:    call void @streaming_compatible_body()
; CHECK-NEXT:    call void @streaming_compatible_body()
; CHECK-NEXT:    ret void
;
  call void @streaming_caller_multiple_streaming_compatible_callees()
  ret void
}