╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ compiler_rt.zig ──────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
46 47 pub const test_safety = switch (builtin.zig_backend) { 48 .stage2_aarch64 => false, 49 else => builtin.is_test, 50 }; 51 52 comptime { 53 // Integer routines 54 _ = @import("compiler_rt/count0bits.zig"); 55 _ = @import("compiler_rt/parity.zig"); 56 _ = @import("compiler_rt/popcount.zig"); 57 _ = @import("compiler_rt/bitreverse.zig"); 58 _ = @import("compiler_rt/bswap.zig"); 59 _ = @import("compiler_rt/cmp.zig"); 60 61 _ = @import("compiler_rt/shift.zig"); 62 symbol(&__negsi2, "__negsi2"); 63 symbol(&__negdi2, "__negdi2"); 64 symbol(&__negti2, "__negti2"); 65 _ = @import("compiler_rt/int.zig"); 66 _ = @import("compiler_rt/mulXi3.zig"); 67 _ = @import("compiler_rt/udivmod.zig"); 68 69 _ = @import("compiler_rt/absv.zig"); 70 _ = @import("compiler_rt/absvsi2.zig"); 71 _ = @import("compiler_rt/absvdi2.zig"); 72 _ = @import("compiler_rt/absvti2.zig"); 73 _ = @import("compiler_rt/negv.zig"); 74 75 _ = @import("compiler_rt/addvsi3.zig"); 76 _ = @import("compiler_rt/addvdi3.zig"); 77 78 _ = @import("compiler_rt/subvsi3.zig"); 79 _ = @import("compiler_rt/subvdi3.zig"); 80 81 _ = @import("compiler_rt/mulvsi3.zig"); 82 83 _ = @import("compiler_rt/mulo.zig"); 84 85 // Float routines 86 // conversion 87 _ = @import("compiler_rt/extendf.zig"); 88 _ = @import("compiler_rt/truncf.zig"); 89 _ = @import("compiler_rt/int_from_float.zig"); 90 _ = @import("compiler_rt/float_from_int.zig"); 91 92 // comparison 93 _ = @import("compiler_rt/comparef.zig"); 94 95 // arithmetic 96 _ = @import("compiler_rt/addf3.zig"); 97 _ = @import("compiler_rt/mulf3.zig"); 98 99 _ = @import("compiler_rt/divsf3.zig"); 100 _ = @import("compiler_rt/divdf3.zig"); 101 _ = @import("compiler_rt/divxf3.zig"); 102 _ = @import("compiler_rt/divtf3.zig"); 103 104 symbol(&__neghf2, "__neghf2"); 105 if (want_aeabi) { 106 symbol(&__aeabi_fneg, "__aeabi_fneg"); 107 symbol(&__aeabi_dneg, "__aeabi_dneg"); 108 } else { 109 symbol(&__negsf2, "__negsf2"); 110 symbol(&__negdf2, "__negdf2"); 111 } 112 if (want_ppc_abi) { 113 symbol(&__negtf2, "__negkf2"); 114 } else { 115 symbol(&__negtf2, "__negtf2"); 116 } 117 symbol(&__negxf2, "__negxf2"); 118 119 // other 120 _ = @import("compiler_rt/powiXf2.zig"); 121 _ = @import("compiler_rt/mulc3.zig"); 122 _ = @import("compiler_rt/divc3.zig"); 123 124 // Math routines. Alphabetically sorted. 125 _ = @import("compiler_rt/cos.zig"); 126 _ = @import("compiler_rt/exp.zig"); 127 _ = @import("compiler_rt/exp2.zig"); 128 _ = @import("compiler_rt/fabs.zig"); 129 _ = @import("compiler_rt/floor_ceil.zig"); 130 _ = @import("compiler_rt/fma.zig"); 131 _ = @import("compiler_rt/fmax.zig"); 132 _ = @import("compiler_rt/fmin.zig"); 133 _ = @import("compiler_rt/fmod.zig"); 134 _ = @import("compiler_rt/log.zig"); 135 _ = @import("compiler_rt/log10.zig"); 136 _ = @import("compiler_rt/log2.zig"); 137 _ = @import("compiler_rt/round.zig"); 138 _ = @import("compiler_rt/sin.zig"); 139 _ = @import("compiler_rt/sincos.zig"); 140 _ = @import("compiler_rt/sqrt.zig"); 141 _ = @import("compiler_rt/tan.zig"); 142 _ = @import("compiler_rt/trunc.zig"); 143 144 // BigInt. Alphabetically sorted. 145 _ = @import("compiler_rt/divmodei4.zig"); 146 _ = @import("compiler_rt/udivmodei4.zig"); 147 148 if (builtin.cpu.arch.isWasm()) _ = @import("compiler_rt/limb64.zig"); 149 150 // extra 151 _ = @import("compiler_rt/os_version_check.zig"); 152 _ = @import("compiler_rt/emutls.zig"); 153 _ = @import("compiler_rt/arm.zig"); 154 _ = @import("compiler_rt/aulldiv.zig"); 155 _ = @import("compiler_rt/aullrem.zig"); 156 _ = @import("compiler_rt/clear_cache.zig"); 157 _ = @import("compiler_rt/hexagon.zig"); 158 159 if (builtin.object_format != .c) { 160 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/atomics.zig"); 161 _ = @import("compiler_rt/stack_probe.zig"); 162 163 // macOS has these functions inside libSystem. 164 if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) { 165 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/aarch64_outline_atomics.zig"); 166 } 167 168 _ = @import("compiler_rt/memcpy.zig"); 169 if (!ofmt_c) { 170 symbol(&memset, "memset"); 171 } 172 _ = @import("compiler_rt/memmove.zig"); 173 symbol(&memcmp, "memcmp"); 174 symbol(&bcmp, "bcmp"); 175 _ = @import("compiler_rt/ssp.zig"); 176 symbol(&strlen, "strlen"); 177 } 178 179 // Temporarily used for uefi until https://github.com/ziglang/zig/issues/21630 is addressed. 180 if (!builtin.link_libc and (builtin.os.tag == .windows or builtin.os.tag == .uefi) and (builtin.abi == .none or builtin.abi == .msvc)) { 181 symbol(&_fltused, "_fltused"); 182 } 183 } 184 185 var _fltused: c_int = 1; 186 187 fn strlen(s: [*:0]const c_char) callconv(.c) usize { 188 return std.mem.len(s); 189 } 190 191 fn memcmp(vl: [*]const u8, vr: [*]const u8, n: usize) callconv(.c) c_int { 192 var i: usize = 0; 193 while (i < n) : (i += 1) { 194 const compared = @as(c_int, vl[i]) -% @as(c_int, vr[i]); 195 if (compared != 0) return compared; 196 } 197 return 0; 198 } 199 200 test "memcmp" { 201 const arr0 = &[_]u8{ 1, 1, 1 }; 202 const arr1 = &[_]u8{ 1, 1, 1 }; 203 const arr2 = &[_]u8{ 1, 0, 1 }; 204 const arr3 = &[_]u8{ 1, 2, 1 }; 205 const arr4 = &[_]u8{ 1, 0xff, 1 }; 206 207 try std.testing.expect(memcmp(arr0, arr1, 3) == 0); 208 try std.testing.expect(memcmp(arr0, arr2, 3) > 0); 209 try std.testing.expect(memcmp(arr0, arr3, 3) < 0); 210 211 try std.testing.expect(memcmp(arr0, arr4, 3) < 0); 212 try std.testing.expect(memcmp(arr4, arr0, 3) > 0); 213 } 214 215 pub const PreferredLoadStoreElement = element: { 216 if (std.simd.suggestVectorLength(u8)) |vec_size| { 217 const Vec = @Vector(vec_size, u8); 218 219 if (@sizeOf(Vec) == vec_size and std.math.isPowerOfTwo(vec_size)) { 220 break :element Vec; 221 } 222 } 223 break :element usize; 224 }; 225 226 pub const want_aeabi = switch (builtin.abi) { 227 .eabi, 228 .eabihf, 229 .musleabi, 230 .musleabihf, 231 .gnueabi, 232 .gnueabihf, 233 .android, 234 .androideabi, 235 => builtin.cpu.arch.isArm(), 236 else => false, 237 }; 238 239 /// These functions are required on Windows on ARM. They are provided by MSVC libc, but in libc-less 240 /// builds or when linking MinGW libc they are our responsibility. 241 /// Temporarily used for thumb-uefi until https://github.com/ziglang/zig/issues/21630 is addressed. 242 pub const want_windows_arm_abi = e: { 243 if (!builtin.cpu.arch.isArm()) break :e false; 244 switch (builtin.os.tag) { 245 .windows, .uefi => {}, 246 else => break :e false, 247 } 248 // The ABI is needed, but it's only our reponsibility if libc won't provide it. 249 break :e builtin.abi.isGnu() or !builtin.link_libc; 250 }; 251 252 /// These functions are required by on Windows on x86 on some ABIs. They are provided by MSVC libc, 253 /// but in libc-less builds they are our responsibility. 254 pub const want_windows_x86_msvc_abi = e: { 255 if (builtin.cpu.arch != .x86) break :e false; 256 if (builtin.os.tag != .windows) break :e false; 257 switch (builtin.abi) { 258 .none, .msvc, .itanium => {}, 259 else => break :e false, 260 } 261 // The ABI is needed, but it's only our responsibility if libc won't provide it. 262 break :e !builtin.link_libc; 263 }; 264 265 pub const want_ppc_abi = builtin.cpu.arch.isPowerPC(); 266 267 pub const want_float_exceptions = !builtin.cpu.arch.isWasm(); 268 269 /// This governs whether to use these symbol names for f16/f32 conversions 270 /// rather than the standard names: 271 /// * __gnu_f2h_ieee 272 /// * __gnu_h2f_ieee 273 /// Known correct configurations: 274 /// x86_64-freestanding-none => true 275 /// x86_64-linux-none => true 276 /// x86_64-linux-gnu => true 277 /// x86_64-linux-musl => true 278 /// x86_64-linux-eabi => true 279 /// arm-linux-musleabihf => true 280 /// arm-linux-gnueabihf => true 281 /// arm-linux-eabihf => false 282 /// wasm32-wasi-musl => false 283 /// wasm32-freestanding-none => false 284 /// x86_64-windows-gnu => true 285 /// x86_64-windows-msvc => true 286 /// any-macos-any => false 287 pub const gnu_f16_abi = switch (builtin.cpu.arch) { 288 .wasm32, 289 .wasm64, 290 .riscv64, 291 .riscv64be, 292 .riscv32, 293 .riscv32be, 294 => false, 295 296 .x86, .x86_64 => true, 297 298 .arm, .armeb, .thumb, .thumbeb => switch (builtin.abi) { 299 .eabi, .eabihf => false, 300 else => true, 301 }, 302 303 else => !builtin.os.tag.isDarwin(), 304 }; 305 306 pub const want_sparc64_abi = builtin.cpu.arch == .sparc64; 307 pub const want_sparc32_abi = builtin.cpu.arch == .sparc; 308 309 /// For operations converting between `f16` and another floating point type. 310 pub fn f16Conv(comptime OtherType: type) type { 311 switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 16)) { 312 .hard => {}, 313 .soft => return softFloatAbi(f16), 314 } 315 if (builtin.cpu.arch.isX86() and builtin.os.tag.isDarwin()) switch (OtherType) { 316 else => unreachable, 317 // Starting with LLVM 16, Darwin uses different abi for f16 318 // depending on the type of the other return/argument..??? 319 f32, f64 => return softFloatAbi(f16), 320 f80, f128 => {}, 321 }; 322 return hardFloatAbi(f16); 323 } 324 pub const @"f16" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 16)) { 325 .hard => hardFloatAbi(f16), 326 .soft => softFloatAbi(f16), 327 }; 328 pub const @"f32" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 32)) { 329 .hard => hardFloatAbi(f32), 330 .soft => softFloatAbi(f32), 331 }; 332 pub const @"f64" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 64)) { 333 .hard => hardFloatAbi(f64), 334 .soft => softFloatAbi(f64), 335 }; 336 pub const @"f80" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 80)) { 337 .hard => hardFloatAbi(f80), 338 .soft => struct { 339 pub const Abi = extern struct { mantissa: u64, exponent: u16 }; 340 const Repr = packed struct { mantissa: u64, exponent: u16 }; 341 pub inline fn toAbi(raw: f80) Abi { 342 const repr: Repr = @bitCast(raw); 343 return .{ .mantissa = repr.mantissa, .exponent = repr.exponent }; 344 } 345 pub inline fn fromAbi(abi: Abi) f80 { 346 const repr: Repr = .{ .mantissa = abi.mantissa, .exponent = abi.exponent }; 347 return @bitCast(repr); 348 } 349 pub const complex = complexAbi(f80, @This()); 350 }, 351 }; 352 pub const @"f128" = switch (std.zig.target.compilerRtFloatAbi(&builtin.target, 128)) { 353 .hard => hardFloatAbi(f128), 354 .soft => struct { 355 pub const Abi = switch (builtin.cpu.arch.endian()) { 356 .big => extern struct { hi: u64, lo: u64 }, 357 .little => extern struct { lo: u64, hi: u64 }, 358 }; 359 const Repr = packed struct { lo: u64, hi: u64 }; 360 pub inline fn toAbi(raw: f128) Abi { 361 const repr: Repr = @bitCast(raw); 362 return .{ .lo = repr.lo, .hi = repr.hi }; 363 } 364 pub inline fn fromAbi(abi: Abi) f128 { 365 const repr: Repr = .{ .lo = abi.lo, .hi = abi.hi }; 366 return @bitCast(repr); 367 } 368 pub const complex = complexAbi(f128, @This()); 369 }, 370 }; 371 fn hardFloatAbi(comptime Float: type) type { 372 return struct { 373 pub const Abi = Float; 374 pub inline fn toAbi(raw: Float) Abi { 375 return raw; 376 } 377 pub inline fn fromAbi(abi: Abi) Float { 378 return abi; 379 } 380 pub const complex = complexAbi(Float, @This()); 381 }; 382 } 383 fn softFloatAbi(comptime Float: type) type { 384 return struct { 385 pub const Abi = @Int(.unsigned, @bitSizeOf(Float)); 386 pub inline fn toAbi(raw: Float) Abi { 387 return @bitCast(raw); 388 } 389 pub inline fn fromAbi(abi: Abi) Float { 390 return @bitCast(abi); 391 } 392 pub const complex = complexAbi(Float, @This()); 393 }; 394 } 395 fn complexAbi(comptime Float: type, comptime float: type) type { 396 return struct { 397 pub const Abi = extern struct { real: float.Abi, imag: float.Abi }; 398 pub inline fn toAbi(raw: Complex(Float)) Abi { 399 return .{ .real = float.toAbi(raw.real), .imag = float.toAbi(raw.imag) }; 400 } 401 pub inline fn fromAbi(abi: Abi) Complex(Float) { 402 return .{ .real = float.fromAbi(abi.real), .imag = float.fromAbi(abi.imag) }; 403 } 404 }; 405 } 406 407 pub fn Complex(comptime Float: type) type { 408 return struct { real: Float, imag: Float }; 409 } 410 411 pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { 412 switch (Z) { 413 u16 => { 414 // 16x16 --> 32 bit multiply 415 const product = @as(u32, a) * @as(u32, b); 416 hi.* = @intCast(product >> 16); 417 lo.* = @truncate(product); 418 }, 419 u32 => { 420 // 32x32 --> 64 bit multiply 421 const product = @as(u64, a) * @as(u64, b); 422 hi.* = @truncate(product >> 32); 423 lo.* = @truncate(product); 424 }, 425 u64 => { 426 const S = struct { 427 fn loWord(x: u64) u64 { 428 return @as(u32, @truncate(x)); 429 } 430 fn hiWord(x: u64) u64 { 431 return @as(u32, @truncate(x >> 32)); 432 } 433 }; 434 // 64x64 -> 128 wide multiply for platforms that don't have such an operation; 435 // many 64-bit platforms have this operation, but they tend to have hardware 436 // floating-point, so we don't bother with a special case for them here. 437 // Each of the component 32x32 -> 64 products 438 const plolo: u64 = S.loWord(a) * S.loWord(b); 439 const plohi: u64 = S.loWord(a) * S.hiWord(b); 440 const philo: u64 = S.hiWord(a) * S.loWord(b); 441 const phihi: u64 = S.hiWord(a) * S.hiWord(b); 442 // Sum terms that contribute to lo in a way that allows us to get the carry 443 const r0: u64 = S.loWord(plolo); 444 const r1: u64 = S.hiWord(plolo) +% S.loWord(plohi) +% S.loWord(philo); 445 lo.* = r0 +% (r1 << 32); 446 // Sum terms contributing to hi with the carry from lo 447 hi.* = S.hiWord(plohi) +% S.hiWord(philo) +% S.hiWord(r1) +% phihi; 448 }, 449 u128 => { 450 const Word_LoMask: u64 = 0x00000000ffffffff; 451 const Word_HiMask: u64 = 0xffffffff00000000; 452 const Word_FullMask: u64 = 0xffffffffffffffff; 453 const S = struct { 454 fn Word_1(x: u128) u64 { 455 return @as(u32, @truncate(x >> 96)); 456 } 457 fn Word_2(x: u128) u64 { 458 return @as(u32, @truncate(x >> 64)); 459 } 460 fn Word_3(x: u128) u64 { 461 return @as(u32, @truncate(x >> 32)); 462 } 463 fn Word_4(x: u128) u64 { 464 return @as(u32, @truncate(x)); 465 } 466 }; 467 // 128x128 -> 256 wide multiply for platforms that don't have such an operation; 468 // many 64-bit platforms have this operation, but they tend to have hardware 469 // floating-point, so we don't bother with a special case for them here. 470 471 const product11: u64 = S.Word_1(a) * S.Word_1(b); 472 const product12: u64 = S.Word_1(a) * S.Word_2(b); 473 const product13: u64 = S.Word_1(a) * S.Word_3(b); 474 const product14: u64 = S.Word_1(a) * S.Word_4(b); 475 const product21: u64 = S.Word_2(a) * S.Word_1(b); 476 const product22: u64 = S.Word_2(a) * S.Word_2(b); 477 const product23: u64 = S.Word_2(a) * S.Word_3(b); 478 const product24: u64 = S.Word_2(a) * S.Word_4(b); 479 const product31: u64 = S.Word_3(a) * S.Word_1(b); 480 const product32: u64 = S.Word_3(a) * S.Word_2(b); 481 const product33: u64 = S.Word_3(a) * S.Word_3(b); 482 const product34: u64 = S.Word_3(a) * S.Word_4(b); 483 const product41: u64 = S.Word_4(a) * S.Word_1(b); 484 const product42: u64 = S.Word_4(a) * S.Word_2(b); 485 const product43: u64 = S.Word_4(a) * S.Word_3(b); 486 const product44: u64 = S.Word_4(a) * S.Word_4(b); 487 488 const sum0: u128 = @as(u128, product44); 489 const sum1: u128 = @as(u128, product34) +% 490 @as(u128, product43); 491 const sum2: u128 = @as(u128, product24) +% 492 @as(u128, product33) +% 493 @as(u128, product42); 494 const sum3: u128 = @as(u128, product14) +% 495 @as(u128, product23) +% 496 @as(u128, product32) +% 497 @as(u128, product41); 498 const sum4: u128 = @as(u128, product13) +% 499 @as(u128, product22) +% 500 @as(u128, product31); 501 const sum5: u128 = @as(u128, product12) +% 502 @as(u128, product21); 503 const sum6: u128 = @as(u128, product11); 504 505 const r0: u128 = (sum0 & Word_FullMask) +% 506 ((sum1 & Word_LoMask) << 32); 507 const r1: u128 = (sum0 >> 64) +% 508 ((sum1 >> 32) & Word_FullMask) +% 509 (sum2 & Word_FullMask) +% 510 ((sum3 << 32) & Word_HiMask); 511 512 lo.* = r0 +% (r1 << 64); 513 hi.* = (r1 >> 64) +% 514 (sum1 >> 96) +% 515 (sum2 >> 64) +% 516 (sum3 >> 32) +% 517 sum4 +% 518 (sum5 << 32) +% 519 (sum6 << 64); 520 }, 521 else => @compileError("unsupported"), 522 } 523 } 524 525 pub fn normalize(comptime T: type, significand: *@Int(.unsigned, @typeInfo(T).float.bits)) i32 { 526 const Z = @Int(.unsigned, @typeInfo(T).float.bits); 527 const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T); 528 529 const shift = @clz(significand.*) - @clz(integerBit); 530 significand.* <<= @as(std.math.Log2Int(Z), @intCast(shift)); 531 return @as(i32, 1) - shift; 532 } 533 534 pub inline fn fneg(a: anytype) @TypeOf(a) { 535 const F = @TypeOf(a); 536 const bits = @typeInfo(F).float.bits; 537 const U = @Int(.unsigned, bits); 538 const sign_bit_mask = @as(U, 1) << (bits - 1); 539 const negated = @as(U, @bitCast(a)) ^ sign_bit_mask; 540 return @bitCast(negated); 541 } 542 543 fn __neghf2(a: compiler_rt.f16.Abi) callconv(.c) compiler_rt.f16.Abi { 544 return compiler_rt.f16.toAbi(fneg(compiler_rt.f16.fromAbi(a))); 545 } 546 547 fn __negsf2(a: compiler_rt.f32.Abi) callconv(.c) compiler_rt.f32.Abi { 548 return compiler_rt.f32.toAbi(fneg(compiler_rt.f32.fromAbi(a))); 549 } 550 551 fn __negdf2(a: compiler_rt.f64.Abi) callconv(.c) compiler_rt.f64.Abi { 552 return compiler_rt.f64.toAbi(fneg(compiler_rt.f64.fromAbi(a))); 553 } 554 555 fn __negxf2(a: compiler_rt.f80.Abi) callconv(.c) compiler_rt.f80.Abi { 556 return compiler_rt.f80.toAbi(fneg(compiler_rt.f80.fromAbi(a))); 557 } 558 559 fn __negtf2(a: compiler_rt.f128.Abi) callconv(.c) compiler_rt.f128.Abi { 560 return compiler_rt.f128.toAbi(fneg(compiler_rt.f128.fromAbi(a))); 561 } 562 563 fn __aeabi_fneg(a: f32) callconv(.{ .arm_aapcs = .{} }) f32 { 564 return fneg(a); 565 } 566 567 fn __aeabi_dneg(a: f64) callconv(.{ .arm_aapcs = .{} }) f64 { 568 return fneg(a); 569 } 570 571 /// Allows to access underlying bits as two equally sized lower and higher 572 /// signed or unsigned integers. 573 pub fn HalveInt(comptime T: type, comptime signed_half: bool) type { 574 return extern union { 575 pub const bits = @divExact(@typeInfo(T).int.bits, 2); 576 pub const HalfTU = @Int(.unsigned, bits); 577 pub const HalfTS = @Int(.signed, bits); 578 pub const HalfT = if (signed_half) HalfTS else HalfTU; 579 580 all: T, 581 s: if (native_endian == .little) 582 extern struct { low: HalfT, high: HalfT } 583 else 584 extern struct { high: HalfT, low: HalfT }, 585 }; 586 } 587 588 pub fn __negsi2(a: i32) callconv(.c) i32 { 589 return negXi2(i32, a); 590 } 591 592 pub fn __negdi2(a: i64) callconv(.c) i64 { 593 return negXi2(i64, a); 594 } 595 596 pub fn __negti2(a: i128) callconv(.c) i128 { 597 return negXi2(i128, a); 598 } 599 600 inline fn negXi2(comptime T: type, a: T) T { 601 return -a; 602 } 603 604 fn memsetSmallPowerOf2(d: [*]u8, b: u8, comptime size: usize) void { 605 @disableIntrinsics(); 606 607 if (size > @sizeOf(usize)) { 608 d[0..size].* = @splat(b); 609 } else { 610 const T = @Int(.unsigned, 8 * size); 611 var splatted: T = 0; // Setting this to undefined causes a memset call and thus infinite recursion in Debug test-compiler-rt. 612 @as(*[size]u8, @ptrCast(&splatted)).* = @splat(b); 613 @as(*align(1) T, @ptrCast(d)).* = splatted; 614 } 615 } 616 617 fn shortMemset( 618 log_min: comptime_int, 619 log_max: comptime_int, 620 d: [*]u8, 621 b: u8, 622 len: usize, 623 ) void { 624 @disableIntrinsics(); 625 626 if (log_min + 1 != log_max) { 627 const mid = (log_min + log_max) / 2; 628 if (len > 1 << mid) { 629 shortMemset(mid, log_max, d, b, len); 630 } else { 631 shortMemset(log_min, mid, d, b, len); 632 } 633 } else { 634 const size = 1 << log_min; 635 636 memsetSmallPowerOf2(d, b, size); 637 memsetSmallPowerOf2(d + len - size, b, size); 638 } 639 } 640 641 fn fastMemset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 { 642 @disableIntrinsics(); 643 644 const b: u8 = @truncate(@as(c_uint, @bitCast(c))); 645 const n = std.simd.suggestVectorLength(u8) orelse @sizeOf(usize); 646 647 const d = dest.?; 648 649 if (len > 2 * n) { 650 memsetSmallPowerOf2(d, b, n); 651 652 const begin_aligned = std.mem.alignBackward(usize, @intFromPtr(d) + n, n); 653 const end_aligned = std.mem.alignForward(usize, @intFromPtr(d) + len - n, n); 654 655 const aligned_ptr: [*]align(n) u8 = @ptrFromInt(begin_aligned); 656 657 var i: usize = 0; 658 while (true) { 659 memsetSmallPowerOf2(aligned_ptr + n * i, b, n); 660 661 i += 1; 662 if (i == @divExact(end_aligned - begin_aligned, n)) 663 break; 664 } 665 666 memsetSmallPowerOf2(d + len - n, b, n); 667 } else { 668 if (len == 0) return dest; 669 670 shortMemset(0, @ctz(@as(usize, 2 * n)), d, b, len); 671 } 672 673 return dest; 674 } 675 676 fn smallMemset(dest: ?[*]u8, c: c_int, len: usize) callconv(.c) ?[*]u8 { 677 @disableIntrinsics(); 678 679 const b: u8 = @truncate(@as(c_uint, @bitCast(c))); 680 681 if (len != 0) { 682 var d = dest.?; 683 var n = len; 684 while (true) { 685 d[0] = b; 686 n -= 1; 687 if (n == 0) break; 688 d += 1; 689 } 690 } 691 692 return dest; 693 } 694 695 pub const memset = if (builtin.optimize == .small) 696 smallMemset 697 else 698 fastMemset; 699 700 pub fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.c) c_int { 701 @setRuntimeSafety(false); 702 703 var index: usize = 0; 704 while (index != n) : (index += 1) { 705 if (vl[index] != vr[index]) { 706 return 1; 707 } 708 } 709 710 return 0; 711 } 712 713 test "bcmp" { 714 const base_arr = &[_]u8{ 1, 1, 1 }; 715 const arr1 = &[_]u8{ 1, 1, 1 }; 716 const arr2 = &[_]u8{ 1, 0, 1 }; 717 const arr3 = &[_]u8{ 1, 2, 1 }; 718 719 try std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0); 720 try std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0); 721 try std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0); 722 } 723 724 test { 725 _ = @import("compiler_rt/negsi2_test.zig"); 726 _ = @import("compiler_rt/negdi2_test.zig"); 727 _ = @import("compiler_rt/negti2_test.zig"); 728 } 729