; 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> , 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 ) ret void }