blob: 00860a96e544217394806018799143eba375791f [file] [edit]
; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_50 | FileCheck %s
; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_50 | %ptxas-verify %}
; The expansion of small memcpy/memmove/memset can raise the alignment of
; under-aligned stack objects. Verify this also works on NVPTX, where generic
; allocas are lowered to local-address-space allocas before codegen, both for
; direct uses and for uses in a different basic block.
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
target triple = "nvptx64-nvidia-cuda"
declare void @use(ptr)
define void @memcpy_alloca() {
; CHECK-LABEL: memcpy_alloca(
; CHECK: .local .align 4 .b8 __local_depot{{[0-9]+}}[16];
; CHECK: st.local.b8
; CHECK: st.local.b16
; CHECK: st.local.b32
; CHECK-NOT: st.local.b8
; CHECK: ret;
%a = alloca [7 x i8], align 1
%b = alloca [7 x i8], align 1
call void @use(ptr %a)
call void @use(ptr %b)
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %a, ptr align 1 %b, i64 7, i1 false)
call void @use(ptr %a)
ret void
}
define void @memcpy_alloca_cross_bb(i1 %c) {
; CHECK-LABEL: memcpy_alloca_cross_bb(
; CHECK: .local .align 4 .b8 __local_depot{{[0-9]+}}[16];
; CHECK: st.local.b8
; CHECK: st.local.b16
; CHECK: st.local.b32
; CHECK-NOT: st.local.b8
; CHECK: ret;
entry:
%a = alloca [7 x i8], align 1
%b = alloca [7 x i8], align 1
call void @use(ptr %a)
call void @use(ptr %b)
br i1 %c, label %copy, label %exit
copy:
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %a, ptr align 1 %b, i64 7, i1 false)
call void @use(ptr %a)
br label %exit
exit:
ret void
}
; The source object's alignment was raised when expanding the first memcpy;
; the loads of the second copy can only learn about it through the frame object.
define void @memcpy_alloca_raised_src(i1 %c, ptr %p) {
; CHECK-LABEL: memcpy_alloca_raised_src(
; CHECK: .local .align 4 .b8 __local_depot{{[0-9]+}}[16];
; CHECK: ld.local.b8
; CHECK: ld.local.b16
; CHECK: ld.local.b32
; CHECK-NOT: ld.local.b8
; CHECK: ret;
entry:
%a = alloca [7 x i8], align 1
%b = alloca [7 x i8], align 1
call void @use(ptr %a)
call void @use(ptr %b)
br i1 %c, label %copy1, label %exit
copy1:
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %b, ptr align 1 %p, i64 7, i1 false)
br label %copy2
copy2:
call void @llvm.memcpy.p0.p0.i64(ptr align 1 %a, ptr align 1 %b, i64 7, i1 false)
call void @use(ptr %a)
br label %exit
exit:
ret void
}
define void @memmove_alloca() {
; CHECK-LABEL: memmove_alloca(
; CHECK: .local .align 4 .b8 __local_depot{{[0-9]+}}[16];
; CHECK: st.local.b8
; CHECK: st.local.b16
; CHECK: st.local.b32
; CHECK-NOT: st.local.b8
; CHECK: ret;
%a = alloca [7 x i8], align 1
%b = alloca [7 x i8], align 1
call void @use(ptr %a)
call void @use(ptr %b)
call void @llvm.memmove.p0.p0.i64(ptr align 1 %a, ptr align 1 %b, i64 7, i1 false)
call void @use(ptr %a)
ret void
}
define void @memset_alloca() {
; CHECK-LABEL: memset_alloca(
; CHECK: .local .align 4 .b8 __local_depot{{[0-9]+}}[8];
; CHECK: st.local.b8
; CHECK: st.local.b16
; CHECK: st.local.b32
; CHECK-NOT: st.local.b8
; CHECK: ret;
%a = alloca [7 x i8], align 1
call void @use(ptr %a)
call void @llvm.memset.p0.i64(ptr align 1 %a, i8 0, i64 7, i1 false)
call void @use(ptr %a)
ret void
}
; Local-address-space alloca lowering also lets DAGCombiner refine the alignment
; of under-aligned plain loads and stores through the frame object.
define i32 @underaligned_load_store(i32 %v) {
; CHECK-LABEL: underaligned_load_store(
; CHECK: ld.local.b32
; CHECK: st.local.b32
; CHECK-NOT: .local.b8
; CHECK: ret;
%a = alloca i32, align 4
call void @use(ptr %a)
%l = load i32, ptr %a, align 1
store i32 %v, ptr %a, align 1
call void @use(ptr %a)
ret i32 %l
}