blob: be6356218c1b13a35bf70e6a0c8482f563533e7c [file] [log] [blame] [edit]
; RUN: opt %s -minsfi-expand-allocas -S | FileCheck %s
!llvm.module.flags = !{!0}
!0 = !{i32 1, !"Debug Info Version", i32 3}
target datalayout = "p:32:32:32"
target triple = "le32-unknown-nacl"
; Check that the stack pointer global variable is created. This does not check
; the initial value of the stack ptr.
; CHECK: @__sfi_stack_ptr = internal global i32
declare i8* @llvm.stacksave()
declare void @llvm.stackrestore(i8* %ptr)
declare void @foo()
define i32 @test_no_alloca(i1 %cond) {
br i1 %cond, label %IfOne, label %IfNotOne
IfOne:
call void @foo()
ret i32 2
IfNotOne:
ret i32 3
}
; CHECK-LABEL: define i32 @test_no_alloca(i1 %cond) {
; CHECK-NEXT: br i1 %cond, label %IfOne, label %IfNotOne
; CHECK: IfOne:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: ret i32 2
; CHECK: IfNotOne:
; CHECK-NEXT: ret i32 3
; CHECK-NEXT: }
define i8* @test_const_alloca() {
%ptr = alloca i8, i32 9, !dbg !1
ret i8* %ptr
}
; CHECK-LABEL: define i8* @test_const_alloca() {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, 9
; CHECK-NEXT: %ptr = inttoptr i32 %1 to i8*, !dbg !1
; CHECK-NEXT: ret i8* %ptr
; CHECK-NEXT: }
define i8* @test_const_alloca_align() {
%ptr = alloca i8, i32 9, align 536870912 ; biggest possible alignment
ret i8* %ptr
}
; CHECK-LABEL: define i8* @test_const_alloca_align() {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, 9
; CHECK-NEXT: %2 = and i32 %1, -536870912
; CHECK-NEXT: %ptr = inttoptr i32 %2 to i8*
; CHECK-NEXT: ret i8* %ptr
; CHECK-NEXT: }
define i8* @test_variable_length_alloca(i32 %size) {
%ptr = alloca i8, i32 %size, !dbg !1
ret i8* %ptr
}
; CHECK-LABEL: define i8* @test_variable_length_alloca(i32 %size) {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, %size
; CHECK-NEXT: %ptr = inttoptr i32 %1 to i8*, !dbg !1
; CHECK-NEXT: ret i8* %ptr
; CHECK-NEXT: }
define i8* @test_variable_length_alloca_align(i32 %size) {
%ptr = alloca i8, i32 %size, align 32
ret i8* %ptr
}
; CHECK-LABEL: define i8* @test_variable_length_alloca_align(i32 %size) {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, %size
; CHECK-NEXT: %2 = and i32 %1, -32
; CHECK-NEXT: %ptr = inttoptr i32 %2 to i8*
; CHECK-NEXT: ret i8* %ptr
; CHECK-NEXT: }
define i8* @test_const_after_const_alloca() {
%ptr1 = alloca i8, i32 4
%ptr2 = alloca i8, i32 8
ret i8* %ptr2
}
; CHECK-LABEL: define i8* @test_const_after_const_alloca() {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, 4
; CHECK-NEXT: %ptr1 = inttoptr i32 %1 to i8*
; CHECK-NEXT: %2 = sub i32 %1, 8
; CHECK-NEXT: %ptr2 = inttoptr i32 %2 to i8*
; CHECK-NEXT: ret i8* %ptr2
; CHECK-NEXT: }
define i8* @test_const_after_variable_alloca(i32 %size) {
%ptr1 = alloca i8, i32 %size
%ptr2 = alloca i8, i32 19
ret i8* %ptr2
}
; CHECK-LABEL: define i8* @test_const_after_variable_alloca(i32 %size) {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, %size
; CHECK-NEXT: %ptr1 = inttoptr i32 %1 to i8*
; CHECK-NEXT: %2 = sub i32 %1, 19
; CHECK-NEXT: %ptr2 = inttoptr i32 %2 to i8*
; CHECK-NEXT: ret i8* %ptr2
; CHECK-NEXT: }
define i8* @test_stacksave() {
%ptr = call i8* @llvm.stacksave(), !dbg !1
ret i8* %ptr
}
; CHECK-LABEL: define i8* @test_stacksave() {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %ptr = inttoptr i32 %frame_top to i8*, !dbg !1
; CHECK-NEXT: ret i8* %ptr
; CHECK-NEXT: }
define i8* @test_stacksave_after_alloca() {
%ptr1 = alloca i8, i32 11
%ptr2 = call i8* @llvm.stacksave(), !dbg !1
ret i8* %ptr2
}
; CHECK-LABEL: define i8* @test_stacksave_after_alloca() {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, 11
; CHECK-NEXT: %ptr1 = inttoptr i32 %1 to i8*
; CHECK-NEXT: %ptr2 = inttoptr i32 %1 to i8*, !dbg !1
; CHECK-NEXT: ret i8* %ptr2
; CHECK-NEXT: }
define i8* @test_stackrestore(i8* %new_stack) {
call void @llvm.stackrestore(i8* %new_stack), !dbg !1
%ptr = alloca i8, i32 5, !dbg !3
ret i8* %ptr
}
; CHECK-LABEL: define i8* @test_stackrestore(i8* %new_stack) {
; CHECK-NEXT: frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = ptrtoint i8* %new_stack to i32, !dbg !1
; CHECK-NEXT: %2 = sub i32 %1, 5
; CHECK-NEXT: %ptr = inttoptr i32 %2 to i8*, !dbg !3
; CHECK-NEXT: ret i8* %ptr
; CHECK-NEXT: }
define i8* @test_stackrestore_after_push(i8* %new_stack) {
%ptr1 = alloca i8, i32 5, !dbg !1
call void @llvm.stackrestore(i8* %new_stack), !dbg !3
%ptr2 = alloca i8, i32 6, !dbg !4
ret i8* %ptr2
}
; CHECK-LABEL: define i8* @test_stackrestore_after_push(i8* %new_stack) {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, 5
; CHECK-NEXT: %ptr1 = inttoptr i32 %1 to i8*, !dbg !1
; CHECK-NEXT: %2 = ptrtoint i8* %new_stack to i32, !dbg !3
; CHECK-NEXT: %3 = sub i32 %2, 6
; CHECK-NEXT: %ptr2 = inttoptr i32 %3 to i8*, !dbg !4
; CHECK-NEXT: ret i8* %ptr2
; CHECK-NEXT: }
define i8* @test_stackptr_bb_propagation(i1 %cond) {
%ptr1 = alloca i8, i32 8
br i1 %cond, label %IfOne, label %IfNotOne
IfOne:
ret i8* %ptr1
IfNotOne:
%ptr2 = alloca i8, i32 4
ret i8* %ptr2
}
; CHECK-LABEL: define i8* @test_stackptr_bb_propagation(i1 %cond) {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %1 = sub i32 %frame_top, 8
; CHECK-NEXT: %ptr1 = inttoptr i32 %1 to i8*
; CHECK-NEXT: br i1 %cond, label %IfOne, label %IfNotOne
; CHECK: IfOne:
; CHECK-NEXT: %2 = phi i32 [ %1, %0 ]
; CHECK-NEXT: ret i8* %ptr1
; CHECK: IfNotOne:
; CHECK-NEXT: %3 = phi i32 [ %1, %0 ]
; CHECK-NEXT: %4 = sub i32 %3, 4
; CHECK-NEXT: %ptr2 = inttoptr i32 %4 to i8*
; CHECK-NEXT: ret i8* %ptr2
; CHECK-NEXT: }
define i8* @test_scoped_alloca(i1 %cmp) {
br label %loop
loop:
%stacksave = call i8* @llvm.stacksave()
%ptr = alloca i8, i32 17
call void @llvm.stackrestore(i8* %stacksave)
br i1 %cmp, label %done, label %loop
done:
ret i8* %ptr
}
; CHECK-LABEL: define i8* @test_scoped_alloca(i1 %cmp) {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: %1 = phi i32 [ %frame_top, %0 ], [ %3, %loop ]
; CHECK-NEXT: %stacksave = inttoptr i32 %1 to i8*
; CHECK-NEXT: %2 = sub i32 %1, 17
; CHECK-NEXT: %ptr = inttoptr i32 %2 to i8*
; CHECK-NEXT: %3 = ptrtoint i8* %stacksave to i32
; CHECK-NEXT: br i1 %cmp, label %done, label %loop
; CHECK: done:
; CHECK-NEXT: %4 = phi i32 [ %3, %loop ]
; CHECK-NEXT: ret i8* %ptr
; CHECK-NEXT: }
define i8* @test_global_ptr_updates(i32 %size) {
%ptr0 = call i8* @llvm.stacksave()
%ptr1 = alloca i8, i32 32
%ptr2 = alloca i8, i32 %size
call void @llvm.stackrestore(i8* %ptr0)
call void @foo()
ret i8* %ptr2
}
; CHECK-LABEL: define i8* @test_global_ptr_updates(i32 %size) {
; CHECK-NEXT: %frame_top = load i32, i32* @__sfi_stack_ptr
; CHECK-NEXT: %ptr0 = inttoptr i32 %frame_top to i8*
; CHECK-NEXT: %1 = sub i32 %frame_top, 32
; CHECK-NEXT: store i32 %1, i32* @__sfi_stack_ptr
; CHECK-NEXT: %ptr1 = inttoptr i32 %1 to i8*
; CHECK-NEXT: %2 = sub i32 %1, %size
; CHECK-NEXT: store i32 %2, i32* @__sfi_stack_ptr
; CHECK-NEXT: %ptr2 = inttoptr i32 %2 to i8*
; CHECK-NEXT: %3 = ptrtoint i8* %ptr0 to i32
; CHECK-NEXT: store i32 %3, i32* @__sfi_stack_ptr
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: store i32 %frame_top, i32* @__sfi_stack_ptr
; CHECK-NEXT: ret i8* %ptr2
; CHECK-NEXT: }
define i32 @_start_minsfi(i32 %args) {
ret i32 0
}
; CHECK-LABEL: define i32 @_start_minsfi(i32 %args) {
; CHECK-NEXT: store i32 %args, i32* @__sfi_stack_ptr
; CHECK-NEXT: ret i32 0
; CHECK-NEXT: }
!1 = !MDLocation(line: 1, column: 13, scope: !2)
!2 = !MDSubprogram(name: "foo")
!3 = !MDLocation(line: 2, column: 10, scope: !2)
!4 = !MDLocation(line: 2, column: 3, scope: !2)