| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -S -mtriple=spirv64-- --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s |
| |
| %struct.agg = type { i32, double } |
| |
| define spir_func void @variadic_sink(i32 noundef %tag, ...) { |
| ; CHECK-LABEL: define spir_func void @variadic_sink( |
| ; CHECK-SAME: i32 noundef [[TAG:%.*]], ptr [[VARARGS:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[AP:%.*]] = alloca ptr, align 8 |
| ; CHECK-NEXT: store ptr [[VARARGS]], ptr [[AP]], align 8 |
| ; CHECK-NEXT: switch i32 [[TAG]], label %[[SW_DEFAULT:.*]] [ |
| ; CHECK-NEXT: i32 0, label %[[SW_BB:.*]] |
| ; CHECK-NEXT: i32 1, label %[[SW_BB1:.*]] |
| ; CHECK-NEXT: i32 2, label %[[SW_BB4:.*]] |
| ; CHECK-NEXT: i32 3, label %[[SW_BB7:.*]] |
| ; CHECK-NEXT: i32 4, label %[[SW_BB10:.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: [[SW_BB]]: |
| ; CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 3 |
| ; CHECK-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP0]], i64 -4) |
| ; CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i64 4 |
| ; CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARGP_CUR_ALIGNED]], align 4 |
| ; CHECK-NEXT: br label %[[SW_EPILOG:.*]] |
| ; CHECK: [[SW_BB1]]: |
| ; CHECK-NEXT: [[ARGP_CUR2:%.*]] = load ptr, ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR2]], i32 7 |
| ; CHECK-NEXT: [[ARGP_CUR2_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP2]], i64 -8) |
| ; CHECK-NEXT: [[ARGP_NEXT3:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR2_ALIGNED]], i64 8 |
| ; CHECK-NEXT: store ptr [[ARGP_NEXT3]], ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr [[ARGP_CUR2_ALIGNED]], align 8 |
| ; CHECK-NEXT: br label %[[SW_EPILOG]] |
| ; CHECK: [[SW_BB4]]: |
| ; CHECK-NEXT: [[ARGP_CUR5:%.*]] = load ptr, ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR5]], i32 7 |
| ; CHECK-NEXT: [[ARGP_CUR5_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP4]], i64 -8) |
| ; CHECK-NEXT: [[ARGP_NEXT6:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR5_ALIGNED]], i64 8 |
| ; CHECK-NEXT: store ptr [[ARGP_NEXT6]], ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[ARGP_CUR5_ALIGNED]], align 8 |
| ; CHECK-NEXT: br label %[[SW_EPILOG]] |
| ; CHECK: [[SW_BB7]]: |
| ; CHECK-NEXT: [[ARGP_CUR8:%.*]] = load ptr, ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR8]], i32 7 |
| ; CHECK-NEXT: [[ARGP_CUR8_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP6]], i64 -8) |
| ; CHECK-NEXT: [[ARGP_NEXT9:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR8_ALIGNED]], i64 16 |
| ; CHECK-NEXT: store ptr [[ARGP_NEXT9]], ptr [[AP]], align 8 |
| ; CHECK-NEXT: br label %[[SW_EPILOG]] |
| ; CHECK: [[SW_BB10]]: |
| ; CHECK-NEXT: [[ARGP_CUR11:%.*]] = load ptr, ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR11]], i32 15 |
| ; CHECK-NEXT: [[ARGP_CUR11_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP7]], i64 -16) |
| ; CHECK-NEXT: [[ARGP_NEXT12:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR11_ALIGNED]], i64 16 |
| ; CHECK-NEXT: store ptr [[ARGP_NEXT12]], ptr [[AP]], align 8 |
| ; CHECK-NEXT: [[TMP8:%.*]] = load <4 x float>, ptr [[ARGP_CUR11_ALIGNED]], align 16 |
| ; CHECK-NEXT: br label %[[SW_EPILOG]] |
| ; CHECK: [[SW_DEFAULT]]: |
| ; CHECK-NEXT: br label %[[SW_EPILOG]] |
| ; CHECK: [[SW_EPILOG]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %ap = alloca ptr, align 8 |
| call void @llvm.va_start.p0(ptr %ap) |
| switch i32 %tag, label %sw.default [ |
| i32 0, label %sw.bb |
| i32 1, label %sw.bb1 |
| i32 2, label %sw.bb4 |
| i32 3, label %sw.bb7 |
| i32 4, label %sw.bb10 |
| ] |
| |
| sw.bb: ; preds = %entry |
| %argp.cur = load ptr, ptr %ap, align 8 |
| %0 = getelementptr inbounds i8, ptr %argp.cur, i32 3 |
| %argp.cur.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %0, i64 -4) |
| %argp.next = getelementptr inbounds i8, ptr %argp.cur.aligned, i64 4 |
| store ptr %argp.next, ptr %ap, align 8 |
| %1 = load i32, ptr %argp.cur.aligned, align 4 |
| br label %sw.epilog |
| |
| sw.bb1: ; preds = %entry |
| %argp.cur2 = load ptr, ptr %ap, align 8 |
| %2 = getelementptr inbounds i8, ptr %argp.cur2, i32 7 |
| %argp.cur2.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %2, i64 -8) |
| %argp.next3 = getelementptr inbounds i8, ptr %argp.cur2.aligned, i64 8 |
| store ptr %argp.next3, ptr %ap, align 8 |
| %3 = load i64, ptr %argp.cur2.aligned, align 8 |
| br label %sw.epilog |
| |
| sw.bb4: ; preds = %entry |
| %argp.cur5 = load ptr, ptr %ap, align 8 |
| %4 = getelementptr inbounds i8, ptr %argp.cur5, i32 7 |
| %argp.cur5.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %4, i64 -8) |
| %argp.next6 = getelementptr inbounds i8, ptr %argp.cur5.aligned, i64 8 |
| store ptr %argp.next6, ptr %ap, align 8 |
| %5 = load double, ptr %argp.cur5.aligned, align 8 |
| br label %sw.epilog |
| |
| sw.bb7: ; preds = %entry |
| %argp.cur8 = load ptr, ptr %ap, align 8 |
| %6 = getelementptr inbounds i8, ptr %argp.cur8, i32 7 |
| %argp.cur8.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %6, i64 -8) |
| %argp.next9 = getelementptr inbounds i8, ptr %argp.cur8.aligned, i64 16 |
| store ptr %argp.next9, ptr %ap, align 8 |
| br label %sw.epilog |
| |
| sw.bb10: ; preds = %entry |
| %argp.cur11 = load ptr, ptr %ap, align 8 |
| %7 = getelementptr inbounds i8, ptr %argp.cur11, i32 15 |
| %argp.cur11.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %7, i64 -16) |
| %argp.next12 = getelementptr inbounds i8, ptr %argp.cur11.aligned, i64 16 |
| store ptr %argp.next12, ptr %ap, align 8 |
| %8 = load <4 x float>, ptr %argp.cur11.aligned, align 16 |
| br label %sw.epilog |
| |
| sw.default: ; preds = %entry |
| br label %sw.epilog |
| |
| sw.epilog: ; preds = %sw.default, %sw.bb10, %sw.bb7, %sw.bb4, %sw.bb1, %sw.bb |
| call void @llvm.va_end.p0(ptr %ap) |
| ret void |
| } |
| |
| define spir_func void @call_i32() { |
| ; CHECK-LABEL: define spir_func void @call_i32() { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VARARG_BUFFER:%.*]] = alloca [[CALL_I32_VARARG:%.*]], align 4 |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[CALL_I32_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0 |
| ; CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4 |
| ; CHECK-NEXT: call spir_func void @variadic_sink(i32 noundef 0, ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| call spir_func void (i32, ...) @variadic_sink(i32 noundef 0, i32 noundef 1) |
| ret void |
| } |
| |
| define spir_func void @call_i64() { |
| ; CHECK-LABEL: define spir_func void @call_i64() { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VARARG_BUFFER:%.*]] = alloca [[CALL_I64_VARARG:%.*]], align 8 |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[CALL_I64_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0 |
| ; CHECK-NEXT: store i64 1, ptr [[TMP0]], align 8 |
| ; CHECK-NEXT: call spir_func void @variadic_sink(i32 noundef 1, ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| call spir_func void (i32, ...) @variadic_sink(i32 noundef 1, i64 noundef 1) |
| ret void |
| } |
| |
| define spir_func void @call_f64() { |
| ; CHECK-LABEL: define spir_func void @call_f64() { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VARARG_BUFFER:%.*]] = alloca [[CALL_F64_VARARG:%.*]], align 8 |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[CALL_F64_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0 |
| ; CHECK-NEXT: store double 1.000000e+00, ptr [[TMP0]], align 8 |
| ; CHECK-NEXT: call spir_func void @variadic_sink(i32 noundef 2, ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| call spir_func void (i32, ...) @variadic_sink(i32 noundef 2, double noundef 1.000000e+00) |
| ret void |
| } |
| |
| define spir_func void @call_struct() { |
| ; CHECK-LABEL: define spir_func void @call_struct() { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8 |
| ; CHECK-NEXT: [[VARARG_BUFFER:%.*]] = alloca [[CALL_STRUCT_VARARG:%.*]], align 8 |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 0 |
| ; CHECK-NEXT: store i32 1, ptr [[A]], align 8 |
| ; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[DOTCOMPOUNDLITERAL]], i64 4 |
| ; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP0]], i8 0, i64 4, i1 false) |
| ; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds nuw [[STRUCT_AGG]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 1 |
| ; CHECK-NEXT: store double 2.000000e+00, ptr [[B]], align 8 |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw [[CALL_STRUCT_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0 |
| ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[TMP1]], ptr [[DOTCOMPOUNDLITERAL]], i64 16, i1 false) |
| ; CHECK-NEXT: call spir_func void @variadic_sink(i32 noundef 3, ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %.compoundliteral = alloca %struct.agg, align 8 |
| %a = getelementptr inbounds nuw %struct.agg, ptr %.compoundliteral, i32 0, i32 0 |
| store i32 1, ptr %a, align 8 |
| %0 = getelementptr i8, ptr %.compoundliteral, i64 4 |
| call void @llvm.memset.p0.i64(ptr align 4 %0, i8 0, i64 4, i1 false) |
| %b = getelementptr inbounds nuw %struct.agg, ptr %.compoundliteral, i32 0, i32 1 |
| store double 2.000000e+00, ptr %b, align 8 |
| call spir_func void (i32, ...) @variadic_sink(i32 noundef 3, ptr noundef byval(%struct.agg) align 8 %.compoundliteral) |
| ret void |
| } |
| |
| define spir_func void @call_vector() { |
| ; CHECK-LABEL: define spir_func void @call_vector() { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VARARG_BUFFER:%.*]] = alloca [[CALL_VECTOR_VARARG:%.*]], align 16 |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[CALL_VECTOR_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0 |
| ; CHECK-NEXT: store <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00>, ptr [[TMP0]], align 16 |
| ; CHECK-NEXT: call spir_func void @variadic_sink(i32 noundef 4, ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[VARARG_BUFFER]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| call spir_func void (i32, ...) @variadic_sink(i32 noundef 4, <4 x float> noundef <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00>) |
| ret void |
| } |