blob: 74c8161833c952a42a915c9a49581991df4a2bda [file] [edit]
; RUN: llc -mtriple=hexagon < %s | FileCheck %s
;; Small frame (< probe size): no probing loop, normal allocframe.
; CHECK-LABEL: small_frame:
; CHECK: allocframe(r29,#128):raw
; CHECK-NOT: cmp.gtu
; CHECK: dealloc_return
define void @small_frame() #0 {
entry:
%a = alloca [128 x i8], align 1
call void @use(ptr %a)
ret void
}
;; Large frame (> probe size): probing loop emitted.
; CHECK-LABEL: large_frame:
; CHECK: allocframe(r29,#0):raw
; CHECK: r28 = add(r29,#-8192)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r28)
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r28
define void @large_frame() #0 {
entry:
%a = alloca [8192 x i8], align 1
call void @use(ptr %a)
ret void
}
;; Exact multiple of probe size: probing loop still emitted.
; CHECK-LABEL: exact_multiple:
; CHECK: allocframe(r29,#0):raw
; CHECK: r28 = add(r29,#-12288)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r28)
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r28
define void @exact_multiple() #0 {
entry:
%a = alloca [12288 x i8], align 1
call void @use(ptr %a)
ret void
}
;; No frame pointer path with no call: probing works without allocframe.
; CHECK-LABEL: no_fp_large:
; CHECK-NOT: allocframe
; CHECK: r28 = add(r29,#-8192)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r28)
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r28
define void @no_fp_large() #1 {
entry:
%a = alloca [8192 x i8], align 1
store volatile i8 0, ptr %a
ret void
}
;; Custom probe size of 512 bytes.
; CHECK-LABEL: custom_probe_size:
; CHECK: allocframe(r29,#0):raw
; CHECK: r28 = add(r29,#-8192)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-512)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r28)
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r28
define void @custom_probe_size() #2 {
entry:
%a = alloca [8192 x i8], align 1
call void @use(ptr %a)
ret void
}
;; No probe attribute: normal codegen, no probing.
; CHECK-LABEL: no_probe:
; CHECK: allocframe
; CHECK-NOT: cmp.gtu
; CHECK: dealloc_return
define void @no_probe() {
entry:
%a = alloca [8192 x i8], align 1
call void @use(ptr %a)
ret void
}
;; Frame >= ALLOCFRAME_MAX (16384): allocframe(#0) + probed alloc.
; CHECK-LABEL: very_large_frame:
; CHECK: allocframe(r29,#0):raw
; CHECK: r28 = add(r29,#-20480)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r28)
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r28
define void @very_large_frame() #0 {
entry:
%a = alloca [20480 x i8], align 1
call void @use(ptr %a)
ret void
}
;; Frame == probe size exactly: no probing loop, normal allocframe.
; CHECK-LABEL: exact_probe_size:
; CHECK: allocframe(r29,#4096):raw
; CHECK-NOT: cmp.gtu
; CHECK: dealloc_return
define void @exact_probe_size() #0 {
entry:
%a = alloca [4096 x i8], align 1
call void @use(ptr %a)
ret void
}
;; Large frame requiring constant-extended immediate (> 32767).
; CHECK-LABEL: const_extd_frame:
; CHECK: allocframe(r29,#0):raw
; CHECK: r28 = add(r29,##-65536)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r28)
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r28
define void @const_extd_frame() #0 {
entry:
%a = alloca [65536 x i8], align 1
call void @use(ptr %a)
ret void
}
;; Callee-saved register spills coexist with probing.
; CHECK-LABEL: callee_saved_regs:
; CHECK: allocframe(r29,#0):raw
; CHECK: r28 = add(r29,#-8216)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r28)
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r28
; CHECK: memd(r29+##{{[0-9]+}}) = r{{[0-9]+}}:{{[0-9]+}}
; CHECK: dealloc_return
define void @callee_saved_regs(ptr %p) #0 {
entry:
%a = alloca [8192 x i8], align 1
call void @use(ptr %a)
call void asm sideeffect "", "~{r16},~{r17},~{r18},~{r19}"()
call void @use(ptr %p)
ret void
}
;; VLA (dynamic alloca): probe loop emitted for runtime-sized allocation.
; CHECK-LABEL: vla_basic:
; CHECK: allocframe
; CHECK: r[[TGT:[0-9]+]] = sub(r29,r{{[0-9]+}})
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r[[TGT]])
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r[[TGT]]
define void @vla_basic(i32 %n) #0 {
entry:
%sz = zext i32 %n to i64
%buf = alloca i8, i64 %sz, align 1
call void @use(ptr %buf)
ret void
}
;; VLA without probe attribute: plain sub(r29,Rs), no probe loop.
; CHECK-LABEL: vla_no_probe:
; CHECK: sub(r29,r
; CHECK-NOT: cmp.gtu
; CHECK: dealloc_return
define void @vla_no_probe(i32 %n) {
entry:
%sz = zext i32 %n to i64
%buf = alloca i8, i64 %sz, align 1
call void @use(ptr %buf)
ret void
}
;; Static large frame + VLA: two separate probe loops are emitted.
; CHECK-LABEL: vla_and_static:
; CHECK: allocframe(r29,#0):raw
; CHECK: r28 = add(r29,#-8200)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r28)
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r28
; CHECK: r[[TGT2:[0-9]+]] = sub(r29,r{{[0-9]+}})
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r[[TGT2]])
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r[[TGT2]]
define void @vla_and_static(i32 %n) #0 {
entry:
%static = alloca [8192 x i8], align 1
%sz = zext i32 %n to i64
%dyn = alloca i8, i64 %sz, align 1
call void @use2(ptr %static, ptr %dyn)
ret void
}
;; VLA with alignment > 8: target pointer is aligned before probing.
; CHECK-LABEL: vla_align16:
; CHECK: allocframe
; CHECK: r[[TGT3:[0-9]+]] = sub(r29,r{{[0-9]+}})
; CHECK: r[[TGT3]] = and(r[[TGT3]],#-16)
; CHECK: .LBB{{[0-9]+}}_{{[0-9]+}}:
; CHECK: {
; CHECK-NEXT: r29 = add(r29,#-4096)
; CHECK-NEXT: }
; CHECK-NEXT: {
; CHECK-NEXT: p0 = cmp.gtu(r29,r[[TGT3]])
; CHECK-NEXT: if (p0.new) jump:t .LBB
; CHECK-NEXT: memw(r29+#0) = #0
; CHECK-NEXT: }
; CHECK: r29 = r[[TGT3]]
define void @vla_align16(i32 %n) #0 {
entry:
%sz = zext i32 %n to i64
%buf = alloca i8, i64 %sz, align 16
call void @use(ptr %buf)
ret void
}
declare void @use(ptr)
declare void @use2(ptr, ptr)
attributes #0 = { "probe-stack"="inline-asm" }
attributes #1 = { nounwind "frame-pointer"="none" "probe-stack"="inline-asm" }
attributes #2 = { "probe-stack"="inline-asm" "stack-probe-size"="512" }