authorgravatar for mathieusuen@yahoo.frMathieu Suen <mathieusuen@yahoo.fr> 2026-01-20 15:15:57+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-06 13:06:49+00:00
log36b65ab59e5e514ad06a11cde96b87c565d86ac8
tree33e1edfa980caefe0eac488562585ae544946432
parentd84a638e8b6ffeb95dfafef59e6305bd0e139d4e
signaturelock-open Commit is signed but in an unrecognized format.

Air: add "unwrap" functions for loading extra data


14 files changed, 861 insertions(+), 890 deletions(-)

src/Air.zig+254-13
...@@ -281,16 +281,21 @@ pub const Inst = struct {...@@ -281,16 +281,21 @@ pub const Inst = struct {
281 /// also supports enums and pointers.281 /// also supports enums and pointers.
282 /// Uses the `ty_op` field.282 /// Uses the `ty_op` field.
283 bitcast,283 bitcast,
284 /// Uses the `ty_pl` field with payload `Block`. A block runs its body which always ends284 /// A block runs its body which always ends with a `noreturn` instruction,
285 /// with a `noreturn` instruction, so the only way to proceed to the code after the `block`285 /// so the only way to proceed to the code after the `block` is to encounter a `br`
286 /// is to encounter a `br` that targets this `block`. If the `block` type is `noreturn`,286 /// that targets this `block`. If the `block` type is `noreturn`,
287 /// then there do not exist any `br` instructions targeting this `block`.287 /// then there do not exist any `br` instructions targeting this `block`.
288 /// Uses the `ty_pl` field with payload `Block`.
289 ///
290 /// See `unwrapBlock` for a way to load this tag's data.
288 block,291 block,
289 /// A labeled block of code that loops forever. The body must be `noreturn`: loops292 /// A labeled block of code that loops forever. The body must be `noreturn`: loops
290 /// occur through an explicit `repeat` instruction pointing back to this one.293 /// occur through an explicit `repeat` instruction pointing back to this one.
291 /// Result type is always `noreturn`; no instructions in a block follow this one.294 /// Result type is always `noreturn`; no instructions in a block follow this one.
292 /// There is always at least one `repeat` instruction referencing the loop.295 /// There is always at least one `repeat` instruction referencing the loop.
293 /// Uses the `ty_pl` field. Payload is `Block`.296 /// Uses the `ty_pl` field. Payload is `Block`.
297 ///
298 /// See `unwrapBlock` for a way to load this tag's data.
294 loop,299 loop,
295 /// Sends control flow back to the beginning of a parent `loop` body.300 /// Sends control flow back to the beginning of a parent `loop` body.
296 /// Uses the `repeat` field.301 /// Uses the `repeat` field.
...@@ -319,6 +324,8 @@ pub const Inst = struct {...@@ -319,6 +324,8 @@ pub const Inst = struct {
319 /// Result type is the return type of the function being called.324 /// Result type is the return type of the function being called.
320 /// Uses the `pl_op` field with the `Call` payload. operand is the callee.325 /// Uses the `pl_op` field with the `Call` payload. operand is the callee.
321 /// Triggers `resolveTypeLayout` on the return type of the callee.326 /// Triggers `resolveTypeLayout` on the return type of the callee.
327 ///
328 /// See `unwrapCall` for a way to load this tag's data.
322 call,329 call,
323 /// Same as `call` except with the `always_tail` attribute.330 /// Same as `call` except with the `always_tail` attribute.
324 call_always_tail,331 call_always_tail,
...@@ -436,14 +443,20 @@ pub const Inst = struct {...@@ -436,14 +443,20 @@ pub const Inst = struct {
436 /// Conditional branch.443 /// Conditional branch.
437 /// Result type is always noreturn; no instructions in a block follow this one.444 /// Result type is always noreturn; no instructions in a block follow this one.
438 /// Uses the `pl_op` field. Operand is the condition. Payload is `CondBr`.445 /// Uses the `pl_op` field. Operand is the condition. Payload is `CondBr`.
446 ///
447 /// See `unwrapCondBr` for a way to load this tags's data.
439 cond_br,448 cond_br,
440 /// Switch branch.449 /// Switch branch.
441 /// Result type is always noreturn; no instructions in a block follow this one.450 /// Result type is always noreturn; no instructions in a block follow this one.
442 /// Uses the `pl_op` field. Operand is the condition. Payload is `SwitchBr`.451 /// Uses the `pl_op` field. Operand is the condition. Payload is `SwitchBr`.
452 ///
453 /// See `unwrapSwitch` for a way to load this tags's data.
443 switch_br,454 switch_br,
444 /// Switch branch which can dispatch back to itself with a different operand.455 /// Switch branch which can dispatch back to itself with a different operand.
445 /// Result type is always noreturn; no instructions in a block follow this one.456 /// Result type is always noreturn; no instructions in a block follow this one.
446 /// Uses the `pl_op` field. Operand is the condition. Payload is `SwitchBr`.457 /// Uses the `pl_op` field. Operand is the condition. Payload is `SwitchBr`.
458 ///
459 /// See `unwrapSwitch` for a way to load this tags's data.
447 loop_switch_br,460 loop_switch_br,
448 /// Dispatches back to a branch of a parent `loop_switch_br`.461 /// Dispatches back to a branch of a parent `loop_switch_br`.
449 /// Result type is always noreturn; no instructions in a block follow this one.462 /// Result type is always noreturn; no instructions in a block follow this one.
...@@ -458,6 +471,8 @@ pub const Inst = struct {...@@ -458,6 +471,8 @@ pub const Inst = struct {
458 /// payload value, as if `unwrap_errunion_payload` was executed on the operand.471 /// payload value, as if `unwrap_errunion_payload` was executed on the operand.
459 /// The error branch is considered to have a branch hint of `.unlikely`.472 /// The error branch is considered to have a branch hint of `.unlikely`.
460 /// Uses the `pl_op` field. Payload is `Try`.473 /// Uses the `pl_op` field. Payload is `Try`.
474 ///
475 /// See `unwrapTry` for a way to load this tag's data.
461 @"try",476 @"try",
462 /// Same as `try` except the error branch hint is `.cold`.477 /// Same as `try` except the error branch hint is `.cold`.
463 try_cold,478 try_cold,
...@@ -465,6 +480,8 @@ pub const Inst = struct {...@@ -465,6 +480,8 @@ pub const Inst = struct {
465 /// result is a pointer to the payload. Result is as if `unwrap_errunion_payload_ptr`480 /// result is a pointer to the payload. Result is as if `unwrap_errunion_payload_ptr`
466 /// was executed on the operand.481 /// was executed on the operand.
467 /// Uses the `ty_pl` field. Payload is `TryPtr`.482 /// Uses the `ty_pl` field. Payload is `TryPtr`.
483 ///
484 /// See `unwrapTryPtr` for a way to load this tag's data.
468 try_ptr,485 try_ptr,
469 /// Same as `try_ptr` except the error branch hint is `.cold`.486 /// Same as `try_ptr` except the error branch hint is `.cold`.
470 try_ptr_cold,487 try_ptr_cold,
...@@ -476,6 +493,8 @@ pub const Inst = struct {...@@ -476,6 +493,8 @@ pub const Inst = struct {
476 dbg_empty_stmt,493 dbg_empty_stmt,
477 /// A block that represents an inlined function call.494 /// A block that represents an inlined function call.
478 /// Uses the `ty_pl` field. Payload is `DbgInlineBlock`.495 /// Uses the `ty_pl` field. Payload is `DbgInlineBlock`.
496 ///
497 /// See `unwrapBlock` for a way to load this tag's data.
479 dbg_inline_block,498 dbg_inline_block,
480 /// Marks the beginning of a local variable. The operand is a pointer pointing499 /// Marks the beginning of a local variable. The operand is a pointer pointing
481 /// to the storage for the variable. The local may be a const or a var.500 /// to the storage for the variable. The local may be a const or a var.
...@@ -715,7 +734,7 @@ pub const Inst = struct {...@@ -715,7 +734,7 @@ pub const Inst = struct {
715 /// Uses the `ty_pl` field, where the payload index points to:734 /// Uses the `ty_pl` field, where the payload index points to:
716 /// 1. mask_elem: ShuffleOneMask // for each `mask_len`, which comes from `ty_pl.ty`735 /// 1. mask_elem: ShuffleOneMask // for each `mask_len`, which comes from `ty_pl.ty`
717 /// 2. operand: Ref // guaranteed not to be an interned value736 /// 2. operand: Ref // guaranteed not to be an interned value
718 /// See `unwrapShuffleOne`.737 /// See `unwrapShuffleOne` for a way to load this tag's data.
719 shuffle_one,738 shuffle_one,
720 /// Constructs a vector by selecting elements from two vectors based on a mask. Each mask739 /// Constructs a vector by selecting elements from two vectors based on a mask. Each mask
721 /// element is either an index into one of the vectors, or "undef".740 /// element is either an index into one of the vectors, or "undef".
...@@ -723,7 +742,7 @@ pub const Inst = struct {...@@ -723,7 +742,7 @@ pub const Inst = struct {
723 /// 1. mask_elem: ShuffleOneMask // for each `mask_len`, which comes from `ty_pl.ty`742 /// 1. mask_elem: ShuffleOneMask // for each `mask_len`, which comes from `ty_pl.ty`
724 /// 2. operand_a: Ref // guaranteed not to be an interned value743 /// 2. operand_a: Ref // guaranteed not to be an interned value
725 /// 3. operand_b: Ref // guaranteed not to be an interned value744 /// 3. operand_b: Ref // guaranteed not to be an interned value
726 /// See `unwrapShuffleTwo`.745 /// See `unwrapShuffleTwo` for a way to load this tag's data..
727 shuffle_two,746 shuffle_two,
728 /// Constructs a vector element-wise from `a` or `b` based on `pred`.747 /// Constructs a vector element-wise from `a` or `b` based on `pred`.
729 /// Uses the `pl_op` field with `pred` as operand, and payload `Bin`.748 /// Uses the `pl_op` field with `pred` as operand, and payload `Bin`.
...@@ -944,6 +963,8 @@ pub const Inst = struct {...@@ -944,6 +963,8 @@ pub const Inst = struct {
944 /// The calling convention is given by `func.@"callconv"(target)`.963 /// The calling convention is given by `func.@"callconv"(target)`.
945 /// The return type (and hence the result type of this instruction) is `func.returnType()`.964 /// The return type (and hence the result type of this instruction) is `func.returnType()`.
946 /// The parameter types are the types of the arguments given in `Air.Call`.965 /// The parameter types are the types of the arguments given in `Air.Call`.
966 ///
967 /// See `unwrapCompilerRtCall` for a way to load this tag's data.
947 legalize_compiler_rt_call,968 legalize_compiler_rt_call,
948969
949 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {970 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {
...@@ -1445,18 +1466,18 @@ pub const ShuffleTwoMask = enum(u32) {...@@ -1445,18 +1466,18 @@ pub const ShuffleTwoMask = enum(u32) {
1445/// Trailing:1466/// Trailing:
1446/// 0. `Inst.Ref` for every outputs_len1467/// 0. `Inst.Ref` for every outputs_len
1447/// 1. `Inst.Ref` for every inputs_len1468/// 1. `Inst.Ref` for every inputs_len
1448/// 2. for every outputs_len1469/// 2. A number of u32 elements follow according to the equation `(source_len + 3) / 4`.
1470/// Memory starting at this position is reinterpreted as the source bytes.
1471/// 3. for every outputs_len
1449/// - constraint: memory at this position is reinterpreted as a null1472/// - constraint: memory at this position is reinterpreted as a null
1450/// terminated string.1473/// terminated string.
1451/// - name: memory at this position is reinterpreted as a null1474/// - name: memory at this position is reinterpreted as a null
1452/// terminated string. pad to the next u32 after the null byte.1475/// terminated string. pad to the next u32 after the null byte.
1453/// 3. for every inputs_len1476/// 4. for every inputs_len
1454/// - constraint: memory at this position is reinterpreted as a null1477/// - constraint: memory at this position is reinterpreted as a null
1455/// terminated string.1478/// terminated string.
1456/// - name: memory at this position is reinterpreted as a null1479/// - name: memory at this position is reinterpreted as a null
1457/// terminated string. pad to the next u32 after the null byte.1480/// terminated string. pad to the next u32 after the null byte.
1458/// 4. A number of u32 elements follow according to the equation `(source_len + 3) / 4`.
1459/// Memory starting at this position is reinterpreted as the source bytes.
1460pub const Asm = struct {1481pub const Asm = struct {
1461 /// Length of the assembly source in bytes.1482 /// Length of the assembly source in bytes.
1462 source_len: u32,1483 source_len: u32,
...@@ -2157,11 +2178,229 @@ pub fn unwrapSwitch(air: *const Air, switch_inst: Inst.Index) UnwrappedSwitch {...@@ -2157,11 +2178,229 @@ pub fn unwrapSwitch(air: *const Air, switch_inst: Inst.Index) UnwrappedSwitch {
2157 };2178 };
2158}2179}
21592180
2160pub fn unwrapShuffleOne(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index) struct {2181pub const UnwrappedDbgInlineBlock = struct {
2182 func: InternPool.Index,
2183 body: []const Inst.Index,
2184 ty: Type,
2185};
2186
2187pub fn unwrapDbgBlock(air: *const Air, inst_index: Inst.Index) UnwrappedDbgInlineBlock {
2188 const data = air.instructions.items(.data)[@intFromEnum(inst_index)];
2189 const tag = air.instructions.items(.tag)[@intFromEnum(inst_index)];
2190 assert(tag == .dbg_inline_block);
2191 const payload = data.ty_pl.payload;
2192 const extra = air.extraData(Air.DbgInlineBlock, payload);
2193 return .{
2194 .func = extra.data.func,
2195 .ty = data.ty_pl.ty.toType(),
2196 .body = @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]),
2197 };
2198}
2199
2200pub const UnwrappedBlock = struct {
2201 body: []const Inst.Index,
2202 ty: Type,
2203};
2204
2205pub fn unwrapBlock(air: *const Air, inst_index: Inst.Index) UnwrappedBlock {
2206 const data = air.instructions.items(.data)[@intFromEnum(inst_index)];
2207 const tag = air.instructions.items(.tag)[@intFromEnum(inst_index)];
2208 const payload = switch (tag) {
2209 .block, .loop => data.ty_pl.payload,
2210 else => unreachable,
2211 };
2212 const extra = air.extraData(Air.Block, payload);
2213 return .{
2214 .ty = data.ty_pl.ty.toType(),
2215 .body = @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]),
2216 };
2217}
2218
2219pub const UnwrappedCall = struct {
2220 callee: Inst.Ref,
2221 args: []const Air.Inst.Ref,
2222};
2223
2224pub fn unwrapCall(air: *const Air, inst_index: Inst.Index) UnwrappedCall {
2225 const data = air.instructions.items(.data)[@intFromEnum(inst_index)];
2226 const tag = air.instructions.items(.tag)[@intFromEnum(inst_index)];
2227 const payload = switch (tag) {
2228 .call, .call_always_tail, .call_never_tail, .call_never_inline => data.pl_op.payload,
2229 else => unreachable,
2230 };
2231 const extra = air.extraData(Air.Call, payload);
2232 return .{
2233 .callee = data.pl_op.operand,
2234 .args = @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len]),
2235 };
2236}
2237
2238pub const UnwrappedCompilerRtCall = struct {
2239 func: CompilerRtFunc,
2240 args: []const Air.Inst.Ref,
2241};
2242
2243pub fn unwrapCompilerRtCall(air: *const Air, inst_index: Inst.Index) UnwrappedCompilerRtCall {
2244 const data = air.instructions.items(.data)[@intFromEnum(inst_index)];
2245 const tag = air.instructions.items(.tag)[@intFromEnum(inst_index)];
2246 assert(tag == .legalize_compiler_rt_call);
2247 const payload = data.legalize_compiler_rt_call.payload;
2248 const extra = air.extraData(Air.Call, payload);
2249 return .{
2250 .func = data.legalize_compiler_rt_call.func,
2251 .args = @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len]),
2252 };
2253}
2254
2255pub const UnwrappedCondBr = struct {
2256 condition: Inst.Ref,
2257 then_body: []const Inst.Index,
2258 else_body: []const Inst.Index,
2259 branch_hints: CondBr.BranchHints,
2260};
2261
2262pub fn unwrapCondBr(air: *const Air, inst_index: Inst.Index) UnwrappedCondBr {
2263 const data = air.instructions.items(.data)[@intFromEnum(inst_index)];
2264 const tag = air.instructions.items(.tag)[@intFromEnum(inst_index)];
2265 assert(tag == .cond_br);
2266 const payload = data.pl_op.payload;
2267 const extra = air.extraData(Air.CondBr, payload);
2268 return .{
2269 .condition = data.pl_op.operand,
2270 .then_body = @ptrCast(air.extra.items[extra.end..][0..extra.data.then_body_len]),
2271 .else_body = @ptrCast(air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]),
2272 .branch_hints = extra.data.branch_hints,
2273 };
2274}
2275
2276pub const UnwrappedTry = struct {
2277 error_union: Inst.Ref,
2278 else_body: []const Inst.Index,
2279};
2280
2281pub fn unwrapTry(air: *const Air, inst_index: Inst.Index) UnwrappedTry {
2282 const data = air.instructions.items(.data)[@intFromEnum(inst_index)];
2283 const tag = air.instructions.items(.tag)[@intFromEnum(inst_index)];
2284 assert(tag == .@"try" or tag == .try_cold);
2285 const payload = data.pl_op.payload;
2286 const extra = air.extraData(Air.Try, payload);
2287 return .{
2288 .error_union = data.pl_op.operand,
2289 .else_body = @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]),
2290 };
2291}
2292
2293pub const UnwrappedTryPtr = struct {
2294 error_union_payload_ptr_ty: Inst.Ref,
2295 error_union_ptr: Inst.Ref,
2296 else_body: []const Inst.Index,
2297};
2298
2299pub fn unwrapTryPtr(air: *const Air, inst_index: Inst.Index) UnwrappedTryPtr {
2300 const data = air.instructions.items(.data)[@intFromEnum(inst_index)];
2301 const tag = air.instructions.items(.tag)[@intFromEnum(inst_index)];
2302 assert(tag == .try_ptr or tag == .try_ptr_cold);
2303 const payload = data.ty_pl.payload;
2304 const extra = air.extraData(Air.TryPtr, payload);
2305 return .{
2306 .error_union_ptr = extra.data.ptr,
2307 .error_union_payload_ptr_ty = data.ty_pl.ty,
2308 .else_body = @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]),
2309 };
2310}
2311
2312pub const UnwrappedAsm = struct {
2313 outputs: []const Air.Inst.Ref,
2314 inputs: []const Air.Inst.Ref,
2315 source: [:0]u8,
2316 input_constraint_names: []const u32,
2317 output_constraint_names: []const u32,
2318 clobbers: InternPool.Index,
2319 is_volatile: bool,
2320
2321 const AsmIterator = struct {
2322 current: u32,
2323 operands: []const Air.Inst.Ref,
2324 constraint_names: []const u32,
2325
2326 pub fn next(self: *AsmIterator) ?struct { constraint: []const u8, operand: Inst.Ref, name: []const u8, index: u32 } {
2327 if (self.current >= self.operands.len) {
2328 return null;
2329 }
2330 defer {
2331 self.current += 1;
2332 }
2333
2334 const constraint_name = std.mem.sliceAsBytes(self.constraint_names);
2335 const constraint = std.mem.sliceTo(constraint_name, 0);
2336 const name = std.mem.sliceTo(constraint_name[constraint.len + 1 ..], 0);
2337 // This equation accounts for the fact that even if we have exactly 4 bytes
2338 // for the string, we still use the next u32 for the null terminator.
2339 const next_offset = std.math.divCeil(usize, constraint.len + 1 + name.len + 1, @sizeOf(u32)) catch unreachable;
2340 self.constraint_names = self.constraint_names[next_offset..];
2341
2342 return .{
2343 .constraint = constraint,
2344 .operand = self.operands[self.current],
2345 .name = name,
2346 .index = self.current,
2347 };
2348 }
2349 };
2350
2351 pub fn iterateInputs(self: *const UnwrappedAsm) AsmIterator {
2352 return .{
2353 .current = 0,
2354 .operands = self.inputs,
2355 .constraint_names = self.input_constraint_names,
2356 };
2357 }
2358
2359 pub fn iterateOutputs(self: *const UnwrappedAsm) AsmIterator {
2360 return .{
2361 .current = 0,
2362 .operands = self.outputs,
2363 .constraint_names = self.output_constraint_names,
2364 };
2365 }
2366};
2367
2368pub fn unwrapAsm(air: *const Air, inst_index: Inst.Index) UnwrappedAsm {
2369 const data = air.instructions.items(.data)[@intFromEnum(inst_index)];
2370 const tag = air.instructions.items(.tag)[@intFromEnum(inst_index)];
2371 assert(tag == .assembly);
2372 const payload = data.ty_pl.payload;
2373 const extra = air.extraData(Air.Asm, payload);
2374 const source_start = extra.end + extra.data.flags.outputs_len + extra.data.inputs_len;
2375 const output_constraint_name_start = source_start + (extra.data.source_len / 4) + 1;
2376 const output_constraint_name = air.extra.items[output_constraint_name_start..];
2377 const outputs: []Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..extra.data.flags.outputs_len]);
2378 // Get the input names and constraints offset place after the output.
2379 var it = UnwrappedAsm.AsmIterator{
2380 .current = 0,
2381 .constraint_names = output_constraint_name,
2382 .operands = outputs,
2383 };
2384 while (it.next()) |_| {}
2385
2386 return .{
2387 .clobbers = extra.data.clobbers,
2388 .is_volatile = extra.data.flags.is_volatile,
2389 .inputs = @ptrCast(air.extra.items[extra.end + extra.data.flags.outputs_len ..][0..extra.data.inputs_len]),
2390 .outputs = outputs,
2391 .source = std.mem.sliceAsBytes(air.extra.items[source_start..])[0..extra.data.source_len :0],
2392 .output_constraint_names = output_constraint_name,
2393 .input_constraint_names = it.constraint_names,
2394 };
2395}
2396
2397pub const UnwrappedShuffleOne = struct {
2161 result_ty: Type,2398 result_ty: Type,
2162 operand: Inst.Ref,2399 operand: Inst.Ref,
2163 mask: []const ShuffleOneMask,2400 mask: []const ShuffleOneMask,
2164} {2401};
2402
2403pub fn unwrapShuffleOne(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index) UnwrappedShuffleOne {
2165 const inst = air.instructions.get(@intFromEnum(inst_index));2404 const inst = air.instructions.get(@intFromEnum(inst_index));
2166 switch (inst.tag) {2405 switch (inst.tag) {
2167 .shuffle_one => {},2406 .shuffle_one => {},
...@@ -2177,12 +2416,14 @@ pub fn unwrapShuffleOne(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index...@@ -2177,12 +2416,14 @@ pub fn unwrapShuffleOne(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index
2177 };2416 };
2178}2417}
21792418
2180pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index) struct {2419pub const UnwrappedShuffleTwo = struct {
2181 result_ty: Type,2420 result_ty: Type,
2182 operand_a: Inst.Ref,2421 operand_a: Inst.Ref,
2183 operand_b: Inst.Ref,2422 operand_b: Inst.Ref,
2184 mask: []const ShuffleTwoMask,2423 mask: []const ShuffleTwoMask,
2185} {2424};
2425
2426pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index) UnwrappedShuffleTwo {
2186 const inst = air.instructions.get(@intFromEnum(inst_index));2427 const inst = air.instructions.get(@intFromEnum(inst_index));
2187 switch (inst.tag) {2428 switch (inst.tag) {
2188 .shuffle_two => {},2429 .shuffle_two => {},
src/Air/Liveness.zig+39-52
...@@ -17,6 +17,7 @@ const trace = @import("../tracy.zig").trace;...@@ -17,6 +17,7 @@ const trace = @import("../tracy.zig").trace;
17const Air = @import("../Air.zig");17const Air = @import("../Air.zig");
18const InternPool = @import("../InternPool.zig");18const InternPool = @import("../InternPool.zig");
19const Zcu = @import("../Zcu.zig");19const Zcu = @import("../Zcu.zig");
20const Type = @import("../Type.zig");
2021
21pub const Verify = @import("Liveness/Verify.zig");22pub const Verify = @import("Liveness/Verify.zig");
2223
...@@ -609,13 +610,11 @@ fn analyzeInst(...@@ -609,13 +610,11 @@ fn analyzeInst(
609 },610 },
610611
611 .call, .call_always_tail, .call_never_tail, .call_never_inline => {612 .call, .call_always_tail, .call_never_tail, .call_never_inline => {
612 const inst_data = inst_datas[@intFromEnum(inst)].pl_op;613 const call = a.air.unwrapCall(inst);
613 const callee = inst_data.operand;614 const args = call.args;
614 const extra = a.air.extraData(Air.Call, inst_data.payload);
615 const args = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra.items[extra.end..][0..extra.data.args_len]));
616 if (args.len + 1 <= bpi - 1) {615 if (args.len + 1 <= bpi - 1) {
617 var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);616 var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);
618 buf[0] = callee;617 buf[0] = call.callee;
619 @memcpy(buf[1..][0..args.len], args);618 @memcpy(buf[1..][0..args.len], args);
620 return analyzeOperands(a, pass, data, inst, buf);619 return analyzeOperands(a, pass, data, inst, buf);
621 }620 }
...@@ -627,7 +626,7 @@ fn analyzeInst(...@@ -627,7 +626,7 @@ fn analyzeInst(
627 i -= 1;626 i -= 1;
628 try big.feed(args[i]);627 try big.feed(args[i]);
629 }628 }
630 try big.feed(callee);629 try big.feed(call.callee);
631 return big.finish();630 return big.finish();
632 },631 },
633 .select => {632 .select => {
...@@ -708,18 +707,15 @@ fn analyzeInst(...@@ -708,18 +707,15 @@ fn analyzeInst(
708 .switch_dispatch => return analyzeInstSwitchDispatch(a, pass, data, inst),707 .switch_dispatch => return analyzeInstSwitchDispatch(a, pass, data, inst),
709708
710 .assembly => {709 .assembly => {
711 const extra = a.air.extraData(Air.Asm, inst_datas[@intFromEnum(inst)].ty_pl.payload);710 const unwrapped_asm = a.air.unwrapAsm(inst);
712 const outputs_len = extra.data.flags.outputs_len;711
713 var extra_i: usize = extra.end;712 const outputs = unwrapped_asm.outputs;
714 const outputs = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra.items[extra_i..][0..outputs_len]));713 const inputs = unwrapped_asm.inputs;
715 extra_i += outputs.len;
716 const inputs = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra.items[extra_i..][0..extra.data.inputs_len]));
717 extra_i += inputs.len;
718714
719 const num_operands = simple: {715 const num_operands = simple: {
720 var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);716 var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);
721 var buf_index: usize = 0;717 var buf_index: usize = 0;
722 for (outputs) |output| {718 for (unwrapped_asm.outputs) |output| {
723 if (output != .none) {719 if (output != .none) {
724 if (buf_index < buf.len) buf[buf_index] = output;720 if (buf_index < buf.len) buf[buf_index] = output;
725 buf_index += 1;721 buf_index += 1;
...@@ -748,15 +744,13 @@ fn analyzeInst(...@@ -748,15 +744,13 @@ fn analyzeInst(
748 }744 }
749 return big.finish();745 return big.finish();
750 },746 },
751747 .dbg_inline_block => {
752 inline .block, .dbg_inline_block => |comptime_tag| {748 const block = a.air.unwrapDbgBlock(inst);
753 const ty_pl = inst_datas[@intFromEnum(inst)].ty_pl;749 return analyzeInstBlock(a, pass, data, inst, block.ty, block.body);
754 const extra = a.air.extraData(switch (comptime_tag) {750 },
755 .block => Air.Block,751 .block => {
756 .dbg_inline_block => Air.DbgInlineBlock,752 const block = a.air.unwrapBlock(inst);
757 else => unreachable,753 return analyzeInstBlock(a, pass, data, inst, block.ty, block.body);
758 }, ty_pl.payload);
759 return analyzeInstBlock(a, pass, data, inst, ty_pl.ty, @ptrCast(a.air.extra.items[extra.end..][0..extra.data.body_len]));
760 },754 },
761 .loop => return analyzeInstLoop(a, pass, data, inst),755 .loop => return analyzeInstLoop(a, pass, data, inst),
762756
...@@ -778,8 +772,8 @@ fn analyzeInst(...@@ -778,8 +772,8 @@ fn analyzeInst(
778 },772 },
779773
780 .legalize_compiler_rt_call => {774 .legalize_compiler_rt_call => {
781 const extra = a.air.extraData(Air.Call, inst_datas[@intFromEnum(inst)].legalize_compiler_rt_call.payload);775 const rt_call = a.air.unwrapCompilerRtCall(inst);
782 const args: []const Air.Inst.Ref = @ptrCast(a.air.extra.items[extra.end..][0..extra.data.args_len]);776 const args = rt_call.args;
783 if (args.len <= bpi - 1) {777 if (args.len <= bpi - 1) {
784 var buf: [bpi - 1]Air.Inst.Ref = @splat(.none);778 var buf: [bpi - 1]Air.Inst.Ref = @splat(.none);
785 @memcpy(buf[0..args.len], args);779 @memcpy(buf[0..args.len], args);
...@@ -972,7 +966,7 @@ fn analyzeInstBlock(...@@ -972,7 +966,7 @@ fn analyzeInstBlock(
972 comptime pass: LivenessPass,966 comptime pass: LivenessPass,
973 data: *LivenessPassData(pass),967 data: *LivenessPassData(pass),
974 inst: Air.Inst.Index,968 inst: Air.Inst.Index,
975 ty: Air.Inst.Ref,969 ty: Type,
976 body: []const Air.Inst.Index,970 body: []const Air.Inst.Index,
977) !void {971) !void {
978 const gpa = a.gpa;972 const gpa = a.gpa;
...@@ -1005,7 +999,7 @@ fn analyzeInstBlock(...@@ -1005,7 +999,7 @@ fn analyzeInstBlock(
1005999
1006 // If the block is noreturn, block deaths not only aren't useful, they're impossible to1000 // If the block is noreturn, block deaths not only aren't useful, they're impossible to
1007 // find: there could be more stuff alive after the block than before it!1001 // find: there could be more stuff alive after the block than before it!
1008 if (!a.intern_pool.isNoReturn(ty.toType().toIntern())) {1002 if (!a.intern_pool.isNoReturn(ty.toIntern())) {
1009 // The block kills the difference in the live sets1003 // The block kills the difference in the live sets
1010 const block_scope = data.block_scopes.get(inst).?;1004 const block_scope = data.block_scopes.get(inst).?;
1011 const num_deaths = data.live_set.count() - block_scope.live_set.count();1005 const num_deaths = data.live_set.count() - block_scope.live_set.count();
...@@ -1139,9 +1133,8 @@ fn analyzeInstLoop(...@@ -1139,9 +1133,8 @@ fn analyzeInstLoop(
1139 data: *LivenessPassData(pass),1133 data: *LivenessPassData(pass),
1140 inst: Air.Inst.Index,1134 inst: Air.Inst.Index,
1141) !void {1135) !void {
1142 const inst_datas = a.air.instructions.items(.data);1136 const block = a.air.unwrapBlock(inst);
1143 const extra = a.air.extraData(Air.Block, inst_datas[@intFromEnum(inst)].ty_pl.payload);1137 const body = block.body;
1144 const body: []const Air.Inst.Index = @ptrCast(a.air.extra.items[extra.end..][0..extra.data.body_len]);
1145 const gpa = a.gpa;1138 const gpa = a.gpa;
11461139
1147 try analyzeOperands(a, pass, data, inst, .{ .none, .none, .none });1140 try analyzeOperands(a, pass, data, inst, .{ .none, .none, .none });
...@@ -1187,44 +1180,38 @@ fn analyzeInstCondBr(...@@ -1187,44 +1180,38 @@ fn analyzeInstCondBr(
1187 inst: Air.Inst.Index,1180 inst: Air.Inst.Index,
1188 comptime inst_type: enum { cond_br, @"try", try_ptr },1181 comptime inst_type: enum { cond_br, @"try", try_ptr },
1189) !void {1182) !void {
1190 const inst_datas = a.air.instructions.items(.data);
1191 const gpa = a.gpa;1183 const gpa = a.gpa;
11921184
1193 const extra = switch (inst_type) {1185 const unwrapped_cond = switch (inst_type) {
1194 .cond_br => a.air.extraData(Air.CondBr, inst_datas[@intFromEnum(inst)].pl_op.payload),1186 .cond_br => a.air.unwrapCondBr(inst),
1195 .@"try" => a.air.extraData(Air.Try, inst_datas[@intFromEnum(inst)].pl_op.payload),1187 .@"try" => a.air.unwrapTry(inst),
1196 .try_ptr => a.air.extraData(Air.TryPtr, inst_datas[@intFromEnum(inst)].ty_pl.payload),1188 .try_ptr => a.air.unwrapTryPtr(inst),
1197 };1189 };
11981190
1199 const condition = switch (inst_type) {1191 const condition = switch (inst_type) {
1200 .cond_br, .@"try" => inst_datas[@intFromEnum(inst)].pl_op.operand,1192 .cond_br => unwrapped_cond.condition,
1201 .try_ptr => extra.data.ptr,1193 .@"try" => unwrapped_cond.error_union,
1194 .try_ptr => unwrapped_cond.error_union_ptr,
1202 };1195 };
12031196
1204 const then_body: []const Air.Inst.Index = switch (inst_type) {1197 const then_body = switch (inst_type) {
1205 .cond_br => @ptrCast(a.air.extra.items[extra.end..][0..extra.data.then_body_len]),1198 .cond_br => unwrapped_cond.then_body,
1206 else => &.{}, // we won't use this1199 // The "then body" is just the remainder of this block
1200 else => &.{},
1207 };1201 };
12081202
1209 const else_body: []const Air.Inst.Index = @ptrCast(switch (inst_type) {1203 const else_body = switch (inst_type) {
1210 .cond_br => a.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len],1204 .cond_br, .@"try", .try_ptr => unwrapped_cond.else_body,
1211 .@"try", .try_ptr => a.air.extra.items[extra.end..][0..extra.data.body_len],1205 };
1212 });
12131206
1214 switch (pass) {1207 switch (pass) {
1215 .loop_analysis => {1208 .loop_analysis => {
1216 switch (inst_type) {1209 try analyzeBody(a, pass, data, then_body);
1217 .cond_br => try analyzeBody(a, pass, data, then_body),
1218 .@"try", .try_ptr => {},
1219 }
1220 try analyzeBody(a, pass, data, else_body);1210 try analyzeBody(a, pass, data, else_body);
1221 },1211 },
12221212
1223 .main_analysis => {1213 .main_analysis => {
1224 switch (inst_type) {1214 try analyzeBody(a, pass, data, then_body);
1225 .cond_br => try analyzeBody(a, pass, data, then_body),
1226 .@"try", .try_ptr => {}, // The "then body" is just the remainder of this block
1227 }
1228 var then_live = data.live_set.move();1215 var then_live = data.live_set.move();
1229 defer then_live.deinit(gpa);1216 defer then_live.deinit(gpa);
12301217
src/Air/Liveness/Verify.zig+24-46
...@@ -345,37 +345,26 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -345,37 +345,26 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
345 try self.verifyInst(inst);345 try self.verifyInst(inst);
346 },346 },
347 .call, .call_always_tail, .call_never_tail, .call_never_inline => {347 .call, .call_always_tail, .call_never_tail, .call_never_inline => {
348 const pl_op = data[@intFromEnum(inst)].pl_op;348 const call = self.air.unwrapCall(inst);
349 const extra = self.air.extraData(Air.Call, pl_op.payload);349 const args = call.args;
350 const args = @as(
351 []const Air.Inst.Ref,
352 @ptrCast(self.air.extra.items[extra.end..][0..extra.data.args_len]),
353 );
354350
355 var bt = self.liveness.iterateBigTomb(inst);351 var bt = self.liveness.iterateBigTomb(inst);
356 try self.verifyOperand(inst, pl_op.operand, bt.feed());352 try self.verifyOperand(inst, call.callee, bt.feed());
357 for (args) |arg| {353 for (args) |arg| {
358 try self.verifyOperand(inst, arg, bt.feed());354 try self.verifyOperand(inst, arg, bt.feed());
359 }355 }
360 try self.verifyInst(inst);356 try self.verifyInst(inst);
361 },357 },
362 .assembly => {358 .assembly => {
363 const ty_pl = data[@intFromEnum(inst)].ty_pl;359 const unwrapped_asm = self.air.unwrapAsm(inst);
364 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
365 const outputs_len = extra.data.flags.outputs_len;
366 var extra_i = extra.end;
367 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..outputs_len]);
368 extra_i += outputs.len;
369 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
370 extra_i += inputs.len;
371360
372 var bt = self.liveness.iterateBigTomb(inst);361 var bt = self.liveness.iterateBigTomb(inst);
373 for (outputs) |output| {362 for (unwrapped_asm.outputs) |output| {
374 if (output != .none) {363 if (output != .none) {
375 try self.verifyOperand(inst, output, bt.feed());364 try self.verifyOperand(inst, output, bt.feed());
376 }365 }
377 }366 }
378 for (inputs) |input| {367 for (unwrapped_asm.inputs) |input| {
379 try self.verifyOperand(inst, input, bt.feed());368 try self.verifyOperand(inst, input, bt.feed());
380 }369 }
381 try self.verifyInst(inst);370 try self.verifyInst(inst);
...@@ -383,13 +372,12 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -383,13 +372,12 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
383372
384 // control flow373 // control flow
385 .@"try", .try_cold => {374 .@"try", .try_cold => {
386 const pl_op = data[@intFromEnum(inst)].pl_op;375 const unwrapped_try = self.air.unwrapTry(inst);
387 const extra = self.air.extraData(Air.Try, pl_op.payload);376 const try_body = unwrapped_try.else_body;
388 const try_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);
389377
390 const cond_br_liveness = self.liveness.getCondBr(inst);378 const cond_br_liveness = self.liveness.getCondBr(inst);
391379
392 try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));380 try self.verifyOperand(inst, unwrapped_try.error_union, self.liveness.operandDies(inst, 0));
393381
394 var live = try self.live.clone(self.gpa);382 var live = try self.live.clone(self.gpa);
395 defer live.deinit(self.gpa);383 defer live.deinit(self.gpa);
...@@ -405,13 +393,12 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -405,13 +393,12 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
405 try self.verifyInst(inst);393 try self.verifyInst(inst);
406 },394 },
407 .try_ptr, .try_ptr_cold => {395 .try_ptr, .try_ptr_cold => {
408 const ty_pl = data[@intFromEnum(inst)].ty_pl;396 const unwrapped_try = self.air.unwrapTryPtr(inst);
409 const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);397 const try_body = unwrapped_try.else_body;
410 const try_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);
411398
412 const cond_br_liveness = self.liveness.getCondBr(inst);399 const cond_br_liveness = self.liveness.getCondBr(inst);
413400
414 try self.verifyOperand(inst, extra.data.ptr, self.liveness.operandDies(inst, 0));401 try self.verifyOperand(inst, unwrapped_try.error_union_ptr, self.liveness.operandDies(inst, 0));
415402
416 var live = try self.live.clone(self.gpa);403 var live = try self.live.clone(self.gpa);
417 defer live.deinit(self.gpa);404 defer live.deinit(self.gpa);
...@@ -458,17 +445,11 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -458,17 +445,11 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
458 .block, .dbg_inline_block => |tag| {445 .block, .dbg_inline_block => |tag| {
459 const ty_pl = data[@intFromEnum(inst)].ty_pl;446 const ty_pl = data[@intFromEnum(inst)].ty_pl;
460 const block_ty = ty_pl.ty.toType();447 const block_ty = ty_pl.ty.toType();
461 const block_body: []const Air.Inst.Index = @ptrCast(switch (tag) {448 const block_body = switch (tag) {
462 inline .block, .dbg_inline_block => |comptime_tag| body: {449 .block => self.air.unwrapBlock(inst).body,
463 const extra = self.air.extraData(switch (comptime_tag) {450 .dbg_inline_block => self.air.unwrapDbgBlock(inst).body,
464 .block => Air.Block,
465 .dbg_inline_block => Air.DbgInlineBlock,
466 else => unreachable,
467 }, ty_pl.payload);
468 break :body self.air.extra.items[extra.end..][0..extra.data.body_len];
469 },
470 else => unreachable,451 else => unreachable,
471 });452 };
472 const block_liveness = self.liveness.getBlock(inst);453 const block_liveness = self.liveness.getBlock(inst);
473454
474 var orig_live = try self.live.clone(self.gpa);455 var orig_live = try self.live.clone(self.gpa);
...@@ -501,9 +482,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -501,9 +482,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
501 try self.verifyInstOperands(inst, .{ .none, .none, .none });482 try self.verifyInstOperands(inst, .{ .none, .none, .none });
502 },483 },
503 .loop => {484 .loop => {
504 const ty_pl = data[@intFromEnum(inst)].ty_pl;485 const block = self.air.unwrapBlock(inst);
505 const extra = self.air.extraData(Air.Block, ty_pl.payload);
506 const loop_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);
507486
508 // The same stuff should be alive after the loop as before it.487 // The same stuff should be alive after the loop as before it.
509 const gop = try self.loops.getOrPut(self.gpa, inst);488 const gop = try self.loops.getOrPut(self.gpa, inst);
...@@ -514,18 +493,17 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -514,18 +493,17 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
514 }493 }
515 gop.value_ptr.* = try self.live.clone(self.gpa);494 gop.value_ptr.* = try self.live.clone(self.gpa);
516495
517 try self.verifyBody(loop_body);496 try self.verifyBody(block.body);
518497
519 try self.verifyInstOperands(inst, .{ .none, .none, .none });498 try self.verifyInstOperands(inst, .{ .none, .none, .none });
520 },499 },
521 .cond_br => {500 .cond_br => {
522 const pl_op = data[@intFromEnum(inst)].pl_op;501 const cond_br = self.air.unwrapCondBr(inst);
523 const extra = self.air.extraData(Air.CondBr, pl_op.payload);502 const then_body = cond_br.then_body;
524 const then_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.then_body_len]);503 const else_body = cond_br.else_body;
525 const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
526 const cond_br_liveness = self.liveness.getCondBr(inst);504 const cond_br_liveness = self.liveness.getCondBr(inst);
527505
528 try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));506 try self.verifyOperand(inst, cond_br.condition, self.liveness.operandDies(inst, 0));
529507
530 var live = try self.live.clone(self.gpa);508 var live = try self.live.clone(self.gpa);
531 defer live.deinit(self.gpa);509 defer live.deinit(self.gpa);
...@@ -589,8 +567,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -589,8 +567,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
589 try self.verifyInstOperands(inst, .{ pl_op.operand, bin.lhs, bin.rhs });567 try self.verifyInstOperands(inst, .{ pl_op.operand, bin.lhs, bin.rhs });
590 },568 },
591 .legalize_compiler_rt_call => {569 .legalize_compiler_rt_call => {
592 const extra = self.air.extraData(Air.Call, data[@intFromEnum(inst)].legalize_compiler_rt_call.payload);570 const rt_call = self.air.unwrapCompilerRtCall(inst);
593 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.args_len]);571 const args = rt_call.args;
594 var bt = self.liveness.iterateBigTomb(inst);572 var bt = self.liveness.iterateBigTomb(inst);
595 for (args) |arg| {573 for (args) |arg| {
596 try self.verifyOperand(inst, arg, bt.feed());574 try self.verifyOperand(inst, arg, bt.feed());
src/Air/print.zig+52-86
...@@ -395,25 +395,17 @@ const Writer = struct {...@@ -395,25 +395,17 @@ const Writer = struct {
395 fn writeBlock(w: *Writer, s: *std.Io.Writer, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void {395 fn writeBlock(w: *Writer, s: *std.Io.Writer, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void {
396 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;396 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
397 try w.writeType(s, ty_pl.ty.toType());397 try w.writeType(s, ty_pl.ty.toType());
398 const body: []const Air.Inst.Index = @ptrCast(switch (tag) {398
399 inline .block, .dbg_inline_block => |comptime_tag| body: {399 const body = switch (tag) {
400 const extra = w.air.extraData(switch (comptime_tag) {400 .block => w.air.unwrapBlock(inst).body,
401 .block => Air.Block,401 .dbg_inline_block => body: {
402 .dbg_inline_block => Air.DbgInlineBlock,402 const dbg_block = w.air.unwrapDbgBlock(inst);
403 else => unreachable,403 try s.writeAll(", ");
404 }, ty_pl.payload);404 try w.writeInstRef(s, Air.internedToRef(dbg_block.func), false);
405 switch (comptime_tag) {405 break :body dbg_block.body;
406 .block => {},
407 .dbg_inline_block => {
408 try s.writeAll(", ");
409 try w.writeInstRef(s, Air.internedToRef(extra.data.func), false);
410 },
411 else => unreachable,
412 }
413 break :body w.air.extra.items[extra.end..][0..extra.data.body_len];
414 },406 },
415 else => unreachable,407 else => unreachable,
416 });408 };
417 if (w.skip_body) return s.writeAll(", ...");409 if (w.skip_body) return s.writeAll(", ...");
418 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|410 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
419 liveness.getBlock(inst)411 liveness.getBlock(inst)
...@@ -434,16 +426,14 @@ const Writer = struct {...@@ -434,16 +426,14 @@ const Writer = struct {
434 }426 }
435427
436 fn writeLoop(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {428 fn writeLoop(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
437 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;429 const block = w.air.unwrapBlock(inst);
438 const extra = w.air.extraData(Air.Block, ty_pl.payload);
439 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
440430
441 try w.writeType(s, ty_pl.ty.toType());431 try w.writeType(s, block.ty);
442 if (w.skip_body) return s.writeAll(", ...");432 if (w.skip_body) return s.writeAll(", ...");
443 try s.writeAll(", {\n");433 try s.writeAll(", {\n");
444 const old_indent = w.indent;434 const old_indent = w.indent;
445 w.indent += 2;435 w.indent += 2;
446 try w.writeBody(s, body);436 try w.writeBody(s, block.body);
447 w.indent = old_indent;437 w.indent = old_indent;
448 try s.splatByteAll(' ', w.indent);438 try s.splatByteAll(' ', w.indent);
449 try s.writeAll("}");439 try s.writeAll("}");
...@@ -532,11 +522,10 @@ const Writer = struct {...@@ -532,11 +522,10 @@ const Writer = struct {
532 }522 }
533523
534 fn writeLegalizeCompilerRtCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {524 fn writeLegalizeCompilerRtCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
535 const inst_data = w.air.instructions.items(.data)[@intFromEnum(inst)].legalize_compiler_rt_call;525 const rt_call = w.air.unwrapCompilerRtCall(inst);
536 const extra = w.air.extraData(Air.Call, inst_data.payload);526 const args = rt_call.args;
537 const args: []const Air.Inst.Ref = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len]);
538527
539 try s.print("{t}, [", .{inst_data.func});528 try s.print("{t}, [", .{rt_call.func});
540 for (args, 0..) |arg, i| {529 for (args, 0..) |arg, i| {
541 if (i != 0) try s.writeAll(", ");530 if (i != 0) try s.writeAll(", ");
542 try w.writeOperand(s, inst, i, arg);531 try w.writeOperand(s, inst, i, arg);
...@@ -666,11 +655,8 @@ const Writer = struct {...@@ -666,11 +655,8 @@ const Writer = struct {
666 }655 }
667656
668 fn writeAssembly(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {657 fn writeAssembly(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
669 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;658 const unwrapped_asm = w.air.unwrapAsm(inst);
670 const extra = w.air.extraData(Air.Asm, ty_pl.payload);659 const is_volatile = unwrapped_asm.is_volatile;
671 const is_volatile = extra.data.flags.is_volatile;
672 const outputs_len = extra.data.flags.outputs_len;
673 var extra_i: usize = extra.end;
674 var op_index: usize = 0;660 var op_index: usize = 0;
675661
676 const ret_ty = w.typeOfIndex(inst);662 const ret_ty = w.typeOfIndex(inst);
...@@ -680,49 +666,33 @@ const Writer = struct {...@@ -680,49 +666,33 @@ const Writer = struct {
680 try s.writeAll(", volatile");666 try s.writeAll(", volatile");
681 }667 }
682668
683 const outputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..outputs_len]));669 var it = unwrapped_asm.iterateOutputs();
684 extra_i += outputs.len;670 while (it.next()) |out| {
685 const inputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.inputs_len]));671 const name = out.name;
686 extra_i += inputs.len;672 const constraint = out.constraint;
687673 if (out.operand == .none) {
688 for (outputs) |output| {
689 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
690 const constraint = std.mem.sliceTo(extra_bytes, 0);
691 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
692
693 // This equation accounts for the fact that even if we have exactly 4 bytes
694 // for the strings and their null terminators, we still use the next u32
695 // for the null terminator.
696 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
697
698 if (output == .none) {
699 try s.print(", [{s}] -> {s}", .{ name, constraint });674 try s.print(", [{s}] -> {s}", .{ name, constraint });
700 } else {675 } else {
701 try s.print(", [{s}] out {s} = (", .{ name, constraint });676 try s.print(", [{s}] out {s} = (", .{ name, constraint });
702 try w.writeOperand(s, inst, op_index, output);677 try w.writeOperand(s, inst, op_index, out.operand);
703 op_index += 1;678 op_index += 1;
704 try s.writeByte(')');679 try s.writeByte(')');
705 }680 }
706 }681 }
707682
708 for (inputs) |input| {683 it = unwrapped_asm.iterateInputs();
709 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);684 while (it.next()) |in| {
710 const constraint = std.mem.sliceTo(extra_bytes, 0);685 const name = in.name;
711 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);686 const constraint = in.constraint;
712 // This equation accounts for the fact that even if we have exactly 4 bytes
713 // for the strings and their null terminators, we still use the next u32
714 // for the null terminator.
715 extra_i += (constraint.len + name.len + 1) / 4 + 1;
716
717 try s.print(", [{s}] in {s} = (", .{ name, constraint });687 try s.print(", [{s}] in {s} = (", .{ name, constraint });
718 try w.writeOperand(s, inst, op_index, input);688 try w.writeOperand(s, inst, op_index, in.operand);
719 op_index += 1;689 op_index += 1;
720 try s.writeByte(')');690 try s.writeByte(')');
721 }691 }
722692
723 const zcu = w.pt.zcu;693 const zcu = w.pt.zcu;
724 const ip = &zcu.intern_pool;694 const ip = &zcu.intern_pool;
725 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;695 const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
726 const struct_type: Type = .fromInterned(aggregate.ty);696 const struct_type: Type = .fromInterned(aggregate.ty);
727 switch (aggregate.storage) {697 switch (aggregate.storage) {
728 .elems => |elems| for (elems, 0..) |elem, i| {698 .elems => |elems| for (elems, 0..) |elem, i| {
...@@ -750,7 +720,7 @@ const Writer = struct {...@@ -750,7 +720,7 @@ const Writer = struct {
750 try s.print(", {x}", .{bytes});720 try s.print(", {x}", .{bytes});
751 },721 },
752 }722 }
753 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];723 const asm_source = unwrapped_asm.source;
754 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});724 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});
755 }725 }
756726
...@@ -767,10 +737,9 @@ const Writer = struct {...@@ -767,10 +737,9 @@ const Writer = struct {
767 }737 }
768738
769 fn writeCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {739 fn writeCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
770 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;740 const call = w.air.unwrapCall(inst);
771 const extra = w.air.extraData(Air.Call, pl_op.payload);741 const args = call.args;
772 const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len]));742 try w.writeOperand(s, inst, 0, call.callee);
773 try w.writeOperand(s, inst, 0, pl_op.operand);
774 try s.writeAll(", [");743 try s.writeAll(", [");
775 for (args, 0..) |arg, i| {744 for (args, 0..) |arg, i| {
776 if (i != 0) try s.writeAll(", ");745 if (i != 0) try s.writeAll(", ");
...@@ -792,15 +761,14 @@ const Writer = struct {...@@ -792,15 +761,14 @@ const Writer = struct {
792 }761 }
793762
794 fn writeTry(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {763 fn writeTry(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
795 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;764 const unwrapped_try = w.air.unwrapTry(inst);
796 const extra = w.air.extraData(Air.Try, pl_op.payload);765 const body = unwrapped_try.else_body;
797 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
798 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|766 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
799 liveness.getCondBr(inst)767 liveness.getCondBr(inst)
800 else768 else
801 .{ .then_deaths = &.{}, .else_deaths = &.{} };769 .{ .then_deaths = &.{}, .else_deaths = &.{} };
802770
803 try w.writeOperand(s, inst, 0, pl_op.operand);771 try w.writeOperand(s, inst, 0, unwrapped_try.error_union);
804 if (w.skip_body) return s.writeAll(", ...");772 if (w.skip_body) return s.writeAll(", ...");
805 try s.writeAll(", {\n");773 try s.writeAll(", {\n");
806 const old_indent = w.indent;774 const old_indent = w.indent;
...@@ -826,18 +794,17 @@ const Writer = struct {...@@ -826,18 +794,17 @@ const Writer = struct {
826 }794 }
827795
828 fn writeTryPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {796 fn writeTryPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
829 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;797 const unwrapped_try = w.air.unwrapTryPtr(inst);
830 const extra = w.air.extraData(Air.TryPtr, ty_pl.payload);798 const body = unwrapped_try.else_body;
831 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
832 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|799 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
833 liveness.getCondBr(inst)800 liveness.getCondBr(inst)
834 else801 else
835 .{ .then_deaths = &.{}, .else_deaths = &.{} };802 .{ .then_deaths = &.{}, .else_deaths = &.{} };
836803
837 try w.writeOperand(s, inst, 0, extra.data.ptr);804 try w.writeOperand(s, inst, 0, unwrapped_try.error_union_ptr);
838805
839 try s.writeAll(", ");806 try s.writeAll(", ");
840 try w.writeType(s, ty_pl.ty.toType());807 try w.writeType(s, unwrapped_try.error_union_payload_ptr_ty.toType());
841 if (w.skip_body) return s.writeAll(", ...");808 if (w.skip_body) return s.writeAll(", ...");
842 try s.writeAll(", {\n");809 try s.writeAll(", {\n");
843 const old_indent = w.indent;810 const old_indent = w.indent;
...@@ -863,23 +830,22 @@ const Writer = struct {...@@ -863,23 +830,22 @@ const Writer = struct {
863 }830 }
864831
865 fn writeCondBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {832 fn writeCondBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
866 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;833 const cond_br = w.air.unwrapCondBr(inst);
867 const extra = w.air.extraData(Air.CondBr, pl_op.payload);834 const then_body = cond_br.then_body;
868 const then_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.then_body_len]);835 const else_body = cond_br.else_body;
869 const else_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
870 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|836 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
871 liveness.getCondBr(inst)837 liveness.getCondBr(inst)
872 else838 else
873 .{ .then_deaths = &.{}, .else_deaths = &.{} };839 .{ .then_deaths = &.{}, .else_deaths = &.{} };
874840
875 try w.writeOperand(s, inst, 0, pl_op.operand);841 try w.writeOperand(s, inst, 0, cond_br.condition);
876 if (w.skip_body) return s.writeAll(", ...");842 if (w.skip_body) return s.writeAll(", ...");
877 try s.writeAll(",");843 try s.writeAll(",");
878 if (extra.data.branch_hints.true != .none) {844 if (cond_br.branch_hints.true != .none) {
879 try s.print(" {s}", .{@tagName(extra.data.branch_hints.true)});845 try s.print(" {s}", .{@tagName(cond_br.branch_hints.true)});
880 }846 }
881 if (extra.data.branch_hints.then_cov != .none) {847 if (cond_br.branch_hints.then_cov != .none) {
882 try s.print(" {s}", .{@tagName(extra.data.branch_hints.then_cov)});848 try s.print(" {s}", .{@tagName(cond_br.branch_hints.then_cov)});
883 }849 }
884 try s.writeAll(" {\n");850 try s.writeAll(" {\n");
885 const old_indent = w.indent;851 const old_indent = w.indent;
...@@ -897,11 +863,11 @@ const Writer = struct {...@@ -897,11 +863,11 @@ const Writer = struct {
897 try w.writeBody(s, then_body);863 try w.writeBody(s, then_body);
898 try s.splatByteAll(' ', old_indent);864 try s.splatByteAll(' ', old_indent);
899 try s.writeAll("},");865 try s.writeAll("},");
900 if (extra.data.branch_hints.false != .none) {866 if (cond_br.branch_hints.false != .none) {
901 try s.print(" {s}", .{@tagName(extra.data.branch_hints.false)});867 try s.print(" {s}", .{@tagName(cond_br.branch_hints.false)});
902 }868 }
903 if (extra.data.branch_hints.else_cov != .none) {869 if (cond_br.branch_hints.else_cov != .none) {
904 try s.print(" {s}", .{@tagName(extra.data.branch_hints.else_cov)});870 try s.print(" {s}", .{@tagName(cond_br.branch_hints.else_cov)});
905 }871 }
906 try s.writeAll(" {\n");872 try s.writeAll(" {\n");
907873
src/Air/types_resolved.zig+26-26
...@@ -170,21 +170,21 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {...@@ -170,21 +170,21 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
170 .block,170 .block,
171 .loop,171 .loop,
172 => {172 => {
173 const extra = air.extraData(Air.Block, data.ty_pl.payload);173 const block = air.unwrapBlock(inst);
174 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;174 if (!checkType(block.ty, zcu)) return false;
175 if (!checkBody(175 if (!checkBody(
176 air,176 air,
177 @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]),177 block.body,
178 zcu,178 zcu,
179 )) return false;179 )) return false;
180 },180 },
181181
182 .dbg_inline_block => {182 .dbg_inline_block => {
183 const extra = air.extraData(Air.DbgInlineBlock, data.ty_pl.payload);183 const block = air.unwrapDbgBlock(inst);
184 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;184 if (!checkType(block.ty, zcu)) return false;
185 if (!checkBody(185 if (!checkBody(
186 air,186 air,
187 @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]),187 block.body,
188 zcu,188 zcu,
189 )) return false;189 )) return false;
190 },190 },
...@@ -342,9 +342,9 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {...@@ -342,9 +342,9 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
342 .call_never_tail,342 .call_never_tail,
343 .call_never_inline,343 .call_never_inline,
344 => {344 => {
345 const extra = air.extraData(Air.Call, data.pl_op.payload);345 const call = air.unwrapCall(inst);
346 const args: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len]);346 const args = call.args;
347 if (!checkRef(data.pl_op.operand, zcu)) return false;347 if (!checkRef(call.callee, zcu)) return false;
348 for (args) |arg| if (!checkRef(arg, zcu)) return false;348 for (args) |arg| if (!checkRef(arg, zcu)) return false;
349 },349 },
350350
...@@ -356,37 +356,37 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {...@@ -356,37 +356,37 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
356 },356 },
357357
358 .@"try", .try_cold => {358 .@"try", .try_cold => {
359 const extra = air.extraData(Air.Try, data.pl_op.payload);359 const unwrapped_try = air.unwrapTry(inst);
360 if (!checkRef(data.pl_op.operand, zcu)) return false;360 if (!checkRef(unwrapped_try.error_union, zcu)) return false;
361 if (!checkBody(361 if (!checkBody(
362 air,362 air,
363 @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]),363 unwrapped_try.else_body,
364 zcu,364 zcu,
365 )) return false;365 )) return false;
366 },366 },
367367
368 .try_ptr, .try_ptr_cold => {368 .try_ptr, .try_ptr_cold => {
369 const extra = air.extraData(Air.TryPtr, data.ty_pl.payload);369 const unwrapped_try = air.unwrapTryPtr(inst);
370 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;370 if (!checkType(unwrapped_try.error_union_payload_ptr_ty.toType(), zcu)) return false;
371 if (!checkRef(extra.data.ptr, zcu)) return false;371 if (!checkRef(unwrapped_try.error_union_ptr, zcu)) return false;
372 if (!checkBody(372 if (!checkBody(
373 air,373 air,
374 @ptrCast(air.extra.items[extra.end..][0..extra.data.body_len]),374 unwrapped_try.else_body,
375 zcu,375 zcu,
376 )) return false;376 )) return false;
377 },377 },
378378
379 .cond_br => {379 .cond_br => {
380 const extra = air.extraData(Air.CondBr, data.pl_op.payload);380 const cond_br = air.unwrapCondBr(inst);
381 if (!checkRef(data.pl_op.operand, zcu)) return false;381 if (!checkRef(cond_br.condition, zcu)) return false;
382 if (!checkBody(382 if (!checkBody(
383 air,383 air,
384 @ptrCast(air.extra.items[extra.end..][0..extra.data.then_body_len]),384 cond_br.then_body,
385 zcu,385 zcu,
386 )) return false;386 )) return false;
387 if (!checkBody(387 if (!checkBody(
388 air,388 air,
389 @ptrCast(air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]),389 cond_br.else_body,
390 zcu,390 zcu,
391 )) return false;391 )) return false;
392 },392 },
...@@ -407,20 +407,20 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {...@@ -407,20 +407,20 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
407 },407 },
408408
409 .assembly => {409 .assembly => {
410 const extra = air.extraData(Air.Asm, data.ty_pl.payload);410 const unwrapped_asm = air.unwrapAsm(inst);
411 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;411 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
412 // Luckily, we only care about the inputs and outputs, so we don't have to do412 // Luckily, we only care about the inputs and outputs, so we don't have to do
413 // the whole null-terminated string dance.413 // the whole null-terminated string dance.
414 const outputs_len = extra.data.flags.outputs_len;414 const outputs = unwrapped_asm.outputs;
415 const outputs: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..outputs_len]);415 const inputs = unwrapped_asm.inputs;
416 const inputs: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end + outputs_len ..][0..extra.data.inputs_len]);416
417 for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false;417 for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false;
418 for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;418 for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;
419 },419 },
420420
421 .legalize_compiler_rt_call => {421 .legalize_compiler_rt_call => {
422 const extra = air.extraData(Air.Call, data.legalize_compiler_rt_call.payload);422 const rt_call = air.unwrapCompilerRtCall(inst);
423 const args: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len]);423 const args = rt_call.args;
424 for (args) |arg| if (!checkRef(arg, zcu)) return false;424 for (args) |arg| if (!checkRef(arg, zcu)) return false;
425 },425 },
426426
src/Sema.zig+6-6
...@@ -16226,6 +16226,12 @@ fn zirAsm(...@@ -16226,6 +16226,12 @@ fn zirAsm(
16226 });16226 });
16227 sema.appendRefsAssumeCapacity(out_args);16227 sema.appendRefsAssumeCapacity(out_args);
16228 sema.appendRefsAssumeCapacity(args);16228 sema.appendRefsAssumeCapacity(args);
16229 {
16230 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
16231 @memcpy(buffer[0..asm_source.len], asm_source);
16232 buffer[asm_source.len] = 0;
16233 sema.air_extra.items.len += asm_source.len / 4 + 1;
16234 }
16229 for (outputs) |o| {16235 for (outputs) |o| {
16230 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());16236 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
16231 @memcpy(buffer[0..o.c.len], o.c);16237 @memcpy(buffer[0..o.c.len], o.c);
...@@ -16242,12 +16248,6 @@ fn zirAsm(...@@ -16242,12 +16248,6 @@ fn zirAsm(
16242 buffer[input.c.len + 1 + input.n.len] = 0;16248 buffer[input.c.len + 1 + input.n.len] = 0;
16243 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;16249 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;
16244 }16250 }
16245 {
16246 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
16247 @memcpy(buffer[0..asm_source.len], asm_source);
16248 buffer[asm_source.len] = 0;
16249 sema.air_extra.items.len += asm_source.len / 4 + 1;
16250 }
16251 return asm_air;16251 return asm_air;
16252}16252}
1625316253
src/codegen/aarch64/Select.zig+86-112
...@@ -274,10 +274,9 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -274,10 +274,9 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
274 },274 },
275 .assembly => {275 .assembly => {
276 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;276 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
277 const extra = isel.air.extraData(Air.Asm, ty_pl.payload);277 const unwrapped_asm = isel.air.unwrapAsm(air_inst_index);
278 const operands: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0 .. extra.data.flags.outputs_len + extra.data.inputs_len]);
279278
280 for (operands) |operand| if (operand != .none) try isel.analyzeUse(operand);279 for (unwrapped_asm.outputs) |operand| if (operand != .none) try isel.analyzeUse(operand);
281 if (ty_pl.ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {});280 if (ty_pl.ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {});
282281
283 air_body_index += 1;282 air_body_index += 1;
...@@ -355,23 +354,23 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -355,23 +354,23 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
355 continue :air_tag air_tags[@intFromEnum(air_inst_index)];354 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
356 },355 },
357 inline .block, .dbg_inline_block => |air_tag| {356 inline .block, .dbg_inline_block => |air_tag| {
358 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;357 const air_body_block = switch (air_tag) {
359 const extra = isel.air.extraData(switch (air_tag) {
360 else => comptime unreachable,358 else => comptime unreachable,
361 .block => Air.Block,359 .block => isel.air.unwrapBlock(air_inst_index),
362 .dbg_inline_block => Air.DbgInlineBlock,360 .dbg_inline_block => isel.air.unwrapDbgBlock(air_inst_index),
363 }, ty_pl.payload);361 };
364 const result_ty = ty_pl.ty.toInterned().?;362
363 const result_ty = air_body_block.ty.toIntern();
365364
366 if (result_ty == .noreturn_type) {365 if (result_ty == .noreturn_type) {
367 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));366 try isel.analyze(air_body_block.body);
368367
369 air_body_index += 1;368 air_body_index += 1;
370 break :air_tag;369 break :air_tag;
371 }370 }
372371
373 assert(!(try isel.blocks.getOrPut(gpa, air_inst_index)).found_existing);372 assert(!(try isel.blocks.getOrPut(gpa, air_inst_index)).found_existing);
374 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));373 try isel.analyze(air_body_block.body);
375 const block_entry = isel.blocks.pop().?;374 const block_entry = isel.blocks.pop().?;
376 assert(block_entry.key == air_inst_index);375 assert(block_entry.key == air_inst_index);
377376
...@@ -382,8 +381,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -382,8 +381,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
382 continue :air_tag air_tags[@intFromEnum(air_inst_index)];381 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
383 },382 },
384 .loop => {383 .loop => {
385 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;384 const air_body_block = isel.air.unwrapBlock(air_inst_index);
386 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
387385
388 const initial_dom_start = isel.dom_start;386 const initial_dom_start = isel.dom_start;
389 const initial_dom_len = isel.dom_len;387 const initial_dom_len = isel.dom_len;
...@@ -399,7 +397,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -399,7 +397,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
399 .repeat_list = undefined,397 .repeat_list = undefined,
400 });398 });
401 try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable);399 try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable);
402 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));400 try isel.analyze(air_body_block.body);
403 for (401 for (
404 isel.dom.items[initial_dom_start..].ptr,402 isel.dom.items[initial_dom_start..].ptr,
405 isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable],403 isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable],
...@@ -429,18 +427,17 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -429,18 +427,17 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
429 .call_never_tail,427 .call_never_tail,
430 .call_never_inline,428 .call_never_inline,
431 => {429 => {
432 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;430 const air_call = isel.air.unwrapCall(air_inst_index);
433 const extra = isel.air.extraData(Air.Call, pl_op.payload);431 const args = air_call.args;
434 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
435 isel.saved_registers.insert(.lr);432 isel.saved_registers.insert(.lr);
436 const callee_ty = isel.air.typeOf(pl_op.operand, ip);433 const callee_ty = isel.air.typeOf(air_call.callee, ip);
437 const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {434 const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {
438 else => unreachable,435 else => unreachable,
439 .func_type => |func_type| func_type,436 .func_type => |func_type| func_type,
440 .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type,437 .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type,
441 };438 };
442439
443 try isel.analyzeUse(pl_op.operand);440 try isel.analyzeUse(air_call.callee);
444 var param_it: CallAbiIterator = .init;441 var param_it: CallAbiIterator = .init;
445 for (args, 0..) |arg, arg_index| {442 for (args, 0..) |arg, arg_index| {
446 const restore_values_len = isel.values.items.len;443 const restore_values_len = isel.values.items.len;
...@@ -549,13 +546,12 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -549,13 +546,12 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
549 continue :air_tag air_tags[@intFromEnum(air_inst_index)];546 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
550 },547 },
551 .cond_br => {548 .cond_br => {
552 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;549 const cond_br = isel.air.unwrapCondBr(air_inst_index);
553 const extra = isel.air.extraData(Air.CondBr, pl_op.payload);
554550
555 try isel.analyzeUse(pl_op.operand);551 try isel.analyzeUse(cond_br.condition);
556552
557 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len]));553 try isel.analyze(cond_br.then_body);
558 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]));554 try isel.analyze(cond_br.else_body);
559555
560 air_body_index += 1;556 air_body_index += 1;
561 },557 },
...@@ -610,11 +606,10 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -610,11 +606,10 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
610 air_body_index += 1;606 air_body_index += 1;
611 },607 },
612 .@"try", .try_cold => {608 .@"try", .try_cold => {
613 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;609 const unwrapped_try = isel.air.unwrapTry(air_inst_index);
614 const extra = isel.air.extraData(Air.Try, pl_op.payload);
615610
616 try isel.analyzeUse(pl_op.operand);611 try isel.analyzeUse(unwrapped_try.error_union);
617 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));612 try isel.analyze(unwrapped_try.else_body);
618 try isel.def_order.putNoClobber(gpa, air_inst_index, {});613 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
619614
620 air_body_index += 1;615 air_body_index += 1;
...@@ -622,11 +617,10 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -622,11 +617,10 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
622 continue :air_tag air_tags[@intFromEnum(air_inst_index)];617 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
623 },618 },
624 .try_ptr, .try_ptr_cold => {619 .try_ptr, .try_ptr_cold => {
625 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;620 const unwrapped_try = isel.air.unwrapTryPtr(air_inst_index);
626 const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload);
627621
628 try isel.analyzeUse(extra.data.ptr);622 try isel.analyzeUse(unwrapped_try.error_union_ptr);
629 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));623 try isel.analyze(unwrapped_try.else_body);
630 try isel.def_order.putNoClobber(gpa, air_inst_index, {});624 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
631625
632 air_body_index += 1;626 air_body_index += 1;
...@@ -2698,12 +2692,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2698,12 +2692,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2698 .inferred_alloc, .inferred_alloc_comptime => unreachable,2692 .inferred_alloc, .inferred_alloc_comptime => unreachable,
2699 .assembly => {2693 .assembly => {
2700 const ty_pl = air.data(air.inst_index).ty_pl;2694 const ty_pl = air.data(air.inst_index).ty_pl;
2701 const extra = isel.air.extraData(Air.Asm, ty_pl.payload);2695 const unwrapped_asm = isel.air.unwrapAsm(air.inst_index);
2702 var extra_index = extra.end;2696 const inputs = unwrapped_asm.inputs;
2703 const outputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.flags.outputs_len]);
2704 extra_index += outputs.len;
2705 const inputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.inputs_len]);
2706 extra_index += inputs.len;
27072697
2708 var as: codegen.aarch64.Assemble = .{2698 var as: codegen.aarch64.Assemble = .{
2709 .source = undefined,2699 .source = undefined,
...@@ -2711,15 +2701,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2711,15 +2701,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2711 };2701 };
2712 defer as.operands.deinit(gpa);2702 defer as.operands.deinit(gpa);
27132703
2714 for (outputs) |output| {2704 var it = unwrapped_asm.iterateOutputs();
2715 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);2705 while (it.next()) |output| {
2716 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]), 0);2706 const constraint = output.constraint;
2717 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);2707 const name = output.name;
2718 // This equation accounts for the fact that even if we have exactly 4 bytes
2719 // for the string, we still use the next u32 for the null terminator.
2720 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
27212708
2722 switch (output) {2709 switch (output.operand) {
2723 else => return isel.fail("invalid constraint: '{s}'", .{constraint}),2710 else => return isel.fail("invalid constraint: '{s}'", .{constraint}),
2724 .none => if (std.mem.startsWith(u8, constraint, "={") and std.mem.endsWith(u8, constraint, "}")) {2711 .none => if (std.mem.startsWith(u8, constraint, "={") and std.mem.endsWith(u8, constraint, "}")) {
2725 const output_reg = Register.parse(constraint["={".len .. constraint.len - "}".len]) orelse2712 const output_reg = Register.parse(constraint["={".len .. constraint.len - "}".len]) orelse
...@@ -2760,54 +2747,51 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2760,54 +2747,51 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2760 }2747 }
27612748
2762 const input_mats = try gpa.alloc(Value.Materialize, inputs.len);2749 const input_mats = try gpa.alloc(Value.Materialize, inputs.len);
2750 var index: u32 = 0;
2763 defer gpa.free(input_mats);2751 defer gpa.free(input_mats);
2764 const inputs_extra_index = extra_index;2752 it = unwrapped_asm.iterateInputs();
2765 for (inputs, input_mats) |input, *input_mat| {2753 while (it.next()) |input| : (index += 1) {
2766 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);2754 const constraint = input.constraint;
2767 const constraint = std.mem.sliceTo(extra_bytes, 0);2755 const name = input.name;
2768 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
2769 // This equation accounts for the fact that even if we have exactly 4 bytes
2770 // for the string, we still use the next u32 for the null terminator.
2771 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
27722756
2773 if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {2757 if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {
2774 const input_reg = Register.parse(constraint["{".len .. constraint.len - "}".len]) orelse2758 const input_reg = Register.parse(constraint["{".len .. constraint.len - "}".len]) orelse
2775 return isel.fail("invalid constraint: '{s}'", .{constraint});2759 return isel.fail("invalid constraint: '{s}'", .{constraint});
2776 input_mat.* = .{ .vi = try isel.use(input), .ra = input_reg.alias };2760 input_mats[index] = .{ .vi = try isel.use(input.operand), .ra = input_reg.alias };
2777 if (!std.mem.eql(u8, name, "_")) {2761 if (!std.mem.eql(u8, name, "_")) {
2778 const operand_gop = try as.operands.getOrPut(gpa, name);2762 const operand_gop = try as.operands.getOrPut(gpa, name);
2779 if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name});2763 if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name});
2780 const input_ty = isel.air.typeOf(input, ip);2764 const input_ty = isel.air.typeOf(input.operand, ip);
2781 operand_gop.value_ptr.* = .{ .register = switch (input_ty.abiSize(zcu)) {2765 operand_gop.value_ptr.* = .{ .register = switch (input_ty.abiSize(zcu)) {
2782 0 => unreachable,2766 0 => unreachable,
2783 1...4 => input_reg.alias.w(),2767 1...4 => input_reg.alias.w(),
2784 5...8 => input_reg.alias.x(),2768 5...8 => input_reg.alias.x(),
2785 else => return isel.fail("too big input type: '{f}'", .{2769 else => return isel.fail("too big input type: '{f}'", .{
2786 isel.fmtType(isel.air.typeOf(input, ip)),2770 isel.fmtType(isel.air.typeOf(input.operand, ip)),
2787 }),2771 }),
2788 } };2772 } };
2789 }2773 }
2790 } else if (std.mem.eql(u8, constraint, "r")) {2774 } else if (std.mem.eql(u8, constraint, "r")) {
2791 const input_vi = try isel.use(input);2775 const input_vi = try isel.use(input.operand);
2792 input_mat.* = try input_vi.matReg(isel);2776 input_mats[index] = try input_vi.matReg(isel);
2793 if (!std.mem.eql(u8, name, "_")) {2777 if (!std.mem.eql(u8, name, "_")) {
2794 const operand_gop = try as.operands.getOrPut(gpa, name);2778 const operand_gop = try as.operands.getOrPut(gpa, name);
2795 if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name});2779 if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name});
2796 operand_gop.value_ptr.* = .{ .register = switch (input_vi.size(isel)) {2780 operand_gop.value_ptr.* = .{ .register = switch (input_vi.size(isel)) {
2797 0 => unreachable,2781 0 => unreachable,
2798 1...4 => input_mat.ra.w(),2782 1...4 => input_mats[index].ra.w(),
2799 5...8 => input_mat.ra.x(),2783 5...8 => input_mats[index].ra.x(),
2800 else => return isel.fail("too big input type: '{f}'", .{2784 else => return isel.fail("too big input type: '{f}'", .{
2801 isel.fmtType(isel.air.typeOf(input, ip)),2785 isel.fmtType(isel.air.typeOf(input.operand, ip)),
2802 }),2786 }),
2803 } };2787 } };
2804 }2788 }
2805 } else if (std.mem.eql(u8, name, "_")) {2789 } else if (std.mem.eql(u8, name, "_")) {
2806 input_mat.vi = try isel.use(input);2790 input_mats[index].vi = try isel.use(input.operand);
2807 } else return isel.fail("invalid constraint: '{s}'", .{constraint});2791 } else return isel.fail("invalid constraint: '{s}'", .{constraint});
2808 }2792 }
28092793
2810 const clobbers = ip.indexToKey(extra.data.clobbers).aggregate;2794 const clobbers = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
2811 const clobbers_ty: ZigType = .fromInterned(clobbers.ty);2795 const clobbers_ty: ZigType = .fromInterned(clobbers.ty);
2812 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {2796 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
2813 switch (switch (clobbers.storage) {2797 switch (switch (clobbers.storage) {
...@@ -2858,7 +2842,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2858,7 +2842,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2858 }2842 }
2859 }2843 }
28602844
2861 as.source = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..])[0..extra.data.source_len :0];2845 as.source = unwrapped_asm.source;
2862 const asm_start = isel.instructions.items.len;2846 const asm_start = isel.instructions.items.len;
2863 while (as.nextInstruction() catch |err| switch (err) {2847 while (as.nextInstruction() catch |err| switch (err) {
2864 error.InvalidSyntax => {2848 error.InvalidSyntax => {
...@@ -2872,21 +2856,18 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2872,21 +2856,18 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
2872 }) |instruction| try isel.emit(instruction);2856 }) |instruction| try isel.emit(instruction);
2873 std.mem.reverse(codegen.aarch64.encoding.Instruction, isel.instructions.items[asm_start..]);2857 std.mem.reverse(codegen.aarch64.encoding.Instruction, isel.instructions.items[asm_start..]);
28742858
2875 extra_index = inputs_extra_index;2859 it = unwrapped_asm.iterateInputs();
2876 for (input_mats) |input_mat| {2860 index = 0;
2877 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);2861 while (it.next()) |input| : (index += 1) {
2878 const constraint = std.mem.sliceTo(extra_bytes, 0);2862 const constraint = input.constraint;
2879 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);2863 const name = input.name;
2880 // This equation accounts for the fact that even if we have exactly 4 bytes
2881 // for the string, we still use the next u32 for the null terminator.
2882 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
28832864
2884 if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {2865 if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {
2885 try input_mat.vi.liveOut(isel, input_mat.ra);2866 try input_mats[index].vi.liveOut(isel, input_mats[index].ra);
2886 } else if (std.mem.eql(u8, constraint, "r")) {2867 } else if (std.mem.eql(u8, constraint, "r")) {
2887 try input_mat.finish(isel);2868 try input_mats[index].finish(isel);
2888 } else if (std.mem.eql(u8, name, "_")) {2869 } else if (std.mem.eql(u8, name, "_")) {
2889 try input_mat.vi.mat(isel);2870 try input_mats[index].vi.mat(isel);
2890 } else unreachable;2871 } else unreachable;
2891 }2872 }
28922873
...@@ -3515,16 +3496,16 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3515,16 +3496,16 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3515 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3496 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3516 },3497 },
3517 .block => {3498 .block => {
3518 const ty_pl = air.data(air.inst_index).ty_pl;3499 const unwrapped_block = isel.air.unwrapBlock(air.inst_index);
3519 const extra = isel.air.extraData(Air.Block, ty_pl.payload);3500 try isel.block(
3520 try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(3501 air.inst_index,
3521 isel.air.extra.items[extra.end..][0..extra.data.body_len],3502 unwrapped_block.ty,
3522 ));3503 unwrapped_block.body,
3504 );
3523 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3505 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3524 },3506 },
3525 .loop => {3507 .loop => {
3526 const ty_pl = air.data(air.inst_index).ty_pl;3508 const unwrapped_block = isel.air.unwrapBlock(air.inst_index);
3527 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
3528 const loops = isel.loops.values();3509 const loops = isel.loops.values();
3529 const loop_index = isel.loops.getIndex(air.inst_index).?;3510 const loop_index = isel.loops.getIndex(air.inst_index).?;
3530 const loop = &loops[loop_index];3511 const loop = &loops[loop_index];
...@@ -3558,7 +3539,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3558,7 +3539,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
35583539
3559 loop.live_registers = isel.live_registers;3540 loop.live_registers = isel.live_registers;
3560 loop.repeat_list = Loop.empty_list;3541 loop.repeat_list = Loop.empty_list;
3561 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));3542 try isel.body(unwrapped_block.body);
3562 try isel.merge(&loop.live_registers, .{ .fill_extra = true });3543 try isel.merge(&loop.live_registers, .{ .fill_extra = true });
35633544
3564 var repeat_label = loop.repeat_list;3545 var repeat_label = loop.repeat_list;
...@@ -3608,10 +3589,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3608,10 +3589,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3608 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3589 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3609 },3590 },
3610 .call => {3591 .call => {
3611 const pl_op = air.data(air.inst_index).pl_op;3592 const air_call = isel.air.unwrapCall(air.inst_index);
3612 const extra = isel.air.extraData(Air.Call, pl_op.payload);3593 const args = air_call.args;
3613 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);3594 const callee_ty = isel.air.typeOf(air_call.callee, ip);
3614 const callee_ty = isel.air.typeOf(pl_op.operand, ip);
3615 const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {3595 const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {
3616 else => unreachable,3596 else => unreachable,
3617 .func_type => |func_type| func_type,3597 .func_type => |func_type| func_type,
...@@ -3649,7 +3629,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3649,7 +3629,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3649 try call.finishReturn(isel);3629 try call.finishReturn(isel);
36503630
3651 try call.prepareCallee(isel);3631 try call.prepareCallee(isel);
3652 if (pl_op.operand.toInterned()) |ct_callee| {3632 if (air_call.callee.toInterned()) |ct_callee| {
3653 try isel.nav_relocs.append(gpa, switch (ip.indexToKey(ct_callee)) {3633 try isel.nav_relocs.append(gpa, switch (ip.indexToKey(ct_callee)) {
3654 else => unreachable,3634 else => unreachable,
3655 inline .@"extern", .func => |func| .{3635 inline .@"extern", .func => |func| .{
...@@ -3666,7 +3646,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3666,7 +3646,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3666 });3646 });
3667 try isel.emit(.bl(0));3647 try isel.emit(.bl(0));
3668 } else {3648 } else {
3669 const callee_vi = try isel.use(pl_op.operand);3649 const callee_vi = try isel.use(air_call.callee);
3670 const callee_mat = try callee_vi.matReg(isel);3650 const callee_mat = try callee_vi.matReg(isel);
3671 try isel.emit(.blr(callee_mat.ra.x()));3651 try isel.emit(.blr(callee_mat.ra.x()));
3672 try callee_mat.finish(isel);3652 try callee_mat.finish(isel);
...@@ -4523,16 +4503,15 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4523,16 +4503,15 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4523 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;4503 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4524 },4504 },
4525 .cond_br => {4505 .cond_br => {
4526 const pl_op = air.data(air.inst_index).pl_op;4506 const cond_br = isel.air.unwrapCondBr(air.inst_index);
4527 const extra = isel.air.extraData(Air.CondBr, pl_op.payload);
45284507
4529 try isel.body(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]));4508 try isel.body(cond_br.then_body);
4530 const else_label = isel.instructions.items.len;4509 const else_label = isel.instructions.items.len;
4531 const else_live_registers = isel.live_registers;4510 const else_live_registers = isel.live_registers;
4532 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len]));4511 try isel.body(cond_br.else_body);
4533 try isel.merge(&else_live_registers, .{});4512 try isel.merge(&else_live_registers, .{});
45344513
4535 const cond_vi = try isel.use(pl_op.operand);4514 const cond_vi = try isel.use(cond_br.condition);
4536 const cond_mat = try cond_vi.matReg(isel);4515 const cond_mat = try cond_vi.matReg(isel);
4537 try isel.emit(.tbz(4516 try isel.emit(.tbz(
4538 cond_mat.ra.x(),4517 cond_mat.ra.x(),
...@@ -4819,13 +4798,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4819,13 +4798,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4819 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;4798 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4820 },4799 },
4821 .@"try", .try_cold => {4800 .@"try", .try_cold => {
4822 const pl_op = air.data(air.inst_index).pl_op;4801 const unwrapped_try = isel.air.unwrapTry(air.inst_index);
4823 const extra = isel.air.extraData(Air.Try, pl_op.payload);4802 const error_union_ty = isel.air.typeOf(unwrapped_try.error_union, &zcu.intern_pool);
4824 const error_union_ty = isel.air.typeOf(pl_op.operand, ip);
4825 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;4803 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
4826 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);4804 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
48274805
4828 const error_union_vi = try isel.use(pl_op.operand);4806 const error_union_vi = try isel.use(unwrapped_try.error_union);
4829 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| {4807 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| {
4830 defer payload_vi.value.deref(isel);4808 defer payload_vi.value.deref(isel);
48314809
...@@ -4840,7 +4818,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4840,7 +4818,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
48404818
4841 const cont_label = isel.instructions.items.len;4819 const cont_label = isel.instructions.items.len;
4842 const cont_live_registers = isel.live_registers;4820 const cont_live_registers = isel.live_registers;
4843 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));4821 try isel.body(unwrapped_try.else_body);
4844 try isel.merge(&cont_live_registers, .{});4822 try isel.merge(&cont_live_registers, .{});
48454823
4846 var error_set_part_it = error_union_vi.field(4824 var error_set_part_it = error_union_vi.field(
...@@ -4859,18 +4837,17 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4859,18 +4837,17 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4859 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;4837 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4860 },4838 },
4861 .try_ptr, .try_ptr_cold => {4839 .try_ptr, .try_ptr_cold => {
4862 const ty_pl = air.data(air.inst_index).ty_pl;4840 const unwrapped_try = isel.air.unwrapTryPtr(air.inst_index);
4863 const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload);4841 const error_union_ty = isel.air.typeOf(unwrapped_try.error_union_ptr, ip).childType(zcu);
4864 const error_union_ty = isel.air.typeOf(extra.data.ptr, ip).childType(zcu);
4865 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;4842 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
4866 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);4843 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
48674844
4868 const error_union_ptr_vi = try isel.use(extra.data.ptr);4845 const error_union_ptr_vi = try isel.use(unwrapped_try.error_union_ptr);
4869 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);4846 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
4870 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {4847 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
4871 defer payload_ptr_vi.value.deref(isel);4848 defer payload_ptr_vi.value.deref(isel);
4872 switch (codegen.errUnionPayloadOffset(ty_pl.ty.toType().childType(zcu), zcu)) {4849 switch (codegen.errUnionPayloadOffset(unwrapped_try.error_union_payload_ptr_ty.toType().childType(zcu), zcu)) {
4873 0 => try payload_ptr_vi.value.move(isel, extra.data.ptr),4850 0 => try payload_ptr_vi.value.move(isel, unwrapped_try.error_union_ptr),
4874 else => |payload_offset| {4851 else => |payload_offset| {
4875 const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;4852 const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
4876 const lo12: u12 = @truncate(payload_offset >> 0);4853 const lo12: u12 = @truncate(payload_offset >> 0);
...@@ -4887,7 +4864,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4887,7 +4864,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
48874864
4888 const cont_label = isel.instructions.items.len;4865 const cont_label = isel.instructions.items.len;
4889 const cont_live_registers = isel.live_registers;4866 const cont_live_registers = isel.live_registers;
4890 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));4867 try isel.body(unwrapped_try.else_body);
4891 try isel.merge(&cont_live_registers, .{});4868 try isel.merge(&cont_live_registers, .{});
48924869
4893 const error_set_ra = try isel.allocIntReg();4870 const error_set_ra = try isel.allocIntReg();
...@@ -4913,11 +4890,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4913,11 +4890,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4913 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;4890 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4914 },4891 },
4915 .dbg_inline_block => {4892 .dbg_inline_block => {
4916 const ty_pl = air.data(air.inst_index).ty_pl;4893 const dbg_block = isel.air.unwrapDbgBlock(air.inst_index);
4917 const extra = isel.air.extraData(Air.DbgInlineBlock, ty_pl.payload);4894 try isel.block(air.inst_index, dbg_block.ty, dbg_block.body);
4918 try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(
4919 isel.air.extra.items[extra.end..][0..extra.data.body_len],
4920 ));
4921 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;4895 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4922 },4896 },
4923 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => {4897 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => {
src/codegen/c.zig+65-96
...@@ -4622,9 +4622,8 @@ fn airCall(...@@ -4622,9 +4622,8 @@ fn airCall(
4622 const gpa = f.object.dg.gpa;4622 const gpa = f.object.dg.gpa;
4623 const w = &f.object.code.writer;4623 const w = &f.object.code.writer;
46244624
4625 const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;4625 const call = f.air.unwrapCall(inst);
4626 const extra = f.air.extraData(Air.Call, pl_op.payload);4626 const args = call.args;
4627 const args: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[extra.end..][0..extra.data.args_len]);
46284627
4629 const resolved_args = try gpa.alloc(CValue, args.len);4628 const resolved_args = try gpa.alloc(CValue, args.len);
4630 defer gpa.free(resolved_args);4629 defer gpa.free(resolved_args);
...@@ -4653,15 +4652,15 @@ fn airCall(...@@ -4653,15 +4652,15 @@ fn airCall(
4653 }4652 }
4654 }4653 }
46554654
4656 const callee = try f.resolveInst(pl_op.operand);4655 const callee = try f.resolveInst(call.callee);
46574656
4658 {4657 {
4659 var bt = iterateBigTomb(f, inst);4658 var bt = iterateBigTomb(f, inst);
4660 try bt.feed(pl_op.operand);4659 try bt.feed(call.callee);
4661 for (args) |arg| try bt.feed(arg);4660 for (args) |arg| try bt.feed(arg);
4662 }4661 }
46634662
4664 const callee_ty = f.typeOf(pl_op.operand);4663 const callee_ty = f.typeOf(call.callee);
4665 const callee_is_ptr = switch (callee_ty.zigTypeTag(zcu)) {4664 const callee_is_ptr = switch (callee_ty.zigTypeTag(zcu)) {
4666 .@"fn" => false,4665 .@"fn" => false,
4667 .pointer => true,4666 .pointer => true,
...@@ -4698,7 +4697,7 @@ fn airCall(...@@ -4698,7 +4697,7 @@ fn airCall(
46984697
4699 callee: {4698 callee: {
4700 known: {4699 known: {
4701 const callee_val = (try f.air.value(pl_op.operand, pt)) orelse break :known;4700 const callee_val = (try f.air.value(call.callee, pt)) orelse break :known;
4702 const fn_nav, const need_cast = switch (ip.indexToKey(callee_val.toIntern())) {4701 const fn_nav, const need_cast = switch (ip.indexToKey(callee_val.toIntern())) {
4703 .@"extern" => |@"extern"| .{ @"extern".owner_nav, false },4702 .@"extern" => |@"extern"| .{ @"extern".owner_nav, false },
4704 .func => |func| .{ func.owner_nav, Type.fromInterned(func.ty).fnCallingConvention(zcu) != .naked and4703 .func => |func| .{ func.owner_nav, Type.fromInterned(func.ty).fnCallingConvention(zcu) != .naked and
...@@ -4796,13 +4795,12 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4796,13 +4795,12 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
4796 const pt = f.object.dg.pt;4795 const pt = f.object.dg.pt;
4797 const zcu = pt.zcu;4796 const zcu = pt.zcu;
4798 const ip = &zcu.intern_pool;4797 const ip = &zcu.intern_pool;
4799 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4798 const block = f.air.unwrapDbgBlock(inst);
4800 const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);4799 const owner_nav = ip.getNav(zcu.funcInfo(block.func).owner_nav);
4801 const owner_nav = ip.getNav(zcu.funcInfo(extra.data.func).owner_nav);
4802 const w = &f.object.code.writer;4800 const w = &f.object.code.writer;
4803 try w.print("/* inline:{f} */", .{owner_nav.fqn.fmt(&zcu.intern_pool)});4801 try w.print("/* inline:{f} */", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
4804 try f.object.newline();4802 try f.object.newline();
4805 return lowerBlock(f, inst, @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]));4803 return lowerBlock(f, inst, block.body);
4806}4804}
48074805
4808fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {4806fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4822,9 +4820,8 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4822,9 +4820,8 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
4822}4820}
48234821
4824fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {4822fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
4825 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4823 const block = f.air.unwrapBlock(inst);
4826 const extra = f.air.extraData(Air.Block, ty_pl.payload);4824 return lowerBlock(f, inst, block.body);
4827 return lowerBlock(f, inst, @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]));
4828}4825}
48294826
4830fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index) !CValue {4827fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index) !CValue {
...@@ -4873,21 +4870,19 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -4873,21 +4870,19 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)
4873}4870}
48744871
4875fn airTry(f: *Function, inst: Air.Inst.Index) !CValue {4872fn airTry(f: *Function, inst: Air.Inst.Index) !CValue {
4876 const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;4873 const pt = f.object.dg.pt;
4877 const extra = f.air.extraData(Air.Try, pl_op.payload);4874 const unwrapped_try = f.air.unwrapTry(inst);
4878 const body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]);4875 const body = unwrapped_try.else_body;
4879 const err_union_ty = f.typeOf(pl_op.operand);4876 const err_union_ty = f.air.typeOf(unwrapped_try.error_union, &pt.zcu.intern_pool);
4880 return lowerTry(f, inst, pl_op.operand, body, err_union_ty, false);4877 return lowerTry(f, inst, unwrapped_try.error_union, body, err_union_ty, false);
4881}4878}
48824879
4883fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue {4880fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue {
4884 const pt = f.object.dg.pt;4881 const pt = f.object.dg.pt;
4885 const zcu = pt.zcu;4882 const unwrapped_try = f.air.unwrapTryPtr(inst);
4886 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4883 const body = unwrapped_try.else_body;
4887 const extra = f.air.extraData(Air.TryPtr, ty_pl.payload);4884 const err_union_ty = f.air.typeOf(unwrapped_try.error_union_ptr, &pt.zcu.intern_pool).childType(pt.zcu);
4888 const body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]);4885 return lowerTry(f, inst, unwrapped_try.error_union_ptr, body, err_union_ty, true);
4889 const err_union_ty = f.typeOf(extra.data.ptr).childType(zcu);
4890 return lowerTry(f, inst, extra.data.ptr, body, err_union_ty, true);
4891}4886}
48924887
4893fn lowerTry(4888fn lowerTry(
...@@ -5216,9 +5211,7 @@ fn airUnreach(o: *Object) !void {...@@ -5216,9 +5211,7 @@ fn airUnreach(o: *Object) !void {
5216}5211}
52175212
5218fn airLoop(f: *Function, inst: Air.Inst.Index) !void {5213fn airLoop(f: *Function, inst: Air.Inst.Index) !void {
5219 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5214 const block = f.air.unwrapBlock(inst);
5220 const loop = f.air.extraData(Air.Block, ty_pl.payload);
5221 const body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[loop.end..][0..loop.data.body_len]);
5222 const w = &f.object.code.writer;5215 const w = &f.object.code.writer;
52235216
5224 // `repeat` instructions matching this loop will branch to5217 // `repeat` instructions matching this loop will branch to
...@@ -5227,16 +5220,15 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !void {...@@ -5227,16 +5220,15 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !void {
5227 // construct at all!5220 // construct at all!
5228 try w.print("zig_loop_{d}:", .{@intFromEnum(inst)});5221 try w.print("zig_loop_{d}:", .{@intFromEnum(inst)});
5229 try f.object.newline();5222 try f.object.newline();
5230 try genBodyInner(f, body); // no need to restore state, we're noreturn5223 try genBodyInner(f, block.body); // no need to restore state, we're noreturn
5231}5224}
52325225
5233fn airCondBr(f: *Function, inst: Air.Inst.Index) !void {5226fn airCondBr(f: *Function, inst: Air.Inst.Index) !void {
5234 const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5227 const cond_br = f.air.unwrapCondBr(inst);
5235 const cond = try f.resolveInst(pl_op.operand);5228 const cond = try f.resolveInst(cond_br.condition);
5236 try reap(f, inst, &.{pl_op.operand});5229 try reap(f, inst, &.{cond_br.condition});
5237 const extra = f.air.extraData(Air.CondBr, pl_op.payload);5230 const then_body = cond_br.then_body;
5238 const then_body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[extra.end..][0..extra.data.then_body_len]);5231 const else_body = cond_br.else_body;
5239 const else_body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
5240 const liveness_condbr = f.liveness.getCondBr(inst);5232 const liveness_condbr = f.liveness.getCondBr(inst);
5241 const w = &f.object.code.writer;5233 const w = &f.object.code.writer;
52425234
...@@ -5439,16 +5431,11 @@ fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool...@@ -5439,16 +5431,11 @@ fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool
5439fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {5431fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5440 const pt = f.object.dg.pt;5432 const pt = f.object.dg.pt;
5441 const zcu = pt.zcu;5433 const zcu = pt.zcu;
5442 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5434 const unwrapped_asm = f.air.unwrapAsm(inst);
5443 const extra = f.air.extraData(Air.Asm, ty_pl.payload);5435 const is_volatile = unwrapped_asm.is_volatile;
5444 const is_volatile = extra.data.flags.is_volatile;
5445 const outputs_len = extra.data.flags.outputs_len;
5446 const gpa = f.object.dg.gpa;5436 const gpa = f.object.dg.gpa;
5447 var extra_i: usize = extra.end;5437 const outputs = unwrapped_asm.outputs;
5448 const outputs: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[extra_i..][0..outputs_len]);5438 const inputs = unwrapped_asm.inputs;
5449 extra_i += outputs.len;
5450 const inputs: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[extra_i..][0..extra.data.inputs_len]);
5451 extra_i += inputs.len;
54525439
5453 const result = result: {5440 const result = result: {
5454 const w = &f.object.code.writer;5441 const w = &f.object.code.writer;
...@@ -5469,14 +5456,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5469,14 +5456,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5469 } else .none;5456 } else .none;
54705457
5471 const locals_begin: LocalIndex = @intCast(f.locals.items.len);5458 const locals_begin: LocalIndex = @intCast(f.locals.items.len);
5472 const constraints_extra_begin = extra_i;5459 var it = unwrapped_asm.iterateOutputs();
5473 for (outputs) |output| {5460 while (it.next()) |output| {
5474 const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]);5461 const constraint = output.constraint;
5475 const constraint = mem.sliceTo(extra_bytes, 0);
5476 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
5477 // This equation accounts for the fact that even if we have exactly 4 bytes
5478 // for the string, we still use the next u32 for the null terminator.
5479 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
54805462
5481 if (constraint.len < 2 or constraint[0] != '=' or5463 if (constraint.len < 2 or constraint[0] != '=' or
5482 (constraint[1] == '{' and constraint[constraint.len - 1] != '}'))5464 (constraint[1] == '{' and constraint[constraint.len - 1] != '}'))
...@@ -5486,7 +5468,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5486,7 +5468,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
54865468
5487 const is_reg = constraint[1] == '{';5469 const is_reg = constraint[1] == '{';
5488 if (is_reg) {5470 if (is_reg) {
5489 const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(zcu);5471 const output_ty = if (output.operand == .none) inst_ty else f.typeOf(output.operand).childType(zcu);
5490 try w.writeAll("register ");5472 try w.writeAll("register ");
5491 const output_local = try f.allocLocalValue(.{5473 const output_local = try f.allocLocalValue(.{
5492 .ctype = try f.ctypeFromType(output_ty, .complete),5474 .ctype = try f.ctypeFromType(output_ty, .complete),
...@@ -5505,13 +5487,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5505,13 +5487,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5505 try f.object.newline();5487 try f.object.newline();
5506 }5488 }
5507 }5489 }
5508 for (inputs) |input| {5490
5509 const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]);5491 it = unwrapped_asm.iterateInputs();
5510 const constraint = mem.sliceTo(extra_bytes, 0);5492 while (it.next()) |input| {
5511 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);5493 const constraint = input.constraint;
5512 // This equation accounts for the fact that even if we have exactly 4 bytes
5513 // for the string, we still use the next u32 for the null terminator.
5514 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
55155494
5516 if (constraint.len < 1 or mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or5495 if (constraint.len < 1 or mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or
5517 (constraint[0] == '{' and constraint[constraint.len - 1] != '}'))5496 (constraint[0] == '{' and constraint[constraint.len - 1] != '}'))
...@@ -5520,9 +5499,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5520,9 +5499,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5520 }5499 }
55215500
5522 const is_reg = constraint[0] == '{';5501 const is_reg = constraint[0] == '{';
5523 const input_val = try f.resolveInst(input);5502 const input_val = try f.resolveInst(input.operand);
5524 if (asmInputNeedsLocal(f, constraint, input_val)) {5503 if (asmInputNeedsLocal(f, constraint, input_val)) {
5525 const input_ty = f.typeOf(input);5504 const input_ty = f.typeOf(input.operand);
5526 if (is_reg) try w.writeAll("register ");5505 if (is_reg) try w.writeAll("register ");
5527 const input_local = try f.allocLocalValue(.{5506 const input_local = try f.allocLocalValue(.{
5528 .ctype = try f.ctypeFromType(input_ty, .complete),5507 .ctype = try f.ctypeFromType(input_ty, .complete),
...@@ -5545,7 +5524,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5545,7 +5524,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5545 }5524 }
55465525
5547 {5526 {
5548 const asm_source = mem.sliceAsBytes(f.air.extra.items[extra_i..])[0..extra.data.source_len];5527 const asm_source = unwrapped_asm.source;
55495528
5550 var stack = std.heap.stackFallback(256, f.object.dg.gpa);5529 var stack = std.heap.stackFallback(256, f.object.dg.gpa);
5551 const allocator = stack.get();5530 const allocator = stack.get();
...@@ -5599,18 +5578,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5599,18 +5578,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5599 try w.print("({f}", .{fmtStringLiteral(fixed_asm_source[0..dst_i], null)});5578 try w.print("({f}", .{fmtStringLiteral(fixed_asm_source[0..dst_i], null)});
5600 }5579 }
56015580
5602 extra_i = constraints_extra_begin;
5603 var locals_index = locals_begin;5581 var locals_index = locals_begin;
5604 try w.writeByte(':');5582 try w.writeByte(':');
5605 for (outputs, 0..) |output, index| {5583
5606 const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]);5584 it = unwrapped_asm.iterateOutputs();
5607 const constraint = mem.sliceTo(extra_bytes, 0);5585 while (it.next()) |output| {
5608 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);5586 const constraint = output.constraint;
5609 // This equation accounts for the fact that even if we have exactly 4 bytes5587 const name = output.name;
5610 // for the string, we still use the next u32 for the null terminator.5588
5611 extra_i += (constraint.len + name.len + (2 + 3)) / 4;5589 if (output.index > 0) try w.writeByte(',');
5612
5613 if (index > 0) try w.writeByte(',');
5614 try w.writeByte(' ');5590 try w.writeByte(' ');
5615 if (!mem.eql(u8, name, "_")) try w.print("[{s}]", .{name});5591 if (!mem.eql(u8, name, "_")) try w.print("[{s}]", .{name});
5616 const is_reg = constraint[1] == '{';5592 const is_reg = constraint[1] == '{';
...@@ -5618,28 +5594,26 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5618,28 +5594,26 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5618 if (is_reg) {5594 if (is_reg) {
5619 try f.writeCValue(w, .{ .local = locals_index }, .Other);5595 try f.writeCValue(w, .{ .local = locals_index }, .Other);
5620 locals_index += 1;5596 locals_index += 1;
5621 } else if (output == .none) {5597 } else if (output.operand == .none) {
5622 try f.writeCValue(w, inst_local, .FunctionArgument);5598 try f.writeCValue(w, inst_local, .FunctionArgument);
5623 } else {5599 } else {
5624 try f.writeCValueDeref(w, try f.resolveInst(output));5600 try f.writeCValueDeref(w, try f.resolveInst(output.operand));
5625 }5601 }
5626 try w.writeByte(')');5602 try w.writeByte(')');
5627 }5603 }
5628 try w.writeByte(':');5604 try w.writeByte(':');
5629 for (inputs, 0..) |input, index| {5605
5630 const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]);5606 it = unwrapped_asm.iterateInputs();
5631 const constraint = mem.sliceTo(extra_bytes, 0);5607 while (it.next()) |input| {
5632 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);5608 const constraint = input.constraint;
5633 // This equation accounts for the fact that even if we have exactly 4 bytes5609 const name = input.name;
5634 // for the string, we still use the next u32 for the null terminator.5610
5635 extra_i += (constraint.len + name.len + (2 + 3)) / 4;5611 if (input.index > 0) try w.writeByte(',');
5636
5637 if (index > 0) try w.writeByte(',');
5638 try w.writeByte(' ');5612 try w.writeByte(' ');
5639 if (!mem.eql(u8, name, "_")) try w.print("[{s}]", .{name});5613 if (!mem.eql(u8, name, "_")) try w.print("[{s}]", .{name});
56405614
5641 const is_reg = constraint[0] == '{';5615 const is_reg = constraint[0] == '{';
5642 const input_val = try f.resolveInst(input);5616 const input_val = try f.resolveInst(input.operand);
5643 try w.print("{f}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)});5617 try w.print("{f}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)});
5644 try f.writeCValue(w, if (asmInputNeedsLocal(f, constraint, input_val)) local: {5618 try f.writeCValue(w, if (asmInputNeedsLocal(f, constraint, input_val)) local: {
5645 const input_local_idx = locals_index;5619 const input_local_idx = locals_index;
...@@ -5650,7 +5624,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5650,7 +5624,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5650 }5624 }
5651 try w.writeByte(':');5625 try w.writeByte(':');
5652 const ip = &zcu.intern_pool;5626 const ip = &zcu.intern_pool;
5653 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;5627 const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
5654 const struct_type: Type = .fromInterned(aggregate.ty);5628 const struct_type: Type = .fromInterned(aggregate.ty);
5655 switch (aggregate.storage) {5629 switch (aggregate.storage) {
5656 .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {5630 .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {
...@@ -5697,22 +5671,17 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5697,22 +5671,17 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5697 try w.writeAll(");");5671 try w.writeAll(");");
5698 try f.object.newline();5672 try f.object.newline();
56995673
5700 extra_i = constraints_extra_begin;
5701 locals_index = locals_begin;5674 locals_index = locals_begin;
5702 for (outputs) |output| {5675 it = unwrapped_asm.iterateOutputs();
5703 const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]);5676 while (it.next()) |output| {
5704 const constraint = mem.sliceTo(extra_bytes, 0);5677 const constraint = output.constraint;
5705 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
5706 // This equation accounts for the fact that even if we have exactly 4 bytes
5707 // for the string, we still use the next u32 for the null terminator.
5708 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
57095678
5710 const is_reg = constraint[1] == '{';5679 const is_reg = constraint[1] == '{';
5711 if (is_reg) {5680 if (is_reg) {
5712 try f.writeCValueDeref(w, if (output == .none)5681 try f.writeCValueDeref(w, if (output.operand == .none)
5713 .{ .local_ref = inst_local.new_local }5682 .{ .local_ref = inst_local.new_local }
5714 else5683 else
5715 try f.resolveInst(output));5684 try f.resolveInst(output.operand));
5716 try w.writeAll(" = ");5685 try w.writeAll(" = ");
5717 try f.writeCValue(w, .{ .local = locals_index }, .Other);5686 try f.writeCValue(w, .{ .local = locals_index }, .Other);
5718 locals_index += 1;5687 locals_index += 1;
src/codegen/llvm.zig+62-85
...@@ -5258,14 +5258,13 @@ pub const FuncGen = struct {...@@ -5258,14 +5258,13 @@ pub const FuncGen = struct {
5258 };5258 };
52595259
5260 fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !Builder.Value {5260 fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !Builder.Value {
5261 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5261 const air_call = self.air.unwrapCall(inst);
5262 const extra = self.air.extraData(Air.Call, pl_op.payload);5262 const args = air_call.args;
5263 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.args_len]);
5264 const o = self.ng.object;5263 const o = self.ng.object;
5265 const pt = self.ng.pt;5264 const pt = self.ng.pt;
5266 const zcu = pt.zcu;5265 const zcu = pt.zcu;
5267 const ip = &zcu.intern_pool;5266 const ip = &zcu.intern_pool;
5268 const callee_ty = self.typeOf(pl_op.operand);5267 const callee_ty = self.typeOf(air_call.callee);
5269 const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) {5268 const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) {
5270 .@"fn" => callee_ty,5269 .@"fn" => callee_ty,
5271 .pointer => callee_ty.childType(zcu),5270 .pointer => callee_ty.childType(zcu),
...@@ -5273,7 +5272,7 @@ pub const FuncGen = struct {...@@ -5273,7 +5272,7 @@ pub const FuncGen = struct {
5273 };5272 };
5274 const fn_info = zcu.typeToFunc(zig_fn_ty).?;5273 const fn_info = zcu.typeToFunc(zig_fn_ty).?;
5275 const return_type = Type.fromInterned(fn_info.return_type);5274 const return_type = Type.fromInterned(fn_info.return_type);
5276 const llvm_fn = try self.resolveInst(pl_op.operand);5275 const llvm_fn = try self.resolveInst(air_call.callee);
5277 const target = zcu.getTarget();5276 const target = zcu.getTarget();
5278 const sret = firstParamSRet(fn_info, zcu, target);5277 const sret = firstParamSRet(fn_info, zcu, target);
52795278
...@@ -5934,9 +5933,8 @@ pub const FuncGen = struct {...@@ -5934,9 +5933,8 @@ pub const FuncGen = struct {
5934 }5933 }
59355934
5936 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {5935 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5937 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5936 const block = self.air.unwrapBlock(inst);
5938 const extra = self.air.extraData(Air.Block, ty_pl.payload);5937 return self.lowerBlock(inst, null, block.body);
5939 return self.lowerBlock(inst, null, @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]));
5940 }5938 }
59415939
5942 fn lowerBlock(5940 fn lowerBlock(
...@@ -6216,11 +6214,10 @@ pub const FuncGen = struct {...@@ -6216,11 +6214,10 @@ pub const FuncGen = struct {
6216 }6214 }
62176215
6218 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !void {6216 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !void {
6219 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6217 const cond_br = self.air.unwrapCondBr(inst);
6220 const cond = try self.resolveInst(pl_op.operand);6218 const cond = try self.resolveInst(cond_br.condition);
6221 const extra = self.air.extraData(Air.CondBr, pl_op.payload);6219 const then_body = cond_br.then_body;
6222 const then_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.then_body_len]);6220 const else_body = cond_br.else_body;
6223 const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
62246221
6225 const Hint = enum {6222 const Hint = enum {
6226 none,6223 none,
...@@ -6230,22 +6227,22 @@ pub const FuncGen = struct {...@@ -6230,22 +6227,22 @@ pub const FuncGen = struct {
6230 then_cold,6227 then_cold,
6231 else_cold,6228 else_cold,
6232 };6229 };
6233 const hint: Hint = switch (extra.data.branch_hints.true) {6230 const hint: Hint = switch (cond_br.branch_hints.true) {
6234 .none => switch (extra.data.branch_hints.false) {6231 .none => switch (cond_br.branch_hints.false) {
6235 .none => .none,6232 .none => .none,
6236 .likely => .else_likely,6233 .likely => .else_likely,
6237 .unlikely => .then_likely,6234 .unlikely => .then_likely,
6238 .cold => .else_cold,6235 .cold => .else_cold,
6239 .unpredictable => .unpredictable,6236 .unpredictable => .unpredictable,
6240 },6237 },
6241 .likely => switch (extra.data.branch_hints.false) {6238 .likely => switch (cond_br.branch_hints.false) {
6242 .none => .then_likely,6239 .none => .then_likely,
6243 .likely => .unpredictable,6240 .likely => .unpredictable,
6244 .unlikely => .then_likely,6241 .unlikely => .then_likely,
6245 .cold => .else_cold,6242 .cold => .else_cold,
6246 .unpredictable => .unpredictable,6243 .unpredictable => .unpredictable,
6247 },6244 },
6248 .unlikely => switch (extra.data.branch_hints.false) {6245 .unlikely => switch (cond_br.branch_hints.false) {
6249 .none => .else_likely,6246 .none => .else_likely,
6250 .likely => .else_likely,6247 .likely => .else_likely,
6251 .unlikely => .unpredictable,6248 .unlikely => .unpredictable,
...@@ -6267,35 +6264,33 @@ pub const FuncGen = struct {...@@ -6267,35 +6264,33 @@ pub const FuncGen = struct {
62676264
6268 self.wip.cursor = .{ .block = then_block };6265 self.wip.cursor = .{ .block = then_block };
6269 if (hint == .then_cold) _ = try self.wip.callIntrinsicAssumeCold();6266 if (hint == .then_cold) _ = try self.wip.callIntrinsicAssumeCold();
6270 try self.genBodyDebugScope(null, then_body, extra.data.branch_hints.then_cov);6267 try self.genBodyDebugScope(null, then_body, cond_br.branch_hints.then_cov);
62716268
6272 self.wip.cursor = .{ .block = else_block };6269 self.wip.cursor = .{ .block = else_block };
6273 if (hint == .else_cold) _ = try self.wip.callIntrinsicAssumeCold();6270 if (hint == .else_cold) _ = try self.wip.callIntrinsicAssumeCold();
6274 try self.genBodyDebugScope(null, else_body, extra.data.branch_hints.else_cov);6271 try self.genBodyDebugScope(null, else_body, cond_br.branch_hints.else_cov);
62756272
6276 // No need to reset the insert cursor since this instruction is noreturn.6273 // No need to reset the insert cursor since this instruction is noreturn.
6277 }6274 }
62786275
6279 fn airTry(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {6276 fn airTry(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {
6280 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6277 const unwrapped_try = self.air.unwrapTry(inst);
6281 const err_union = try self.resolveInst(pl_op.operand);6278 const err_union = try self.resolveInst(unwrapped_try.error_union);
6282 const extra = self.air.extraData(Air.Try, pl_op.payload);6279 const body = unwrapped_try.else_body;
6283 const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);6280 const err_union_ty = self.typeOf(unwrapped_try.error_union);
6284 const err_union_ty = self.typeOf(pl_op.operand);
6285 const is_unused = self.liveness.isUnused(inst);6281 const is_unused = self.liveness.isUnused(inst);
6286 return lowerTry(self, err_union, body, err_union_ty, false, false, is_unused, err_cold);6282 return lowerTry(self, err_union, body, err_union_ty, false, false, is_unused, err_cold);
6287 }6283 }
62886284
6289 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {6285 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {
6290 const zcu = self.ng.pt.zcu;6286 const zcu = self.ng.pt.zcu;
6291 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6287 const unwrapped_try = self.air.unwrapTryPtr(inst);
6292 const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);6288 const err_union_ptr = try self.resolveInst(unwrapped_try.error_union_ptr);
6293 const err_union_ptr = try self.resolveInst(extra.data.ptr);6289 const body = unwrapped_try.else_body;
6294 const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);6290 const err_union_ty = self.typeOf(unwrapped_try.error_union_ptr).childType(zcu);
6295 const err_union_ty = self.typeOf(extra.data.ptr).childType(zcu);
6296 const is_unused = self.liveness.isUnused(inst);6291 const is_unused = self.liveness.isUnused(inst);
62976292
6298 self.maybeMarkAllowZeroAccess(self.typeOf(extra.data.ptr).ptrInfo(zcu));6293 self.maybeMarkAllowZeroAccess(self.typeOf(unwrapped_try.error_union_ptr).ptrInfo(zcu));
62996294
6300 return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused, err_cold);6295 return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused, err_cold);
6301 }6296 }
...@@ -6627,9 +6622,8 @@ pub const FuncGen = struct {...@@ -6627,9 +6622,8 @@ pub const FuncGen = struct {
6627 }6622 }
66286623
6629 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !void {6624 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !void {
6630 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6625 const block = self.air.unwrapBlock(inst);
6631 const loop = self.air.extraData(Air.Block, ty_pl.payload);6626 const body = block.body;
6632 const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[loop.end..][0..loop.data.body_len]);
6633 const loop_block = try self.wip.block(1, "Loop"); // `airRepeat` will increment incoming each time6627 const loop_block = try self.wip.block(1, "Loop"); // `airRepeat` will increment incoming each time
6634 _ = try self.wip.br(loop_block);6628 _ = try self.wip.br(loop_block);
66356629
...@@ -7137,10 +7131,9 @@ pub const FuncGen = struct {...@@ -7137,10 +7131,9 @@ pub const FuncGen = struct {
7137 }7131 }
71387132
7139 fn airDbgInlineBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {7133 fn airDbgInlineBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7140 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;7134 const block = self.air.unwrapDbgBlock(inst);
7141 const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
7142 self.arg_inline_index = 0;7135 self.arg_inline_index = 0;
7143 return self.lowerBlock(inst, extra.data.func, @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]));7136 return self.lowerBlock(inst, block.func, block.body);
7144 }7137 }
71457138
7146 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {7139 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
...@@ -7262,17 +7255,12 @@ pub const FuncGen = struct {...@@ -7262,17 +7255,12 @@ pub const FuncGen = struct {
7262 // this implementation feeds the inline assembly code directly to LLVM.7255 // this implementation feeds the inline assembly code directly to LLVM.
72637256
7264 const o = self.ng.object;7257 const o = self.ng.object;
7265 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;7258 const unwrapped_asm = self.air.unwrapAsm(inst);
7266 const extra = self.air.extraData(Air.Asm, ty_pl.payload);7259 const is_volatile = unwrapped_asm.is_volatile;
7267 const is_volatile = extra.data.flags.is_volatile;
7268 const outputs_len = extra.data.flags.outputs_len;
7269 const gpa = self.gpa;7260 const gpa = self.gpa;
7270 var extra_i: usize = extra.end;
72717261
7272 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..outputs_len]);7262 const outputs = unwrapped_asm.outputs;
7273 extra_i += outputs.len;7263 const inputs = unwrapped_asm.inputs;
7274 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
7275 extra_i += inputs.len;
72767264
7277 var llvm_constraints: std.ArrayList(u8) = .empty;7265 var llvm_constraints: std.ArrayList(u8) = .empty;
7278 defer llvm_constraints.deinit(gpa);7266 defer llvm_constraints.deinit(gpa);
...@@ -7305,14 +7293,10 @@ pub const FuncGen = struct {...@@ -7305,14 +7293,10 @@ pub const FuncGen = struct {
7305 var name_map: std.StringArrayHashMapUnmanaged(u16) = .empty;7293 var name_map: std.StringArrayHashMapUnmanaged(u16) = .empty;
7306 try name_map.ensureUnusedCapacity(arena, max_param_count);7294 try name_map.ensureUnusedCapacity(arena, max_param_count);
73077295
7308 var rw_extra_i = extra_i;7296 var it = unwrapped_asm.iterateOutputs();
7309 for (outputs, llvm_ret_indirect, llvm_rw_vals) |output, *is_indirect, *llvm_rw_val| {7297 while (it.next()) |output| {
7310 const extra_bytes = std.mem.sliceAsBytes(self.air.extra.items[extra_i..]);7298 const constraint = output.constraint;
7311 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);7299 const name = output.name;
7312 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
7313 // This equation accounts for the fact that even if we have exactly 4 bytes
7314 // for the string, we still use the next u32 for the null terminator.
7315 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
73167300
7317 try llvm_constraints.ensureUnusedCapacity(gpa, constraint.len + 3);7301 try llvm_constraints.ensureUnusedCapacity(gpa, constraint.len + 3);
7318 if (total_i != 0) {7302 if (total_i != 0) {
...@@ -7320,15 +7304,15 @@ pub const FuncGen = struct {...@@ -7320,15 +7304,15 @@ pub const FuncGen = struct {
7320 }7304 }
7321 llvm_constraints.appendAssumeCapacity('=');7305 llvm_constraints.appendAssumeCapacity('=');
73227306
7323 if (output != .none) {7307 if (output.operand != .none) {
7324 const output_inst = try self.resolveInst(output);7308 const output_inst = try self.resolveInst(output.operand);
7325 const output_ty = self.typeOf(output);7309 const output_ty = self.typeOf(output.operand);
7326 assert(output_ty.zigTypeTag(zcu) == .pointer);7310 assert(output_ty.zigTypeTag(zcu) == .pointer);
7327 const elem_llvm_ty = try o.lowerPtrElemTy(pt, output_ty.childType(zcu));7311 const elem_llvm_ty = try o.lowerPtrElemTy(pt, output_ty.childType(zcu));
73287312
7329 switch (constraint[0]) {7313 switch (constraint[0]) {
7330 '=' => {},7314 '=' => {},
7331 '+' => llvm_rw_val.* = output_inst,7315 '+' => llvm_rw_vals[output.index] = output_inst,
7332 else => return self.todo("unsupported output constraint on output type '{c}'", .{7316 else => return self.todo("unsupported output constraint on output type '{c}'", .{
7333 constraint[0],7317 constraint[0],
7334 }),7318 }),
...@@ -7337,8 +7321,8 @@ pub const FuncGen = struct {...@@ -7337,8 +7321,8 @@ pub const FuncGen = struct {
7337 self.maybeMarkAllowZeroAccess(output_ty.ptrInfo(zcu));7321 self.maybeMarkAllowZeroAccess(output_ty.ptrInfo(zcu));
73387322
7339 // Pass any non-return outputs indirectly, if the constraint accepts a memory location7323 // Pass any non-return outputs indirectly, if the constraint accepts a memory location
7340 is_indirect.* = constraintAllowsMemory(constraint);7324 llvm_ret_indirect[output.index] = constraintAllowsMemory(constraint);
7341 if (is_indirect.*) {7325 if (llvm_ret_indirect[output.index]) {
7342 // Pass the result by reference as an indirect output (e.g. "=*m")7326 // Pass the result by reference as an indirect output (e.g. "=*m")
7343 llvm_constraints.appendAssumeCapacity('*');7327 llvm_constraints.appendAssumeCapacity('*');
73447328
...@@ -7359,7 +7343,7 @@ pub const FuncGen = struct {...@@ -7359,7 +7343,7 @@ pub const FuncGen = struct {
7359 }),7343 }),
7360 }7344 }
73617345
7362 is_indirect.* = false;7346 llvm_ret_indirect[output.index] = false;
73637347
7364 const ret_ty = self.typeOfIndex(inst);7348 const ret_ty = self.typeOfIndex(inst);
7365 llvm_ret_types[llvm_ret_i] = try o.lowerType(pt, ret_ty);7349 llvm_ret_types[llvm_ret_i] = try o.lowerType(pt, ret_ty);
...@@ -7387,16 +7371,13 @@ pub const FuncGen = struct {...@@ -7387,16 +7371,13 @@ pub const FuncGen = struct {
7387 total_i += 1;7371 total_i += 1;
7388 }7372 }
73897373
7390 for (inputs) |input| {7374 it = unwrapped_asm.iterateInputs();
7391 const extra_bytes = std.mem.sliceAsBytes(self.air.extra.items[extra_i..]);7375 while (it.next()) |input| {
7392 const constraint = std.mem.sliceTo(extra_bytes, 0);7376 const constraint = input.constraint;
7393 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);7377 const name = input.name;
7394 // This equation accounts for the fact that even if we have exactly 4 bytes
7395 // for the string, we still use the next u32 for the null terminator.
7396 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
73977378
7398 const arg_llvm_value = try self.resolveInst(input);7379 const arg_llvm_value = try self.resolveInst(input.operand);
7399 const arg_ty = self.typeOf(input);7380 const arg_ty = self.typeOf(input.operand);
7400 const is_by_ref = isByRef(arg_ty, zcu);7381 const is_by_ref = isByRef(arg_ty, zcu);
7401 if (is_by_ref) {7382 if (is_by_ref) {
7402 if (constraintAllowsMemory(constraint)) {7383 if (constraintAllowsMemory(constraint)) {
...@@ -7452,27 +7433,23 @@ pub const FuncGen = struct {...@@ -7452,27 +7433,23 @@ pub const FuncGen = struct {
7452 total_i += 1;7433 total_i += 1;
7453 }7434 }
74547435
7455 for (outputs, llvm_ret_indirect, llvm_rw_vals, 0..) |output, is_indirect, llvm_rw_val, output_index| {7436 it = unwrapped_asm.iterateOutputs();
7456 const extra_bytes = std.mem.sliceAsBytes(self.air.extra.items[rw_extra_i..]);7437 while (it.next()) |output| {
7457 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[rw_extra_i..]), 0);7438 const constraint = output.constraint;
7458 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
7459 // This equation accounts for the fact that even if we have exactly 4 bytes
7460 // for the string, we still use the next u32 for the null terminator.
7461 rw_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
74627439
7463 if (constraint[0] != '+') continue;7440 if (constraint[0] != '+') continue;
74647441
7465 const rw_ty = self.typeOf(output);7442 const rw_ty = self.typeOf(output.operand);
7466 const llvm_elem_ty = try o.lowerPtrElemTy(pt, rw_ty.childType(zcu));7443 const llvm_elem_ty = try o.lowerPtrElemTy(pt, rw_ty.childType(zcu));
7467 if (is_indirect) {7444 if (llvm_ret_indirect[output.index]) {
7468 llvm_param_values[llvm_param_i] = llvm_rw_val;7445 llvm_param_values[llvm_param_i] = llvm_rw_vals[output.index];
7469 llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip);7446 llvm_param_types[llvm_param_i] = llvm_rw_vals[output.index].typeOfWip(&self.wip);
7470 } else {7447 } else {
7471 const alignment = rw_ty.abiAlignment(zcu).toLlvm();7448 const alignment = rw_ty.abiAlignment(zcu).toLlvm();
7472 const loaded = try self.wip.load(7449 const loaded = try self.wip.load(
7473 if (rw_ty.isVolatilePtr(zcu)) .@"volatile" else .normal,7450 if (rw_ty.isVolatilePtr(zcu)) .@"volatile" else .normal,
7474 llvm_elem_ty,7451 llvm_elem_ty,
7475 llvm_rw_val,7452 llvm_rw_vals[output.index],
7476 alignment,7453 alignment,
7477 "",7454 "",
7478 );7455 );
...@@ -7480,18 +7457,18 @@ pub const FuncGen = struct {...@@ -7480,18 +7457,18 @@ pub const FuncGen = struct {
7480 llvm_param_types[llvm_param_i] = llvm_elem_ty;7457 llvm_param_types[llvm_param_i] = llvm_elem_ty;
7481 }7458 }
74827459
7483 try llvm_constraints.print(gpa, ",{d}", .{output_index});7460 try llvm_constraints.print(gpa, ",{d}", .{output.index});
74847461
7485 // In the case of indirect inputs, LLVM requires the callsite to have7462 // In the case of indirect inputs, LLVM requires the callsite to have
7486 // an elementtype(<ty>) attribute.7463 // an elementtype(<ty>) attribute.
7487 llvm_param_attrs[llvm_param_i] = if (is_indirect) llvm_elem_ty else .none;7464 llvm_param_attrs[llvm_param_i] = if (llvm_ret_indirect[output.index]) llvm_elem_ty else .none;
74887465
7489 llvm_param_i += 1;7466 llvm_param_i += 1;
7490 total_i += 1;7467 total_i += 1;
7491 }7468 }
74927469
7493 const ip = &zcu.intern_pool;7470 const ip = &zcu.intern_pool;
7494 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;7471 const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
7495 const struct_type: Type = .fromInterned(aggregate.ty);7472 const struct_type: Type = .fromInterned(aggregate.ty);
7496 if (total_i != 0) try llvm_constraints.append(gpa, ',');7473 if (total_i != 0) try llvm_constraints.append(gpa, ',');
7497 switch (aggregate.storage) {7474 switch (aggregate.storage) {
...@@ -7539,7 +7516,7 @@ pub const FuncGen = struct {...@@ -7539,7 +7516,7 @@ pub const FuncGen = struct {
75397516
7540 if (std.mem.endsWith(u8, llvm_constraints.items, ",")) llvm_constraints.items.len -= 1;7517 if (std.mem.endsWith(u8, llvm_constraints.items, ",")) llvm_constraints.items.len -= 1;
75417518
7542 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];7519 const asm_source = unwrapped_asm.source;
75437520
7544 // hackety hacks until stage2 has proper inline asm in the frontend.7521 // hackety hacks until stage2 has proper inline asm in the frontend.
7545 var rendered_template = std.array_list.Managed(u8).init(gpa);7522 var rendered_template = std.array_list.Managed(u8).init(gpa);
src/codegen/riscv64/CodeGen.zig+48-74
...@@ -3627,11 +3627,11 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3627,11 +3627,11 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
3627}3627}
36283628
3629fn airTry(func: *Func, inst: Air.Inst.Index) !void {3629fn airTry(func: *Func, inst: Air.Inst.Index) !void {
3630 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;3630 const zcu = func.pt.zcu;
3631 const extra = func.air.extraData(Air.Try, pl_op.payload);3631 const unwrapped_try = func.air.unwrapTry(inst);
3632 const body: []const Air.Inst.Index = @ptrCast(func.air.extra.items[extra.end..][0..extra.data.body_len]);3632 const body = unwrapped_try.else_body;
3633 const operand_ty = func.typeOf(pl_op.operand);3633 const operand_ty = func.air.typeOf(unwrapped_try.error_union, &zcu.intern_pool);
3634 const result = try func.genTry(inst, pl_op.operand, body, operand_ty, false);3634 const result = try func.genTry(inst, unwrapped_try.error_union, body, operand_ty, false);
3635 return func.finishAir(inst, result, .{ .none, .none, .none });3635 return func.finishAir(inst, result, .{ .none, .none, .none });
3636}3636}
36373637
...@@ -4801,10 +4801,8 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {...@@ -4801,10 +4801,8 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {
48014801
4802fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {4802fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
4803 if (modifier == .always_tail) return func.fail("TODO implement tail calls for riscv64", .{});4803 if (modifier == .always_tail) return func.fail("TODO implement tail calls for riscv64", .{});
4804 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;4804 const call = func.air.unwrapCall(inst);
4805 const callee = pl_op.operand;4805 const arg_refs = call.args;
4806 const extra = func.air.extraData(Air.Call, pl_op.payload);
4807 const arg_refs: []const Air.Inst.Ref = @ptrCast(func.air.extra.items[extra.end..][0..extra.data.args_len]);
48084806
4809 const expected_num_args = 8;4807 const expected_num_args = 8;
4810 const ExpectedContents = extern struct {4808 const ExpectedContents = extern struct {
...@@ -4822,10 +4820,10 @@ fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4822,10 +4820,10 @@ fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4822 defer allocator.free(arg_vals);4820 defer allocator.free(arg_vals);
4823 for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref };4821 for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref };
48244822
4825 const call_ret = try func.genCall(.{ .air = callee }, arg_tys, arg_vals);4823 const call_ret = try func.genCall(.{ .air = call.callee }, arg_tys, arg_vals);
48264824
4827 var bt = func.liveness.iterateBigTomb(inst);4825 var bt = func.liveness.iterateBigTomb(inst);
4828 try func.feed(&bt, pl_op.operand);4826 try func.feed(&bt, call.callee);
4829 for (arg_refs) |arg_ref| try func.feed(&bt, arg_ref);4827 for (arg_refs) |arg_ref| try func.feed(&bt, arg_ref);
48304828
4831 const result = if (func.liveness.isUnused(inst)) .unreach else call_ret;4829 const result = if (func.liveness.isUnused(inst)) .unreach else call_ret;
...@@ -5218,9 +5216,8 @@ fn airDbgStmt(func: *Func, inst: Air.Inst.Index) !void {...@@ -5218,9 +5216,8 @@ fn airDbgStmt(func: *Func, inst: Air.Inst.Index) !void {
5218}5216}
52195217
5220fn airDbgInlineBlock(func: *Func, inst: Air.Inst.Index) !void {5218fn airDbgInlineBlock(func: *Func, inst: Air.Inst.Index) !void {
5221 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5219 const block = func.air.unwrapDbgBlock(inst);
5222 const extra = func.air.extraData(Air.DbgInlineBlock, ty_pl.payload);5220 try func.lowerBlock(inst, block.body);
5223 try func.lowerBlock(inst, @ptrCast(func.air.extra.items[extra.end..][0..extra.data.body_len]));
5224}5221}
52255222
5226fn airDbgVar(func: *Func, inst: Air.Inst.Index) InnerError!void {5223fn airDbgVar(func: *Func, inst: Air.Inst.Index) InnerError!void {
...@@ -5271,19 +5268,18 @@ fn genVarDbgInfo(...@@ -5271,19 +5268,18 @@ fn genVarDbgInfo(
5271}5268}
52725269
5273fn airCondBr(func: *Func, inst: Air.Inst.Index) !void {5270fn airCondBr(func: *Func, inst: Air.Inst.Index) !void {
5274 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5271 const cond_br = func.air.unwrapCondBr(inst);
5275 const cond = try func.resolveInst(pl_op.operand);5272 const cond = try func.resolveInst(cond_br.condition);
5276 const cond_ty = func.typeOf(pl_op.operand);5273 const cond_ty = func.typeOf(cond_br.condition);
5277 const extra = func.air.extraData(Air.CondBr, pl_op.payload);5274 const then_body = cond_br.then_body;
5278 const then_body: []const Air.Inst.Index = @ptrCast(func.air.extra.items[extra.end..][0..extra.data.then_body_len]);5275 const else_body = cond_br.else_body;
5279 const else_body: []const Air.Inst.Index = @ptrCast(func.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
5280 const liveness_cond_br = func.liveness.getCondBr(inst);5276 const liveness_cond_br = func.liveness.getCondBr(inst);
52815277
5282 // If the condition dies here in this condbr instruction, process5278 // If the condition dies here in this condbr instruction, process
5283 // that death now instead of later as this has an effect on5279 // that death now instead of later as this has an effect on
5284 // whether it needs to be spilled in the branches5280 // whether it needs to be spilled in the branches
5285 if (func.liveness.operandDies(inst, 0)) {5281 if (func.liveness.operandDies(inst, 0)) {
5286 if (pl_op.operand.toIndex()) |op_inst| try func.processDeath(op_inst);5282 if (cond_br.condition.toIndex()) |op_inst| try func.processDeath(op_inst);
5287 }5283 }
52885284
5289 func.scope_generation += 1;5285 func.scope_generation += 1;
...@@ -5633,10 +5629,7 @@ fn airIsNonErrPtr(func: *Func, inst: Air.Inst.Index) !void {...@@ -5633,10 +5629,7 @@ fn airIsNonErrPtr(func: *Func, inst: Air.Inst.Index) !void {
56335629
5634fn airLoop(func: *Func, inst: Air.Inst.Index) !void {5630fn airLoop(func: *Func, inst: Air.Inst.Index) !void {
5635 // A loop is a setup to be able to jump back to the beginning.5631 // A loop is a setup to be able to jump back to the beginning.
5636 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5632 const body = func.air.unwrapBlock(inst);
5637 const loop = func.air.extraData(Air.Block, ty_pl.payload);
5638 const body: []const Air.Inst.Index = @ptrCast(func.air.extra.items[loop.end..][0..loop.data.body_len]);
5639
5640 func.scope_generation += 1;5633 func.scope_generation += 1;
5641 const state = try func.saveState();5634 const state = try func.saveState();
56425635
...@@ -5646,7 +5639,7 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void {...@@ -5646,7 +5639,7 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void {
5646 });5639 });
5647 defer assert(func.loops.remove(inst));5640 defer assert(func.loops.remove(inst));
56485641
5649 try func.genBody(body);5642 try func.genBody(body.body);
56505643
5651 func.finishAirBookkeeping();5644 func.finishAirBookkeeping();
5652}5645}
...@@ -5663,9 +5656,8 @@ fn jump(func: *Func, index: Mir.Inst.Index) !Mir.Inst.Index {...@@ -5663,9 +5656,8 @@ fn jump(func: *Func, index: Mir.Inst.Index) !Mir.Inst.Index {
5663}5656}
56645657
5665fn airBlock(func: *Func, inst: Air.Inst.Index) !void {5658fn airBlock(func: *Func, inst: Air.Inst.Index) !void {
5666 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5659 const block = func.air.unwrapBlock(inst);
5667 const extra = func.air.extraData(Air.Block, ty_pl.payload);5660 try func.lowerBlock(inst, block.body);
5668 try func.lowerBlock(inst, @ptrCast(func.air.extra.items[extra.end..][0..extra.data.body_len]));
5669}5661}
56705662
5671fn lowerBlock(func: *Func, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {5663fn lowerBlock(func: *Func, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
...@@ -6053,15 +6045,9 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {...@@ -6053,15 +6045,9 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
6053}6045}
60546046
6055fn airAsm(func: *Func, inst: Air.Inst.Index) !void {6047fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6056 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6048 const unwrapped_asm = func.air.unwrapAsm(inst);
6057 const extra = func.air.extraData(Air.Asm, ty_pl.payload);6049 const outputs = unwrapped_asm.outputs;
6058 const outputs_len = extra.data.flags.outputs_len;6050 const inputs = unwrapped_asm.inputs;
6059 var extra_i: usize = extra.end;
6060 const outputs: []const Air.Inst.Ref =
6061 @ptrCast(func.air.extra.items[extra_i..][0..outputs_len]);
6062 extra_i += outputs.len;
6063 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra.items[extra_i..][0..extra.data.inputs_len]);
6064 extra_i += inputs.len;
60656051
6066 var result: MCValue = .none;6052 var result: MCValue = .none;
6067 var args = std.array_list.Managed(MCValue).init(func.gpa);6053 var args = std.array_list.Managed(MCValue).init(func.gpa);
...@@ -6076,19 +6062,15 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6076,19 +6062,15 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6076 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));6062 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));
6077 defer arg_map.deinit();6063 defer arg_map.deinit();
60786064
6079 var outputs_extra_i = extra_i;6065 var it = unwrapped_asm.iterateOutputs();
6080 for (outputs) |output| {6066 while (it.next()) |output| {
6081 const extra_bytes = mem.sliceAsBytes(func.air.extra.items[extra_i..]);6067 const constraint = output.constraint;
6082 const constraint = mem.sliceTo(mem.sliceAsBytes(func.air.extra.items[extra_i..]), 0);6068 const name = output.name;
6083 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
6084 // This equation accounts for the fact that even if we have exactly 4 bytes
6085 // for the string, we still use the next u32 for the null terminator.
6086 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
60876069
6088 const is_read = switch (constraint[0]) {6070 const is_read = switch (constraint[0]) {
6089 '=' => false,6071 '=' => false,
6090 '+' => read: {6072 '+' => read: {
6091 if (output == .none) return func.fail(6073 if (output.operand == .none) return func.fail(
6092 "read-write constraint unsupported for asm result: '{s}'",6074 "read-write constraint unsupported for asm result: '{s}'",
6093 .{constraint},6075 .{constraint},
6094 );6076 );
...@@ -6100,7 +6082,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6100,7 +6082,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6100 const rest = constraint[@as(usize, 1) + @intFromBool(is_early_clobber) ..];6082 const rest = constraint[@as(usize, 1) + @intFromBool(is_early_clobber) ..];
6101 const arg_mcv: MCValue = arg_mcv: {6083 const arg_mcv: MCValue = arg_mcv: {
6102 const arg_maybe_reg: ?Register = if (mem.eql(u8, rest, "m"))6084 const arg_maybe_reg: ?Register = if (mem.eql(u8, rest, "m"))
6103 if (output != .none) null else return func.fail(6085 if (output.operand != .none) null else return func.fail(
6104 "memory constraint unsupported for asm result: '{s}'",6086 "memory constraint unsupported for asm result: '{s}'",
6105 .{constraint},6087 .{constraint},
6106 )6088 )
...@@ -6115,7 +6097,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6115,7 +6097,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6115 break :arg_mcv args.items[index];6097 break :arg_mcv args.items[index];
6116 } else return func.fail("invalid constraint: '{s}'", .{constraint});6098 } else return func.fail("invalid constraint: '{s}'", .{constraint});
6117 break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {6099 break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
6118 const ptr_mcv = try func.resolveInst(output);6100 const ptr_mcv = try func.resolveInst(output.operand);
6119 switch (ptr_mcv) {6101 switch (ptr_mcv) {
6120 .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|6102 .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
6121 break :arg ptr_mcv.deref(),6103 break :arg ptr_mcv.deref(),
...@@ -6131,20 +6113,17 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6131,20 +6113,17 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6131 if (!mem.eql(u8, name, "_"))6113 if (!mem.eql(u8, name, "_"))
6132 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));6114 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
6133 args.appendAssumeCapacity(arg_mcv);6115 args.appendAssumeCapacity(arg_mcv);
6134 if (output == .none) result = arg_mcv;6116 if (output.operand == .none) result = arg_mcv;
6135 if (is_read) try func.load(arg_mcv, .{ .air_ref = output }, func.typeOf(output));6117 if (is_read) try func.load(arg_mcv, .{ .air_ref = output.operand }, func.typeOf(output.operand));
6136 }6118 }
61376119
6138 for (inputs) |input| {6120 it = unwrapped_asm.iterateInputs();
6139 const input_bytes = mem.sliceAsBytes(func.air.extra.items[extra_i..]);6121 while (it.next()) |input| {
6140 const constraint = mem.sliceTo(input_bytes, 0);6122 const constraint = input.constraint;
6141 const name = mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);6123 const name = input.name;
6142 // This equation accounts for the fact that even if we have exactly 4 bytes
6143 // for the string, we still use the next u32 for the null terminator.
6144 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
61456124
6146 const ty = func.typeOf(input);6125 const ty = func.typeOf(input.operand);
6147 const input_mcv = try func.resolveInst(input);6126 const input_mcv = try func.resolveInst(input.operand);
6148 const arg_mcv: MCValue = if (mem.eql(u8, constraint, "X"))6127 const arg_mcv: MCValue = if (mem.eql(u8, constraint, "X"))
6149 input_mcv6128 input_mcv
6150 else if (mem.startsWith(u8, constraint, "{") and mem.endsWith(u8, constraint, "}")) arg: {6129 else if (mem.startsWith(u8, constraint, "{") and mem.endsWith(u8, constraint, "}")) arg: {
...@@ -6171,7 +6150,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6171,7 +6150,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
61716150
6172 const zcu = func.pt.zcu;6151 const zcu = func.pt.zcu;
6173 const ip = &zcu.intern_pool;6152 const ip = &zcu.intern_pool;
6174 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;6153 const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
6175 const struct_type: Type = .fromInterned(aggregate.ty);6154 const struct_type: Type = .fromInterned(aggregate.ty);
6176 switch (aggregate.storage) {6155 switch (aggregate.storage) {
6177 .elems => |elems| for (elems, 0..) |elem, i| {6156 .elems => |elems| for (elems, 0..) |elem, i| {
...@@ -6231,7 +6210,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6231,7 +6210,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6231 labels.deinit(func.gpa);6210 labels.deinit(func.gpa);
6232 }6211 }
62336212
6234 const asm_source = std.mem.sliceAsBytes(func.air.extra.items[extra_i..])[0..extra.data.source_len];6213 const asm_source = unwrapped_asm.source;
6235 var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;");6214 var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;");
6236 next_line: while (line_it.next()) |line| {6215 next_line: while (line_it.next()) |line| {
6237 var mnem_it = mem.tokenizeAny(u8, line, " \t");6216 var mnem_it = mem.tokenizeAny(u8, line, " \t");
...@@ -6499,19 +6478,14 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6499,19 +6478,14 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6499 while (label_it.next()) |label| if (label.value_ptr.pending_relocs.items.len > 0)6478 while (label_it.next()) |label| if (label.value_ptr.pending_relocs.items.len > 0)
6500 return func.fail("undefined label: '{s}'", .{label.key_ptr.*});6479 return func.fail("undefined label: '{s}'", .{label.key_ptr.*});
65016480
6502 for (outputs, args.items[0..outputs.len]) |output, arg_mcv| {6481 it = unwrapped_asm.iterateOutputs();
6503 const extra_bytes = mem.sliceAsBytes(func.air.extra.items[outputs_extra_i..]);6482 while (it.next()) |output| {
6504 const constraint =6483 const constraint = output.constraint;
6505 mem.sliceTo(mem.sliceAsBytes(func.air.extra.items[outputs_extra_i..]), 0);6484
6506 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);6485 if (output.operand == .none) continue;
6507 // This equation accounts for the fact that even if we have exactly 4 bytes6486 if (args.items[output.index] != .register) continue;
6508 // for the string, we still use the next u32 for the null terminator.
6509 outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
6510
6511 if (output == .none) continue;
6512 if (arg_mcv != .register) continue;
6513 if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) continue;6487 if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) continue;
6514 try func.store(.{ .air_ref = output }, arg_mcv, func.typeOf(output));6488 try func.store(.{ .air_ref = output.operand }, args.items[output.index], func.typeOf(output.operand));
6515 }6489 }
65166490
6517 simple: {6491 simple: {
src/codegen/sparc64/CodeGen.zig+40-64
...@@ -877,15 +877,10 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -877,15 +877,10 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
877}877}
878878
879fn airAsm(self: *Self, inst: Air.Inst.Index) !void {879fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
880 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;880 const unwrapped_asm = self.air.unwrapAsm(inst);
881 const extra = self.air.extraData(Air.Asm, ty_pl.payload);881 const is_volatile = unwrapped_asm.is_volatile;
882 const is_volatile = extra.data.flags.is_volatile;882 const outputs = unwrapped_asm.outputs;
883 const outputs_len = extra.data.flags.outputs_len;883 const inputs = unwrapped_asm.inputs;
884 var extra_i: usize = extra.end;
885 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i .. extra_i + outputs_len]);
886 extra_i += outputs.len;
887 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i .. extra_i + extra.data.inputs_len]);
888 extra_i += inputs.len;
889884
890 const dead = !is_volatile and self.liveness.isUnused(inst);885 const dead = !is_volatile and self.liveness.isUnused(inst);
891 const result: MCValue = if (dead) .dead else result: {886 const result: MCValue = if (dead) .dead else result: {
...@@ -893,27 +888,18 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -893,27 +888,18 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
893 return self.fail("TODO implement codegen for asm with more than 1 output", .{});888 return self.fail("TODO implement codegen for asm with more than 1 output", .{});
894 }889 }
895890
896 const output_constraint: ?[]const u8 = for (outputs) |output| {891 var it = unwrapped_asm.iterateOutputs();
897 if (output != .none) {892 const output_constraint: ?[]const u8 = while (it.next()) |output| {
893 if (output.operand != .none) {
898 return self.fail("TODO implement codegen for non-expr asm", .{});894 return self.fail("TODO implement codegen for non-expr asm", .{});
899 }895 }
900 const extra_bytes = std.mem.sliceAsBytes(self.air.extra.items[extra_i..]);896
901 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);897 break output.constraint;
902 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
903 // This equation accounts for the fact that even if we have exactly 4 bytes
904 // for the string, we still use the next u32 for the null terminator.
905 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
906
907 break constraint;
908 } else null;898 } else null;
909899
910 for (inputs) |input| {900 it = unwrapped_asm.iterateInputs();
911 const input_bytes = std.mem.sliceAsBytes(self.air.extra.items[extra_i..]);901 while (it.next()) |input| {
912 const constraint = std.mem.sliceTo(input_bytes, 0);902 const constraint = input.constraint;
913 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
914 // This equation accounts for the fact that even if we have exactly 4 bytes
915 // for the string, we still use the next u32 for the null terminator.
916 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
917903
918 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {904 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
919 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});905 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
...@@ -922,15 +908,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -922,15 +908,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
922 const reg = parseRegName(reg_name) orelse908 const reg = parseRegName(reg_name) orelse
923 return self.fail("unrecognized register: '{s}'", .{reg_name});909 return self.fail("unrecognized register: '{s}'", .{reg_name});
924910
925 const arg_mcv = try self.resolveInst(input);911 const arg_mcv = try self.resolveInst(input.operand);
926 try self.register_manager.getReg(reg, null);912 try self.register_manager.getReg(reg, null);
927 try self.genSetReg(self.typeOf(input), reg, arg_mcv);913 try self.genSetReg(self.typeOf(input.operand), reg, arg_mcv);
928 }914 }
929915
930 // TODO honor the clobbers916 // TODO honor the clobbers
931 _ = extra.data.clobbers;917 _ = unwrapped_asm.clobbers;
932918
933 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];919 const asm_source = unwrapped_asm.source;
934920
935 if (mem.eql(u8, asm_source, "ta 0x6d")) {921 if (mem.eql(u8, asm_source, "ta 0x6d")) {
936 _ = try self.addInst(.{922 _ = try self.addInst(.{
...@@ -1109,9 +1095,8 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -1109,9 +1095,8 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
1109}1095}
11101096
1111fn airBlock(self: *Self, inst: Air.Inst.Index) !void {1097fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
1112 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;1098 const block = self.air.unwrapBlock(inst);
1113 const extra = self.air.extraData(Air.Block, ty_pl.payload);1099 try self.lowerBlock(inst, block.body);
1114 try self.lowerBlock(inst, @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]));
1115}1100}
11161101
1117fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {1102fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
...@@ -1276,11 +1261,9 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {...@@ -1276,11 +1261,9 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
1276fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {1261fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
1277 if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch});1262 if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch});
12781263
1279 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;1264 const call = self.air.unwrapCall(inst);
1280 const callee = pl_op.operand;1265 const args = call.args;
1281 const extra = self.air.extraData(Air.Call, pl_op.payload);1266 const ty = self.typeOf(call.callee);
1282 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra.end .. extra.end + extra.data.args_len]);
1283 const ty = self.typeOf(callee);
1284 const pt = self.pt;1267 const pt = self.pt;
1285 const zcu = pt.zcu;1268 const zcu = pt.zcu;
1286 const ip = &zcu.intern_pool;1269 const ip = &zcu.intern_pool;
...@@ -1327,7 +1310,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1327,7 +1310,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
13271310
1328 // Due to incremental compilation, how function calls are generated depends1311 // Due to incremental compilation, how function calls are generated depends
1329 // on linking.1312 // on linking.
1330 if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {1313 if (try self.air.value(call.callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
1331 .func => {1314 .func => {
1332 return self.fail("TODO implement calling functions", .{});1315 return self.fail("TODO implement calling functions", .{});
1333 },1316 },
...@@ -1339,7 +1322,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1339,7 +1322,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1339 },1322 },
1340 } else {1323 } else {
1341 assert(ty.zigTypeTag(zcu) == .pointer);1324 assert(ty.zigTypeTag(zcu) == .pointer);
1342 const mcv = try self.resolveInst(callee);1325 const mcv = try self.resolveInst(call.callee);
1343 try self.genSetReg(ty, .o7, mcv);1326 try self.genSetReg(ty, .o7, mcv);
13441327
1345 _ = try self.addInst(.{1328 _ = try self.addInst(.{
...@@ -1365,13 +1348,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1365,13 +1348,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
13651348
1366 if (args.len + 1 <= Air.Liveness.bpi - 1) {1349 if (args.len + 1 <= Air.Liveness.bpi - 1) {
1367 var buf = [1]Air.Inst.Ref{.none} ** (Air.Liveness.bpi - 1);1350 var buf = [1]Air.Inst.Ref{.none} ** (Air.Liveness.bpi - 1);
1368 buf[0] = callee;1351 buf[0] = call.callee;
1369 @memcpy(buf[1..][0..args.len], args);1352 @memcpy(buf[1..][0..args.len], args);
1370 return self.finishAir(inst, result, buf);1353 return self.finishAir(inst, result, buf);
1371 }1354 }
13721355
1373 var bt = try self.iterateBigTomb(inst, 1 + args.len);1356 var bt = try self.iterateBigTomb(inst, 1 + args.len);
1374 bt.feed(callee);1357 bt.feed(call.callee);
1375 for (args) |arg| {1358 for (args) |arg| {
1376 bt.feed(arg);1359 bt.feed(arg);
1377 }1360 }
...@@ -1451,9 +1434,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -1451,9 +1434,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
1451}1434}
14521435
1453fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {1436fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
1454 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;1437 _ = inst;
1455 const extra = self.air.extraData(Air.Block, ty_pl.payload);
1456 _ = extra;
14571438
1458 return self.fail("TODO implement airCmpxchg for {}", .{1439 return self.fail("TODO implement airCmpxchg for {}", .{
1459 self.target.cpu.arch,1440 self.target.cpu.arch,
...@@ -1461,11 +1442,10 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -1461,11 +1442,10 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
1461}1442}
14621443
1463fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {1444fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
1464 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;1445 const cond_br = self.air.unwrapCondBr(inst);
1465 const condition = try self.resolveInst(pl_op.operand);1446 const condition = try self.resolveInst(cond_br.condition);
1466 const extra = self.air.extraData(Air.CondBr, pl_op.payload);1447 const then_body = cond_br.then_body;
1467 const then_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.then_body_len]);1448 const else_body = cond_br.else_body;
1468 const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
1469 const liveness_condbr = self.liveness.getCondBr(inst);1449 const liveness_condbr = self.liveness.getCondBr(inst);
14701450
1471 // Here we emit a branch to the false section.1451 // Here we emit a branch to the false section.
...@@ -1475,7 +1455,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1475,7 +1455,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
1475 // that death now instead of later as this has an effect on1455 // that death now instead of later as this has an effect on
1476 // whether it needs to be spilled in the branches1456 // whether it needs to be spilled in the branches
1477 if (self.liveness.operandDies(inst, 0)) {1457 if (self.liveness.operandDies(inst, 0)) {
1478 if (pl_op.operand.toIndex()) |op_index| {1458 if (cond_br.condition.toIndex()) |op_index| {
1479 self.processDeath(op_index);1459 self.processDeath(op_index);
1480 }1460 }
1481 }1461 }
...@@ -1613,10 +1593,9 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -1613,10 +1593,9 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
1613}1593}
16141594
1615fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {1595fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
1616 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;1596 const block = self.air.unwrapDbgBlock(inst);
1617 const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
1618 // TODO emit debug info for function change1597 // TODO emit debug info for function change
1619 try self.lowerBlock(inst, @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]));1598 try self.lowerBlock(inst, block.body);
1620}1599}
16211600
1622fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {1601fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1780,12 +1759,10 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1780,12 +1759,10 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
17801759
1781fn airLoop(self: *Self, inst: Air.Inst.Index) !void {1760fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
1782 // A loop is a setup to be able to jump back to the beginning.1761 // A loop is a setup to be able to jump back to the beginning.
1783 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;1762 const block = self.air.unwrapBlock(inst);
1784 const loop = self.air.extraData(Air.Block, ty_pl.payload);
1785 const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[loop.end .. loop.end + loop.data.body_len]);
1786 const start: u32 = @intCast(self.mir_instructions.len);1763 const start: u32 = @intCast(self.mir_instructions.len);
17871764
1788 try self.genBody(body);1765 try self.genBody(block.body);
1789 try self.jump(start);1766 try self.jump(start);
17901767
1791 return self.finishAirBookkeeping();1768 return self.finishAirBookkeeping();
...@@ -2606,12 +2583,11 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -2606,12 +2583,11 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
2606}2583}
26072584
2608fn airTry(self: *Self, inst: Air.Inst.Index) !void {2585fn airTry(self: *Self, inst: Air.Inst.Index) !void {
2609 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;2586 const unwrapped_try = self.air.unwrapTry(inst);
2610 const extra = self.air.extraData(Air.Try, pl_op.payload);2587 const body = unwrapped_try.else_body;
2611 const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);
2612 const result: MCValue = result: {2588 const result: MCValue = result: {
2613 const error_union_ty = self.typeOf(pl_op.operand);2589 const error_union_ty = self.air.typeOf(unwrapped_try.error_union, &self.pt.zcu.intern_pool);
2614 const error_union = try self.resolveInst(pl_op.operand);2590 const error_union = try self.resolveInst(unwrapped_try.error_union);
2615 const is_err_result = try self.isErr(error_union_ty, error_union);2591 const is_err_result = try self.isErr(error_union_ty, error_union);
2616 const reloc = try self.condBr(is_err_result);2592 const reloc = try self.condBr(is_err_result);
26172593
...@@ -2620,7 +2596,7 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void {...@@ -2620,7 +2596,7 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void {
2620 try self.performReloc(reloc);2596 try self.performReloc(reloc);
2621 break :result try self.errUnionPayload(error_union, error_union_ty);2597 break :result try self.errUnionPayload(error_union, error_union_ty);
2622 };2598 };
2623 return self.finishAir(inst, result, .{ pl_op.operand, .none, .none });2599 return self.finishAir(inst, result, .{ unwrapped_try.error_union, .none, .none });
2624}2600}
26252601
2626fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {2602fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
src/codegen/spirv/CodeGen.zig+47-79
...@@ -5002,9 +5002,8 @@ fn genStructuredBody(...@@ -5002,9 +5002,8 @@ fn genStructuredBody(
5002}5002}
50035003
5004fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5004fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5005 const inst_datas = cg.air.instructions.items(.data);5005 const block = cg.air.unwrapBlock(inst);
5006 const extra = cg.air.extraData(Air.Block, inst_datas[@intFromEnum(inst)].ty_pl.payload);5006 return cg.lowerBlock(inst, block.body);
5007 return cg.lowerBlock(inst, @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]));
5008}5007}
50095008
5010fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) !?Id {5009fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) !?Id {
...@@ -5188,11 +5187,10 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5188,11 +5187,10 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
51885187
5189fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {5188fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
5190 const gpa = cg.module.gpa;5189 const gpa = cg.module.gpa;
5191 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5190 const cond_br = cg.air.unwrapCondBr(inst);
5192 const cond_br = cg.air.extraData(Air.CondBr, pl_op.payload);5191 const then_body = cond_br.then_body;
5193 const then_body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[cond_br.end..][0..cond_br.data.then_body_len]);5192 const else_body = cond_br.else_body;
5194 const else_body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[cond_br.end + then_body.len ..][0..cond_br.data.else_body_len]);5193 const condition_id = try cg.resolve(cond_br.condition);
5195 const condition_id = try cg.resolve(pl_op.operand);
51965194
5197 const then_label = cg.module.allocId();5195 const then_label = cg.module.allocId();
5198 const else_label = cg.module.allocId();5196 const else_label = cg.module.allocId();
...@@ -5251,9 +5249,7 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5251,9 +5249,7 @@ fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
52515249
5252fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {5250fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
5253 const gpa = cg.module.gpa;5251 const gpa = cg.module.gpa;
5254 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5252 const block = cg.air.unwrapBlock(inst);
5255 const loop = cg.air.extraData(Air.Block, ty_pl.payload);
5256 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[loop.end..][0..loop.data.body_len]);
52575253
5258 const body_label = cg.module.allocId();5254 const body_label = cg.module.allocId();
52595255
...@@ -5284,7 +5280,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5284,7 +5280,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
5284 const next_block = try cg.genStructuredBody(.{ .loop = .{5280 const next_block = try cg.genStructuredBody(.{ .loop = .{
5285 .merge_label = merge_label,5281 .merge_label = merge_label,
5286 .continue_label = continue_label,5282 .continue_label = continue_label,
5287 } }, body);5283 } }, block.body);
5288 try cg.structuredBreak(next_block);5284 try cg.structuredBreak(next_block);
52895285
5290 try cg.beginSpvBlock(continue_label);5286 try cg.beginSpvBlock(continue_label);
...@@ -5294,7 +5290,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5294,7 +5290,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
5294 .unstructured => {5290 .unstructured => {
5295 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });5291 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });
5296 try cg.beginSpvBlock(body_label);5292 try cg.beginSpvBlock(body_label);
5297 try cg.genBody(body);5293 try cg.genBody(block.body);
52985294
5299 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });5295 try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label });
5300 },5296 },
...@@ -5375,12 +5371,11 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5375,12 +5371,11 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
5375fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5371fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5376 const gpa = cg.module.gpa;5372 const gpa = cg.module.gpa;
5377 const zcu = cg.module.zcu;5373 const zcu = cg.module.zcu;
5378 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5374 const unwrapped_try = cg.air.unwrapTry(inst);
5379 const err_union_id = try cg.resolve(pl_op.operand);5375 const body = unwrapped_try.else_body;
5380 const extra = cg.air.extraData(Air.Try, pl_op.payload);
5381 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]);
53825376
5383 const err_union_ty = cg.typeOf(pl_op.operand);5377 const err_union_id = try cg.resolve(unwrapped_try.error_union);
5378 const err_union_ty = cg.air.typeOf(unwrapped_try.error_union, &zcu.intern_pool);
5384 const payload_ty = cg.typeOfIndex(inst);5379 const payload_ty = cg.typeOfIndex(inst);
53855380
5386 const bool_ty_id = try cg.resolveType(.bool, .direct);5381 const bool_ty_id = try cg.resolveType(.bool, .direct);
...@@ -5882,12 +5877,11 @@ fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5882,12 +5877,11 @@ fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {
58825877
5883fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5878fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5884 const zcu = cg.module.zcu;5879 const zcu = cg.module.zcu;
5885 const inst_datas = cg.air.instructions.items(.data);5880 const block = cg.air.unwrapDbgBlock(inst);
5886 const extra = cg.air.extraData(Air.DbgInlineBlock, inst_datas[@intFromEnum(inst)].ty_pl.payload);
5887 const old_base_line = cg.base_line;5881 const old_base_line = cg.base_line;
5888 defer cg.base_line = old_base_line;5882 defer cg.base_line = old_base_line;
5889 cg.base_line = zcu.navSrcLine(zcu.funcInfo(extra.data.func).owner_nav);5883 cg.base_line = zcu.navSrcLine(zcu.funcInfo(block.func).owner_nav);
5890 return cg.lowerBlock(inst, @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]));5884 return cg.lowerBlock(inst, block.body);
5891}5885}
58925886
5893fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {5887fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {
...@@ -5900,52 +5894,34 @@ fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5900,52 +5894,34 @@ fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {
5900fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5894fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5901 const gpa = cg.module.gpa;5895 const gpa = cg.module.gpa;
5902 const zcu = cg.module.zcu;5896 const zcu = cg.module.zcu;
5903 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5897 const unwrapped_asm = cg.air.unwrapAsm(inst);
5904 const extra = cg.air.extraData(Air.Asm, ty_pl.payload);
59055898
5906 const is_volatile = extra.data.flags.is_volatile;5899 const is_volatile = unwrapped_asm.is_volatile;
5907 const outputs_len = extra.data.flags.outputs_len;5900 const outputs_len = unwrapped_asm.outputs.len;
59085901
5909 if (!is_volatile and cg.liveness.isUnused(inst)) return null;5902 if (!is_volatile and cg.liveness.isUnused(inst)) return null;
59105903
5911 var extra_i: usize = extra.end;5904 if (outputs_len > 1) {
5912 const outputs: []const Air.Inst.Ref = @ptrCast(cg.air.extra.items[extra_i..][0..outputs_len]);
5913 extra_i += outputs.len;
5914 const inputs: []const Air.Inst.Ref = @ptrCast(cg.air.extra.items[extra_i..][0..extra.data.inputs_len]);
5915 extra_i += inputs.len;
5916
5917 if (outputs.len > 1) {
5918 return cg.todo("implement inline asm with more than 1 output", .{});5905 return cg.todo("implement inline asm with more than 1 output", .{});
5919 }5906 }
59205907
5921 var ass: Assembler = .{ .cg = cg };5908 var ass: Assembler = .{ .cg = cg };
5922 defer ass.deinit();5909 defer ass.deinit();
59235910
5924 var output_extra_i = extra_i;5911 var it = unwrapped_asm.iterateOutputs();
5925 for (outputs) |output| {5912 while (it.next()) |out| {
5926 if (output != .none) {5913 if (out.operand != .none) {
5927 return cg.todo("implement inline asm with non-returned output", .{});5914 return cg.todo("implement inline asm with non-returned output", .{});
5928 }5915 }
5929 const extra_bytes = std.mem.sliceAsBytes(cg.air.extra.items[extra_i..]);
5930 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(cg.air.extra.items[extra_i..]), 0);
5931 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
5932 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
5933 // TODO: Record output and use it somewhere.
5934 }5916 }
59355917
5936 for (inputs) |input| {5918 it = unwrapped_asm.iterateInputs();
5937 const extra_bytes = std.mem.sliceAsBytes(cg.air.extra.items[extra_i..]);5919 while (it.next()) |in| {
5938 const constraint = std.mem.sliceTo(extra_bytes, 0);5920 const input_ty = cg.typeOf(in.operand);
5939 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
5940 // This equation accounts for the fact that even if we have exactly 4 bytes
5941 // for the string, we still use the next u32 for the null terminator.
5942 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
5943
5944 const input_ty = cg.typeOf(input);
59455921
5946 if (std.mem.eql(u8, constraint, "c")) {5922 if (std.mem.eql(u8, in.constraint, "c")) {
5947 // constant5923 // constant
5948 const val = (try cg.air.value(input, cg.pt)) orelse {5924 const val = (try cg.air.value(in.operand, cg.pt)) orelse {
5949 return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{});5925 return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{});
5950 };5926 };
59515927
...@@ -5971,37 +5947,36 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5971,37 +5947,36 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
59715947
5972 .undef => return cg.fail("assembly input with 'c' constraint cannot be undefined", .{}),5948 .undef => return cg.fail("assembly input with 'c' constraint cannot be undefined", .{}),
59735949
5974 .int => try ass.value_map.put(gpa, name, .{ .constant = @intCast(val.toUnsignedInt(zcu)) }),5950 .int => try ass.value_map.put(gpa, in.name, .{ .constant = @intCast(val.toUnsignedInt(zcu)) }),
5975 .enum_literal => |str| try ass.value_map.put(gpa, name, .{ .string = str.toSlice(ip) }),5951 .enum_literal => |str| try ass.value_map.put(gpa, in.name, .{ .string = str.toSlice(ip) }),
59765952
5977 else => unreachable, // TODO5953 else => unreachable, // TODO
5978 }5954 }
5979 } else if (std.mem.eql(u8, constraint, "t")) {5955 } else if (std.mem.eql(u8, in.constraint, "t")) {
5980 // type5956 // type
5981 if (input_ty.zigTypeTag(zcu) == .type) {5957 if (input_ty.zigTypeTag(zcu) == .type) {
5982 // This assembly input is a type instead of a value.5958 // This assembly input is a type instead of a value.
5983 // That's fine for now, just make sure to resolve it as such.5959 // That's fine for now, just make sure to resolve it as such.
5984 const val = (try cg.air.value(input, cg.pt)).?;5960 const val = (try cg.air.value(in.operand, cg.pt)).?;
5985 const ty_id = try cg.resolveType(val.toType(), .direct);5961 const ty_id = try cg.resolveType(val.toType(), .direct);
5986 try ass.value_map.put(gpa, name, .{ .ty = ty_id });5962 try ass.value_map.put(gpa, in.name, .{ .ty = ty_id });
5987 } else {5963 } else {
5988 const ty_id = try cg.resolveType(input_ty, .direct);5964 const ty_id = try cg.resolveType(input_ty, .direct);
5989 try ass.value_map.put(gpa, name, .{ .ty = ty_id });5965 try ass.value_map.put(gpa, in.name, .{ .ty = ty_id });
5990 }5966 }
5991 } else {5967 } else {
5992 if (input_ty.zigTypeTag(zcu) == .type) {5968 if (input_ty.zigTypeTag(zcu) == .type) {
5993 return cg.fail("use the 't' constraint to supply types to SPIR-V inline assembly", .{});5969 return cg.fail("use the 't' constraint to supply types to SPIR-V inline assembly", .{});
5994 }5970 }
59955971
5996 const val_id = try cg.resolve(input);5972 const val_id = try cg.resolve(in.operand);
5997 try ass.value_map.put(gpa, name, .{ .value = val_id });5973 try ass.value_map.put(gpa, in.name, .{ .value = val_id });
5998 }5974 }
5999 }5975 }
6000
6001 // TODO: do something with clobbers5976 // TODO: do something with clobbers
6002 _ = extra.data.clobbers;5977 _ = unwrapped_asm.clobbers;
60035978
6004 const asm_source = std.mem.sliceAsBytes(cg.air.extra.items[extra_i..])[0..extra.data.source_len];5979 const asm_source = unwrapped_asm.source;
60055980
6006 ass.assemble(asm_source) catch |err| switch (err) {5981 ass.assemble(asm_source) catch |err| switch (err) {
6007 error.AssembleFail => {5982 error.AssembleFail => {
...@@ -6033,26 +6008,20 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6033,26 +6008,20 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6033 else => |others| return others,6008 else => |others| return others,
6034 };6009 };
60356010
6036 for (outputs) |output| {6011 it = unwrapped_asm.iterateOutputs();
6037 _ = output;6012 while (it.next()) |out| {
6038 const extra_bytes = std.mem.sliceAsBytes(cg.air.extra.items[output_extra_i..]);6013 const result = ass.value_map.get(out.name) orelse return {
6039 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(cg.air.extra.items[output_extra_i..]), 0);6014 return cg.fail("invalid asm output '{s}'", .{out.name});
6040 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
6041 output_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
6042
6043 const result = ass.value_map.get(name) orelse return {
6044 return cg.fail("invalid asm output '{s}'", .{name});
6045 };6015 };
6046
6047 switch (result) {6016 switch (result) {
6048 .just_declared, .unresolved_forward_reference => unreachable,6017 .just_declared, .unresolved_forward_reference => unreachable,
6049 .ty => return cg.fail("cannot return spir-v type as value from assembly", .{}),6018 .ty => return cg.fail("cannot return spir-v type as value from assembly", .{}),
6050 .value => |ref| return ref,6019 .value => |ref| return ref,
6051 .constant, .string => return cg.fail("cannot return constant from assembly", .{}),6020 .constant, .string => return cg.fail("cannot return constant from assembly", .{}),
6052 }6021 }
6053
6054 // TODO: Multiple results6022 // TODO: Multiple results
6055 // TODO: Check that the output type from assembly is the same as the type actually expected by Zig.6023 // TODO: Check that the output type from assembly is the same as the type actually expected by Zig.
6024
6056 }6025 }
60576026
6058 return null;6027 return null;
...@@ -6063,10 +6032,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -6063,10 +6032,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
60636032
6064 const gpa = cg.module.gpa;6033 const gpa = cg.module.gpa;
6065 const zcu = cg.module.zcu;6034 const zcu = cg.module.zcu;
6066 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6035 const air_call = cg.air.unwrapCall(inst);
6067 const extra = cg.air.extraData(Air.Call, pl_op.payload);6036 const args = air_call.args;
6068 const args: []const Air.Inst.Ref = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.args_len]);6037 const callee_ty = cg.typeOf(air_call.callee);
6069 const callee_ty = cg.typeOf(pl_op.operand);
6070 const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) {6038 const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) {
6071 .@"fn" => callee_ty,6039 .@"fn" => callee_ty,
6072 .pointer => return cg.fail("cannot call function pointers", .{}),6040 .pointer => return cg.fail("cannot call function pointers", .{}),
...@@ -6077,7 +6045,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -6077,7 +6045,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
60776045
6078 const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type));6046 const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type));
6079 const result_id = cg.module.allocId();6047 const result_id = cg.module.allocId();
6080 const callee_id = try cg.resolve(pl_op.operand);6048 const callee_id = try cg.resolve(air_call.callee);
60816049
6082 comptime assert(zig_call_abi_ver == 3);6050 comptime assert(zig_call_abi_ver == 3);
60836051
src/codegen/wasm/CodeGen.zig+26-34
...@@ -2137,10 +2137,9 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2137,10 +2137,9 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
21372137
2138fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {2138fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {
2139 if (modifier == .always_tail) return cg.fail("TODO implement tail calls for wasm", .{});2139 if (modifier == .always_tail) return cg.fail("TODO implement tail calls for wasm", .{});
2140 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;2140 const call = cg.air.unwrapCall(inst);
2141 const extra = cg.air.extraData(Air.Call, pl_op.payload);2141 const args = call.args;
2142 const args: []const Air.Inst.Ref = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.args_len]);2142 const ty = cg.typeOf(call.callee);
2143 const ty = cg.typeOf(pl_op.operand);
21442143
2145 const pt = cg.pt;2144 const pt = cg.pt;
2146 const zcu = pt.zcu;2145 const zcu = pt.zcu;
...@@ -2155,7 +2154,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -2155,7 +2154,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
2155 const first_param_sret = firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), zcu, cg.target);2154 const first_param_sret = firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), zcu, cg.target);
21562155
2157 const callee: ?InternPool.Nav.Index = blk: {2156 const callee: ?InternPool.Nav.Index = blk: {
2158 const func_val = (try cg.air.value(pl_op.operand, pt)) orelse break :blk null;2157 const func_val = (try cg.air.value(call.callee, pt)) orelse break :blk null;
21592158
2160 switch (ip.indexToKey(func_val.toIntern())) {2159 switch (ip.indexToKey(func_val.toIntern())) {
2161 inline .func, .@"extern" => |x| break :blk x.owner_nav,2160 inline .func, .@"extern" => |x| break :blk x.owner_nav,
...@@ -2189,7 +2188,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -2189,7 +2188,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
2189 // in this case we call a function pointer2188 // in this case we call a function pointer
2190 // so load its value onto the stack2189 // so load its value onto the stack
2191 assert(ty.zigTypeTag(zcu) == .pointer);2190 assert(ty.zigTypeTag(zcu) == .pointer);
2192 const operand = try cg.resolveInst(pl_op.operand);2191 const operand = try cg.resolveInst(call.callee);
2193 try cg.emitWValue(operand);2192 try cg.emitWValue(operand);
21942193
2195 try cg.mir_func_tys.put(cg.gpa, fn_ty.toIntern(), {});2194 try cg.mir_func_tys.put(cg.gpa, fn_ty.toIntern(), {});
...@@ -2233,7 +2232,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -2233,7 +2232,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
2233 };2232 };
22342233
2235 var bt = try cg.iterateBigTomb(inst, 1 + args.len);2234 var bt = try cg.iterateBigTomb(inst, 1 + args.len);
2236 bt.feed(pl_op.operand);2235 bt.feed(call.callee);
2237 for (args) |arg| bt.feed(arg);2236 for (args) |arg| bt.feed(arg);
2238 return bt.finishAir(result_value);2237 return bt.finishAir(result_value);
2239}2238}
...@@ -3335,9 +3334,8 @@ fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {...@@ -3335,9 +3334,8 @@ fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {
3335}3334}
33363335
3337fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {3336fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3338 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3337 const block = cg.air.unwrapBlock(inst);
3339 const extra = cg.air.extraData(Air.Block, ty_pl.payload);3338 try cg.lowerBlock(inst, block.ty, block.body);
3340 try cg.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]));
3341}3339}
33423340
3343fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {3341fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
...@@ -3381,9 +3379,7 @@ fn endBlock(cg: *CodeGen) !void {...@@ -3381,9 +3379,7 @@ fn endBlock(cg: *CodeGen) !void {
3381}3379}
33823380
3383fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {3381fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3384 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3382 const block = cg.air.unwrapBlock(inst);
3385 const loop = cg.air.extraData(Air.Block, ty_pl.payload);
3386 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[loop.end..][0..loop.data.body_len]);
33873383
3388 // result type of loop is always 'noreturn', meaning we can always3384 // result type of loop is always 'noreturn', meaning we can always
3389 // emit the wasm type 'block_empty'.3385 // emit the wasm type 'block_empty'.
...@@ -3392,18 +3388,17 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3392,18 +3388,17 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3392 try cg.loops.putNoClobber(cg.gpa, inst, cg.block_depth);3388 try cg.loops.putNoClobber(cg.gpa, inst, cg.block_depth);
3393 defer assert(cg.loops.remove(inst));3389 defer assert(cg.loops.remove(inst));
33943390
3395 try cg.genBody(body);3391 try cg.genBody(block.body);
3396 try cg.endBlock();3392 try cg.endBlock();
33973393
3398 return cg.finishAir(inst, .none, &.{});3394 return cg.finishAir(inst, .none, &.{});
3399}3395}
34003396
3401fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {3397fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3402 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;3398 const cond_br = cg.air.unwrapCondBr(inst);
3403 const condition = try cg.resolveInst(pl_op.operand);3399 const condition = try cg.resolveInst(cond_br.condition);
3404 const extra = cg.air.extraData(Air.CondBr, pl_op.payload);3400 const then_body = cond_br.then_body;
3405 const then_body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.then_body_len]);3401 const else_body = cond_br.else_body;
3406 const else_body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
3407 const liveness_condbr = cg.liveness.getCondBr(inst);3402 const liveness_condbr = cg.liveness.getCondBr(inst);
34083403
3409 // result type is always noreturn, so use `block_empty` as type.3404 // result type is always noreturn, so use `block_empty` as type.
...@@ -6423,10 +6418,9 @@ fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6423,10 +6418,9 @@ fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6423}6418}
64246419
6425fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6420fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6426 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6421 const block = cg.air.unwrapDbgBlock(inst);
6427 const extra = cg.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
6428 // TODO6422 // TODO
6429 try cg.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]));6423 try cg.lowerBlock(inst, block.ty, block.body);
6430}6424}
64316425
6432fn airDbgVar(6426fn airDbgVar(
...@@ -6441,24 +6435,22 @@ fn airDbgVar(...@@ -6441,24 +6435,22 @@ fn airDbgVar(
6441}6435}
64426436
6443fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6437fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6444 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6438 const unwrapped_try = cg.air.unwrapTry(inst);
6445 const err_union = try cg.resolveInst(pl_op.operand);6439 const body = unwrapped_try.else_body;
6446 const extra = cg.air.extraData(Air.Try, pl_op.payload);6440 const err_union = try cg.resolveInst(unwrapped_try.error_union);
6447 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]);6441 const err_union_ty = cg.typeOf(unwrapped_try.error_union);
6448 const err_union_ty = cg.typeOf(pl_op.operand);
6449 const result = try lowerTry(cg, inst, err_union, body, err_union_ty, false);6442 const result = try lowerTry(cg, inst, err_union, body, err_union_ty, false);
6450 return cg.finishAir(inst, result, &.{pl_op.operand});6443 return cg.finishAir(inst, result, &.{unwrapped_try.error_union});
6451}6444}
64526445
6453fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6446fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6454 const zcu = cg.pt.zcu;6447 const zcu = cg.pt.zcu;
6455 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6448 const unwrapped_try = cg.air.unwrapTryPtr(inst);
6456 const extra = cg.air.extraData(Air.TryPtr, ty_pl.payload);6449 const err_union_ptr = try cg.resolveInst(unwrapped_try.error_union_ptr);
6457 const err_union_ptr = try cg.resolveInst(extra.data.ptr);6450 const body = unwrapped_try.else_body;
6458 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]);6451 const err_union_ty = cg.typeOf(unwrapped_try.error_union_ptr).childType(zcu);
6459 const err_union_ty = cg.typeOf(extra.data.ptr).childType(zcu);
6460 const result = try lowerTry(cg, inst, err_union_ptr, body, err_union_ty, true);6452 const result = try lowerTry(cg, inst, err_union_ptr, body, err_union_ty, true);
6461 return cg.finishAir(inst, result, &.{extra.data.ptr});6453 return cg.finishAir(inst, result, &.{unwrapped_try.error_union_ptr});
6462}6454}
64636455
6464fn lowerTry(6456fn lowerTry(
src/codegen/x86_64/CodeGen.zig+86-117
...@@ -67348,21 +67348,19 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -67348,21 +67348,19 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
67348 },67348 },
67349 .bitcast => try cg.airBitCast(inst),67349 .bitcast => try cg.airBitCast(inst),
67350 .block => {67350 .block => {
67351 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;67351 const block = cg.air.unwrapBlock(inst);
67352 const block = cg.air.extraData(Air.Block, ty_pl.payload);
67353 if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_enter_block_none);67352 if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_enter_block_none);
67354 try cg.lowerBlock(inst, @ptrCast(cg.air.extra.items[block.end..][0..block.data.body_len]));67353 try cg.lowerBlock(inst, block.body);
67355 if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_leave_block_none);67354 if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_leave_block_none);
67356 },67355 },
67357 .loop => {67356 .loop => {
67358 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;67357 const block = cg.air.unwrapBlock(inst);
67359 const block = cg.air.extraData(Air.Block, ty_pl.payload);
67360 try cg.loops.putNoClobber(cg.gpa, inst, .{67358 try cg.loops.putNoClobber(cg.gpa, inst, .{
67361 .state = try cg.saveState(),67359 .state = try cg.saveState(),
67362 .target = @intCast(cg.mir_instructions.len),67360 .target = @intCast(cg.mir_instructions.len),
67363 });67361 });
67364 defer assert(cg.loops.remove(inst));67362 defer assert(cg.loops.remove(inst));
67365 try cg.genBodyBlock(@ptrCast(cg.air.extra.items[block.end..][0..block.data.body_len]));67363 try cg.genBodyBlock(block.body);
67366 },67364 },
67367 .repeat => {67365 .repeat => {
67368 const repeat = air_datas[@intFromEnum(inst)].repeat;67366 const repeat = air_datas[@intFromEnum(inst)].repeat;
...@@ -89048,17 +89046,16 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -89048,17 +89046,16 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
89048 try cg.asmOpOnly(.{ ._, .nop });89046 try cg.asmOpOnly(.{ ._, .nop });
89049 },89047 },
89050 .dbg_inline_block => {89048 .dbg_inline_block => {
89051 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;89049 const dbg_inline_block = cg.air.unwrapDbgBlock(inst);
89052 const dbg_inline_block = cg.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
89053 const old_inline_func = cg.inline_func;89050 const old_inline_func = cg.inline_func;
89054 defer cg.inline_func = old_inline_func;89051 defer cg.inline_func = old_inline_func;
89055 cg.inline_func = dbg_inline_block.data.func;89052 cg.inline_func = dbg_inline_block.func;
89056 if (!cg.mod.strip) _ = try cg.addInst(.{89053 if (!cg.mod.strip) _ = try cg.addInst(.{
89057 .tag = .pseudo,89054 .tag = .pseudo,
89058 .ops = .pseudo_dbg_enter_inline_func,89055 .ops = .pseudo_dbg_enter_inline_func,
89059 .data = .{ .ip_index = dbg_inline_block.data.func },89056 .data = .{ .ip_index = dbg_inline_block.func },
89060 });89057 });
89061 try cg.lowerBlock(inst, @ptrCast(cg.air.extra.items[dbg_inline_block.end..][0..dbg_inline_block.data.body_len]));89058 try cg.lowerBlock(inst, dbg_inline_block.body);
89062 if (!cg.mod.strip) _ = try cg.addInst(.{89059 if (!cg.mod.strip) _ = try cg.addInst(.{
89063 .tag = .pseudo,89060 .tag = .pseudo,
89064 .ops = .pseudo_dbg_leave_inline_func,89061 .ops = .pseudo_dbg_leave_inline_func,
...@@ -175916,10 +175913,8 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue...@@ -175916,10 +175913,8 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue
175916fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier, opts: CopyOptions) !void {175913fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier, opts: CopyOptions) !void {
175917 if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});175914 if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});
175918175915
175919 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;175916 const call = self.air.unwrapCall(inst);
175920 const extra = self.air.extraData(Air.Call, pl_op.payload);175917 const arg_refs = call.args;
175921 const arg_refs: []const Air.Inst.Ref =
175922 @ptrCast(self.air.extra.items[extra.end..][0..extra.data.args_len]);
175923175918
175924 const ExpectedContents = extern struct {175919 const ExpectedContents = extern struct {
175925 tys: [32][@sizeOf(Type)]u8 align(@alignOf(Type)),175920 tys: [32][@sizeOf(Type)]u8 align(@alignOf(Type)),
...@@ -175937,10 +175932,10 @@ fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -175937,10 +175932,10 @@ fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
175937 defer allocator.free(arg_vals);175932 defer allocator.free(arg_vals);
175938 for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref };175933 for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref };
175939175934
175940 const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals, opts);175935 const ret = try self.genCall(.{ .air = call.callee }, arg_tys, arg_vals, opts);
175941175936
175942 var bt = self.liveness.iterateBigTomb(inst);175937 var bt = self.liveness.iterateBigTomb(inst);
175943 try self.feed(&bt, pl_op.operand);175938 try self.feed(&bt, call.callee);
175944 for (arg_refs) |arg_ref| try self.feed(&bt, arg_ref);175939 for (arg_refs) |arg_ref| try self.feed(&bt, arg_ref);
175945175940
175946 const result = if (self.liveness.isUnused(inst)) .unreach else ret;175941 const result = if (self.liveness.isUnused(inst)) .unreach else ret;
...@@ -176300,20 +176295,18 @@ fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -176300,20 +176295,18 @@ fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void {
176300}176295}
176301176296
176302fn airTry(self: *CodeGen, inst: Air.Inst.Index) !void {176297fn airTry(self: *CodeGen, inst: Air.Inst.Index) !void {
176303 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;176298 const unwrapped_try = self.air.unwrapTry(inst);
176304 const extra = self.air.extraData(Air.Try, pl_op.payload);176299 const body = unwrapped_try.else_body;
176305 const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);176300 const operand_ty = self.typeOf(unwrapped_try.error_union);
176306 const operand_ty = self.typeOf(pl_op.operand);176301 const result = try self.genTry(inst, unwrapped_try.error_union, body, operand_ty, false);
176307 const result = try self.genTry(inst, pl_op.operand, body, operand_ty, false);
176308 return self.finishAir(inst, result, .{ .none, .none, .none });176302 return self.finishAir(inst, result, .{ .none, .none, .none });
176309}176303}
176310176304
176311fn airTryPtr(self: *CodeGen, inst: Air.Inst.Index) !void {176305fn airTryPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
176312 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;176306 const unwrapped_try = self.air.unwrapTryPtr(inst);
176313 const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);176307 const body = unwrapped_try.else_body;
176314 const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);176308 const operand_ty = self.typeOf(unwrapped_try.error_union_ptr);
176315 const operand_ty = self.typeOf(extra.data.ptr);176309 const result = try self.genTry(inst, unwrapped_try.error_union_ptr, body, operand_ty, true);
176316 const result = try self.genTry(inst, extra.data.ptr, body, operand_ty, true);
176317 return self.finishAir(inst, result, .{ .none, .none, .none });176310 return self.finishAir(inst, result, .{ .none, .none, .none });
176318}176311}
176319176312
...@@ -176391,21 +176384,20 @@ fn genCondBrMir(self: *CodeGen, ty: Type, mcv: MCValue) !Mir.Inst.Index {...@@ -176391,21 +176384,20 @@ fn genCondBrMir(self: *CodeGen, ty: Type, mcv: MCValue) !Mir.Inst.Index {
176391}176384}
176392176385
176393fn airCondBr(self: *CodeGen, inst: Air.Inst.Index) !void {176386fn airCondBr(self: *CodeGen, inst: Air.Inst.Index) !void {
176394 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;176387 const cond_br = self.air.unwrapCondBr(inst);
176395 const cond = try self.resolveInst(pl_op.operand);176388 const then_body = cond_br.then_body;
176396 const cond_ty = self.typeOf(pl_op.operand);176389 const else_body = cond_br.else_body;
176397 const extra = self.air.extraData(Air.CondBr, pl_op.payload);176390
176398 const then_body: []const Air.Inst.Index =176391 const cond = try self.resolveInst(cond_br.condition);
176399 @ptrCast(self.air.extra.items[extra.end..][0..extra.data.then_body_len]);176392 const cond_ty = self.typeOf(cond_br.condition);
176400 const else_body: []const Air.Inst.Index =176393
176401 @ptrCast(self.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
176402 const liveness_cond_br = self.liveness.getCondBr(inst);176394 const liveness_cond_br = self.liveness.getCondBr(inst);
176403176395
176404 // If the condition dies here in this condbr instruction, process176396 // If the condition dies here in this condbr instruction, process
176405 // that death now instead of later as this has an effect on176397 // that death now instead of later as this has an effect on
176406 // whether it needs to be spilled in the branches176398 // whether it needs to be spilled in the branches
176407 if (self.liveness.operandDies(inst, 0)) {176399 if (self.liveness.operandDies(inst, 0)) {
176408 if (pl_op.operand.toIndex()) |op_inst| try self.processDeath(op_inst, .{});176400 if (cond_br.condition.toIndex()) |op_inst| try self.processDeath(op_inst, .{});
176409 }176401 }
176410176402
176411 const state = try self.saveState();176403 const state = try self.saveState();
...@@ -177124,14 +177116,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177124,14 +177116,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177124 @setEvalBranchQuota(1_100);177116 @setEvalBranchQuota(1_100);
177125 const pt = self.pt;177117 const pt = self.pt;
177126 const zcu = pt.zcu;177118 const zcu = pt.zcu;
177127 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;177119 const unwrapped_asm = self.air.unwrapAsm(inst);
177128 const extra = self.air.extraData(Air.Asm, ty_pl.payload);177120
177129 const outputs_len = extra.data.flags.outputs_len;177121 const outputs = unwrapped_asm.outputs;
177130 var extra_i: usize = extra.end;177122 const inputs = unwrapped_asm.inputs;
177131 const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..outputs_len]);
177132 extra_i += outputs.len;
177133 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra_i..][0..extra.data.inputs_len]);
177134 extra_i += inputs.len;
177135177123
177136 var result: MCValue = .none;177124 var result: MCValue = .none;
177137 var args: std.array_list.Managed(MCValue) = .init(self.gpa);177125 var args: std.array_list.Managed(MCValue) = .init(self.gpa);
...@@ -177146,36 +177134,29 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177146,36 +177134,29 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177146 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));177134 try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));
177147 defer arg_map.deinit();177135 defer arg_map.deinit();
177148177136
177149 var outputs_extra_i = extra_i;177137 var it = unwrapped_asm.iterateOutputs();
177150 for (outputs) |output| {177138 while (it.next()) |out| {
177151 const extra_bytes = std.mem.sliceAsBytes(self.air.extra.items[extra_i..]);177139 const maybe_inst = switch (out.operand) {
177152 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[extra_i..]), 0);
177153 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
177154 // This equation accounts for the fact that even if we have exactly 4 bytes
177155 // for the string, we still use the next u32 for the null terminator.
177156 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
177157
177158 const maybe_inst = switch (output) {
177159 .none => inst,177140 .none => inst,
177160 else => null,177141 else => null,
177161 };177142 };
177162 const ty = switch (output) {177143 const ty = switch (out.operand) {
177163 .none => self.typeOfIndex(inst),177144 .none => self.typeOfIndex(inst),
177164 else => self.typeOf(output).childType(zcu),177145 else => self.typeOf(out.operand).childType(zcu),
177165 };177146 };
177166 const is_read = switch (constraint[0]) {177147 const is_read = switch (out.constraint[0]) {
177167 '=' => false,177148 '=' => false,
177168 '+' => read: {177149 '+' => read: {
177169 if (output == .none) return self.fail(177150 if (out.operand == .none) return self.fail(
177170 "read-write constraint unsupported for asm result: '{s}'",177151 "read-write constraint unsupported for asm result: '{s}'",
177171 .{constraint},177152 .{out.constraint},
177172 );177153 );
177173 break :read true;177154 break :read true;
177174 },177155 },
177175 else => return self.fail("invalid constraint: '{s}'", .{constraint}),177156 else => return self.fail("invalid constraint: '{s}'", .{out.constraint}),
177176 };177157 };
177177 const is_early_clobber = constraint[1] == '&';177158 const is_early_clobber = out.constraint[1] == '&';
177178 const rest = constraint[@as(usize, 1) + @intFromBool(is_early_clobber) ..];177159 const rest = out.constraint[@as(usize, 1) + @intFromBool(is_early_clobber) ..];
177179 const arg_mcv: MCValue = arg_mcv: {177160 const arg_mcv: MCValue = arg_mcv: {
177180 const arg_maybe_reg: ?Register = if (std.mem.eql(u8, rest, "r") or177161 const arg_maybe_reg: ?Register = if (std.mem.eql(u8, rest, "r") or
177181 std.mem.eql(u8, rest, "f") or std.mem.eql(u8, rest, "x"))177162 std.mem.eql(u8, rest, "f") or std.mem.eql(u8, rest, "x"))
...@@ -177189,30 +177170,30 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177189,30 +177170,30 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177189 @intCast(ty.abiSize(zcu)),177170 @intCast(ty.abiSize(zcu)),
177190 )177171 )
177191 else if (std.mem.eql(u8, rest, "m"))177172 else if (std.mem.eql(u8, rest, "m"))
177192 if (output != .none) null else return self.fail(177173 if (out.operand != .none) null else return self.fail(
177193 "memory constraint unsupported for asm result: '{s}'",177174 "memory constraint unsupported for asm result: '{s}'",
177194 .{constraint},177175 .{out.constraint},
177195 )177176 )
177196 else if (std.mem.eql(u8, rest, "g") or177177 else if (std.mem.eql(u8, rest, "g") or
177197 std.mem.eql(u8, rest, "rm") or std.mem.eql(u8, rest, "mr") or177178 std.mem.eql(u8, rest, "rm") or std.mem.eql(u8, rest, "mr") or
177198 std.mem.eql(u8, rest, "r,m") or std.mem.eql(u8, rest, "m,r"))177179 std.mem.eql(u8, rest, "r,m") or std.mem.eql(u8, rest, "m,r"))
177199 self.register_manager.tryAllocReg(maybe_inst, abi.RegisterClass.gp) orelse177180 self.register_manager.tryAllocReg(maybe_inst, abi.RegisterClass.gp) orelse
177200 if (output != .none)177181 if (out.operand != .none)
177201 null177182 null
177202 else177183 else
177203 return self.fail("ran out of registers lowering inline asm", .{})177184 return self.fail("ran out of registers lowering inline asm", .{})
177204 else if (std.mem.startsWith(u8, rest, "{") and std.mem.endsWith(u8, rest, "}"))177185 else if (std.mem.startsWith(u8, rest, "{") and std.mem.endsWith(u8, rest, "}"))
177205 parseRegName(rest["{".len .. rest.len - "}".len]) orelse177186 parseRegName(rest["{".len .. rest.len - "}".len]) orelse
177206 return self.fail("invalid register constraint: '{s}'", .{constraint})177187 return self.fail("invalid register constraint: '{s}'", .{out.constraint})
177207 else if (rest.len == 1 and std.ascii.isDigit(rest[0])) {177188 else if (rest.len == 1 and std.ascii.isDigit(rest[0])) {
177208 const index = std.fmt.charToDigit(rest[0], 10) catch unreachable;177189 const index = std.fmt.charToDigit(rest[0], 10) catch unreachable;
177209 if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{177190 if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{
177210 constraint,177191 out.constraint,
177211 });177192 });
177212 break :arg_mcv args.items[index];177193 break :arg_mcv args.items[index];
177213 } else return self.fail("invalid constraint: '{s}'", .{constraint});177194 } else return self.fail("invalid constraint: '{s}'", .{out.constraint});
177214 break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {177195 break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
177215 const ptr_mcv = try self.resolveInst(output);177196 const ptr_mcv = try self.resolveInst(out.operand);
177216 switch (ptr_mcv) {177197 switch (ptr_mcv) {
177217 .immediate => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|177198 .immediate => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|
177218 break :arg ptr_mcv.deref(),177199 break :arg ptr_mcv.deref(),
...@@ -177223,30 +177204,24 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177223,30 +177204,24 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177223 };177204 };
177224 };177205 };
177225 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |tracked_index| {177206 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |tracked_index| {
177226 try self.register_manager.getRegIndex(tracked_index, if (output == .none) inst else null);177207 try self.register_manager.getRegIndex(tracked_index, if (out.operand == .none) inst else null);
177227 _ = self.register_manager.lockRegIndexAssumeUnused(tracked_index);177208 _ = self.register_manager.lockRegIndexAssumeUnused(tracked_index);
177228 };177209 };
177229 if (!std.mem.eql(u8, name, "_"))177210 if (!std.mem.eql(u8, out.name, "_"))
177230 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));177211 arg_map.putAssumeCapacityNoClobber(out.name, @intCast(args.items.len));
177231 args.appendAssumeCapacity(arg_mcv);177212 args.appendAssumeCapacity(arg_mcv);
177232 if (output == .none) result = arg_mcv;177213 if (out.operand == .none) result = arg_mcv;
177233 if (is_read) try self.load(arg_mcv, self.typeOf(output), .{ .air_ref = output });177214 if (is_read) try self.load(arg_mcv, self.typeOf(out.operand), .{ .air_ref = out.operand });
177234 }177215 }
177235177216
177236 for (inputs) |input| {177217 it = unwrapped_asm.iterateInputs();
177237 const input_bytes = std.mem.sliceAsBytes(self.air.extra.items[extra_i..]);177218 while (it.next()) |in| {
177238 const constraint = std.mem.sliceTo(input_bytes, 0);177219 const ty = self.typeOf(in.operand);
177239 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);177220 const input_mcv = try self.resolveInst(in.operand);
177240 // This equation accounts for the fact that even if we have exactly 4 bytes177221 const arg_mcv: MCValue = if (std.mem.eql(u8, in.constraint, "r") or
177241 // for the string, we still use the next u32 for the null terminator.177222 std.mem.eql(u8, in.constraint, "f") or std.mem.eql(u8, in.constraint, "x"))
177242 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
177243
177244 const ty = self.typeOf(input);
177245 const input_mcv = try self.resolveInst(input);
177246 const arg_mcv: MCValue = if (std.mem.eql(u8, constraint, "r") or
177247 std.mem.eql(u8, constraint, "f") or std.mem.eql(u8, constraint, "x"))
177248 arg: {177223 arg: {
177249 const rc = switch (constraint[0]) {177224 const rc = switch (in.constraint[0]) {
177250 'r' => abi.RegisterClass.gp,177225 'r' => abi.RegisterClass.gp,
177251 'f' => abi.RegisterClass.x87,177226 'f' => abi.RegisterClass.x87,
177252 'x' => abi.RegisterClass.sse,177227 'x' => abi.RegisterClass.sse,
...@@ -177258,14 +177233,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177258,14 +177233,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177258 const reg = try self.register_manager.allocReg(null, rc);177233 const reg = try self.register_manager.allocReg(null, rc);
177259 try self.genSetReg(reg, ty, input_mcv, .{});177234 try self.genSetReg(reg, ty, input_mcv, .{});
177260 break :arg .{ .register = registerAlias(reg, @intCast(ty.abiSize(zcu))) };177235 break :arg .{ .register = registerAlias(reg, @intCast(ty.abiSize(zcu))) };
177261 } else if (std.mem.eql(u8, constraint, "i") or std.mem.eql(u8, constraint, "n"))177236 } else if (std.mem.eql(u8, in.constraint, "i") or std.mem.eql(u8, in.constraint, "n"))
177262 switch (input_mcv) {177237 switch (input_mcv) {
177263 .immediate => |imm| .{ .immediate = imm },177238 .immediate => |imm| .{ .immediate = imm },
177264 else => return self.fail("immediate operand requires comptime value: '{s}'", .{177239 else => return self.fail("immediate operand requires comptime value: '{s}'", .{
177265 constraint,177240 in.constraint,
177266 }),177241 }),
177267 }177242 }
177268 else if (std.mem.eql(u8, constraint, "m")) arg: {177243 else if (std.mem.eql(u8, in.constraint, "m")) arg: {
177269 switch (input_mcv) {177244 switch (input_mcv) {
177270 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|177245 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|
177271 break :arg input_mcv,177246 break :arg input_mcv,
...@@ -177284,9 +177259,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177284,9 +177259,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177284 };177259 };
177285 try self.genSetReg(addr_reg, .usize, input_mcv.address(), .{});177260 try self.genSetReg(addr_reg, .usize, input_mcv.address(), .{});
177286 break :arg .{ .indirect = .{ .reg = addr_reg } };177261 break :arg .{ .indirect = .{ .reg = addr_reg } };
177287 } else if (std.mem.eql(u8, constraint, "g") or177262 } else if (std.mem.eql(u8, in.constraint, "g") or
177288 std.mem.eql(u8, constraint, "rm") or std.mem.eql(u8, constraint, "mr") or177263 std.mem.eql(u8, in.constraint, "rm") or std.mem.eql(u8, in.constraint, "mr") or
177289 std.mem.eql(u8, constraint, "r,m") or std.mem.eql(u8, constraint, "m,r"))177264 std.mem.eql(u8, in.constraint, "r,m") or std.mem.eql(u8, in.constraint, "m,r"))
177290 arg: {177265 arg: {
177291 switch (input_mcv) {177266 switch (input_mcv) {
177292 .register, .indirect, .load_frame => break :arg input_mcv,177267 .register, .indirect, .load_frame => break :arg input_mcv,
...@@ -177297,30 +177272,30 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177297,30 +177272,30 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177297 const temp_mcv = try self.allocTempRegOrMem(ty, true);177272 const temp_mcv = try self.allocTempRegOrMem(ty, true);
177298 try self.genCopy(ty, temp_mcv, input_mcv, .{});177273 try self.genCopy(ty, temp_mcv, input_mcv, .{});
177299 break :arg temp_mcv;177274 break :arg temp_mcv;
177300 } else if (std.mem.eql(u8, constraint, "X"))177275 } else if (std.mem.eql(u8, in.constraint, "X"))
177301 input_mcv177276 input_mcv
177302 else if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) arg: {177277 else if (std.mem.startsWith(u8, in.constraint, "{") and std.mem.endsWith(u8, in.constraint, "}")) arg: {
177303 const reg = parseRegName(constraint["{".len .. constraint.len - "}".len]) orelse177278 const reg = parseRegName(in.constraint["{".len .. in.constraint.len - "}".len]) orelse
177304 return self.fail("invalid register constraint: '{s}'", .{constraint});177279 return self.fail("invalid register constraint: '{s}'", .{in.constraint});
177305 try self.register_manager.getReg(reg, null);177280 try self.register_manager.getReg(reg, null);
177306 try self.genSetReg(reg, ty, input_mcv, .{});177281 try self.genSetReg(reg, ty, input_mcv, .{});
177307 break :arg .{ .register = reg };177282 break :arg .{ .register = reg };
177308 } else if (constraint.len == 1 and std.ascii.isDigit(constraint[0])) arg: {177283 } else if (in.constraint.len == 1 and std.ascii.isDigit(in.constraint[0])) arg: {
177309 const index = std.fmt.charToDigit(constraint[0], 10) catch unreachable;177284 const index = std.fmt.charToDigit(in.constraint[0], 10) catch unreachable;
177310 if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{constraint});177285 if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{in.constraint});
177311 try self.genCopy(ty, args.items[index], input_mcv, .{});177286 try self.genCopy(ty, args.items[index], input_mcv, .{});
177312 break :arg args.items[index];177287 break :arg args.items[index];
177313 } else return self.fail("invalid constraint: '{s}'", .{constraint});177288 } else return self.fail("invalid constraint: '{s}'", .{in.constraint});
177314 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {177289 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
177315 _ = self.register_manager.lockReg(reg);177290 _ = self.register_manager.lockReg(reg);
177316 };177291 };
177317 if (!std.mem.eql(u8, name, "_"))177292 if (!std.mem.eql(u8, in.name, "_"))
177318 arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));177293 arg_map.putAssumeCapacityNoClobber(in.name, @intCast(args.items.len));
177319 args.appendAssumeCapacity(arg_mcv);177294 args.appendAssumeCapacity(arg_mcv);
177320 }177295 }
177321177296
177322 const ip = &zcu.intern_pool;177297 const ip = &zcu.intern_pool;
177323 const aggregate = ip.indexToKey(extra.data.clobbers).aggregate;177298 const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
177324 const struct_type: Type = .fromInterned(aggregate.ty);177299 const struct_type: Type = .fromInterned(aggregate.ty);
177325 switch (aggregate.storage) {177300 switch (aggregate.storage) {
177326 .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {177301 .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {
...@@ -177390,7 +177365,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177390,7 +177365,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177390 labels.deinit(self.gpa);177365 labels.deinit(self.gpa);
177391 }177366 }
177392177367
177393 const asm_source = std.mem.sliceAsBytes(self.air.extra.items[extra_i..])[0..extra.data.source_len];177368 const asm_source = unwrapped_asm.source;
177394 var line_it = std.mem.tokenizeAny(u8, asm_source, "\n\r;");177369 var line_it = std.mem.tokenizeAny(u8, asm_source, "\n\r;");
177395 next_line: while (line_it.next()) |line| {177370 next_line: while (line_it.next()) |line| {
177396 var mnem_it = std.mem.tokenizeAny(u8, line, " \t");177371 var mnem_it = std.mem.tokenizeAny(u8, line, " \t");
...@@ -177821,19 +177796,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177821,19 +177796,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177821 while (label_it.next()) |label| if (label.value_ptr.pending_relocs.items.len > 0)177796 while (label_it.next()) |label| if (label.value_ptr.pending_relocs.items.len > 0)
177822 return self.fail("undefined label: '{s}'", .{label.key_ptr.*});177797 return self.fail("undefined label: '{s}'", .{label.key_ptr.*});
177823177798
177824 for (outputs, args.items[0..outputs.len]) |output, arg_mcv| {177799 it = unwrapped_asm.iterateOutputs();
177825 const extra_bytes = std.mem.sliceAsBytes(self.air.extra.items[outputs_extra_i..]);177800 while (it.next()) |out| {
177826 const constraint =177801 const arg_mcv = args.items[it.current - 1];
177827 std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra.items[outputs_extra_i..]), 0);177802 if (out.operand == .none) continue;
177828 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
177829 // This equation accounts for the fact that even if we have exactly 4 bytes
177830 // for the string, we still use the next u32 for the null terminator.
177831 outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
177832
177833 if (output == .none) continue;
177834 if (arg_mcv != .register) continue;177803 if (arg_mcv != .register) continue;
177835 if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) continue;177804 if (out.constraint.len == 2 and std.ascii.isDigit(out.constraint[1])) continue;
177836 try self.store(self.typeOf(output), .{ .air_ref = output }, arg_mcv, .{});177805 try self.store(self.typeOf(out.operand), .{ .air_ref = out.operand }, arg_mcv, .{});
177837 }177806 }
177838177807
177839 simple: {177808 simple: {