| ; Test passing variable argument lists in 64-bit calls on z/OS. | |
| ; RUN: llc < %s -mtriple=s390x-ibm-zos -mcpu=z10 | FileCheck %s | |
| ; RUN: llc < %s -mtriple=s390x-ibm-zos -mcpu=z14 | FileCheck %s -check-prefix=ARCH12 | |
| ; CHECK-LABEL: call_vararg_double0 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: lg 6,8(5) | |
| ; CHECK-NEXT: lg 5,0(5) | |
| ; CHECK-NEXT: llihf 3,1074118262 | |
| ; CHECK-NEXT: oilf 3,3367254360 | |
| ; CHECK-NEXT: lghi 1,1 | |
| ; CHECK-NEXT: lghi 2,2 | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_double0() { | |
| entry: | |
| %retval = call i64 (i64, i64, ...) @pass_vararg0(i64 1, i64 2, double 2.718000e+00) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_double1 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: llihf 0,1074118262 | |
| ; CHECK-NEXT: oilf 0,3367254360 | |
| ; CHECK-NEXT: lg 6,8(5) | |
| ; CHECK-NEXT: lg 5,0(5) | |
| ; CHECK-NEXT: llihf 3,1074340036 | |
| ; CHECK-NEXT: oilf 3,2611340116 | |
| ; CHECK-NEXT: lghi 1,1 | |
| ; CHECK-NEXT: lghi 2,2 | |
| ; CHECK-NEXT: stg 0,2200(4) | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_double1() { | |
| entry: | |
| %retval = call i64 (i64, i64, ...) @pass_vararg0(i64 1, i64 2, double 3.141000e+00, double 2.718000e+00) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_double2 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: lg 6,24(5) | |
| ; CHECK-NEXT: lg 5,16(5) | |
| ; CHECK-NEXT: llihf 2,1074118262 | |
| ; CHECK-NEXT: oilf 2,3367254360 | |
| ; CHECK-NEXT: lghi 1,8200 | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_double2() { | |
| entry: | |
| %retval = call i64 (i64, ...) @pass_vararg2(i64 8200, double 2.718000e+00) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_double3 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: llihf 0,1072703839 | |
| ; CHECK-NEXT: oilf 0,2861204133 | |
| ; CHECK-NEXT: lg 6,40(5) | |
| ; CHECK-NEXT: lg 5,32(5) | |
| ; CHECK-NEXT: llihf 1,1074118262 | |
| ; CHECK-NEXT: oilf 1,3367254360 | |
| ; CHECK-NEXT: llihf 2,1074340036 | |
| ; CHECK-NEXT: oilf 2,2611340116 | |
| ; CHECK-NEXT: llihf 3,1073127358 | |
| ; CHECK-NEXT: oilf 3,1992864825 | |
| ; CHECK-NEXT: stg 0,2200(4) | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_double3() { | |
| entry: | |
| %retval = call i64 (...) @pass_vararg3(double 2.718000e+00, double 3.141000e+00, double 1.414000e+00, double 1.010101e+00) | |
| ret i64 %retval | |
| } | |
| ;; TODO: The extra COPY after LGDR is unnecessary (machine-scheduler introduces the overlap). | |
| ; CHECK-LABEL: call_vararg_both0 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: lg 6,40(5) | |
| ; CHECK-NEXT: lg 5,32(5) | |
| ; CHECK-NEXT: lgdr 0,0 | |
| ; CHECK-NEXT: lgr 2,1 | |
| ; CHECK-NEXT: lgr 1,0 | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_both0(i64 %arg0, double %arg1) { | |
| %retval = call i64(...) @pass_vararg3(double %arg1, i64 %arg0) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_long_double0 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: larl 1,L#CPI5_0 | |
| ; CHECK-NEXT: ld 0,0(1) | |
| ; CHECK-NEXT: ld 2,8(1) | |
| ; CHECK-NEXT: lg 6,8(5) | |
| ; CHECK-NEXT: lg 5,0(5) | |
| ; CHECK-NEXT: lgdr 3,0 | |
| ; CHECK-NEXT: lghi 1,1 | |
| ; CHECK-NEXT: lghi 2,2 | |
| ; CHECK-NEXT: std 0,2192(4) | |
| ; CHECK-NEXT: std 2,2200(4) | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_long_double0() { | |
| entry: | |
| %retval = call i64 (i64, i64, ...) @pass_vararg0(i64 1, i64 2, fp128 0xLE0FC1518450562CD4000921FB5444261) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_long_double1 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: lg 6,8(5) | |
| ; CHECK-NEXT: lg 5,0(5) | |
| ; CHECK-NEXT: lgdr 3,0 | |
| ; CHECK-NEXT: lghi 1,1 | |
| ; CHECK-NEXT: lghi 2,2 | |
| ; CHECK-NEXT: std 0,2192(4) | |
| ; CHECK-NEXT: std 2,2200(4) | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_long_double1(fp128 %arg0) { | |
| entry: | |
| %retval = call i64 (i64, i64, ...) @pass_vararg0(i64 1, i64 2, fp128 %arg0) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_long_double2 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: std 4,2208(4) | |
| ; CHECK-NEXT: std 6,2216(4) | |
| ; CHECK-NEXT: lg 6,8(5) | |
| ; CHECK-NEXT: lg 5,0(5) | |
| ; CHECK-NEXT: lgdr 3,0 | |
| ; CHECK-NEXT: lghi 1,1 | |
| ; CHECK-NEXT: lghi 2,2 | |
| ; CHECK-NEXT: std 0,2192(4) | |
| ; CHECK-NEXT: std 2,2200(4) | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_long_double2(fp128 %arg0, fp128 %arg1) { | |
| entry: | |
| %retval = call i64 (i64, i64, ...) @pass_vararg0(i64 1, i64 2, fp128 %arg0, fp128 %arg1) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_long_double3 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: lg 6,40(5) | |
| ; CHECK-NEXT: lg 5,32(5) | |
| ; CHECK-NEXT: lgdr 3,2 | |
| ; CHECK-NEXT: lgdr 2,0 | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_long_double3(fp128 %arg0) { | |
| entry: | |
| %retval = call i64 (...) @pass_vararg3(fp128 %arg0) | |
| ret i64 %retval | |
| } | |
| ; ARCH12-LABEL: call_vec_vararg_test0 DS 0H | |
| ; ARCH12: vlgvg 3,24,1 | |
| ; ARCH12: vlgvg 2,24,0 | |
| ; ARCH12: lghi 1,1 | |
| define void @call_vec_vararg_test0(<2 x double> %v) { | |
| %retval = call i64(i64, ...) @pass_vararg2(i64 1, <2 x double> %v) | |
| ret void | |
| } | |
| ; ARCH12-LABEL: call_vec_vararg_test1 DS 0H | |
| ; ARCH12: larl 1,L#CPI10_0 | |
| ; ARCH12: vl 0,0(1),3 | |
| ; ARCH12: vlgvg 3,24,0 | |
| ; ARCH12: vrepg 2,0,1 | |
| ; ARCH12: vst 25,2208(4),3 | |
| ; ARCH12: vst 24,2192(4),3 | |
| define void @call_vec_vararg_test1(<4 x i32> %v, <2 x i64> %w) { | |
| %retval = call i64(fp128, ...) @pass_vararg1(fp128 0xLE0FC1518450562CD4000921FB5444261, <4 x i32> %v, <2 x i64> %w) | |
| ret void | |
| } | |
| ; ARCH12-LABEL: call_vec_char_vararg_straddle DS 0H | |
| ; ARCH12: vlgvg 3,24,0 | |
| ; ARCH12: lghi 1,1 | |
| ; ARCH12: lghi 2,2 | |
| ; ARCH12: vst 24,2192(4),3 | |
| define void @call_vec_char_vararg_straddle(<16 x i8> %v) { | |
| %retval = call i64(i64, i64, ...) @pass_vararg0(i64 1, i64 2, <16 x i8> %v) | |
| ret void | |
| } | |
| ; ARCH12-LABEL: call_vec_short_vararg_straddle DS 0H | |
| ; ARCH12: vlgvg 3,24,0 | |
| ; ARCH12: lghi 1,1 | |
| ; ARCH12: lghi 2,2 | |
| ; ARCH12: vst 24,2192(4),3 | |
| define void @call_vec_short_vararg_straddle(<8 x i16> %v) { | |
| %retval = call i64(i64, i64, ...) @pass_vararg0(i64 1, i64 2, <8 x i16> %v) | |
| ret void | |
| } | |
| ; ARCH12-LABEL: call_vec_int_vararg_straddle DS 0H | |
| ; ARCH12: vlgvg 3,24,0 | |
| ; ARCH12: lghi 1,1 | |
| ; ARCH12: lghi 2,2 | |
| ; ARCH12: vst 24,2192(4),3 | |
| define void @call_vec_int_vararg_straddle(<4 x i32> %v) { | |
| %retval = call i64(i64, i64, ...) @pass_vararg0(i64 1, i64 2, <4 x i32> %v) | |
| ret void | |
| } | |
| ; ARCH12-LABEL: call_vec_double_vararg_straddle DS 0H | |
| ; ARCH12: vlgvg 3,24,0 | |
| ; ARCH12: lghi 1,1 | |
| ; ARCH12: lghi 2,2 | |
| ; ARCH12: vst 24,2192(4),3 | |
| define void @call_vec_double_vararg_straddle(<2 x double> %v) { | |
| %retval = call i64(i64, i64, ...) @pass_vararg0(i64 1, i64 2, <2 x double> %v) | |
| ret void | |
| } | |
| ; CHECK-LABEL: call_vararg_integral0 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: lgb 0, | |
| ; CHECK-NEXT: lg 6,40(5) | |
| ; CHECK-NEXT: lg 5,32(5) | |
| ; CHECK-NEXT: lghr 2,2 | |
| ; CHECK-NEXT: lgfr 1,1 | |
| ; CHECK-NEXT: stg 0,2200(4) | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_integral0(i32 signext %arg0, i16 signext %arg1, i64 signext %arg2, i8 signext %arg3) { | |
| entry: | |
| %retval = call i64(...) @pass_vararg3(i32 signext %arg0, i16 signext %arg1, i64 signext %arg2, i8 signext %arg3) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_float0 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: lg 6,24(5) | |
| ; CHECK-NEXT: lg 5,16(5) | |
| ; CHECK-NEXT: lghi 1,1 | |
| ; CHECK-NEXT: llihf 2,1073692672 | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_float0() { | |
| entry: | |
| %retval = call i64 (i64, ...) @pass_vararg2(i64 1, float 1.953125) | |
| ret i64 %retval | |
| } | |
| ; CHECK-LABEL: call_vararg_float1 DS 0H | |
| ; CHECK: stmg 6,7,1872(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-192 | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: lg 6,72(5) | |
| ; CHECK-NEXT: lg 5,64(5) | |
| ; CHECK-NEXT: larl 1,L#CPI17_0 | |
| ; CHECK-NEXT: le 0,0(1) | |
| ; CHECK-NEXT: llihf 0,1073692672 | |
| ; CHECK-NEXT: llihh 2,16384 | |
| ; CHECK-NEXT: llihh 3,16392 | |
| ; CHECK-NEXT: stg 0,2200(4) | |
| ; CHECK-NEXT: basr 7,6 | |
| ; CHECK-NEXT: bcr 0,0 | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,192 | |
| ; CHECK-NEXT: b 2(7) | |
| define i64 @call_vararg_float1() { | |
| entry: | |
| %retval = call i64 (float, ...) @pass_vararg4(float 1.0, float 2.0, float 3.0, float 1.953125) | |
| ret i64 %retval | |
| } | |
| ; Derived from C source: | |
| ; #define _VARARG_EXT_ | |
| ; #include <stdarg.h> | |
| ; | |
| ; long pass(long x, ...) { | |
| ; va_list va; | |
| ; va_start(va, x); | |
| ; long ret = va_arg(va, long); | |
| ; va_end(va); | |
| ; return ret; | |
| ; } | |
| ; | |
| ; CHECK-LABEL: pass_vararg DS 0H | |
| ; CHECK: stmg 6,7,1904(4) | |
| ; CHECK-NEXT: L#stack_update{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: aghi 4,-160 | |
| ; CHECK-NEXT: stg 2,2344(4) | |
| ; CHECK-NEXT: stg 3,2352(4) | |
| ; CHECK-NEXT: *FENCE | |
| ; CHECK-NEXT: L#end_of_prologue{{[0-9]+}} DS 0H | |
| ; CHECK-NEXT: la 0,2352(4) | |
| ; CHECK-NEXT: stg 0,2200(4) | |
| ; CHECK-NEXT: lg 3,2344(4) | |
| ; CHECK-NEXT: lg 7,2072(4) | |
| ; CHECK-NEXT: aghi 4,160 | |
| ; CHECK-NEXT: b 2(7) | |
| define hidden i64 @pass_vararg(i64 %x, ...) { | |
| entry: | |
| %va = alloca ptr, align 8 | |
| call void @llvm.va_start(ptr %va) | |
| %argp.cur = load ptr, ptr %va, align 8 | |
| %argp.next = getelementptr inbounds i8, ptr %argp.cur, i64 8 | |
| store ptr %argp.next, ptr %va, align 8 | |
| %ret = load i64, ptr %argp.cur, align 8 | |
| call void @llvm.va_end(ptr %va) | |
| ret i64 %ret | |
| } | |
| declare void @llvm.va_start(ptr) | |
| declare void @llvm.va_end(ptr) | |
| declare i64 @pass_vararg0(i64 %arg0, i64 %arg1, ...) | |
| declare i64 @pass_vararg1(fp128 %arg0, ...) | |
| declare i64 @pass_vararg2(i64 %arg0, ...) | |
| declare i64 @pass_vararg3(...) | |
| declare i64 @pass_vararg4(float, ...) |