╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Air.zig ──────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
2230 idx: u32, 2231 items: []const Inst.Ref, 2232 ranges: []const [2]Inst.Ref, 2233 body: []const Inst.Index, 2234 }; 2235 }; 2236 }; 2237 2238 pub fn unwrapSwitch(air: *const Air, switch_inst: Inst.Index) UnwrappedSwitch { 2239 const inst = air.instructions.get(@backingInt(switch_inst)); 2240 switch (inst.tag) { 2241 .switch_br, .loop_switch_br => {}, 2242 else => unreachable, // assertion failure 2243 } 2244 const pl_op = inst.data.pl_op; 2245 const extra = air.extraData(SwitchBr, pl_op.payload); 2246 const hint_bag_count = @divCeil(extra.data.cases_len + 1, 10); 2247 return .{ 2248 .air = air, 2249 .operand = pl_op.operand, 2250 .cases_len = extra.data.cases_len, 2251 .else_body_len = extra.data.else_body_len, 2252 .branch_hints_start = @intCast(extra.end), 2253 .cases_start = @intCast(extra.end + hint_bag_count), 2254 }; 2255 } 2256 2257 pub const UnwrappedDbgInlineBlock = struct { 2258 func: InternPool.Index, 2259 body: []const Inst.Index, 2260 ty: Type, 2261 }; 2262 2263 pub fn unwrapDbgBlock(air: *const Air, inst_index: Inst.Index) UnwrappedDbgInlineBlock { 2264 const data = air.instructions.items(.data)[@backingInt(inst_index)]; 2265 const tag = air.instructions.items(.tag)[@backingInt(inst_index)]; 2266 assert(tag == .dbg_inline_block); 2267 const payload = data.ty_pl.payload; 2268 const extra = air.extraData(Air.DbgInlineBlock, payload); 2269 return .{ 2270 .func = extra.data.func, 2271 .ty = data.ty_pl.ty, 2272 .body = @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]), 2273 }; 2274 } 2275 2276 pub const UnwrappedBlock = struct { 2277 body: []const Inst.Index, 2278 ty: Type, 2279 }; 2280 2281 pub fn unwrapBlock(air: *const Air, inst_index: Inst.Index) UnwrappedBlock { 2282 const data = air.instructions.items(.data)[@backingInt(inst_index)]; 2283 const tag = air.instructions.items(.tag)[@backingInt(inst_index)]; 2284 const payload = switch (tag) { 2285 .block, .loop => data.ty_pl.payload, 2286 else => unreachable, 2287 }; 2288 const extra = air.extraData(Air.Block, payload); 2289 return .{ 2290 .ty = data.ty_pl.ty, 2291 .body = @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]), 2292 }; 2293 } 2294 2295 pub const UnwrappedCall = struct { 2296 callee: Inst.Ref, 2297 args: []const Air.Inst.Ref, 2298 }; 2299 2300 pub fn unwrapCall(air: *const Air, inst_index: Inst.Index) UnwrappedCall { 2301 const data = air.instructions.items(.data)[@backingInt(inst_index)]; 2302 const tag = air.instructions.items(.tag)[@backingInt(inst_index)]; 2303 const payload = switch (tag) { 2304 .call, .call_always_tail, .call_never_tail, .call_never_inline => data.pl_op.payload, 2305 else => unreachable, 2306 }; 2307 const extra = air.extraData(Air.Call, payload); 2308 return .{ 2309 .callee = data.pl_op.operand, 2310 .args = @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len]), 2311 }; 2312 } 2313 2314 pub const UnwrappedCompilerRtCall = struct { 2315 func: CompilerRtFunc, 2316 args: []const Air.Inst.Ref, 2317 }; 2318 2319 pub fn unwrapCompilerRtCall(air: *const Air, inst_index: Inst.Index) UnwrappedCompilerRtCall { 2320 const data = air.instructions.items(.data)[@backingInt(inst_index)]; 2321 const tag = air.instructions.items(.tag)[@backingInt(inst_index)]; 2322 assert(tag == .legalize_compiler_rt_call); 2323 const payload = data.legalize_compiler_rt_call.payload; 2324 const extra = air.extraData(Air.Call, payload); 2325 return .{ 2326 .func = data.legalize_compiler_rt_call.func, 2327 .args = @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len]), 2328 }; 2329 } 2330 2331 pub const UnwrappedCondBr = struct { 2332 condition: Inst.Ref, 2333 then_body: []const Inst.Index, 2334 else_body: []const Inst.Index, 2335 branch_hints: CondBr.BranchHints, 2336 }; 2337 2338 pub fn unwrapCondBr(air: *const Air, inst_index: Inst.Index) UnwrappedCondBr { 2339 const data = air.instructions.items(.data)[@backingInt(inst_index)]; 2340 const tag = air.instructions.items(.tag)[@backingInt(inst_index)]; 2341 assert(tag == .cond_br); 2342 const payload = data.pl_op.payload; 2343 const extra = air.extraData(Air.CondBr, payload); 2344 return .{ 2345 .condition = data.pl_op.operand, 2346 .then_body = @ptrCast(air.extra.items[extra.end..][0..extra.data.then_body_len]), 2347 .else_body = @ptrCast(air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]), 2348 .branch_hints = extra.data.branch_hints, 2349 }; 2350 } 2351 2352 pub const UnwrappedTry = struct { 2353 error_union: Inst.Ref, 2354 else_body: []const Inst.Index, 2355 }; 2356 2357 pub fn unwrapTry(air: *const Air, inst_index: Inst.Index) UnwrappedTry { 2358 const data = air.instructions.items(.data)[@backingInt(inst_index)]; 2359 const tag = air.instructions.items(.tag)[@backingInt(inst_index)]; 2360 assert(tag == .@"try" or tag == .try_cold); 2361 const payload = data.pl_op.payload; 2362 const extra = air.extraData(Air.Try, payload); 2363 return .{ 2364 .error_union = data.pl_op.operand, 2365 .else_body = @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]), 2366 }; 2367 } 2368 2369 pub const UnwrappedTryPtr = struct { 2370 error_union_payload_ptr_ty: Type, 2371 error_union_ptr: Inst.Ref, 2372 else_body: []const Inst.Index, 2373 }; 2374 2375 pub fn unwrapTryPtr(air: *const Air, inst_index: Inst.Index) UnwrappedTryPtr { 2376 const data = air.instructions.items(.data)[@backingInt(inst_index)]; 2377 const tag = air.instructions.items(.tag)[@backingInt(inst_index)]; 2378 assert(tag == .try_ptr or tag == .try_ptr_cold); 2379 const payload = data.ty_pl.payload; 2380 const extra = air.extraData(Air.TryPtr, payload); 2381 return .{ 2382 .error_union_ptr = extra.data.ptr, 2383 .error_union_payload_ptr_ty = data.ty_pl.ty, 2384 .else_body = @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]), 2385 }; 2386 } 2387 2388 pub const UnwrappedAsm = struct { 2389 outputs: []const Air.Inst.Ref, 2390 inputs: []const Air.Inst.Ref, 2391 source: [:0]u8, 2392 input_constraint_names: []const u32, 2393 output_constraint_names: []const u32, 2394 clobbers: InternPool.Index, 2395 is_volatile: bool, 2396 2397 const AsmIterator = struct { 2398 current: u32, 2399 operands: []const Air.Inst.Ref, 2400 constraint_names: []const u32, 2401 2402 pub fn next(self: *AsmIterator) ?struct { constraint: []const u8, operand: Inst.Ref, name: []const u8, index: u32 } { 2403 if (self.current >= self.operands.len) { 2404 return null; 2405 } 2406 defer { 2407 self.current += 1; 2408 } 2409 2410 const constraint_name = std.mem.sliceAsBytes(self.constraint_names); 2411 const constraint = std.mem.sliceTo(constraint_name, 0); 2412 const name = std.mem.sliceTo(constraint_name[constraint.len + 1 ..], 0); 2413 // This equation accounts for the fact that even if we have exactly 4 bytes 2414 // for the string, we still use the next u32 for the null terminator. 2415 const next_offset = @divCeil(constraint.len + 1 + name.len + 1, @sizeOf(u32)); 2416 self.constraint_names = self.constraint_names[next_offset..]; 2417 2418 return .{ 2419 .constraint = constraint, 2420 .operand = self.operands[self.current], 2421 .name = name, 2422 .index = self.current, 2423 }; 2424 } 2425 }; 2426 2427 pub fn iterateInputs(self: *const UnwrappedAsm) AsmIterator { 2428 return .{ 2429 .current = 0, 2430 .operands = self.inputs, 2431 .constraint_names = self.input_constraint_names, 2432 }; 2433 } 2434 2435 pub fn iterateOutputs(self: *const UnwrappedAsm) AsmIterator { 2436 return .{ 2437 .current = 0, 2438 .operands = self.outputs, 2439 .constraint_names = self.output_constraint_names, 2440 }; 2441 } 2442 }; 2443 2444 pub fn unwrapAsm(air: *const Air, inst_index: Inst.Index) UnwrappedAsm { 2445 const data = air.instructions.items(.data)[@backingInt(inst_index)]; 2446 const tag = air.instructions.items(.tag)[@backingInt(inst_index)]; 2447 assert(tag == .assembly); 2448 const payload = data.ty_pl.payload; 2449 const extra = air.extraData(Air.Asm, payload); 2450 const source_start = extra.end + extra.data.flags.outputs_len + extra.data.inputs_len; 2451 const output_constraint_name_start = source_start + (extra.data.source_len / 4) + 1; 2452 const output_constraint_name = air.extra.items[output_constraint_name_start..]; 2453 const outputs: []Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..extra.data.flags.outputs_len]); 2454 // Get the input names and constraints offset place after the output. 2455 var it = UnwrappedAsm.AsmIterator{ 2456 .current = 0, 2457 .constraint_names = output_constraint_name, 2458 .operands = outputs, 2459 }; 2460 while (it.next()) |_| {} 2461 2462 return .{ 2463 .clobbers = extra.data.clobbers, 2464 .is_volatile = extra.data.flags.is_volatile, 2465 .inputs = @ptrCast(air.extra.items[extra.end + extra.data.flags.outputs_len ..][0..extra.data.inputs_len]), 2466 .outputs = outputs, 2467 .source = std.mem.sliceAsBytes(air.extra.items[source_start..])[0..extra.data.source_len :0], 2468 .output_constraint_names = output_constraint_name, 2469 .input_constraint_names = it.constraint_names, 2470 }; 2471 } 2472 2473 pub const UnwrappedShuffleOne = struct { 2474 result_ty: Type, 2475 operand: Inst.Ref, 2476 mask: []const ShuffleOneMask, 2477 }; 2478 2479 pub fn unwrapShuffleOne(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index) UnwrappedShuffleOne { 2480 const inst = air.instructions.get(@backingInt(inst_index)); 2481 switch (inst.tag) { 2482 .shuffle_one => {}, 2483 else => unreachable, // assertion failure 2484 } 2485 const result_ty: Type = inst.data.ty_pl.ty; 2486 const mask_len: u32 = result_ty.vectorLen(zcu); 2487 const extra_idx = inst.data.ty_pl.payload; 2488 return .{ 2489 .result_ty = result_ty, 2490 .operand = @fromBackingInt(@intCast(air.extra.items[extra_idx + mask_len])), 2491 .mask = @ptrCast(air.extra.items[extra_idx..][0..mask_len]), 2492 }; 2493 } 2494 2495 pub const UnwrappedShuffleTwo = struct { 2496 result_ty: Type, 2497 operand_a: Inst.Ref, 2498 operand_b: Inst.Ref, 2499 mask: []const ShuffleTwoMask, 2500 }; 2501 2502 pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index) UnwrappedShuffleTwo { 2503 const inst = air.instructions.get(@backingInt(inst_index)); 2504 switch (inst.tag) { 2505 .shuffle_two => {}, 2506 else => unreachable, // assertion failure 2507 } 2508 const result_ty: Type = inst.data.ty_pl.ty; 2509 const mask_len: u32 = result_ty.vectorLen(zcu); 2510 const extra_idx = inst.data.ty_pl.payload; 2511 return .{ 2512 .result_ty = result_ty, 2513 .operand_a = @fromBackingInt(@intCast(air.extra.items[extra_idx + mask_len + 0])), 2514 .operand_b = @fromBackingInt(@intCast(air.extra.items[extra_idx + mask_len + 1])), 2515 .mask = @ptrCast(air.extra.items[extra_idx..][0..mask_len]), 2516 }; 2517 } 2518 2519 pub const legalize = Legalize.legalize; 2520 pub const write = print.write; 2521 pub const writeInst = print.writeInst; 2522 pub const dump = print.dump; 2523 pub const dumpInst = print.dumpInst; 2524 2525 pub const CoveragePoint = enum(u1) { 2526 /// Indicates the block is not a place of interest corresponding to 2527 /// a source location for coverage purposes. 2528 none, 2529 /// Point of interest. The next instruction emitted corresponds to 2530 /// a source location used for coverage instrumentation. 2531 poi, 2532 }; 2533 2534 pub const CompilerRtFunc = enum(u32) { 2535 // zig fmt: off 2536 2537 // float simple arithmetic 2538 __addhf3, __addsf3, __adddf3, __addxf3, __addtf3, 2539 __subhf3, __subsf3, __subdf3, __subxf3, __subtf3, 2540 __mulhf3, __mulsf3, __muldf3, __mulxf3, __multf3, 2541 __divhf3, __divsf3, __divdf3, __divxf3, __divtf3, 2542 2543 // float minmax 2544 __fminh, fminf, fmin, __fminx, fminq, 2545 __fmaxh, fmaxf, fmax, __fmaxx, fmaxq, 2546 2547 // float round 2548 __ceilh, ceilf, ceil, __ceilx, ceilq, 2549 __floorh, floorf, floor, __floorx, floorq, 2550 __trunch, truncf, trunc, __truncx, truncq, 2551 __roundh, roundf, round, __roundx, roundq, 2552 2553 // float log 2554 __logh, logf, log, __logx, logq, 2555 __log2h, log2f, log2, __log2x, log2q, 2556 __log10h, log10f, log10, __log10x, log10q, 2557 2558 // float exp 2559 __exph, expf, exp, __expx, expq, 2560 __exp2h, exp2f, exp2, __exp2x, exp2q, 2561 2562 // float trigonometry 2563 __sinh, sinf, sin, __sinx, sinq, 2564 __cosh, cosf, cos, __cosx, cosq, 2565 __tanh, tanf, tan, __tanx, tanq, 2566 2567 // float misc ops 2568 __fabsh, fabsf, fabs, __fabsx, fabsq, 2569 __sqrth, sqrtf, sqrt, __sqrtx, sqrtq, 2570 __fmodh, fmodf, fmod, __fmodx, fmodq, 2571 __fmah, fmaf, fma, __fmax, fmaq, 2572 2573 // float comparison 2574 __eqhf2, __eqsf2, __eqdf2, __eqxf2, __eqtf2, // == iff return == 0 2575 __nehf2, __nesf2, __nedf2, __nexf2, __netf2, // != iff return != 0 2576 __lthf2, __ltsf2, __ltdf2, __ltxf2, __lttf2, // < iff return < 0 2577 __lehf2, __lesf2, __ledf2, __lexf2, __letf2, // <= iff return <= 0 2578 __gthf2, __gtsf2, __gtdf2, __gtxf2, __gttf2, // > iff return > 0 2579 __gehf2, __gesf2, __gedf2, __gexf2, __getf2, // >= iff return >= 0 2580 2581 // AEABI float comparison. On ARM, the `sf`/`df` functions above are not available, 2582 // and these must be used instead. They are not just aliases for the above functions 2583 // because they have a different (better) ABI. 2584 __aeabi_fcmpeq, __aeabi_dcmpeq, // ==, returns bool 2585 __aeabi_fcmplt, __aeabi_dcmplt, // <, returns bool 2586 __aeabi_fcmple, __aeabi_dcmple, // <=, returns bool 2587 __aeabi_fcmpgt, __aeabi_dcmpgt, // >, returns bool 2588 __aeabi_fcmpge, __aeabi_dcmpge, // >=, returns bool 2589 2590 // float shortening 2591 // to f16 // to f32 // to f64 // to f80 2592 __trunctfhf2, __trunctfsf2, __trunctfdf2, __trunctfxf2, // from f128 2593 __truncxfhf2, __truncxfsf2, __truncxfdf2, // from f80 2594 __truncdfhf2, __truncdfsf2, // from f64 2595 __truncsfhf2, // from f32 2596 2597 // float widening 2598 // to f128 // to f80 // to f64 // to f32 2599 __extendhftf2, __extendhfxf2, __extendhfdf2, __extendhfsf2, // from f16 2600 __extendsftf2, __extendsfxf2, __extendsfdf2, // from f32 2601 __extenddftf2, __extenddfxf2, // from f64 2602 __extendxftf2, // from f80 2603 2604 // int to float 2605 __floatsihf, __floatsisf, __floatsidf, __floatsixf, __floatsitf, // i32 to float 2606 __floatdihf, __floatdisf, __floatdidf, __floatdixf, __floatditf, // i64 to float 2607 __floattihf, __floattisf, __floattidf, __floattixf, __floattitf, // i128 to float 2608 __floateihf, __floateisf, __floateidf, __floateixf, __floateitf, // arbitrary iN to float 2609 __floatunsihf, __floatunsisf, __floatunsidf, __floatunsixf, __floatunsitf, // u32 to float 2610 __floatundihf, __floatundisf, __floatundidf, __floatundixf, __floatunditf, // u64 to float 2611 __floatuntihf, __floatuntisf, __floatuntidf, __floatuntixf, __floatuntitf, // u128 to float 2612 __floatuneihf, __floatuneisf, __floatuneidf, __floatuneixf, __floatuneitf, // arbitrary uN to float 2613 2614 // float to int 2615 __fixhfsi, __fixsfsi, __fixdfsi, __fixxfsi, __fixtfsi, // float to i32 2616 __fixhfdi, __fixsfdi, __fixdfdi, __fixxfdi, __fixtfdi, // float to i64 2617 __fixhfti, __fixsfti, __fixdfti, __fixxfti, __fixtfti, // float to i128 2618 __fixhfei, __fixsfei, __fixdfei, __fixxfei, __fixtfei, // float to arbitray iN 2619 __fixunshfsi, __fixunssfsi, __fixunsdfsi, __fixunsxfsi, __fixunstfsi, // float to u32 2620 __fixunshfdi, __fixunssfdi, __fixunsdfdi, __fixunsxfdi, __fixunstfdi, // float to u64 2621 __fixunshfti, __fixunssfti, __fixunsdfti, __fixunsxfti, __fixunstfti, // float to u128 2622 __fixunshfei, __fixunssfei, __fixunsdfei, __fixunsxfei, __fixunstfei, // float to arbitray uN 2623 2624 // zig fmt: on 2625 2626 /// Usually, the tag names of `CompilerRtFunc` match the corresponding symbol name, but not 2627 /// always; some target triples have slightly different compiler-rt ABIs for one reason or 2628 /// another. 2629 pub fn name(f: CompilerRtFunc, target: *const std.Target) []const u8 { 2630 const use_gnu_f16_abi = switch (target.cpu.arch) { 2631 .wasm32, 2632 .wasm64, 2633 .riscv64, 2634 .riscv64be, 2635 .riscv32, 2636 .riscv32be, 2637 => false, 2638 .x86, .x86_64 => true, 2639 .arm, .armeb, .thumb, .thumbeb => switch (target.abi) { 2640 .eabi, .eabihf => false, 2641 else => true, 2642 }, 2643 else => !target.os.tag.isDarwin(), 2644 }; 2645 const use_aeabi = target.cpu.arch.isArm() and switch (target.abi) { 2646 .eabi, 2647 .eabihf, 2648 .musleabi, 2649 .musleabihf, 2650 .gnueabi, 2651 .gnueabihf, 2652 .android, 2653 .androideabi, 2654 => true, 2655 else => false, 2656 }; 2657 2658 // GNU didn't like the standard names specifically for conversions between f16 2659 // and f32, so decided to make their own naming convention with blackjack and 2660 // hookers (but only use it on a few random targets of course). This overrides 2661 // the ARM EABI in some cases. I don't like GNU. 2662 if (use_gnu_f16_abi) switch (f) { 2663 .__truncsfhf2 => return "__gnu_f2h_ieee", 2664 .__extendhfsf2 => return "__gnu_h2f_ieee", 2665 else => {}, 2666 }; 2667 2668 if (use_aeabi) return switch (f) { 2669 .__addsf3 => "__aeabi_fadd", 2670 .__adddf3 => "__aeabi_dadd", 2671 .__subsf3 => "__aeabi_fsub", 2672 .__subdf3 => "__aeabi_dsub", 2673 .__mulsf3 => "__aeabi_fmul", 2674 .__muldf3 => "__aeabi_dmul", 2675 .__divsf3 => "__aeabi_fdiv", 2676 .__divdf3 => "__aeabi_ddiv", 2677 .__truncdfhf2 => "__aeabi_d2h", 2678 .__truncdfsf2 => "__aeabi_d2f", 2679 .__truncsfhf2 => "__aeabi_f2h", 2680 .__extendsfdf2 => "__aeabi_f2d", 2681 .__extendhfsf2 => "__aeabi_h2f", 2682 .__floatsisf => "__aeabi_i2f", 2683 .__floatsidf => "__aeabi_i2d", 2684 .__floatdisf => "__aeabi_l2f", 2685 .__floatdidf => "__aeabi_l2d", 2686 .__floatunsisf => "__aeabi_ui2f", 2687 .__floatunsidf => "__aeabi_ui2d", 2688 .__floatundisf => "__aeabi_ul2f", 2689 .__floatundidf => "__aeabi_ul2d", 2690 .__fixsfsi => "__aeabi_f2iz", 2691 .__fixdfsi => "__aeabi_d2iz", 2692 .__fixsfdi => "__aeabi_f2lz", 2693 .__fixdfdi => "__aeabi_d2lz", 2694 .__fixunssfsi => "__aeabi_f2uiz", 2695 .__fixunsdfsi => "__aeabi_d2uiz", 2696 .__fixunssfdi => "__aeabi_f2ulz", 2697 .__fixunsdfdi => "__aeabi_d2ulz", 2698 2699 // These functions are not available on AEABI. The AEABI equivalents are 2700 // separate fields rather than aliases because they have a different ABI. 2701 .__eqsf2, .__eqdf2 => unreachable, 2702 .__nesf2, .__nedf2 => unreachable, 2703 .__ltsf2, .__ltdf2 => unreachable, 2704 .__lesf2, .__ledf2 => unreachable, 2705 .__gtsf2, .__gtdf2 => unreachable, 2706 .__gesf2, .__gedf2 => unreachable, 2707 2708 else => @tagName(f), 2709 }; 2710 2711 return switch (f) { 2712 // These functions are only available on AEABI. 2713 .__aeabi_fcmpeq, .__aeabi_dcmpeq => unreachable, 2714 .__aeabi_fcmplt, .__aeabi_dcmplt => unreachable, 2715 .__aeabi_fcmple, .__aeabi_dcmple => unreachable, 2716 .__aeabi_fcmpgt, .__aeabi_dcmpgt => unreachable, 2717 .__aeabi_fcmpge, .__aeabi_dcmpge => unreachable, 2718 2719 else => @tagName(f), 2720 }; 2721 } 2722 2723 pub fn @"callconv"(f: CompilerRtFunc, target: *const std.Target) std.lang.CallingConvention { 2724 const use_gnu_f16_abi = switch (target.cpu.arch) { 2725 .wasm32, 2726 .wasm64, 2727 .riscv64, 2728 .riscv64be, 2729 .riscv32, 2730 .riscv32be, 2731 => false, 2732 .x86, .x86_64 => true, 2733 .arm, .armeb, .thumb, .thumbeb => switch (target.abi) { 2734 .eabi, .eabihf => false, 2735 else => true, 2736 }, 2737 else => !target.os.tag.isDarwin(), 2738 }; 2739 const use_aeabi = target.cpu.arch.isArm() and switch (target.abi) { 2740 .eabi, 2741 .eabihf, 2742 .musleabi, 2743 .musleabihf, 2744 .gnueabi, 2745 .gnueabihf, 2746 .android, 2747 .androideabi, 2748 => true, 2749 else => false, 2750 }; 2751 2752 if (use_gnu_f16_abi) switch (f) { 2753 .__truncsfhf2, 2754 .__extendhfsf2, 2755 => return target.cCallingConvention().?, 2756 else => {}, 2757 }; 2758 2759 if (use_aeabi) switch (f) { 2760 // zig fmt: off 2761 .__addsf3, .__adddf3, .__subsf3, .__subdf3, 2762 .__mulsf3, .__muldf3, .__divsf3, .__divdf3, 2763 .__truncdfhf2, .__truncdfsf2, .__truncsfhf2, 2764 .__extendsfdf2, .__extendhfsf2, 2765 .__floatsisf, .__floatsidf, .__floatdisf, .__floatdidf, 2766 .__floatunsisf, .__floatunsidf, .__floatundisf, .__floatundidf, 2767 .__fixsfsi, .__fixdfsi, .__fixsfdi, .__fixdfdi, 2768 .__fixunssfsi, .__fixunsdfsi, .__fixunssfdi, .__fixunsdfdi, 2769 => return .{ .arm_aapcs = .{} }, 2770 // zig fmt: on 2771 else => {}, 2772 }; 2773 2774 return target.cCallingConvention().?; 2775 } 2776 2777 pub fn returnType(f: CompilerRtFunc) Type { 2778 return switch (f) { 2779 .__addhf3, .__subhf3, .__mulhf3, .__divhf3 => .f16, 2780 .__addsf3, .__subsf3, .__mulsf3, .__divsf3 => .f32, 2781 .__adddf3, .__subdf3, .__muldf3, .__divdf3 => .f64, 2782 .__addxf3, .__subxf3, .__mulxf3, .__divxf3 => .f80, 2783 .__addtf3, .__subtf3, .__multf3, .__divtf3 => .f128, 2784 2785 // zig fmt: off 2786 .__fminh, .__fmaxh, 2787 .__ceilh, .__floorh, .__trunch, .__roundh, 2788 .__logh, .__log2h, .__log10h, 2789 .__exph, .__exp2h, 2790 .__sinh, .__cosh, .__tanh, 2791 .__fabsh, .__sqrth, .__fmodh, .__fmah, 2792 => .f16, 2793 .fminf, .fmaxf, 2794 .ceilf, .floorf, .truncf, .roundf, 2795 .logf, .log2f, .log10f, 2796 .expf, .exp2f, 2797 .sinf, .cosf, .tanf, 2798 .fabsf, .sqrtf, .fmodf, .fmaf, 2799 => .f32, 2800 .fmin, .fmax, 2801 .ceil, .floor, .trunc, .round, 2802 .log, .log2, .log10, 2803 .exp, .exp2, 2804 .sin, .cos, .tan, 2805 .fabs, .sqrt, .fmod, .fma, 2806 => .f64, 2807 .__fminx, .__fmaxx, 2808 .__ceilx, .__floorx, .__truncx, .__roundx, 2809 .__logx, .__log2x, .__log10x, 2810 .__expx, .__exp2x, 2811 .__sinx, .__cosx, .__tanx, 2812 .__fabsx, .__sqrtx, .__fmodx, .__fmax, 2813 => .f80, 2814 .fminq, .fmaxq, 2815 .ceilq, .floorq, .truncq, .roundq, 2816 .logq, .log2q, .log10q, 2817 .expq, .exp2q, 2818 .sinq, .cosq, .tanq, 2819 .fabsq, .sqrtq, .fmodq, .fmaq, 2820 => .f128, 2821 // zig fmt: on 2822 2823 .__eqhf2, .__eqsf2, .__eqdf2, .__eqxf2, .__eqtf2 => .i32, 2824 .__nehf2, .__nesf2, .__nedf2, .__nexf2, .__netf2 => .i32, 2825 .__lthf2, .__ltsf2, .__ltdf2, .__ltxf2, .__lttf2 => .i32, 2826 .__lehf2, .__lesf2, .__ledf2, .__lexf2, .__letf2 => .i32, 2827 .__gthf2, .__gtsf2, .__gtdf2, .__gtxf2, .__gttf2 => .i32, 2828 .__gehf2, .__gesf2, .__gedf2, .__gexf2, .__getf2 => .i32, 2829 2830 .__aeabi_fcmpeq, .__aeabi_dcmpeq => .i32, 2831 .__aeabi_fcmplt, .__aeabi_dcmplt => .i32, 2832 .__aeabi_fcmple, .__aeabi_dcmple => .i32, 2833 .__aeabi_fcmpgt, .__aeabi_dcmpgt => .i32, 2834 .__aeabi_fcmpge, .__aeabi_dcmpge => .i32, 2835 2836 .__trunctfhf2, .__truncxfhf2, .__truncdfhf2, .__truncsfhf2 => .f16, 2837 .__trunctfsf2, .__truncxfsf2, .__truncdfsf2 => .f32, 2838 .__trunctfdf2, .__truncxfdf2 => .f64, 2839 .__trunctfxf2 => .f80, 2840 2841 .__extendhftf2, .__extendsftf2, .__extenddftf2, .__extendxftf2 => .f128, 2842 .__extendhfxf2, .__extendsfxf2, .__extenddfxf2 => .f80, 2843 .__extendhfdf2, .__extendsfdf2 => .f64, 2844 .__extendhfsf2 => .f32, 2845 2846 .__floatsihf, .__floatdihf, .__floattihf, .__floateihf => .f16, 2847 .__floatsisf, .__floatdisf, .__floattisf, .__floateisf => .f32, 2848 .__floatsidf, .__floatdidf, .__floattidf, .__floateidf => .f64, 2849 .__floatsixf, .__floatdixf, .__floattixf, .__floateixf => .f80, 2850 .__floatsitf, .__floatditf, .__floattitf, .__floateitf => .f128, 2851 .__floatunsihf, .__floatundihf, .__floatuntihf, .__floatuneihf => .f16, 2852 .__floatunsisf, .__floatundisf, .__floatuntisf, .__floatuneisf => .f32, 2853 .__floatunsidf, .__floatundidf, .__floatuntidf, .__floatuneidf => .f64, 2854 .__floatunsixf, .__floatundixf, .__floatuntixf, .__floatuneixf => .f80, 2855 .__floatunsitf, .__floatunditf, .__floatuntitf, .__floatuneitf => .f128, 2856 2857 .__fixhfsi, .__fixsfsi, .__fixdfsi, .__fixxfsi, .__fixtfsi => .i32, 2858 .__fixhfdi, .__fixsfdi, .__fixdfdi, .__fixxfdi, .__fixtfdi => .i64, 2859 .__fixhfti, .__fixsfti, .__fixdfti, .__fixxfti, .__fixtfti => .i128, 2860 .__fixhfei, .__fixsfei, .__fixdfei, .__fixxfei, .__fixtfei => .void, 2861 .__fixunshfsi, .__fixunssfsi, .__fixunsdfsi, .__fixunsxfsi, .__fixunstfsi => .u32, 2862 .__fixunshfdi, .__fixunssfdi, .__fixunsdfdi, .__fixunsxfdi, .__fixunstfdi => .u64, 2863 .__fixunshfti, .__fixunssfti, .__fixunsdfti, .__fixunsxfti, .__fixunstfti => .u128, 2864 .__fixunshfei, .__fixunssfei, .__fixunsdfei, .__fixunsxfei, .__fixunstfei => .void, 2865 }; 2866 } 2867 }; 2868