diff --git a/CMakeLists.txt b/CMakeLists.txt index 244e48a7bd..f39a05109c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -625,6 +625,7 @@ set(ZIG_STD_FILES "special/compiler_rt/floatuntitf.zig" "special/compiler_rt/index.zig" "special/compiler_rt/muloti4.zig" + "special/compiler_rt/multi3.zig" "special/compiler_rt/truncXfYf2.zig" "special/compiler_rt/udivmod.zig" "special/compiler_rt/udivmoddi4.zig" diff --git a/src/analyze.cpp b/src/analyze.cpp index 42737a22e5..46a8aa7ee8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1084,6 +1084,8 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { } zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481", buf_ptr(&fn_type_id->return_type->name)); + } else if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb) { + return type_size(g, fn_type_id->return_type) > 16; } zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481"); } diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 54a461d0f1..c826af83bc 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -80,6 +80,7 @@ comptime { @export("___chkstk_ms", ___chkstk_ms, linkage); } @export("__divti3", @import("divti3.zig").__divti3_windows_x86_64, linkage); + @export("__multi3", @import("multi3.zig").__multi3_windows_x86_64, linkage); @export("__muloti4", @import("muloti4.zig").__muloti4_windows_x86_64, linkage); @export("__udivti3", @import("udivti3.zig").__udivti3_windows_x86_64, linkage); @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4_windows_x86_64, linkage); @@ -89,6 +90,7 @@ comptime { } } else { @export("__divti3", @import("divti3.zig").__divti3, linkage); + @export("__multi3", @import("multi3.zig").__multi3, linkage); @export("__muloti4", @import("muloti4.zig").__muloti4, linkage); @export("__udivti3", @import("udivti3.zig").__udivti3, linkage); @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage); @@ -149,6 +151,7 @@ extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) AeabiUlDivModResult fn isArmArch() bool { return switch (builtin.arch) { + builtin.Arch.armv8_3a, builtin.Arch.armv8_2a, builtin.Arch.armv8_1a, builtin.Arch.armv8, @@ -160,6 +163,7 @@ fn isArmArch() bool { builtin.Arch.armv7m, builtin.Arch.armv7s, builtin.Arch.armv7k, + builtin.Arch.armv7ve, builtin.Arch.armv6, builtin.Arch.armv6m, builtin.Arch.armv6k, @@ -167,6 +171,7 @@ fn isArmArch() bool { builtin.Arch.armv5, builtin.Arch.armv5te, builtin.Arch.armv4t, + builtin.Arch.armebv8_3a, builtin.Arch.armebv8_2a, builtin.Arch.armebv8_1a, builtin.Arch.armebv8, @@ -178,6 +183,7 @@ fn isArmArch() bool { builtin.Arch.armebv7m, builtin.Arch.armebv7s, builtin.Arch.armebv7k, + builtin.Arch.armebv7ve, builtin.Arch.armebv6, builtin.Arch.armebv6m, builtin.Arch.armebv6k, @@ -185,6 +191,22 @@ fn isArmArch() bool { builtin.Arch.armebv5, builtin.Arch.armebv5te, builtin.Arch.armebv4t, + builtin.Arch.aarch64v8_3a, + builtin.Arch.aarch64v8_2a, + builtin.Arch.aarch64v8_1a, + builtin.Arch.aarch64v8, + builtin.Arch.aarch64v8r, + builtin.Arch.aarch64v8m_baseline, + builtin.Arch.aarch64v8m_mainline, + builtin.Arch.aarch64_bev8_3a, + builtin.Arch.aarch64_bev8_2a, + builtin.Arch.aarch64_bev8_1a, + builtin.Arch.aarch64_bev8, + builtin.Arch.aarch64_bev8r, + builtin.Arch.aarch64_bev8m_baseline, + builtin.Arch.aarch64_bev8m_mainline, + builtin.Arch.thumb, + builtin.Arch.thumbeb, => true, else => false, }; diff --git a/std/special/compiler_rt/multi3.zig b/std/special/compiler_rt/multi3.zig new file mode 100644 index 0000000000..e9ddb82503 --- /dev/null +++ b/std/special/compiler_rt/multi3.zig @@ -0,0 +1,56 @@ +const builtin = @import("builtin"); +const compiler_rt = @import("index.zig"); + +// Ported from git@github.com:llvm-project/llvm-project-20170507.git +// ae684fad6d34858c014c94da69c15e7774a633c3 +// 2018-08-13 + +pub extern fn __multi3(a: i128, b: i128) i128 { + @setRuntimeSafety(builtin.is_test); + const x = twords{.all = a}; + const y = twords{.all = b}; + var r = twords{.all = __mulddi3(x.s.low, y.s.low)}; + r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high; + return r.all; +} + +pub extern fn __multi3_windows_x86_64(a: *const i128, b: *const i128) void { + @setRuntimeSafety(builtin.is_test); + compiler_rt.setXmm0(i128, __multi3(a.*, b.*)); +} + +fn __mulddi3(a: u64, b: u64) i128 { + const bits_in_dword_2 = (@sizeOf(i64) * 8) / 2; + const lower_mask = ~u64(0) >> bits_in_dword_2; + var r: twords = undefined; + r.s.low = (a & lower_mask) *% (b & lower_mask); + var t: u64 = r.s.low >> bits_in_dword_2; + r.s.low &= lower_mask; + t +%= (a >> bits_in_dword_2) *% (b & lower_mask); + r.s.low +%= (t & lower_mask) << bits_in_dword_2; + r.s.high = t >> bits_in_dword_2; + t = r.s.low >> bits_in_dword_2; + r.s.low &= lower_mask; + t +%= (b >> bits_in_dword_2) *% (a & lower_mask); + r.s.low +%= (t & lower_mask) << bits_in_dword_2; + r.s.high +%= t >> bits_in_dword_2; + r.s.high +%= (a >> bits_in_dword_2) *% (b >> bits_in_dword_2); + return r.all; +} + +const twords = extern union { + all: i128, + s: S, + + const S = if (builtin.endian == builtin.Endian.Little) struct { + low: u64, + high: u64, + } else struct { + high: u64, + low: u64, + }; +}; + +test "import multi3" { + _ = @import("multi3_test.zig"); +} diff --git a/std/special/compiler_rt/multi3_test.zig b/std/special/compiler_rt/multi3_test.zig new file mode 100644 index 0000000000..8f02765608 --- /dev/null +++ b/std/special/compiler_rt/multi3_test.zig @@ -0,0 +1,54 @@ +const __multi3 = @import("multi3.zig").__multi3; +const assert = @import("std").debug.assert; + +fn test__multi3(a: i128, b: i128, expected: i128) void { + const x = __multi3(a, b); + assert(x == expected); +} + +test "multi3" { + test__multi3(0, 0, 0); + test__multi3(0, 1, 0); + test__multi3(1, 0, 0); + test__multi3(0, 10, 0); + test__multi3(10, 0, 0); + test__multi3(0, 81985529216486895, 0); + test__multi3(81985529216486895, 0, 0); + + test__multi3(0, -1, 0); + test__multi3(-1, 0, 0); + test__multi3(0, -10, 0); + test__multi3(-10, 0, 0); + test__multi3(0, -81985529216486895, 0); + test__multi3(-81985529216486895, 0, 0); + + test__multi3(1, 1, 1); + test__multi3(1, 10, 10); + test__multi3(10, 1, 10); + test__multi3(1, 81985529216486895, 81985529216486895); + test__multi3(81985529216486895, 1, 81985529216486895); + + test__multi3(1, -1, -1); + test__multi3(1, -10, -10); + test__multi3(-10, 1, -10); + test__multi3(1, -81985529216486895, -81985529216486895); + test__multi3(-81985529216486895, 1, -81985529216486895); + + test__multi3(3037000499, 3037000499, 9223372030926249001); + test__multi3(-3037000499, 3037000499, -9223372030926249001); + test__multi3(3037000499, -3037000499, -9223372030926249001); + test__multi3(-3037000499, -3037000499, 9223372030926249001); + + test__multi3(4398046511103, 2097152, 9223372036852678656); + test__multi3(-4398046511103, 2097152, -9223372036852678656); + test__multi3(4398046511103, -2097152, -9223372036852678656); + test__multi3(-4398046511103, -2097152, 9223372036852678656); + + test__multi3(2097152, 4398046511103, 9223372036852678656); + test__multi3(-2097152, 4398046511103, -9223372036852678656); + test__multi3(2097152, -4398046511103, -9223372036852678656); + test__multi3(-2097152, -4398046511103, 9223372036852678656); + + test__multi3(0x00000000000000B504F333F9DE5BE000, 0x000000000000000000B504F333F9DE5B, + 0x7FFFFFFFFFFFF328DF915DA296E8A000); +}