authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-20 14:45:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-20 14:45:40-07:00
logf3147de7a28767a27406355fd2d93d1bbcec9437
tree3fa1ffc2140e0781959e5f25753beb9c958fad35
parentb9d3527e0ed53c4796ab64b4df7daf0909739807

stage2: extract ZIR printing code into print_zir.zig

also implement textual printing of the ZIR instruction `atomic_rmw`.

4 files changed, 1881 insertions(+), 1855 deletions(-)

CMakeLists.txt+12-10
......@@ -537,16 +537,20 @@ set(ZIG_STAGE2_SOURCES
537537 "${CMAKE_SOURCE_DIR}/lib/std/zig/system.zig"
538538 "${CMAKE_SOURCE_DIR}/lib/std/zig/system/x86.zig"
539539 "${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig"
540 "${CMAKE_SOURCE_DIR}/src/Air.zig"
541 "${CMAKE_SOURCE_DIR}/src/AstGen.zig"
540542 "${CMAKE_SOURCE_DIR}/src/Cache.zig"
541543 "${CMAKE_SOURCE_DIR}/src/Compilation.zig"
542544 "${CMAKE_SOURCE_DIR}/src/DepTokenizer.zig"
545 "${CMAKE_SOURCE_DIR}/src/Liveness.zig"
543546 "${CMAKE_SOURCE_DIR}/src/Module.zig"
544547 "${CMAKE_SOURCE_DIR}/src/Package.zig"
545548 "${CMAKE_SOURCE_DIR}/src/RangeSet.zig"
549 "${CMAKE_SOURCE_DIR}/src/Sema.zig"
546550 "${CMAKE_SOURCE_DIR}/src/ThreadPool.zig"
547551 "${CMAKE_SOURCE_DIR}/src/TypedValue.zig"
548552 "${CMAKE_SOURCE_DIR}/src/WaitGroup.zig"
549 "${CMAKE_SOURCE_DIR}/src/AstGen.zig"
553 "${CMAKE_SOURCE_DIR}/src/Zir.zig"
550554 "${CMAKE_SOURCE_DIR}/src/clang.zig"
551555 "${CMAKE_SOURCE_DIR}/src/clang_options.zig"
552556 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
......@@ -561,17 +565,15 @@ set(ZIG_STAGE2_SOURCES
561565 "${CMAKE_SOURCE_DIR}/src/codegen/x86_64.zig"
562566 "${CMAKE_SOURCE_DIR}/src/glibc.zig"
563567 "${CMAKE_SOURCE_DIR}/src/introspect.zig"
564 "${CMAKE_SOURCE_DIR}/src/Air.zig"
565568 "${CMAKE_SOURCE_DIR}/src/libc_installation.zig"
566569 "${CMAKE_SOURCE_DIR}/src/libcxx.zig"
567570 "${CMAKE_SOURCE_DIR}/src/libtsan.zig"
568571 "${CMAKE_SOURCE_DIR}/src/libunwind.zig"
569572 "${CMAKE_SOURCE_DIR}/src/link.zig"
570573 "${CMAKE_SOURCE_DIR}/src/link/C.zig"
574 "${CMAKE_SOURCE_DIR}/src/link/C/zig.h"
571575 "${CMAKE_SOURCE_DIR}/src/link/Coff.zig"
572576 "${CMAKE_SOURCE_DIR}/src/link/Elf.zig"
573 "${CMAKE_SOURCE_DIR}/src/link/Plan9.zig"
574 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
575577 "${CMAKE_SOURCE_DIR}/src/link/MachO.zig"
576578 "${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig"
577579 "${CMAKE_SOURCE_DIR}/src/link/MachO/Atom.zig"
......@@ -582,20 +584,22 @@ set(ZIG_STAGE2_SOURCES
582584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
583585 "${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig"
584586 "${CMAKE_SOURCE_DIR}/src/link/MachO/commands.zig"
587 "${CMAKE_SOURCE_DIR}/src/link/Plan9.zig"
588 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
585589 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
590 "${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"
586591 "${CMAKE_SOURCE_DIR}/src/link/tapi.zig"
592 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"
587593 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig"
588594 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse/test.zig"
589 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"
590595 "${CMAKE_SOURCE_DIR}/src/link/tapi/yaml.zig"
591 "${CMAKE_SOURCE_DIR}/src/link/C/zig.h"
592 "${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"
593 "${CMAKE_SOURCE_DIR}/src/Liveness.zig"
594596 "${CMAKE_SOURCE_DIR}/src/main.zig"
595597 "${CMAKE_SOURCE_DIR}/src/mingw.zig"
596598 "${CMAKE_SOURCE_DIR}/src/musl.zig"
599 "${CMAKE_SOURCE_DIR}/src/print_air.zig"
597600 "${CMAKE_SOURCE_DIR}/src/print_env.zig"
598601 "${CMAKE_SOURCE_DIR}/src/print_targets.zig"
602 "${CMAKE_SOURCE_DIR}/src/print_zir.zig"
599603 "${CMAKE_SOURCE_DIR}/src/stage1.zig"
600604 "${CMAKE_SOURCE_DIR}/src/target.zig"
601605 "${CMAKE_SOURCE_DIR}/src/tracy.zig"
......@@ -605,8 +609,6 @@ set(ZIG_STAGE2_SOURCES
605609 "${CMAKE_SOURCE_DIR}/src/value.zig"
606610 "${CMAKE_SOURCE_DIR}/src/wasi_libc.zig"
607611 "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"
608 "${CMAKE_SOURCE_DIR}/src/Zir.zig"
609 "${CMAKE_SOURCE_DIR}/src/Sema.zig"
610612)
611613
612614if(MSVC)
src/Zir.zig-1844
......@@ -112,51 +112,6 @@ pub fn deinit(code: *Zir, gpa: *Allocator) void {
112112 code.* = undefined;
113113}
114114
115/// Write human-readable, debug formatted ZIR code to a file.
116pub fn renderAsTextToFile(
117 gpa: *Allocator,
118 scope_file: *Module.Scope.File,
119 fs_file: std.fs.File,
120) !void {
121 var arena = std.heap.ArenaAllocator.init(gpa);
122 defer arena.deinit();
123
124 var writer: Writer = .{
125 .gpa = gpa,
126 .arena = &arena.allocator,
127 .file = scope_file,
128 .code = scope_file.zir,
129 .indent = 0,
130 .parent_decl_node = 0,
131 };
132
133 const main_struct_inst = scope_file.zir.getMainStruct();
134 try fs_file.writer().print("%{d} ", .{main_struct_inst});
135 try writer.writeInstToStream(fs_file.writer(), main_struct_inst);
136 try fs_file.writeAll("\n");
137 const imports_index = scope_file.zir.extra[@enumToInt(ExtraIndex.imports)];
138 if (imports_index != 0) {
139 try fs_file.writeAll("Imports:\n");
140
141 const extra = scope_file.zir.extraData(Inst.Imports, imports_index);
142 var import_i: u32 = 0;
143 var extra_index = extra.end;
144
145 while (import_i < extra.data.imports_len) : (import_i += 1) {
146 const item = scope_file.zir.extraData(Inst.Imports.Item, extra_index);
147 extra_index = item.end;
148
149 const src: LazySrcLoc = .{ .token_abs = item.data.token };
150 const import_path = scope_file.zir.nullTerminatedString(item.data.name);
151 try fs_file.writer().print(" @import(\"{}\") ", .{
152 std.zig.fmtEscapes(import_path),
153 });
154 try writer.writeSrc(fs_file.writer(), src);
155 try fs_file.writer().writeAll("\n");
156 }
157 }
158}
159
160115/// These are untyped instructions generated from an Abstract Syntax Tree.
161116/// The data here is immutable because it is possible to have multiple
162117/// analyses on the same ZIR happening at the same time.
......@@ -2904,1805 +2859,6 @@ pub const Inst = struct {
29042859
29052860pub const SpecialProng = enum { none, @"else", under };
29062861
2907const Writer = struct {
2908 gpa: *Allocator,
2909 arena: *Allocator,
2910 file: *Module.Scope.File,
2911 code: Zir,
2912 indent: u32,
2913 parent_decl_node: u32,
2914
2915 fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index {
2916 return @bitCast(Ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node));
2917 }
2918
2919 fn writeInstToStream(
2920 self: *Writer,
2921 stream: anytype,
2922 inst: Inst.Index,
2923 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2924 const tags = self.code.instructions.items(.tag);
2925 const tag = tags[inst];
2926 try stream.print("= {s}(", .{@tagName(tags[inst])});
2927 switch (tag) {
2928 .array_type,
2929 .as,
2930 .coerce_result_ptr,
2931 .elem_ptr,
2932 .elem_val,
2933 .store,
2934 .store_to_block_ptr,
2935 .store_to_inferred_ptr,
2936 .field_ptr_type,
2937 => try self.writeBin(stream, inst),
2938
2939 .alloc,
2940 .alloc_mut,
2941 .alloc_comptime,
2942 .indexable_ptr_len,
2943 .anyframe_type,
2944 .bit_not,
2945 .bool_not,
2946 .negate,
2947 .negate_wrap,
2948 .load,
2949 .ensure_result_used,
2950 .ensure_result_non_error,
2951 .ret_node,
2952 .ret_load,
2953 .resolve_inferred_alloc,
2954 .optional_type,
2955 .optional_payload_safe,
2956 .optional_payload_unsafe,
2957 .optional_payload_safe_ptr,
2958 .optional_payload_unsafe_ptr,
2959 .err_union_payload_safe,
2960 .err_union_payload_unsafe,
2961 .err_union_payload_safe_ptr,
2962 .err_union_payload_unsafe_ptr,
2963 .err_union_code,
2964 .err_union_code_ptr,
2965 .is_non_null,
2966 .is_non_null_ptr,
2967 .is_non_err,
2968 .is_non_err_ptr,
2969 .typeof,
2970 .typeof_elem,
2971 .struct_init_empty,
2972 .type_info,
2973 .size_of,
2974 .bit_size_of,
2975 .typeof_log2_int_type,
2976 .log2_int_type,
2977 .ptr_to_int,
2978 .error_to_int,
2979 .int_to_error,
2980 .compile_error,
2981 .set_eval_branch_quota,
2982 .enum_to_int,
2983 .align_of,
2984 .bool_to_int,
2985 .embed_file,
2986 .error_name,
2987 .panic,
2988 .set_align_stack,
2989 .set_cold,
2990 .set_float_mode,
2991 .set_runtime_safety,
2992 .sqrt,
2993 .sin,
2994 .cos,
2995 .exp,
2996 .exp2,
2997 .log,
2998 .log2,
2999 .log10,
3000 .fabs,
3001 .floor,
3002 .ceil,
3003 .trunc,
3004 .round,
3005 .tag_name,
3006 .reify,
3007 .type_name,
3008 .frame_type,
3009 .frame_size,
3010 .clz,
3011 .ctz,
3012 .pop_count,
3013 .byte_swap,
3014 .bit_reverse,
3015 .elem_type,
3016 .@"resume",
3017 .@"await",
3018 .await_nosuspend,
3019 .fence,
3020 => try self.writeUnNode(stream, inst),
3021
3022 .ref,
3023 .ret_coerce,
3024 .ensure_err_payload_void,
3025 => try self.writeUnTok(stream, inst),
3026
3027 .bool_br_and,
3028 .bool_br_or,
3029 => try self.writeBoolBr(stream, inst),
3030
3031 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
3032 .param_type => try self.writeParamType(stream, inst),
3033 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
3034 .ptr_type => try self.writePtrType(stream, inst),
3035 .int => try self.writeInt(stream, inst),
3036 .int_big => try self.writeIntBig(stream, inst),
3037 .float => try self.writeFloat(stream, inst),
3038 .float128 => try self.writeFloat128(stream, inst),
3039 .str => try self.writeStr(stream, inst),
3040 .int_type => try self.writeIntType(stream, inst),
3041
3042 .@"break",
3043 .break_inline,
3044 => try self.writeBreak(stream, inst),
3045
3046 .elem_ptr_node,
3047 .elem_val_node,
3048 .field_ptr_named,
3049 .field_val_named,
3050 .slice_start,
3051 .slice_end,
3052 .slice_sentinel,
3053 .array_init,
3054 .array_init_anon,
3055 .array_init_ref,
3056 .array_init_anon_ref,
3057 .union_init_ptr,
3058 .shuffle,
3059 .select,
3060 .atomic_rmw,
3061 .mul_add,
3062 .builtin_call,
3063 .field_parent_ptr,
3064 .memcpy,
3065 .memset,
3066 .builtin_async_call,
3067 => try self.writePlNode(stream, inst),
3068
3069 .struct_init,
3070 .struct_init_ref,
3071 => try self.writeStructInit(stream, inst),
3072
3073 .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst),
3074 .atomic_store => try self.writeAtomicStore(stream, inst),
3075
3076 .struct_init_anon,
3077 .struct_init_anon_ref,
3078 => try self.writeStructInitAnon(stream, inst),
3079
3080 .field_type => try self.writeFieldType(stream, inst),
3081 .field_type_ref => try self.writeFieldTypeRef(stream, inst),
3082
3083 .add,
3084 .addwrap,
3085 .array_cat,
3086 .array_mul,
3087 .mul,
3088 .mulwrap,
3089 .sub,
3090 .subwrap,
3091 .cmp_lt,
3092 .cmp_lte,
3093 .cmp_eq,
3094 .cmp_gte,
3095 .cmp_gt,
3096 .cmp_neq,
3097 .div,
3098 .has_decl,
3099 .has_field,
3100 .mod_rem,
3101 .shl,
3102 .shl_exact,
3103 .shr,
3104 .shr_exact,
3105 .xor,
3106 .store_node,
3107 .error_union_type,
3108 .merge_error_sets,
3109 .bit_and,
3110 .bit_or,
3111 .float_to_int,
3112 .int_to_float,
3113 .int_to_ptr,
3114 .int_to_enum,
3115 .float_cast,
3116 .int_cast,
3117 .err_set_cast,
3118 .ptr_cast,
3119 .truncate,
3120 .align_cast,
3121 .div_exact,
3122 .div_floor,
3123 .div_trunc,
3124 .mod,
3125 .rem,
3126 .bit_offset_of,
3127 .offset_of,
3128 .splat,
3129 .reduce,
3130 .atomic_load,
3131 .bitcast,
3132 .bitcast_result_ptr,
3133 .vector_type,
3134 .maximum,
3135 .minimum,
3136 => try self.writePlNodeBin(stream, inst),
3137
3138 .@"export" => try self.writePlNodeExport(stream, inst),
3139
3140 .call,
3141 .call_chkused,
3142 .call_compile_time,
3143 .call_nosuspend,
3144 .call_async,
3145 => try self.writePlNodeCall(stream, inst),
3146
3147 .block,
3148 .block_inline,
3149 .suspend_block,
3150 .loop,
3151 .validate_struct_init_ptr,
3152 .validate_array_init_ptr,
3153 .c_import,
3154 => try self.writePlNodeBlock(stream, inst),
3155
3156 .condbr,
3157 .condbr_inline,
3158 => try self.writePlNodeCondBr(stream, inst),
3159
3160 .opaque_decl => try self.writeOpaqueDecl(stream, inst, .parent),
3161 .opaque_decl_anon => try self.writeOpaqueDecl(stream, inst, .anon),
3162 .opaque_decl_func => try self.writeOpaqueDecl(stream, inst, .func),
3163
3164 .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),
3165 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
3166 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),
3167
3168 .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none),
3169 .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
3170 .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under),
3171 .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none),
3172 .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
3173 .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under),
3174
3175 .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none),
3176 .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
3177 .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
3178 .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none),
3179 .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
3180 .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
3181
3182 .field_ptr,
3183 .field_val,
3184 => try self.writePlNodeField(stream, inst),
3185
3186 .as_node => try self.writeAs(stream, inst),
3187
3188 .breakpoint,
3189 .repeat,
3190 .repeat_inline,
3191 .alloc_inferred,
3192 .alloc_inferred_mut,
3193 .alloc_inferred_comptime,
3194 => try self.writeNode(stream, inst),
3195
3196 .error_value,
3197 .enum_literal,
3198 .decl_ref,
3199 .decl_val,
3200 .import,
3201 .ret_err_value,
3202 .ret_err_value_code,
3203 .param_anytype,
3204 .param_anytype_comptime,
3205 => try self.writeStrTok(stream, inst),
3206
3207 .param, .param_comptime => try self.writeParam(stream, inst),
3208
3209 .func => try self.writeFunc(stream, inst, false),
3210 .func_inferred => try self.writeFunc(stream, inst, true),
3211
3212 .@"unreachable" => try self.writeUnreachable(stream, inst),
3213
3214 .switch_capture,
3215 .switch_capture_ref,
3216 .switch_capture_multi,
3217 .switch_capture_multi_ref,
3218 .switch_capture_else,
3219 .switch_capture_else_ref,
3220 => try self.writeSwitchCapture(stream, inst),
3221
3222 .dbg_stmt => try self.writeDbgStmt(stream, inst),
3223
3224 .extended => try self.writeExtended(stream, inst),
3225 }
3226 }
3227
3228 fn writeExtended(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3229 const extended = self.code.instructions.items(.data)[inst].extended;
3230 try stream.print("{s}(", .{@tagName(extended.opcode)});
3231 switch (extended.opcode) {
3232 .ret_ptr,
3233 .ret_type,
3234 .this,
3235 .ret_addr,
3236 .error_return_trace,
3237 .frame,
3238 .frame_address,
3239 .builtin_src,
3240 => try self.writeExtNode(stream, extended),
3241
3242 .@"asm" => try self.writeAsm(stream, extended),
3243 .func => try self.writeFuncExtended(stream, extended),
3244 .variable => try self.writeVarExtended(stream, extended),
3245
3246 .compile_log,
3247 .typeof_peer,
3248 => try self.writeNodeMultiOp(stream, extended),
3249
3250 .add_with_overflow,
3251 .sub_with_overflow,
3252 .mul_with_overflow,
3253 .shl_with_overflow,
3254 => try self.writeOverflowArithmetic(stream, extended),
3255
3256 .add_with_saturation,
3257 .sub_with_saturation,
3258 .mul_with_saturation,
3259 .shl_with_saturation,
3260 => try self.writeSaturatingArithmetic(stream, extended),
3261 .struct_decl => try self.writeStructDecl(stream, extended),
3262 .union_decl => try self.writeUnionDecl(stream, extended),
3263 .enum_decl => try self.writeEnumDecl(stream, extended),
3264
3265 .alloc,
3266 .builtin_extern,
3267 .c_undef,
3268 .c_include,
3269 .c_define,
3270 .wasm_memory_size,
3271 .wasm_memory_grow,
3272 => try stream.writeAll("TODO))"),
3273 }
3274 }
3275
3276 fn writeExtNode(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
3277 const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
3278 try stream.writeAll(")) ");
3279 try self.writeSrc(stream, src);
3280 }
3281
3282 fn writeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3283 const inst_data = self.code.instructions.items(.data)[inst].bin;
3284 try self.writeInstRef(stream, inst_data.lhs);
3285 try stream.writeAll(", ");
3286 try self.writeInstRef(stream, inst_data.rhs);
3287 try stream.writeByte(')');
3288 }
3289
3290 fn writeUnNode(
3291 self: *Writer,
3292 stream: anytype,
3293 inst: Inst.Index,
3294 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
3295 const inst_data = self.code.instructions.items(.data)[inst].un_node;
3296 try self.writeInstRef(stream, inst_data.operand);
3297 try stream.writeAll(") ");
3298 try self.writeSrc(stream, inst_data.src());
3299 }
3300
3301 fn writeUnTok(
3302 self: *Writer,
3303 stream: anytype,
3304 inst: Inst.Index,
3305 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
3306 const inst_data = self.code.instructions.items(.data)[inst].un_tok;
3307 try self.writeInstRef(stream, inst_data.operand);
3308 try stream.writeAll(") ");
3309 try self.writeSrc(stream, inst_data.src());
3310 }
3311
3312 fn writeArrayTypeSentinel(
3313 self: *Writer,
3314 stream: anytype,
3315 inst: Inst.Index,
3316 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
3317 const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel;
3318 _ = inst_data;
3319 try stream.writeAll("TODO)");
3320 }
3321
3322 fn writeParamType(
3323 self: *Writer,
3324 stream: anytype,
3325 inst: Inst.Index,
3326 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
3327 const inst_data = self.code.instructions.items(.data)[inst].param_type;
3328 try self.writeInstRef(stream, inst_data.callee);
3329 try stream.print(", {d})", .{inst_data.param_index});
3330 }
3331
3332 fn writePtrTypeSimple(
3333 self: *Writer,
3334 stream: anytype,
3335 inst: Inst.Index,
3336 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
3337 const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple;
3338 const str_allowzero = if (inst_data.is_allowzero) "allowzero, " else "";
3339 const str_const = if (!inst_data.is_mutable) "const, " else "";
3340 const str_volatile = if (inst_data.is_volatile) "volatile, " else "";
3341 try self.writeInstRef(stream, inst_data.elem_type);
3342 try stream.print(", {s}{s}{s}{s})", .{
3343 str_allowzero,
3344 str_const,
3345 str_volatile,
3346 @tagName(inst_data.size),
3347 });
3348 }
3349
3350 fn writePtrType(
3351 self: *Writer,
3352 stream: anytype,
3353 inst: Inst.Index,
3354 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
3355 const inst_data = self.code.instructions.items(.data)[inst].ptr_type;
3356 _ = inst_data;
3357 try stream.writeAll("TODO)");
3358 }
3359
3360 fn writeInt(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3361 const inst_data = self.code.instructions.items(.data)[inst].int;
3362 try stream.print("{d})", .{inst_data});
3363 }
3364
3365 fn writeIntBig(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3366 const inst_data = self.code.instructions.items(.data)[inst].str;
3367 const byte_count = inst_data.len * @sizeOf(std.math.big.Limb);
3368 const limb_bytes = self.code.string_bytes[inst_data.start..][0..byte_count];
3369 // limb_bytes is not aligned properly; we must allocate and copy the bytes
3370 // in order to accomplish this.
3371 const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len);
3372 defer self.gpa.free(limbs);
3373
3374 mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes);
3375 const big_int: std.math.big.int.Const = .{
3376 .limbs = limbs,
3377 .positive = true,
3378 };
3379 const as_string = try big_int.toStringAlloc(self.gpa, 10, .lower);
3380 defer self.gpa.free(as_string);
3381 try stream.print("{s})", .{as_string});
3382 }
3383
3384 fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3385 const number = self.code.instructions.items(.data)[inst].float;
3386 try stream.print("{d})", .{number});
3387 }
3388
3389 fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3390 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3391 const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data;
3392 const src = inst_data.src();
3393 const number = extra.get();
3394 // TODO improve std.format to be able to print f128 values
3395 try stream.print("{d}) ", .{@floatCast(f64, number)});
3396 try self.writeSrc(stream, src);
3397 }
3398
3399 fn writeStr(
3400 self: *Writer,
3401 stream: anytype,
3402 inst: Inst.Index,
3403 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
3404 const inst_data = self.code.instructions.items(.data)[inst].str;
3405 const str = inst_data.get(self.code);
3406 try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
3407 }
3408
3409 fn writePlNode(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3410 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3411 try stream.writeAll("TODO) ");
3412 try self.writeSrc(stream, inst_data.src());
3413 }
3414
3415 fn writeParam(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3416 const inst_data = self.code.instructions.items(.data)[inst].pl_tok;
3417 const extra = self.code.extraData(Inst.Param, inst_data.payload_index);
3418 const body = self.code.extra[extra.end..][0..extra.data.body_len];
3419 try stream.print("\"{}\", ", .{
3420 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)),
3421 });
3422 try stream.writeAll("{\n");
3423 self.indent += 2;
3424 try self.writeBody(stream, body);
3425 self.indent -= 2;
3426 try stream.writeByteNTimes(' ', self.indent);
3427 try stream.writeAll("}) ");
3428 try self.writeSrc(stream, inst_data.src());
3429 }
3430
3431 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3432 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3433 const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data;
3434 try self.writeInstRef(stream, extra.lhs);
3435 try stream.writeAll(", ");
3436 try self.writeInstRef(stream, extra.rhs);
3437 try stream.writeAll(") ");
3438 try self.writeSrc(stream, inst_data.src());
3439 }
3440
3441 fn writePlNodeExport(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3442 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3443 const extra = self.code.extraData(Inst.Export, inst_data.payload_index).data;
3444 const decl_name = self.code.nullTerminatedString(extra.decl_name);
3445
3446 try self.writeInstRef(stream, extra.namespace);
3447 try stream.print(", {}, ", .{std.zig.fmtId(decl_name)});
3448 try self.writeInstRef(stream, extra.options);
3449 try stream.writeAll(") ");
3450 try self.writeSrc(stream, inst_data.src());
3451 }
3452
3453 fn writeStructInit(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3454 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3455 const extra = self.code.extraData(Inst.StructInit, inst_data.payload_index);
3456 var field_i: u32 = 0;
3457 var extra_index = extra.end;
3458
3459 while (field_i < extra.data.fields_len) : (field_i += 1) {
3460 const item = self.code.extraData(Inst.StructInit.Item, extra_index);
3461 extra_index = item.end;
3462
3463 if (field_i != 0) {
3464 try stream.writeAll(", [");
3465 } else {
3466 try stream.writeAll("[");
3467 }
3468 try self.writeInstIndex(stream, item.data.field_type);
3469 try stream.writeAll(", ");
3470 try self.writeInstRef(stream, item.data.init);
3471 try stream.writeAll("]");
3472 }
3473 try stream.writeAll(") ");
3474 try self.writeSrc(stream, inst_data.src());
3475 }
3476
3477 fn writeCmpxchg(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3478 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3479 const extra = self.code.extraData(Inst.Cmpxchg, inst_data.payload_index).data;
3480
3481 try self.writeInstRef(stream, extra.ptr);
3482 try stream.writeAll(", ");
3483 try self.writeInstRef(stream, extra.expected_value);
3484 try stream.writeAll(", ");
3485 try self.writeInstRef(stream, extra.new_value);
3486 try stream.writeAll(", ");
3487 try self.writeInstRef(stream, extra.success_order);
3488 try stream.writeAll(", ");
3489 try self.writeInstRef(stream, extra.failure_order);
3490 try stream.writeAll(") ");
3491 try self.writeSrc(stream, inst_data.src());
3492 }
3493
3494 fn writeAtomicStore(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3495 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3496 const extra = self.code.extraData(Inst.AtomicStore, inst_data.payload_index).data;
3497
3498 try self.writeInstRef(stream, extra.ptr);
3499 try stream.writeAll(", ");
3500 try self.writeInstRef(stream, extra.operand);
3501 try stream.writeAll(", ");
3502 try self.writeInstRef(stream, extra.ordering);
3503 try stream.writeAll(") ");
3504 try self.writeSrc(stream, inst_data.src());
3505 }
3506
3507 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3508 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3509 const extra = self.code.extraData(Inst.StructInitAnon, inst_data.payload_index);
3510 var field_i: u32 = 0;
3511 var extra_index = extra.end;
3512
3513 while (field_i < extra.data.fields_len) : (field_i += 1) {
3514 const item = self.code.extraData(Inst.StructInitAnon.Item, extra_index);
3515 extra_index = item.end;
3516
3517 const field_name = self.code.nullTerminatedString(item.data.field_name);
3518
3519 const prefix = if (field_i != 0) ", [" else "[";
3520 try stream.print("{s}[{s}=", .{ prefix, field_name });
3521 try self.writeInstRef(stream, item.data.init);
3522 try stream.writeAll("]");
3523 }
3524 try stream.writeAll(") ");
3525 try self.writeSrc(stream, inst_data.src());
3526 }
3527
3528 fn writeFieldType(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3529 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3530 const extra = self.code.extraData(Inst.FieldType, inst_data.payload_index).data;
3531 try self.writeInstRef(stream, extra.container_type);
3532 const field_name = self.code.nullTerminatedString(extra.name_start);
3533 try stream.print(", {s}) ", .{field_name});
3534 try self.writeSrc(stream, inst_data.src());
3535 }
3536
3537 fn writeFieldTypeRef(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3538 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3539 const extra = self.code.extraData(Inst.FieldTypeRef, inst_data.payload_index).data;
3540 try self.writeInstRef(stream, extra.container_type);
3541 try stream.writeAll(", ");
3542 try self.writeInstRef(stream, extra.field_name);
3543 try stream.writeAll(") ");
3544 try self.writeSrc(stream, inst_data.src());
3545 }
3546
3547 fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
3548 const extra = self.code.extraData(Inst.NodeMultiOp, extended.operand);
3549 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
3550 const operands = self.code.refSlice(extra.end, extended.small);
3551
3552 for (operands) |operand, i| {
3553 if (i != 0) try stream.writeAll(", ");
3554 try self.writeInstRef(stream, operand);
3555 }
3556 try stream.writeAll(")) ");
3557 try self.writeSrc(stream, src);
3558 }
3559
3560 fn writeAsm(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
3561 const extra = self.code.extraData(Inst.Asm, extended.operand);
3562 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
3563 const outputs_len = @truncate(u5, extended.small);
3564 const inputs_len = @truncate(u5, extended.small >> 5);
3565 const clobbers_len = @truncate(u5, extended.small >> 10);
3566 const is_volatile = @truncate(u1, extended.small >> 15) != 0;
3567 const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
3568
3569 try self.writeFlag(stream, "volatile, ", is_volatile);
3570 try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)});
3571 try stream.writeAll(", ");
3572
3573 var extra_i: usize = extra.end;
3574 var output_type_bits = extra.data.output_type_bits;
3575 {
3576 var i: usize = 0;
3577 while (i < outputs_len) : (i += 1) {
3578 const output = self.code.extraData(Inst.Asm.Output, extra_i);
3579 extra_i = output.end;
3580
3581 const is_type = @truncate(u1, output_type_bits) != 0;
3582 output_type_bits >>= 1;
3583
3584 const name = self.code.nullTerminatedString(output.data.name);
3585 const constraint = self.code.nullTerminatedString(output.data.constraint);
3586 try stream.print("output({}, \"{}\", ", .{
3587 std.zig.fmtId(name), std.zig.fmtEscapes(constraint),
3588 });
3589 try self.writeFlag(stream, "->", is_type);
3590 try self.writeInstRef(stream, output.data.operand);
3591 try stream.writeAll(")");
3592 if (i + 1 < outputs_len) {
3593 try stream.writeAll("), ");
3594 }
3595 }
3596 }
3597 {
3598 var i: usize = 0;
3599 while (i < inputs_len) : (i += 1) {
3600 const input = self.code.extraData(Inst.Asm.Input, extra_i);
3601 extra_i = input.end;
3602
3603 const name = self.code.nullTerminatedString(input.data.name);
3604 const constraint = self.code.nullTerminatedString(input.data.constraint);
3605 try stream.print("input({}, \"{}\", ", .{
3606 std.zig.fmtId(name), std.zig.fmtEscapes(constraint),
3607 });
3608 try self.writeInstRef(stream, input.data.operand);
3609 try stream.writeAll(")");
3610 if (i + 1 < inputs_len) {
3611 try stream.writeAll(", ");
3612 }
3613 }
3614 }
3615 {
3616 var i: usize = 0;
3617 while (i < clobbers_len) : (i += 1) {
3618 const str_index = self.code.extra[extra_i];
3619 extra_i += 1;
3620 const clobber = self.code.nullTerminatedString(str_index);
3621 try stream.print("{}", .{std.zig.fmtId(clobber)});
3622 if (i + 1 < clobbers_len) {
3623 try stream.writeAll(", ");
3624 }
3625 }
3626 }
3627 try stream.writeAll(")) ");
3628 try self.writeSrc(stream, src);
3629 }
3630
3631 fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
3632 const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;
3633 const src: LazySrcLoc = .{ .node_offset = extra.node };
3634
3635 try self.writeInstRef(stream, extra.lhs);
3636 try stream.writeAll(", ");
3637 try self.writeInstRef(stream, extra.rhs);
3638 try stream.writeAll(", ");
3639 try self.writeInstRef(stream, extra.ptr);
3640 try stream.writeAll(")) ");
3641 try self.writeSrc(stream, src);
3642 }
3643
3644 fn writeSaturatingArithmetic(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
3645 const extra = self.code.extraData(Zir.Inst.SaturatingArithmetic, extended.operand).data;
3646 const src: LazySrcLoc = .{ .node_offset = extra.node };
3647
3648 try self.writeInstRef(stream, extra.lhs);
3649 try stream.writeAll(", ");
3650 try self.writeInstRef(stream, extra.rhs);
3651 try stream.writeAll(", ");
3652 try stream.writeAll(") ");
3653 try self.writeSrc(stream, src);
3654 }
3655
3656 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3657 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3658 const extra = self.code.extraData(Inst.Call, inst_data.payload_index);
3659 const args = self.code.refSlice(extra.end, extra.data.args_len);
3660
3661 try self.writeInstRef(stream, extra.data.callee);
3662 try stream.writeAll(", [");
3663 for (args) |arg, i| {
3664 if (i != 0) try stream.writeAll(", ");
3665 try self.writeInstRef(stream, arg);
3666 }
3667 try stream.writeAll("]) ");
3668 try self.writeSrc(stream, inst_data.src());
3669 }
3670
3671 fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3672 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3673 try self.writePlNodeBlockWithoutSrc(stream, inst);
3674 try self.writeSrc(stream, inst_data.src());
3675 }
3676
3677 fn writePlNodeBlockWithoutSrc(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3678 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3679 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
3680 const body = self.code.extra[extra.end..][0..extra.data.body_len];
3681 try stream.writeAll("{\n");
3682 self.indent += 2;
3683 try self.writeBody(stream, body);
3684 self.indent -= 2;
3685 try stream.writeByteNTimes(' ', self.indent);
3686 try stream.writeAll("}) ");
3687 }
3688
3689 fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3690 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3691 const extra = self.code.extraData(Inst.CondBr, inst_data.payload_index);
3692 const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len];
3693 const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
3694 try self.writeInstRef(stream, extra.data.condition);
3695 try stream.writeAll(", {\n");
3696 self.indent += 2;
3697 try self.writeBody(stream, then_body);
3698 self.indent -= 2;
3699 try stream.writeByteNTimes(' ', self.indent);
3700 try stream.writeAll("}, {\n");
3701 self.indent += 2;
3702 try self.writeBody(stream, else_body);
3703 self.indent -= 2;
3704 try stream.writeByteNTimes(' ', self.indent);
3705 try stream.writeAll("}) ");
3706 try self.writeSrc(stream, inst_data.src());
3707 }
3708
3709 fn writeStructDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
3710 const small = @bitCast(Inst.StructDecl.Small, extended.small);
3711
3712 var extra_index: usize = extended.operand;
3713
3714 const src_node: ?i32 = if (small.has_src_node) blk: {
3715 const src_node = @bitCast(i32, self.code.extra[extra_index]);
3716 extra_index += 1;
3717 break :blk src_node;
3718 } else null;
3719
3720 const body_len = if (small.has_body_len) blk: {
3721 const body_len = self.code.extra[extra_index];
3722 extra_index += 1;
3723 break :blk body_len;
3724 } else 0;
3725
3726 const fields_len = if (small.has_fields_len) blk: {
3727 const fields_len = self.code.extra[extra_index];
3728 extra_index += 1;
3729 break :blk fields_len;
3730 } else 0;
3731
3732 const decls_len = if (small.has_decls_len) blk: {
3733 const decls_len = self.code.extra[extra_index];
3734 extra_index += 1;
3735 break :blk decls_len;
3736 } else 0;
3737
3738 try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits);
3739 try stream.print("{s}, {s}, ", .{
3740 @tagName(small.name_strategy), @tagName(small.layout),
3741 });
3742
3743 if (decls_len == 0) {
3744 try stream.writeAll("{}, ");
3745 } else {
3746 try stream.writeAll("{\n");
3747 self.indent += 2;
3748 extra_index = try self.writeDecls(stream, decls_len, extra_index);
3749 self.indent -= 2;
3750 try stream.writeByteNTimes(' ', self.indent);
3751 try stream.writeAll("}, ");
3752 }
3753
3754 const body = self.code.extra[extra_index..][0..body_len];
3755 extra_index += body.len;
3756
3757 if (fields_len == 0) {
3758 assert(body.len == 0);
3759 try stream.writeAll("{}, {})");
3760 } else {
3761 const prev_parent_decl_node = self.parent_decl_node;
3762 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
3763 self.indent += 2;
3764 if (body.len == 0) {
3765 try stream.writeAll("{}, {\n");
3766 } else {
3767 try stream.writeAll("{\n");
3768 try self.writeBody(stream, body);
3769
3770 try stream.writeByteNTimes(' ', self.indent - 2);
3771 try stream.writeAll("}, {\n");
3772 }
3773
3774 const bits_per_field = 4;
3775 const fields_per_u32 = 32 / bits_per_field;
3776 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
3777 var bit_bag_index: usize = extra_index;
3778 extra_index += bit_bags_count;
3779 var cur_bit_bag: u32 = undefined;
3780 var field_i: u32 = 0;
3781 while (field_i < fields_len) : (field_i += 1) {
3782 if (field_i % fields_per_u32 == 0) {
3783 cur_bit_bag = self.code.extra[bit_bag_index];
3784 bit_bag_index += 1;
3785 }
3786 const has_align = @truncate(u1, cur_bit_bag) != 0;
3787 cur_bit_bag >>= 1;
3788 const has_default = @truncate(u1, cur_bit_bag) != 0;
3789 cur_bit_bag >>= 1;
3790 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
3791 cur_bit_bag >>= 1;
3792 const unused = @truncate(u1, cur_bit_bag) != 0;
3793 cur_bit_bag >>= 1;
3794
3795 _ = unused;
3796
3797 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
3798 extra_index += 1;
3799 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
3800 extra_index += 1;
3801
3802 try stream.writeByteNTimes(' ', self.indent);
3803 try self.writeFlag(stream, "comptime ", is_comptime);
3804 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
3805 try self.writeInstRef(stream, field_type);
3806
3807 if (has_align) {
3808 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
3809 extra_index += 1;
3810
3811 try stream.writeAll(" align(");
3812 try self.writeInstRef(stream, align_ref);
3813 try stream.writeAll(")");
3814 }
3815 if (has_default) {
3816 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
3817 extra_index += 1;
3818
3819 try stream.writeAll(" = ");
3820 try self.writeInstRef(stream, default_ref);
3821 }
3822 try stream.writeAll(",\n");
3823 }
3824
3825 self.parent_decl_node = prev_parent_decl_node;
3826 self.indent -= 2;
3827 try stream.writeByteNTimes(' ', self.indent);
3828 try stream.writeAll("})");
3829 }
3830 try self.writeSrcNode(stream, src_node);
3831 }
3832
3833 fn writeUnionDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
3834 const small = @bitCast(Inst.UnionDecl.Small, extended.small);
3835
3836 var extra_index: usize = extended.operand;
3837
3838 const src_node: ?i32 = if (small.has_src_node) blk: {
3839 const src_node = @bitCast(i32, self.code.extra[extra_index]);
3840 extra_index += 1;
3841 break :blk src_node;
3842 } else null;
3843
3844 const tag_type_ref = if (small.has_tag_type) blk: {
3845 const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
3846 extra_index += 1;
3847 break :blk tag_type_ref;
3848 } else .none;
3849
3850 const body_len = if (small.has_body_len) blk: {
3851 const body_len = self.code.extra[extra_index];
3852 extra_index += 1;
3853 break :blk body_len;
3854 } else 0;
3855
3856 const fields_len = if (small.has_fields_len) blk: {
3857 const fields_len = self.code.extra[extra_index];
3858 extra_index += 1;
3859 break :blk fields_len;
3860 } else 0;
3861
3862 const decls_len = if (small.has_decls_len) blk: {
3863 const decls_len = self.code.extra[extra_index];
3864 extra_index += 1;
3865 break :blk decls_len;
3866 } else 0;
3867
3868 try stream.print("{s}, {s}, ", .{
3869 @tagName(small.name_strategy), @tagName(small.layout),
3870 });
3871 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
3872
3873 if (decls_len == 0) {
3874 try stream.writeAll("{}, ");
3875 } else {
3876 try stream.writeAll("{\n");
3877 self.indent += 2;
3878 extra_index = try self.writeDecls(stream, decls_len, extra_index);
3879 self.indent -= 2;
3880 try stream.writeByteNTimes(' ', self.indent);
3881 try stream.writeAll("}, ");
3882 }
3883
3884 assert(fields_len != 0);
3885
3886 if (tag_type_ref != .none) {
3887 try self.writeInstRef(stream, tag_type_ref);
3888 try stream.writeAll(", ");
3889 }
3890
3891 const body = self.code.extra[extra_index..][0..body_len];
3892 extra_index += body.len;
3893
3894 const prev_parent_decl_node = self.parent_decl_node;
3895 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
3896 self.indent += 2;
3897 if (body.len == 0) {
3898 try stream.writeAll("{}, {\n");
3899 } else {
3900 try stream.writeAll("{\n");
3901 try self.writeBody(stream, body);
3902
3903 try stream.writeByteNTimes(' ', self.indent - 2);
3904 try stream.writeAll("}, {\n");
3905 }
3906
3907 const bits_per_field = 4;
3908 const fields_per_u32 = 32 / bits_per_field;
3909 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
3910 const body_end = extra_index;
3911 extra_index += bit_bags_count;
3912 var bit_bag_index: usize = body_end;
3913 var cur_bit_bag: u32 = undefined;
3914 var field_i: u32 = 0;
3915 while (field_i < fields_len) : (field_i += 1) {
3916 if (field_i % fields_per_u32 == 0) {
3917 cur_bit_bag = self.code.extra[bit_bag_index];
3918 bit_bag_index += 1;
3919 }
3920 const has_type = @truncate(u1, cur_bit_bag) != 0;
3921 cur_bit_bag >>= 1;
3922 const has_align = @truncate(u1, cur_bit_bag) != 0;
3923 cur_bit_bag >>= 1;
3924 const has_value = @truncate(u1, cur_bit_bag) != 0;
3925 cur_bit_bag >>= 1;
3926 const unused = @truncate(u1, cur_bit_bag) != 0;
3927 cur_bit_bag >>= 1;
3928
3929 _ = unused;
3930
3931 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
3932 extra_index += 1;
3933 try stream.writeByteNTimes(' ', self.indent);
3934 try stream.print("{}", .{std.zig.fmtId(field_name)});
3935
3936 if (has_type) {
3937 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
3938 extra_index += 1;
3939
3940 try stream.writeAll(": ");
3941 try self.writeInstRef(stream, field_type);
3942 }
3943 if (has_align) {
3944 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
3945 extra_index += 1;
3946
3947 try stream.writeAll(" align(");
3948 try self.writeInstRef(stream, align_ref);
3949 try stream.writeAll(")");
3950 }
3951 if (has_value) {
3952 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
3953 extra_index += 1;
3954
3955 try stream.writeAll(" = ");
3956 try self.writeInstRef(stream, default_ref);
3957 }
3958 try stream.writeAll(",\n");
3959 }
3960
3961 self.parent_decl_node = prev_parent_decl_node;
3962 self.indent -= 2;
3963 try stream.writeByteNTimes(' ', self.indent);
3964 try stream.writeAll("})");
3965 try self.writeSrcNode(stream, src_node);
3966 }
3967
3968 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize {
3969 const parent_decl_node = self.parent_decl_node;
3970 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
3971 var extra_index = extra_start + bit_bags_count;
3972 var bit_bag_index: usize = extra_start;
3973 var cur_bit_bag: u32 = undefined;
3974 var decl_i: u32 = 0;
3975 while (decl_i < decls_len) : (decl_i += 1) {
3976 if (decl_i % 8 == 0) {
3977 cur_bit_bag = self.code.extra[bit_bag_index];
3978 bit_bag_index += 1;
3979 }
3980 const is_pub = @truncate(u1, cur_bit_bag) != 0;
3981 cur_bit_bag >>= 1;
3982 const is_exported = @truncate(u1, cur_bit_bag) != 0;
3983 cur_bit_bag >>= 1;
3984 const has_align = @truncate(u1, cur_bit_bag) != 0;
3985 cur_bit_bag >>= 1;
3986 const has_section = @truncate(u1, cur_bit_bag) != 0;
3987 cur_bit_bag >>= 1;
3988
3989 const sub_index = extra_index;
3990
3991 const hash_u32s = self.code.extra[extra_index..][0..4];
3992 extra_index += 4;
3993 const line = self.code.extra[extra_index];
3994 extra_index += 1;
3995 const decl_name_index = self.code.extra[extra_index];
3996 extra_index += 1;
3997 const decl_index = self.code.extra[extra_index];
3998 extra_index += 1;
3999 const align_inst: Inst.Ref = if (!has_align) .none else inst: {
4000 const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
4001 extra_index += 1;
4002 break :inst inst;
4003 };
4004 const section_inst: Inst.Ref = if (!has_section) .none else inst: {
4005 const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
4006 extra_index += 1;
4007 break :inst inst;
4008 };
4009
4010 const pub_str = if (is_pub) "pub " else "";
4011 const hash_bytes = @bitCast([16]u8, hash_u32s.*);
4012 try stream.writeByteNTimes(' ', self.indent);
4013 if (decl_name_index == 0) {
4014 const name = if (is_exported) "usingnamespace" else "comptime";
4015 try stream.writeAll(pub_str);
4016 try stream.writeAll(name);
4017 } else if (decl_name_index == 1) {
4018 try stream.writeAll("test");
4019 } else {
4020 const raw_decl_name = self.code.nullTerminatedString(decl_name_index);
4021 const decl_name = if (raw_decl_name.len == 0)
4022 self.code.nullTerminatedString(decl_name_index + 1)
4023 else
4024 raw_decl_name;
4025 const test_str = if (raw_decl_name.len == 0) "test " else "";
4026 const export_str = if (is_exported) "export " else "";
4027 try stream.print("[{d}] {s}{s}{s}{}", .{
4028 sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name),
4029 });
4030 if (align_inst != .none) {
4031 try stream.writeAll(" align(");
4032 try self.writeInstRef(stream, align_inst);
4033 try stream.writeAll(")");
4034 }
4035 if (section_inst != .none) {
4036 try stream.writeAll(" linksection(");
4037 try self.writeInstRef(stream, section_inst);
4038 try stream.writeAll(")");
4039 }
4040 }
4041 const tag = self.code.instructions.items(.tag)[decl_index];
4042 try stream.print(" line({d}) hash({}): %{d} = {s}(", .{
4043 line, std.fmt.fmtSliceHexLower(&hash_bytes), decl_index, @tagName(tag),
4044 });
4045
4046 const decl_block_inst_data = self.code.instructions.items(.data)[decl_index].pl_node;
4047 const sub_decl_node_off = decl_block_inst_data.src_node;
4048 self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off);
4049 try self.writePlNodeBlockWithoutSrc(stream, decl_index);
4050 self.parent_decl_node = parent_decl_node;
4051 try self.writeSrc(stream, decl_block_inst_data.src());
4052 try stream.writeAll("\n");
4053 }
4054 return extra_index;
4055 }
4056
4057 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
4058 const small = @bitCast(Inst.EnumDecl.Small, extended.small);
4059 var extra_index: usize = extended.operand;
4060
4061 const src_node: ?i32 = if (small.has_src_node) blk: {
4062 const src_node = @bitCast(i32, self.code.extra[extra_index]);
4063 extra_index += 1;
4064 break :blk src_node;
4065 } else null;
4066
4067 const tag_type_ref = if (small.has_tag_type) blk: {
4068 const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
4069 extra_index += 1;
4070 break :blk tag_type_ref;
4071 } else .none;
4072
4073 const body_len = if (small.has_body_len) blk: {
4074 const body_len = self.code.extra[extra_index];
4075 extra_index += 1;
4076 break :blk body_len;
4077 } else 0;
4078
4079 const fields_len = if (small.has_fields_len) blk: {
4080 const fields_len = self.code.extra[extra_index];
4081 extra_index += 1;
4082 break :blk fields_len;
4083 } else 0;
4084
4085 const decls_len = if (small.has_decls_len) blk: {
4086 const decls_len = self.code.extra[extra_index];
4087 extra_index += 1;
4088 break :blk decls_len;
4089 } else 0;
4090
4091 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
4092 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);
4093
4094 if (decls_len == 0) {
4095 try stream.writeAll("{}, ");
4096 } else {
4097 try stream.writeAll("{\n");
4098 self.indent += 2;
4099 extra_index = try self.writeDecls(stream, decls_len, extra_index);
4100 self.indent -= 2;
4101 try stream.writeByteNTimes(' ', self.indent);
4102 try stream.writeAll("}, ");
4103 }
4104
4105 if (tag_type_ref != .none) {
4106 try self.writeInstRef(stream, tag_type_ref);
4107 try stream.writeAll(", ");
4108 }
4109
4110 const body = self.code.extra[extra_index..][0..body_len];
4111 extra_index += body.len;
4112
4113 if (fields_len == 0) {
4114 assert(body.len == 0);
4115 try stream.writeAll("{}, {})");
4116 } else {
4117 const prev_parent_decl_node = self.parent_decl_node;
4118 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
4119 self.indent += 2;
4120 if (body.len == 0) {
4121 try stream.writeAll("{}, {\n");
4122 } else {
4123 try stream.writeAll("{\n");
4124 try self.writeBody(stream, body);
4125
4126 try stream.writeByteNTimes(' ', self.indent - 2);
4127 try stream.writeAll("}, {\n");
4128 }
4129
4130 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
4131 const body_end = extra_index;
4132 extra_index += bit_bags_count;
4133 var bit_bag_index: usize = body_end;
4134 var cur_bit_bag: u32 = undefined;
4135 var field_i: u32 = 0;
4136 while (field_i < fields_len) : (field_i += 1) {
4137 if (field_i % 32 == 0) {
4138 cur_bit_bag = self.code.extra[bit_bag_index];
4139 bit_bag_index += 1;
4140 }
4141 const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
4142 cur_bit_bag >>= 1;
4143
4144 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
4145 extra_index += 1;
4146
4147 try stream.writeByteNTimes(' ', self.indent);
4148 try stream.print("{}", .{std.zig.fmtId(field_name)});
4149
4150 if (has_tag_value) {
4151 const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
4152 extra_index += 1;
4153
4154 try stream.writeAll(" = ");
4155 try self.writeInstRef(stream, tag_value_ref);
4156 }
4157 try stream.writeAll(",\n");
4158 }
4159 self.parent_decl_node = prev_parent_decl_node;
4160 self.indent -= 2;
4161 try stream.writeByteNTimes(' ', self.indent);
4162 try stream.writeAll("})");
4163 }
4164 try self.writeSrcNode(stream, src_node);
4165 }
4166
4167 fn writeOpaqueDecl(
4168 self: *Writer,
4169 stream: anytype,
4170 inst: Inst.Index,
4171 name_strategy: Inst.NameStrategy,
4172 ) !void {
4173 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4174 const extra = self.code.extraData(Inst.OpaqueDecl, inst_data.payload_index);
4175 const decls_len = extra.data.decls_len;
4176
4177 try stream.print("{s}, ", .{@tagName(name_strategy)});
4178
4179 if (decls_len == 0) {
4180 try stream.writeAll("}) ");
4181 } else {
4182 try stream.writeAll("\n");
4183 self.indent += 2;
4184 _ = try self.writeDecls(stream, decls_len, extra.end);
4185 self.indent -= 2;
4186 try stream.writeByteNTimes(' ', self.indent);
4187 try stream.writeAll("}) ");
4188 }
4189 try self.writeSrc(stream, inst_data.src());
4190 }
4191
4192 fn writeErrorSetDecl(
4193 self: *Writer,
4194 stream: anytype,
4195 inst: Inst.Index,
4196 name_strategy: Inst.NameStrategy,
4197 ) !void {
4198 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4199 const extra = self.code.extraData(Inst.ErrorSetDecl, inst_data.payload_index);
4200 const fields = self.code.extra[extra.end..][0..extra.data.fields_len];
4201
4202 try stream.print("{s}, ", .{@tagName(name_strategy)});
4203
4204 try stream.writeAll("{\n");
4205 self.indent += 2;
4206 for (fields) |str_index| {
4207 const name = self.code.nullTerminatedString(str_index);
4208 try stream.writeByteNTimes(' ', self.indent);
4209 try stream.print("{},\n", .{std.zig.fmtId(name)});
4210 }
4211 self.indent -= 2;
4212 try stream.writeByteNTimes(' ', self.indent);
4213 try stream.writeAll("}) ");
4214
4215 try self.writeSrc(stream, inst_data.src());
4216 }
4217
4218 fn writePlNodeSwitchBr(
4219 self: *Writer,
4220 stream: anytype,
4221 inst: Inst.Index,
4222 special_prong: SpecialProng,
4223 ) !void {
4224 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4225 const extra = self.code.extraData(Inst.SwitchBlock, inst_data.payload_index);
4226 const special: struct {
4227 body: []const Inst.Index,
4228 end: usize,
4229 } = switch (special_prong) {
4230 .none => .{ .body = &.{}, .end = extra.end },
4231 .under, .@"else" => blk: {
4232 const body_len = self.code.extra[extra.end];
4233 const extra_body_start = extra.end + 1;
4234 break :blk .{
4235 .body = self.code.extra[extra_body_start..][0..body_len],
4236 .end = extra_body_start + body_len,
4237 };
4238 },
4239 };
4240
4241 try self.writeInstRef(stream, extra.data.operand);
4242
4243 if (special.body.len != 0) {
4244 const prong_name = switch (special_prong) {
4245 .@"else" => "else",
4246 .under => "_",
4247 else => unreachable,
4248 };
4249 try stream.print(", {s} => {{\n", .{prong_name});
4250 self.indent += 2;
4251 try self.writeBody(stream, special.body);
4252 self.indent -= 2;
4253 try stream.writeByteNTimes(' ', self.indent);
4254 try stream.writeAll("}");
4255 }
4256
4257 var extra_index: usize = special.end;
4258 {
4259 var scalar_i: usize = 0;
4260 while (scalar_i < extra.data.cases_len) : (scalar_i += 1) {
4261 const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
4262 extra_index += 1;
4263 const body_len = self.code.extra[extra_index];
4264 extra_index += 1;
4265 const body = self.code.extra[extra_index..][0..body_len];
4266 extra_index += body_len;
4267
4268 try stream.writeAll(", ");
4269 try self.writeInstRef(stream, item_ref);
4270 try stream.writeAll(" => {\n");
4271 self.indent += 2;
4272 try self.writeBody(stream, body);
4273 self.indent -= 2;
4274 try stream.writeByteNTimes(' ', self.indent);
4275 try stream.writeAll("}");
4276 }
4277 }
4278 try stream.writeAll(") ");
4279 try self.writeSrc(stream, inst_data.src());
4280 }
4281
4282 fn writePlNodeSwitchBlockMulti(
4283 self: *Writer,
4284 stream: anytype,
4285 inst: Inst.Index,
4286 special_prong: SpecialProng,
4287 ) !void {
4288 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4289 const extra = self.code.extraData(Inst.SwitchBlockMulti, inst_data.payload_index);
4290 const special: struct {
4291 body: []const Inst.Index,
4292 end: usize,
4293 } = switch (special_prong) {
4294 .none => .{ .body = &.{}, .end = extra.end },
4295 .under, .@"else" => blk: {
4296 const body_len = self.code.extra[extra.end];
4297 const extra_body_start = extra.end + 1;
4298 break :blk .{
4299 .body = self.code.extra[extra_body_start..][0..body_len],
4300 .end = extra_body_start + body_len,
4301 };
4302 },
4303 };
4304
4305 try self.writeInstRef(stream, extra.data.operand);
4306
4307 if (special.body.len != 0) {
4308 const prong_name = switch (special_prong) {
4309 .@"else" => "else",
4310 .under => "_",
4311 else => unreachable,
4312 };
4313 try stream.print(", {s} => {{\n", .{prong_name});
4314 self.indent += 2;
4315 try self.writeBody(stream, special.body);
4316 self.indent -= 2;
4317 try stream.writeByteNTimes(' ', self.indent);
4318 try stream.writeAll("}");
4319 }
4320
4321 var extra_index: usize = special.end;
4322 {
4323 var scalar_i: usize = 0;
4324 while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) {
4325 const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
4326 extra_index += 1;
4327 const body_len = self.code.extra[extra_index];
4328 extra_index += 1;
4329 const body = self.code.extra[extra_index..][0..body_len];
4330 extra_index += body_len;
4331
4332 try stream.writeAll(", ");
4333 try self.writeInstRef(stream, item_ref);
4334 try stream.writeAll(" => {\n");
4335 self.indent += 2;
4336 try self.writeBody(stream, body);
4337 self.indent -= 2;
4338 try stream.writeByteNTimes(' ', self.indent);
4339 try stream.writeAll("}");
4340 }
4341 }
4342 {
4343 var multi_i: usize = 0;
4344 while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) {
4345 const items_len = self.code.extra[extra_index];
4346 extra_index += 1;
4347 const ranges_len = self.code.extra[extra_index];
4348 extra_index += 1;
4349 const body_len = self.code.extra[extra_index];
4350 extra_index += 1;
4351 const items = self.code.refSlice(extra_index, items_len);
4352 extra_index += items_len;
4353
4354 for (items) |item_ref| {
4355 try stream.writeAll(", ");
4356 try self.writeInstRef(stream, item_ref);
4357 }
4358
4359 var range_i: usize = 0;
4360 while (range_i < ranges_len) : (range_i += 1) {
4361 const item_first = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
4362 extra_index += 1;
4363 const item_last = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
4364 extra_index += 1;
4365
4366 try stream.writeAll(", ");
4367 try self.writeInstRef(stream, item_first);
4368 try stream.writeAll("...");
4369 try self.writeInstRef(stream, item_last);
4370 }
4371
4372 const body = self.code.extra[extra_index..][0..body_len];
4373 extra_index += body_len;
4374 try stream.writeAll(" => {\n");
4375 self.indent += 2;
4376 try self.writeBody(stream, body);
4377 self.indent -= 2;
4378 try stream.writeByteNTimes(' ', self.indent);
4379 try stream.writeAll("}");
4380 }
4381 }
4382 try stream.writeAll(") ");
4383 try self.writeSrc(stream, inst_data.src());
4384 }
4385
4386 fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4387 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4388 const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data;
4389 const name = self.code.nullTerminatedString(extra.field_name_start);
4390 try self.writeInstRef(stream, extra.lhs);
4391 try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)});
4392 try self.writeSrc(stream, inst_data.src());
4393 }
4394
4395 fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4396 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4397 const extra = self.code.extraData(Inst.As, inst_data.payload_index).data;
4398 try self.writeInstRef(stream, extra.dest_type);
4399 try stream.writeAll(", ");
4400 try self.writeInstRef(stream, extra.operand);
4401 try stream.writeAll(") ");
4402 try self.writeSrc(stream, inst_data.src());
4403 }
4404
4405 fn writeNode(
4406 self: *Writer,
4407 stream: anytype,
4408 inst: Inst.Index,
4409 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
4410 const src_node = self.code.instructions.items(.data)[inst].node;
4411 const src: LazySrcLoc = .{ .node_offset = src_node };
4412 try stream.writeAll(") ");
4413 try self.writeSrc(stream, src);
4414 }
4415
4416 fn writeStrTok(
4417 self: *Writer,
4418 stream: anytype,
4419 inst: Inst.Index,
4420 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
4421 const inst_data = self.code.instructions.items(.data)[inst].str_tok;
4422 const str = inst_data.get(self.code);
4423 try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)});
4424 try self.writeSrc(stream, inst_data.src());
4425 }
4426
4427 fn writeFunc(
4428 self: *Writer,
4429 stream: anytype,
4430 inst: Inst.Index,
4431 inferred_error_set: bool,
4432 ) !void {
4433 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4434 const src = inst_data.src();
4435 const extra = self.code.extraData(Inst.Func, inst_data.payload_index);
4436 var extra_index = extra.end;
4437
4438 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
4439 extra_index += ret_ty_body.len;
4440
4441 const body = self.code.extra[extra_index..][0..extra.data.body_len];
4442 extra_index += body.len;
4443
4444 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
4445 if (body.len != 0) {
4446 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
4447 }
4448 return self.writeFuncCommon(
4449 stream,
4450 ret_ty_body,
4451 inferred_error_set,
4452 false,
4453 false,
4454 .none,
4455 .none,
4456 body,
4457 src,
4458 src_locs,
4459 );
4460 }
4461
4462 fn writeFuncExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
4463 const extra = self.code.extraData(Inst.ExtendedFunc, extended.operand);
4464 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
4465 const small = @bitCast(Inst.ExtendedFunc.Small, extended.small);
4466
4467 var extra_index: usize = extra.end;
4468 if (small.has_lib_name) {
4469 const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
4470 extra_index += 1;
4471 try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)});
4472 }
4473 try self.writeFlag(stream, "test, ", small.is_test);
4474 const cc: Inst.Ref = if (!small.has_cc) .none else blk: {
4475 const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
4476 extra_index += 1;
4477 break :blk cc;
4478 };
4479 const align_inst: Inst.Ref = if (!small.has_align) .none else blk: {
4480 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
4481 extra_index += 1;
4482 break :blk align_inst;
4483 };
4484
4485 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
4486 extra_index += ret_ty_body.len;
4487
4488 const body = self.code.extra[extra_index..][0..extra.data.body_len];
4489 extra_index += body.len;
4490
4491 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
4492 if (body.len != 0) {
4493 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
4494 }
4495 return self.writeFuncCommon(
4496 stream,
4497 ret_ty_body,
4498 small.is_inferred_error,
4499 small.is_var_args,
4500 small.is_extern,
4501 cc,
4502 align_inst,
4503 body,
4504 src,
4505 src_locs,
4506 );
4507 }
4508
4509 fn writeVarExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
4510 const extra = self.code.extraData(Inst.ExtendedVar, extended.operand);
4511 const small = @bitCast(Inst.ExtendedVar.Small, extended.small);
4512
4513 try self.writeInstRef(stream, extra.data.var_type);
4514
4515 var extra_index: usize = extra.end;
4516 if (small.has_lib_name) {
4517 const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
4518 extra_index += 1;
4519 try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)});
4520 }
4521 const align_inst: Inst.Ref = if (!small.has_align) .none else blk: {
4522 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
4523 extra_index += 1;
4524 break :blk align_inst;
4525 };
4526 const init_inst: Inst.Ref = if (!small.has_init) .none else blk: {
4527 const init_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
4528 extra_index += 1;
4529 break :blk init_inst;
4530 };
4531 try self.writeFlag(stream, ", is_extern", small.is_extern);
4532 try self.writeOptionalInstRef(stream, ", align=", align_inst);
4533 try self.writeOptionalInstRef(stream, ", init=", init_inst);
4534 try stream.writeAll("))");
4535 }
4536
4537 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4538 const inst_data = self.code.instructions.items(.data)[inst].bool_br;
4539 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
4540 const body = self.code.extra[extra.end..][0..extra.data.body_len];
4541 try self.writeInstRef(stream, inst_data.lhs);
4542 try stream.writeAll(", {\n");
4543 self.indent += 2;
4544 try self.writeBody(stream, body);
4545 self.indent -= 2;
4546 try stream.writeByteNTimes(' ', self.indent);
4547 try stream.writeAll("})");
4548 }
4549
4550 fn writeIntType(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4551 const int_type = self.code.instructions.items(.data)[inst].int_type;
4552 const prefix: u8 = switch (int_type.signedness) {
4553 .signed => 'i',
4554 .unsigned => 'u',
4555 };
4556 try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count });
4557 try self.writeSrc(stream, int_type.src());
4558 }
4559
4560 fn writeBreak(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4561 const inst_data = self.code.instructions.items(.data)[inst].@"break";
4562
4563 try self.writeInstIndex(stream, inst_data.block_inst);
4564 try stream.writeAll(", ");
4565 try self.writeInstRef(stream, inst_data.operand);
4566 try stream.writeAll(")");
4567 }
4568
4569 fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4570 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
4571 const safety_str = if (inst_data.safety) "safe" else "unsafe";
4572 try stream.print("{s}) ", .{safety_str});
4573 try self.writeSrc(stream, inst_data.src());
4574 }
4575
4576 fn writeFuncCommon(
4577 self: *Writer,
4578 stream: anytype,
4579 ret_ty_body: []const Inst.Index,
4580 inferred_error_set: bool,
4581 var_args: bool,
4582 is_extern: bool,
4583 cc: Inst.Ref,
4584 align_inst: Inst.Ref,
4585 body: []const Inst.Index,
4586 src: LazySrcLoc,
4587 src_locs: Zir.Inst.Func.SrcLocs,
4588 ) !void {
4589 if (ret_ty_body.len == 0) {
4590 try stream.writeAll("ret_ty=void");
4591 } else {
4592 try stream.writeAll("ret_ty={\n");
4593 self.indent += 2;
4594 try self.writeBody(stream, ret_ty_body);
4595 self.indent -= 2;
4596 try stream.writeByteNTimes(' ', self.indent);
4597 try stream.writeAll("}");
4598 }
4599
4600 try self.writeOptionalInstRef(stream, ", cc=", cc);
4601 try self.writeOptionalInstRef(stream, ", align=", align_inst);
4602 try self.writeFlag(stream, ", vargs", var_args);
4603 try self.writeFlag(stream, ", extern", is_extern);
4604 try self.writeFlag(stream, ", inferror", inferred_error_set);
4605
4606 if (body.len == 0) {
4607 try stream.writeAll(", body={}) ");
4608 } else {
4609 try stream.writeAll(", body={\n");
4610 self.indent += 2;
4611 try self.writeBody(stream, body);
4612 self.indent -= 2;
4613 try stream.writeByteNTimes(' ', self.indent);
4614 try stream.writeAll("}) ");
4615 }
4616 if (body.len != 0) {
4617 try stream.print("(lbrace={d}:{d},rbrace={d}:{d}) ", .{
4618 src_locs.lbrace_line, @truncate(u16, src_locs.columns),
4619 src_locs.rbrace_line, @truncate(u16, src_locs.columns >> 16),
4620 });
4621 }
4622 try self.writeSrc(stream, src);
4623 }
4624
4625 fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4626 const inst_data = self.code.instructions.items(.data)[inst].switch_capture;
4627 try self.writeInstIndex(stream, inst_data.switch_inst);
4628 try stream.print(", {d})", .{inst_data.prong_index});
4629 }
4630
4631 fn writeDbgStmt(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4632 const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt;
4633 try stream.print("{d}, {d})", .{ inst_data.line, inst_data.column });
4634 }
4635
4636 fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void {
4637 var i: usize = @enumToInt(ref);
4638
4639 if (i < Inst.Ref.typed_value_map.len) {
4640 return stream.print("@{}", .{ref});
4641 }
4642 i -= Inst.Ref.typed_value_map.len;
4643
4644 return self.writeInstIndex(stream, @intCast(Inst.Index, i));
4645 }
4646
4647 fn writeInstIndex(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4648 _ = self;
4649 return stream.print("%{d}", .{inst});
4650 }
4651
4652 fn writeOptionalInstRef(
4653 self: *Writer,
4654 stream: anytype,
4655 prefix: []const u8,
4656 inst: Inst.Ref,
4657 ) !void {
4658 if (inst == .none) return;
4659 try stream.writeAll(prefix);
4660 try self.writeInstRef(stream, inst);
4661 }
4662
4663 fn writeFlag(
4664 self: *Writer,
4665 stream: anytype,
4666 name: []const u8,
4667 flag: bool,
4668 ) !void {
4669 _ = self;
4670 if (!flag) return;
4671 try stream.writeAll(name);
4672 }
4673
4674 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {
4675 const tree = self.file.tree;
4676 const src_loc: Module.SrcLoc = .{
4677 .file_scope = self.file,
4678 .parent_decl_node = self.parent_decl_node,
4679 .lazy = src,
4680 };
4681 // Caller must ensure AST tree is loaded.
4682 const abs_byte_off = src_loc.byteOffset(self.gpa) catch unreachable;
4683 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);
4684 try stream.print("{s}:{d}:{d}", .{
4685 @tagName(src), delta_line.line + 1, delta_line.column + 1,
4686 });
4687 }
4688
4689 fn writeSrcNode(self: *Writer, stream: anytype, src_node: ?i32) !void {
4690 const node_offset = src_node orelse return;
4691 const src: LazySrcLoc = .{ .node_offset = node_offset };
4692 try stream.writeAll(" ");
4693 return self.writeSrc(stream, src);
4694 }
4695
4696 fn writeBody(self: *Writer, stream: anytype, body: []const Inst.Index) !void {
4697 for (body) |inst| {
4698 try stream.writeByteNTimes(' ', self.indent);
4699 try stream.print("%{d} ", .{inst});
4700 try self.writeInstToStream(stream, inst);
4701 try stream.writeByte('\n');
4702 }
4703 }
4704};
4705
47062862pub const DeclIterator = struct {
47072863 extra_index: usize,
47082864 bit_bag_index: usize,
src/main.zig+1-1
......@@ -4132,7 +4132,7 @@ pub fn cmdAstCheck(
41324132 // zig fmt: on
41334133 }
41344134
4135 return Zir.renderAsTextToFile(gpa, &file, io.getStdOut());
4135 return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
41364136}
41374137
41384138/// This is only enabled for debug builds.
src/print_zir.zig created+1868
......@@ -0,0 +1,1868 @@
1const std = @import("std");
2const mem = std.mem;
3const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;
5const Ast = std.zig.Ast;
6
7const Zir = @import("Zir.zig");
8const Module = @import("Module.zig");
9const LazySrcLoc = Module.LazySrcLoc;
10
11/// Write human-readable, debug formatted ZIR code to a file.
12pub fn renderAsTextToFile(
13 gpa: *Allocator,
14 scope_file: *Module.Scope.File,
15 fs_file: std.fs.File,
16) !void {
17 var arena = std.heap.ArenaAllocator.init(gpa);
18 defer arena.deinit();
19
20 var writer: Writer = .{
21 .gpa = gpa,
22 .arena = &arena.allocator,
23 .file = scope_file,
24 .code = scope_file.zir,
25 .indent = 0,
26 .parent_decl_node = 0,
27 };
28
29 const main_struct_inst = scope_file.zir.getMainStruct();
30 try fs_file.writer().print("%{d} ", .{main_struct_inst});
31 try writer.writeInstToStream(fs_file.writer(), main_struct_inst);
32 try fs_file.writeAll("\n");
33 const imports_index = scope_file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)];
34 if (imports_index != 0) {
35 try fs_file.writeAll("Imports:\n");
36
37 const extra = scope_file.zir.extraData(Zir.Inst.Imports, imports_index);
38 var import_i: u32 = 0;
39 var extra_index = extra.end;
40
41 while (import_i < extra.data.imports_len) : (import_i += 1) {
42 const item = scope_file.zir.extraData(Zir.Inst.Imports.Item, extra_index);
43 extra_index = item.end;
44
45 const src: LazySrcLoc = .{ .token_abs = item.data.token };
46 const import_path = scope_file.zir.nullTerminatedString(item.data.name);
47 try fs_file.writer().print(" @import(\"{}\") ", .{
48 std.zig.fmtEscapes(import_path),
49 });
50 try writer.writeSrc(fs_file.writer(), src);
51 try fs_file.writer().writeAll("\n");
52 }
53 }
54}
55
56const Writer = struct {
57 gpa: *Allocator,
58 arena: *Allocator,
59 file: *Module.Scope.File,
60 code: Zir,
61 indent: u32,
62 parent_decl_node: u32,
63
64 fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index {
65 return @bitCast(Ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node));
66 }
67
68 fn writeInstToStream(
69 self: *Writer,
70 stream: anytype,
71 inst: Zir.Inst.Index,
72 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
73 const tags = self.code.instructions.items(.tag);
74 const tag = tags[inst];
75 try stream.print("= {s}(", .{@tagName(tags[inst])});
76 switch (tag) {
77 .array_type,
78 .as,
79 .coerce_result_ptr,
80 .elem_ptr,
81 .elem_val,
82 .store,
83 .store_to_block_ptr,
84 .store_to_inferred_ptr,
85 .field_ptr_type,
86 => try self.writeBin(stream, inst),
87
88 .alloc,
89 .alloc_mut,
90 .alloc_comptime,
91 .indexable_ptr_len,
92 .anyframe_type,
93 .bit_not,
94 .bool_not,
95 .negate,
96 .negate_wrap,
97 .load,
98 .ensure_result_used,
99 .ensure_result_non_error,
100 .ret_node,
101 .ret_load,
102 .resolve_inferred_alloc,
103 .optional_type,
104 .optional_payload_safe,
105 .optional_payload_unsafe,
106 .optional_payload_safe_ptr,
107 .optional_payload_unsafe_ptr,
108 .err_union_payload_safe,
109 .err_union_payload_unsafe,
110 .err_union_payload_safe_ptr,
111 .err_union_payload_unsafe_ptr,
112 .err_union_code,
113 .err_union_code_ptr,
114 .is_non_null,
115 .is_non_null_ptr,
116 .is_non_err,
117 .is_non_err_ptr,
118 .typeof,
119 .typeof_elem,
120 .struct_init_empty,
121 .type_info,
122 .size_of,
123 .bit_size_of,
124 .typeof_log2_int_type,
125 .log2_int_type,
126 .ptr_to_int,
127 .error_to_int,
128 .int_to_error,
129 .compile_error,
130 .set_eval_branch_quota,
131 .enum_to_int,
132 .align_of,
133 .bool_to_int,
134 .embed_file,
135 .error_name,
136 .panic,
137 .set_align_stack,
138 .set_cold,
139 .set_float_mode,
140 .set_runtime_safety,
141 .sqrt,
142 .sin,
143 .cos,
144 .exp,
145 .exp2,
146 .log,
147 .log2,
148 .log10,
149 .fabs,
150 .floor,
151 .ceil,
152 .trunc,
153 .round,
154 .tag_name,
155 .reify,
156 .type_name,
157 .frame_type,
158 .frame_size,
159 .clz,
160 .ctz,
161 .pop_count,
162 .byte_swap,
163 .bit_reverse,
164 .elem_type,
165 .@"resume",
166 .@"await",
167 .await_nosuspend,
168 .fence,
169 => try self.writeUnNode(stream, inst),
170
171 .ref,
172 .ret_coerce,
173 .ensure_err_payload_void,
174 => try self.writeUnTok(stream, inst),
175
176 .bool_br_and,
177 .bool_br_or,
178 => try self.writeBoolBr(stream, inst),
179
180 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
181 .param_type => try self.writeParamType(stream, inst),
182 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
183 .ptr_type => try self.writePtrType(stream, inst),
184 .int => try self.writeInt(stream, inst),
185 .int_big => try self.writeIntBig(stream, inst),
186 .float => try self.writeFloat(stream, inst),
187 .float128 => try self.writeFloat128(stream, inst),
188 .str => try self.writeStr(stream, inst),
189 .int_type => try self.writeIntType(stream, inst),
190
191 .@"break",
192 .break_inline,
193 => try self.writeBreak(stream, inst),
194
195 .elem_ptr_node,
196 .elem_val_node,
197 .field_ptr_named,
198 .field_val_named,
199 .slice_start,
200 .slice_end,
201 .slice_sentinel,
202 .array_init,
203 .array_init_anon,
204 .array_init_ref,
205 .array_init_anon_ref,
206 .union_init_ptr,
207 .shuffle,
208 .select,
209 .mul_add,
210 .builtin_call,
211 .field_parent_ptr,
212 .memcpy,
213 .memset,
214 .builtin_async_call,
215 => try self.writePlNode(stream, inst),
216
217 .struct_init,
218 .struct_init_ref,
219 => try self.writeStructInit(stream, inst),
220
221 .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst),
222 .atomic_store => try self.writeAtomicStore(stream, inst),
223 .atomic_rmw => try self.writeAtomicRmw(stream, inst),
224
225 .struct_init_anon,
226 .struct_init_anon_ref,
227 => try self.writeStructInitAnon(stream, inst),
228
229 .field_type => try self.writeFieldType(stream, inst),
230 .field_type_ref => try self.writeFieldTypeRef(stream, inst),
231
232 .add,
233 .addwrap,
234 .array_cat,
235 .array_mul,
236 .mul,
237 .mulwrap,
238 .sub,
239 .subwrap,
240 .cmp_lt,
241 .cmp_lte,
242 .cmp_eq,
243 .cmp_gte,
244 .cmp_gt,
245 .cmp_neq,
246 .div,
247 .has_decl,
248 .has_field,
249 .mod_rem,
250 .shl,
251 .shl_exact,
252 .shr,
253 .shr_exact,
254 .xor,
255 .store_node,
256 .error_union_type,
257 .merge_error_sets,
258 .bit_and,
259 .bit_or,
260 .float_to_int,
261 .int_to_float,
262 .int_to_ptr,
263 .int_to_enum,
264 .float_cast,
265 .int_cast,
266 .err_set_cast,
267 .ptr_cast,
268 .truncate,
269 .align_cast,
270 .div_exact,
271 .div_floor,
272 .div_trunc,
273 .mod,
274 .rem,
275 .bit_offset_of,
276 .offset_of,
277 .splat,
278 .reduce,
279 .atomic_load,
280 .bitcast,
281 .bitcast_result_ptr,
282 .vector_type,
283 .maximum,
284 .minimum,
285 => try self.writePlNodeBin(stream, inst),
286
287 .@"export" => try self.writePlNodeExport(stream, inst),
288
289 .call,
290 .call_chkused,
291 .call_compile_time,
292 .call_nosuspend,
293 .call_async,
294 => try self.writePlNodeCall(stream, inst),
295
296 .block,
297 .block_inline,
298 .suspend_block,
299 .loop,
300 .validate_struct_init_ptr,
301 .validate_array_init_ptr,
302 .c_import,
303 => try self.writePlNodeBlock(stream, inst),
304
305 .condbr,
306 .condbr_inline,
307 => try self.writePlNodeCondBr(stream, inst),
308
309 .opaque_decl => try self.writeOpaqueDecl(stream, inst, .parent),
310 .opaque_decl_anon => try self.writeOpaqueDecl(stream, inst, .anon),
311 .opaque_decl_func => try self.writeOpaqueDecl(stream, inst, .func),
312
313 .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent),
314 .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon),
315 .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func),
316
317 .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none),
318 .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
319 .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under),
320 .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none),
321 .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
322 .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under),
323
324 .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none),
325 .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
326 .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
327 .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none),
328 .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
329 .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
330
331 .field_ptr,
332 .field_val,
333 => try self.writePlNodeField(stream, inst),
334
335 .as_node => try self.writeAs(stream, inst),
336
337 .breakpoint,
338 .repeat,
339 .repeat_inline,
340 .alloc_inferred,
341 .alloc_inferred_mut,
342 .alloc_inferred_comptime,
343 => try self.writeNode(stream, inst),
344
345 .error_value,
346 .enum_literal,
347 .decl_ref,
348 .decl_val,
349 .import,
350 .ret_err_value,
351 .ret_err_value_code,
352 .param_anytype,
353 .param_anytype_comptime,
354 => try self.writeStrTok(stream, inst),
355
356 .param, .param_comptime => try self.writeParam(stream, inst),
357
358 .func => try self.writeFunc(stream, inst, false),
359 .func_inferred => try self.writeFunc(stream, inst, true),
360
361 .@"unreachable" => try self.writeUnreachable(stream, inst),
362
363 .switch_capture,
364 .switch_capture_ref,
365 .switch_capture_multi,
366 .switch_capture_multi_ref,
367 .switch_capture_else,
368 .switch_capture_else_ref,
369 => try self.writeSwitchCapture(stream, inst),
370
371 .dbg_stmt => try self.writeDbgStmt(stream, inst),
372
373 .extended => try self.writeExtended(stream, inst),
374 }
375 }
376
377 fn writeExtended(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
378 const extended = self.code.instructions.items(.data)[inst].extended;
379 try stream.print("{s}(", .{@tagName(extended.opcode)});
380 switch (extended.opcode) {
381 .ret_ptr,
382 .ret_type,
383 .this,
384 .ret_addr,
385 .error_return_trace,
386 .frame,
387 .frame_address,
388 .builtin_src,
389 => try self.writeExtNode(stream, extended),
390
391 .@"asm" => try self.writeAsm(stream, extended),
392 .func => try self.writeFuncExtended(stream, extended),
393 .variable => try self.writeVarExtended(stream, extended),
394
395 .compile_log,
396 .typeof_peer,
397 => try self.writeNodeMultiOp(stream, extended),
398
399 .add_with_overflow,
400 .sub_with_overflow,
401 .mul_with_overflow,
402 .shl_with_overflow,
403 => try self.writeOverflowArithmetic(stream, extended),
404
405 .add_with_saturation,
406 .sub_with_saturation,
407 .mul_with_saturation,
408 .shl_with_saturation,
409 => try self.writeSaturatingArithmetic(stream, extended),
410 .struct_decl => try self.writeStructDecl(stream, extended),
411 .union_decl => try self.writeUnionDecl(stream, extended),
412 .enum_decl => try self.writeEnumDecl(stream, extended),
413
414 .alloc,
415 .builtin_extern,
416 .c_undef,
417 .c_include,
418 .c_define,
419 .wasm_memory_size,
420 .wasm_memory_grow,
421 => try stream.writeAll("TODO))"),
422 }
423 }
424
425 fn writeExtNode(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
426 const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
427 try stream.writeAll(")) ");
428 try self.writeSrc(stream, src);
429 }
430
431 fn writeBin(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
432 const inst_data = self.code.instructions.items(.data)[inst].bin;
433 try self.writeInstRef(stream, inst_data.lhs);
434 try stream.writeAll(", ");
435 try self.writeInstRef(stream, inst_data.rhs);
436 try stream.writeByte(')');
437 }
438
439 fn writeUnNode(
440 self: *Writer,
441 stream: anytype,
442 inst: Zir.Inst.Index,
443 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
444 const inst_data = self.code.instructions.items(.data)[inst].un_node;
445 try self.writeInstRef(stream, inst_data.operand);
446 try stream.writeAll(") ");
447 try self.writeSrc(stream, inst_data.src());
448 }
449
450 fn writeUnTok(
451 self: *Writer,
452 stream: anytype,
453 inst: Zir.Inst.Index,
454 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
455 const inst_data = self.code.instructions.items(.data)[inst].un_tok;
456 try self.writeInstRef(stream, inst_data.operand);
457 try stream.writeAll(") ");
458 try self.writeSrc(stream, inst_data.src());
459 }
460
461 fn writeArrayTypeSentinel(
462 self: *Writer,
463 stream: anytype,
464 inst: Zir.Inst.Index,
465 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
466 const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel;
467 _ = inst_data;
468 try stream.writeAll("TODO)");
469 }
470
471 fn writeParamType(
472 self: *Writer,
473 stream: anytype,
474 inst: Zir.Inst.Index,
475 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
476 const inst_data = self.code.instructions.items(.data)[inst].param_type;
477 try self.writeInstRef(stream, inst_data.callee);
478 try stream.print(", {d})", .{inst_data.param_index});
479 }
480
481 fn writePtrTypeSimple(
482 self: *Writer,
483 stream: anytype,
484 inst: Zir.Inst.Index,
485 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
486 const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple;
487 const str_allowzero = if (inst_data.is_allowzero) "allowzero, " else "";
488 const str_const = if (!inst_data.is_mutable) "const, " else "";
489 const str_volatile = if (inst_data.is_volatile) "volatile, " else "";
490 try self.writeInstRef(stream, inst_data.elem_type);
491 try stream.print(", {s}{s}{s}{s})", .{
492 str_allowzero,
493 str_const,
494 str_volatile,
495 @tagName(inst_data.size),
496 });
497 }
498
499 fn writePtrType(
500 self: *Writer,
501 stream: anytype,
502 inst: Zir.Inst.Index,
503 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
504 const inst_data = self.code.instructions.items(.data)[inst].ptr_type;
505 _ = inst_data;
506 try stream.writeAll("TODO)");
507 }
508
509 fn writeInt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
510 const inst_data = self.code.instructions.items(.data)[inst].int;
511 try stream.print("{d})", .{inst_data});
512 }
513
514 fn writeIntBig(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
515 const inst_data = self.code.instructions.items(.data)[inst].str;
516 const byte_count = inst_data.len * @sizeOf(std.math.big.Limb);
517 const limb_bytes = self.code.string_bytes[inst_data.start..][0..byte_count];
518 // limb_bytes is not aligned properly; we must allocate and copy the bytes
519 // in order to accomplish this.
520 const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len);
521 defer self.gpa.free(limbs);
522
523 mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes);
524 const big_int: std.math.big.int.Const = .{
525 .limbs = limbs,
526 .positive = true,
527 };
528 const as_string = try big_int.toStringAlloc(self.gpa, 10, .lower);
529 defer self.gpa.free(as_string);
530 try stream.print("{s})", .{as_string});
531 }
532
533 fn writeFloat(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
534 const number = self.code.instructions.items(.data)[inst].float;
535 try stream.print("{d})", .{number});
536 }
537
538 fn writeFloat128(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
539 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
540 const extra = self.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data;
541 const src = inst_data.src();
542 const number = extra.get();
543 // TODO improve std.format to be able to print f128 values
544 try stream.print("{d}) ", .{@floatCast(f64, number)});
545 try self.writeSrc(stream, src);
546 }
547
548 fn writeStr(
549 self: *Writer,
550 stream: anytype,
551 inst: Zir.Inst.Index,
552 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
553 const inst_data = self.code.instructions.items(.data)[inst].str;
554 const str = inst_data.get(self.code);
555 try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
556 }
557
558 fn writePlNode(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
559 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
560 try stream.writeAll("TODO) ");
561 try self.writeSrc(stream, inst_data.src());
562 }
563
564 fn writeParam(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
565 const inst_data = self.code.instructions.items(.data)[inst].pl_tok;
566 const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index);
567 const body = self.code.extra[extra.end..][0..extra.data.body_len];
568 try stream.print("\"{}\", ", .{
569 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)),
570 });
571 try stream.writeAll("{\n");
572 self.indent += 2;
573 try self.writeBody(stream, body);
574 self.indent -= 2;
575 try stream.writeByteNTimes(' ', self.indent);
576 try stream.writeAll("}) ");
577 try self.writeSrc(stream, inst_data.src());
578 }
579
580 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
581 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
582 const extra = self.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
583 try self.writeInstRef(stream, extra.lhs);
584 try stream.writeAll(", ");
585 try self.writeInstRef(stream, extra.rhs);
586 try stream.writeAll(") ");
587 try self.writeSrc(stream, inst_data.src());
588 }
589
590 fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
591 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
592 const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
593 const decl_name = self.code.nullTerminatedString(extra.decl_name);
594
595 try self.writeInstRef(stream, extra.namespace);
596 try stream.print(", {}, ", .{std.zig.fmtId(decl_name)});
597 try self.writeInstRef(stream, extra.options);
598 try stream.writeAll(") ");
599 try self.writeSrc(stream, inst_data.src());
600 }
601
602 fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
603 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
604 const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
605 var field_i: u32 = 0;
606 var extra_index = extra.end;
607
608 while (field_i < extra.data.fields_len) : (field_i += 1) {
609 const item = self.code.extraData(Zir.Inst.StructInit.Item, extra_index);
610 extra_index = item.end;
611
612 if (field_i != 0) {
613 try stream.writeAll(", [");
614 } else {
615 try stream.writeAll("[");
616 }
617 try self.writeInstIndex(stream, item.data.field_type);
618 try stream.writeAll(", ");
619 try self.writeInstRef(stream, item.data.init);
620 try stream.writeAll("]");
621 }
622 try stream.writeAll(") ");
623 try self.writeSrc(stream, inst_data.src());
624 }
625
626 fn writeCmpxchg(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
627 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
628 const extra = self.code.extraData(Zir.Inst.Cmpxchg, inst_data.payload_index).data;
629
630 try self.writeInstRef(stream, extra.ptr);
631 try stream.writeAll(", ");
632 try self.writeInstRef(stream, extra.expected_value);
633 try stream.writeAll(", ");
634 try self.writeInstRef(stream, extra.new_value);
635 try stream.writeAll(", ");
636 try self.writeInstRef(stream, extra.success_order);
637 try stream.writeAll(", ");
638 try self.writeInstRef(stream, extra.failure_order);
639 try stream.writeAll(") ");
640 try self.writeSrc(stream, inst_data.src());
641 }
642
643 fn writeAtomicStore(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
644 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
645 const extra = self.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
646
647 try self.writeInstRef(stream, extra.ptr);
648 try stream.writeAll(", ");
649 try self.writeInstRef(stream, extra.operand);
650 try stream.writeAll(", ");
651 try self.writeInstRef(stream, extra.ordering);
652 try stream.writeAll(") ");
653 try self.writeSrc(stream, inst_data.src());
654 }
655
656 fn writeAtomicRmw(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
657 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
658 const extra = self.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;
659
660 try self.writeInstRef(stream, extra.ptr);
661 try stream.writeAll(", ");
662 try self.writeInstRef(stream, extra.operation);
663 try stream.writeAll(", ");
664 try self.writeInstRef(stream, extra.operand);
665 try stream.writeAll(", ");
666 try self.writeInstRef(stream, extra.ordering);
667 try stream.writeAll(") ");
668 try self.writeSrc(stream, inst_data.src());
669 }
670
671 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
672 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
673 const extra = self.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
674 var field_i: u32 = 0;
675 var extra_index = extra.end;
676
677 while (field_i < extra.data.fields_len) : (field_i += 1) {
678 const item = self.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
679 extra_index = item.end;
680
681 const field_name = self.code.nullTerminatedString(item.data.field_name);
682
683 const prefix = if (field_i != 0) ", [" else "[";
684 try stream.print("{s}[{s}=", .{ prefix, field_name });
685 try self.writeInstRef(stream, item.data.init);
686 try stream.writeAll("]");
687 }
688 try stream.writeAll(") ");
689 try self.writeSrc(stream, inst_data.src());
690 }
691
692 fn writeFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
693 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
694 const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
695 try self.writeInstRef(stream, extra.container_type);
696 const field_name = self.code.nullTerminatedString(extra.name_start);
697 try stream.print(", {s}) ", .{field_name});
698 try self.writeSrc(stream, inst_data.src());
699 }
700
701 fn writeFieldTypeRef(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
702 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
703 const extra = self.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data;
704 try self.writeInstRef(stream, extra.container_type);
705 try stream.writeAll(", ");
706 try self.writeInstRef(stream, extra.field_name);
707 try stream.writeAll(") ");
708 try self.writeSrc(stream, inst_data.src());
709 }
710
711 fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
712 const extra = self.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
713 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
714 const operands = self.code.refSlice(extra.end, extended.small);
715
716 for (operands) |operand, i| {
717 if (i != 0) try stream.writeAll(", ");
718 try self.writeInstRef(stream, operand);
719 }
720 try stream.writeAll(")) ");
721 try self.writeSrc(stream, src);
722 }
723
724 fn writeAsm(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
725 const extra = self.code.extraData(Zir.Inst.Asm, extended.operand);
726 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
727 const outputs_len = @truncate(u5, extended.small);
728 const inputs_len = @truncate(u5, extended.small >> 5);
729 const clobbers_len = @truncate(u5, extended.small >> 10);
730 const is_volatile = @truncate(u1, extended.small >> 15) != 0;
731 const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
732
733 try self.writeFlag(stream, "volatile, ", is_volatile);
734 try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)});
735 try stream.writeAll(", ");
736
737 var extra_i: usize = extra.end;
738 var output_type_bits = extra.data.output_type_bits;
739 {
740 var i: usize = 0;
741 while (i < outputs_len) : (i += 1) {
742 const output = self.code.extraData(Zir.Inst.Asm.Output, extra_i);
743 extra_i = output.end;
744
745 const is_type = @truncate(u1, output_type_bits) != 0;
746 output_type_bits >>= 1;
747
748 const name = self.code.nullTerminatedString(output.data.name);
749 const constraint = self.code.nullTerminatedString(output.data.constraint);
750 try stream.print("output({}, \"{}\", ", .{
751 std.zig.fmtId(name), std.zig.fmtEscapes(constraint),
752 });
753 try self.writeFlag(stream, "->", is_type);
754 try self.writeInstRef(stream, output.data.operand);
755 try stream.writeAll(")");
756 if (i + 1 < outputs_len) {
757 try stream.writeAll("), ");
758 }
759 }
760 }
761 {
762 var i: usize = 0;
763 while (i < inputs_len) : (i += 1) {
764 const input = self.code.extraData(Zir.Inst.Asm.Input, extra_i);
765 extra_i = input.end;
766
767 const name = self.code.nullTerminatedString(input.data.name);
768 const constraint = self.code.nullTerminatedString(input.data.constraint);
769 try stream.print("input({}, \"{}\", ", .{
770 std.zig.fmtId(name), std.zig.fmtEscapes(constraint),
771 });
772 try self.writeInstRef(stream, input.data.operand);
773 try stream.writeAll(")");
774 if (i + 1 < inputs_len) {
775 try stream.writeAll(", ");
776 }
777 }
778 }
779 {
780 var i: usize = 0;
781 while (i < clobbers_len) : (i += 1) {
782 const str_index = self.code.extra[extra_i];
783 extra_i += 1;
784 const clobber = self.code.nullTerminatedString(str_index);
785 try stream.print("{}", .{std.zig.fmtId(clobber)});
786 if (i + 1 < clobbers_len) {
787 try stream.writeAll(", ");
788 }
789 }
790 }
791 try stream.writeAll(")) ");
792 try self.writeSrc(stream, src);
793 }
794
795 fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
796 const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data;
797 const src: LazySrcLoc = .{ .node_offset = extra.node };
798
799 try self.writeInstRef(stream, extra.lhs);
800 try stream.writeAll(", ");
801 try self.writeInstRef(stream, extra.rhs);
802 try stream.writeAll(", ");
803 try self.writeInstRef(stream, extra.ptr);
804 try stream.writeAll(")) ");
805 try self.writeSrc(stream, src);
806 }
807
808 fn writeSaturatingArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
809 const extra = self.code.extraData(Zir.Inst.SaturatingArithmetic, extended.operand).data;
810 const src: LazySrcLoc = .{ .node_offset = extra.node };
811
812 try self.writeInstRef(stream, extra.lhs);
813 try stream.writeAll(", ");
814 try self.writeInstRef(stream, extra.rhs);
815 try stream.writeAll(", ");
816 try stream.writeAll(") ");
817 try self.writeSrc(stream, src);
818 }
819
820 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
821 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
822 const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index);
823 const args = self.code.refSlice(extra.end, extra.data.args_len);
824
825 try self.writeInstRef(stream, extra.data.callee);
826 try stream.writeAll(", [");
827 for (args) |arg, i| {
828 if (i != 0) try stream.writeAll(", ");
829 try self.writeInstRef(stream, arg);
830 }
831 try stream.writeAll("]) ");
832 try self.writeSrc(stream, inst_data.src());
833 }
834
835 fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
836 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
837 try self.writePlNodeBlockWithoutSrc(stream, inst);
838 try self.writeSrc(stream, inst_data.src());
839 }
840
841 fn writePlNodeBlockWithoutSrc(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
842 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
843 const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index);
844 const body = self.code.extra[extra.end..][0..extra.data.body_len];
845 try stream.writeAll("{\n");
846 self.indent += 2;
847 try self.writeBody(stream, body);
848 self.indent -= 2;
849 try stream.writeByteNTimes(' ', self.indent);
850 try stream.writeAll("}) ");
851 }
852
853 fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
854 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
855 const extra = self.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
856 const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len];
857 const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
858 try self.writeInstRef(stream, extra.data.condition);
859 try stream.writeAll(", {\n");
860 self.indent += 2;
861 try self.writeBody(stream, then_body);
862 self.indent -= 2;
863 try stream.writeByteNTimes(' ', self.indent);
864 try stream.writeAll("}, {\n");
865 self.indent += 2;
866 try self.writeBody(stream, else_body);
867 self.indent -= 2;
868 try stream.writeByteNTimes(' ', self.indent);
869 try stream.writeAll("}) ");
870 try self.writeSrc(stream, inst_data.src());
871 }
872
873 fn writeStructDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
874 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
875
876 var extra_index: usize = extended.operand;
877
878 const src_node: ?i32 = if (small.has_src_node) blk: {
879 const src_node = @bitCast(i32, self.code.extra[extra_index]);
880 extra_index += 1;
881 break :blk src_node;
882 } else null;
883
884 const body_len = if (small.has_body_len) blk: {
885 const body_len = self.code.extra[extra_index];
886 extra_index += 1;
887 break :blk body_len;
888 } else 0;
889
890 const fields_len = if (small.has_fields_len) blk: {
891 const fields_len = self.code.extra[extra_index];
892 extra_index += 1;
893 break :blk fields_len;
894 } else 0;
895
896 const decls_len = if (small.has_decls_len) blk: {
897 const decls_len = self.code.extra[extra_index];
898 extra_index += 1;
899 break :blk decls_len;
900 } else 0;
901
902 try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits);
903 try stream.print("{s}, {s}, ", .{
904 @tagName(small.name_strategy), @tagName(small.layout),
905 });
906
907 if (decls_len == 0) {
908 try stream.writeAll("{}, ");
909 } else {
910 try stream.writeAll("{\n");
911 self.indent += 2;
912 extra_index = try self.writeDecls(stream, decls_len, extra_index);
913 self.indent -= 2;
914 try stream.writeByteNTimes(' ', self.indent);
915 try stream.writeAll("}, ");
916 }
917
918 const body = self.code.extra[extra_index..][0..body_len];
919 extra_index += body.len;
920
921 if (fields_len == 0) {
922 assert(body.len == 0);
923 try stream.writeAll("{}, {})");
924 } else {
925 const prev_parent_decl_node = self.parent_decl_node;
926 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
927 self.indent += 2;
928 if (body.len == 0) {
929 try stream.writeAll("{}, {\n");
930 } else {
931 try stream.writeAll("{\n");
932 try self.writeBody(stream, body);
933
934 try stream.writeByteNTimes(' ', self.indent - 2);
935 try stream.writeAll("}, {\n");
936 }
937
938 const bits_per_field = 4;
939 const fields_per_u32 = 32 / bits_per_field;
940 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
941 var bit_bag_index: usize = extra_index;
942 extra_index += bit_bags_count;
943 var cur_bit_bag: u32 = undefined;
944 var field_i: u32 = 0;
945 while (field_i < fields_len) : (field_i += 1) {
946 if (field_i % fields_per_u32 == 0) {
947 cur_bit_bag = self.code.extra[bit_bag_index];
948 bit_bag_index += 1;
949 }
950 const has_align = @truncate(u1, cur_bit_bag) != 0;
951 cur_bit_bag >>= 1;
952 const has_default = @truncate(u1, cur_bit_bag) != 0;
953 cur_bit_bag >>= 1;
954 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
955 cur_bit_bag >>= 1;
956 const unused = @truncate(u1, cur_bit_bag) != 0;
957 cur_bit_bag >>= 1;
958
959 _ = unused;
960
961 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
962 extra_index += 1;
963 const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
964 extra_index += 1;
965
966 try stream.writeByteNTimes(' ', self.indent);
967 try self.writeFlag(stream, "comptime ", is_comptime);
968 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
969 try self.writeInstRef(stream, field_type);
970
971 if (has_align) {
972 const align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
973 extra_index += 1;
974
975 try stream.writeAll(" align(");
976 try self.writeInstRef(stream, align_ref);
977 try stream.writeAll(")");
978 }
979 if (has_default) {
980 const default_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
981 extra_index += 1;
982
983 try stream.writeAll(" = ");
984 try self.writeInstRef(stream, default_ref);
985 }
986 try stream.writeAll(",\n");
987 }
988
989 self.parent_decl_node = prev_parent_decl_node;
990 self.indent -= 2;
991 try stream.writeByteNTimes(' ', self.indent);
992 try stream.writeAll("})");
993 }
994 try self.writeSrcNode(stream, src_node);
995 }
996
997 fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
998 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
999
1000 var extra_index: usize = extended.operand;
1001
1002 const src_node: ?i32 = if (small.has_src_node) blk: {
1003 const src_node = @bitCast(i32, self.code.extra[extra_index]);
1004 extra_index += 1;
1005 break :blk src_node;
1006 } else null;
1007
1008 const tag_type_ref = if (small.has_tag_type) blk: {
1009 const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1010 extra_index += 1;
1011 break :blk tag_type_ref;
1012 } else .none;
1013
1014 const body_len = if (small.has_body_len) blk: {
1015 const body_len = self.code.extra[extra_index];
1016 extra_index += 1;
1017 break :blk body_len;
1018 } else 0;
1019
1020 const fields_len = if (small.has_fields_len) blk: {
1021 const fields_len = self.code.extra[extra_index];
1022 extra_index += 1;
1023 break :blk fields_len;
1024 } else 0;
1025
1026 const decls_len = if (small.has_decls_len) blk: {
1027 const decls_len = self.code.extra[extra_index];
1028 extra_index += 1;
1029 break :blk decls_len;
1030 } else 0;
1031
1032 try stream.print("{s}, {s}, ", .{
1033 @tagName(small.name_strategy), @tagName(small.layout),
1034 });
1035 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
1036
1037 if (decls_len == 0) {
1038 try stream.writeAll("{}, ");
1039 } else {
1040 try stream.writeAll("{\n");
1041 self.indent += 2;
1042 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1043 self.indent -= 2;
1044 try stream.writeByteNTimes(' ', self.indent);
1045 try stream.writeAll("}, ");
1046 }
1047
1048 assert(fields_len != 0);
1049
1050 if (tag_type_ref != .none) {
1051 try self.writeInstRef(stream, tag_type_ref);
1052 try stream.writeAll(", ");
1053 }
1054
1055 const body = self.code.extra[extra_index..][0..body_len];
1056 extra_index += body.len;
1057
1058 const prev_parent_decl_node = self.parent_decl_node;
1059 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1060 self.indent += 2;
1061 if (body.len == 0) {
1062 try stream.writeAll("{}, {\n");
1063 } else {
1064 try stream.writeAll("{\n");
1065 try self.writeBody(stream, body);
1066
1067 try stream.writeByteNTimes(' ', self.indent - 2);
1068 try stream.writeAll("}, {\n");
1069 }
1070
1071 const bits_per_field = 4;
1072 const fields_per_u32 = 32 / bits_per_field;
1073 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
1074 const body_end = extra_index;
1075 extra_index += bit_bags_count;
1076 var bit_bag_index: usize = body_end;
1077 var cur_bit_bag: u32 = undefined;
1078 var field_i: u32 = 0;
1079 while (field_i < fields_len) : (field_i += 1) {
1080 if (field_i % fields_per_u32 == 0) {
1081 cur_bit_bag = self.code.extra[bit_bag_index];
1082 bit_bag_index += 1;
1083 }
1084 const has_type = @truncate(u1, cur_bit_bag) != 0;
1085 cur_bit_bag >>= 1;
1086 const has_align = @truncate(u1, cur_bit_bag) != 0;
1087 cur_bit_bag >>= 1;
1088 const has_value = @truncate(u1, cur_bit_bag) != 0;
1089 cur_bit_bag >>= 1;
1090 const unused = @truncate(u1, cur_bit_bag) != 0;
1091 cur_bit_bag >>= 1;
1092
1093 _ = unused;
1094
1095 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
1096 extra_index += 1;
1097 try stream.writeByteNTimes(' ', self.indent);
1098 try stream.print("{}", .{std.zig.fmtId(field_name)});
1099
1100 if (has_type) {
1101 const field_type = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1102 extra_index += 1;
1103
1104 try stream.writeAll(": ");
1105 try self.writeInstRef(stream, field_type);
1106 }
1107 if (has_align) {
1108 const align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1109 extra_index += 1;
1110
1111 try stream.writeAll(" align(");
1112 try self.writeInstRef(stream, align_ref);
1113 try stream.writeAll(")");
1114 }
1115 if (has_value) {
1116 const default_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1117 extra_index += 1;
1118
1119 try stream.writeAll(" = ");
1120 try self.writeInstRef(stream, default_ref);
1121 }
1122 try stream.writeAll(",\n");
1123 }
1124
1125 self.parent_decl_node = prev_parent_decl_node;
1126 self.indent -= 2;
1127 try stream.writeByteNTimes(' ', self.indent);
1128 try stream.writeAll("})");
1129 try self.writeSrcNode(stream, src_node);
1130 }
1131
1132 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize {
1133 const parent_decl_node = self.parent_decl_node;
1134 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
1135 var extra_index = extra_start + bit_bags_count;
1136 var bit_bag_index: usize = extra_start;
1137 var cur_bit_bag: u32 = undefined;
1138 var decl_i: u32 = 0;
1139 while (decl_i < decls_len) : (decl_i += 1) {
1140 if (decl_i % 8 == 0) {
1141 cur_bit_bag = self.code.extra[bit_bag_index];
1142 bit_bag_index += 1;
1143 }
1144 const is_pub = @truncate(u1, cur_bit_bag) != 0;
1145 cur_bit_bag >>= 1;
1146 const is_exported = @truncate(u1, cur_bit_bag) != 0;
1147 cur_bit_bag >>= 1;
1148 const has_align = @truncate(u1, cur_bit_bag) != 0;
1149 cur_bit_bag >>= 1;
1150 const has_section = @truncate(u1, cur_bit_bag) != 0;
1151 cur_bit_bag >>= 1;
1152
1153 const sub_index = extra_index;
1154
1155 const hash_u32s = self.code.extra[extra_index..][0..4];
1156 extra_index += 4;
1157 const line = self.code.extra[extra_index];
1158 extra_index += 1;
1159 const decl_name_index = self.code.extra[extra_index];
1160 extra_index += 1;
1161 const decl_index = self.code.extra[extra_index];
1162 extra_index += 1;
1163 const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
1164 const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1165 extra_index += 1;
1166 break :inst inst;
1167 };
1168 const section_inst: Zir.Inst.Ref = if (!has_section) .none else inst: {
1169 const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1170 extra_index += 1;
1171 break :inst inst;
1172 };
1173
1174 const pub_str = if (is_pub) "pub " else "";
1175 const hash_bytes = @bitCast([16]u8, hash_u32s.*);
1176 try stream.writeByteNTimes(' ', self.indent);
1177 if (decl_name_index == 0) {
1178 const name = if (is_exported) "usingnamespace" else "comptime";
1179 try stream.writeAll(pub_str);
1180 try stream.writeAll(name);
1181 } else if (decl_name_index == 1) {
1182 try stream.writeAll("test");
1183 } else {
1184 const raw_decl_name = self.code.nullTerminatedString(decl_name_index);
1185 const decl_name = if (raw_decl_name.len == 0)
1186 self.code.nullTerminatedString(decl_name_index + 1)
1187 else
1188 raw_decl_name;
1189 const test_str = if (raw_decl_name.len == 0) "test " else "";
1190 const export_str = if (is_exported) "export " else "";
1191 try stream.print("[{d}] {s}{s}{s}{}", .{
1192 sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name),
1193 });
1194 if (align_inst != .none) {
1195 try stream.writeAll(" align(");
1196 try self.writeInstRef(stream, align_inst);
1197 try stream.writeAll(")");
1198 }
1199 if (section_inst != .none) {
1200 try stream.writeAll(" linksection(");
1201 try self.writeInstRef(stream, section_inst);
1202 try stream.writeAll(")");
1203 }
1204 }
1205 const tag = self.code.instructions.items(.tag)[decl_index];
1206 try stream.print(" line({d}) hash({}): %{d} = {s}(", .{
1207 line, std.fmt.fmtSliceHexLower(&hash_bytes), decl_index, @tagName(tag),
1208 });
1209
1210 const decl_block_inst_data = self.code.instructions.items(.data)[decl_index].pl_node;
1211 const sub_decl_node_off = decl_block_inst_data.src_node;
1212 self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off);
1213 try self.writePlNodeBlockWithoutSrc(stream, decl_index);
1214 self.parent_decl_node = parent_decl_node;
1215 try self.writeSrc(stream, decl_block_inst_data.src());
1216 try stream.writeAll("\n");
1217 }
1218 return extra_index;
1219 }
1220
1221 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1222 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
1223 var extra_index: usize = extended.operand;
1224
1225 const src_node: ?i32 = if (small.has_src_node) blk: {
1226 const src_node = @bitCast(i32, self.code.extra[extra_index]);
1227 extra_index += 1;
1228 break :blk src_node;
1229 } else null;
1230
1231 const tag_type_ref = if (small.has_tag_type) blk: {
1232 const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1233 extra_index += 1;
1234 break :blk tag_type_ref;
1235 } else .none;
1236
1237 const body_len = if (small.has_body_len) blk: {
1238 const body_len = self.code.extra[extra_index];
1239 extra_index += 1;
1240 break :blk body_len;
1241 } else 0;
1242
1243 const fields_len = if (small.has_fields_len) blk: {
1244 const fields_len = self.code.extra[extra_index];
1245 extra_index += 1;
1246 break :blk fields_len;
1247 } else 0;
1248
1249 const decls_len = if (small.has_decls_len) blk: {
1250 const decls_len = self.code.extra[extra_index];
1251 extra_index += 1;
1252 break :blk decls_len;
1253 } else 0;
1254
1255 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
1256 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);
1257
1258 if (decls_len == 0) {
1259 try stream.writeAll("{}, ");
1260 } else {
1261 try stream.writeAll("{\n");
1262 self.indent += 2;
1263 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1264 self.indent -= 2;
1265 try stream.writeByteNTimes(' ', self.indent);
1266 try stream.writeAll("}, ");
1267 }
1268
1269 if (tag_type_ref != .none) {
1270 try self.writeInstRef(stream, tag_type_ref);
1271 try stream.writeAll(", ");
1272 }
1273
1274 const body = self.code.extra[extra_index..][0..body_len];
1275 extra_index += body.len;
1276
1277 if (fields_len == 0) {
1278 assert(body.len == 0);
1279 try stream.writeAll("{}, {})");
1280 } else {
1281 const prev_parent_decl_node = self.parent_decl_node;
1282 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1283 self.indent += 2;
1284 if (body.len == 0) {
1285 try stream.writeAll("{}, {\n");
1286 } else {
1287 try stream.writeAll("{\n");
1288 try self.writeBody(stream, body);
1289
1290 try stream.writeByteNTimes(' ', self.indent - 2);
1291 try stream.writeAll("}, {\n");
1292 }
1293
1294 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
1295 const body_end = extra_index;
1296 extra_index += bit_bags_count;
1297 var bit_bag_index: usize = body_end;
1298 var cur_bit_bag: u32 = undefined;
1299 var field_i: u32 = 0;
1300 while (field_i < fields_len) : (field_i += 1) {
1301 if (field_i % 32 == 0) {
1302 cur_bit_bag = self.code.extra[bit_bag_index];
1303 bit_bag_index += 1;
1304 }
1305 const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
1306 cur_bit_bag >>= 1;
1307
1308 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
1309 extra_index += 1;
1310
1311 try stream.writeByteNTimes(' ', self.indent);
1312 try stream.print("{}", .{std.zig.fmtId(field_name)});
1313
1314 if (has_tag_value) {
1315 const tag_value_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1316 extra_index += 1;
1317
1318 try stream.writeAll(" = ");
1319 try self.writeInstRef(stream, tag_value_ref);
1320 }
1321 try stream.writeAll(",\n");
1322 }
1323 self.parent_decl_node = prev_parent_decl_node;
1324 self.indent -= 2;
1325 try stream.writeByteNTimes(' ', self.indent);
1326 try stream.writeAll("})");
1327 }
1328 try self.writeSrcNode(stream, src_node);
1329 }
1330
1331 fn writeOpaqueDecl(
1332 self: *Writer,
1333 stream: anytype,
1334 inst: Zir.Inst.Index,
1335 name_strategy: Zir.Inst.NameStrategy,
1336 ) !void {
1337 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1338 const extra = self.code.extraData(Zir.Inst.OpaqueDecl, inst_data.payload_index);
1339 const decls_len = extra.data.decls_len;
1340
1341 try stream.print("{s}, ", .{@tagName(name_strategy)});
1342
1343 if (decls_len == 0) {
1344 try stream.writeAll("}) ");
1345 } else {
1346 try stream.writeAll("\n");
1347 self.indent += 2;
1348 _ = try self.writeDecls(stream, decls_len, extra.end);
1349 self.indent -= 2;
1350 try stream.writeByteNTimes(' ', self.indent);
1351 try stream.writeAll("}) ");
1352 }
1353 try self.writeSrc(stream, inst_data.src());
1354 }
1355
1356 fn writeErrorSetDecl(
1357 self: *Writer,
1358 stream: anytype,
1359 inst: Zir.Inst.Index,
1360 name_strategy: Zir.Inst.NameStrategy,
1361 ) !void {
1362 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1363 const extra = self.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index);
1364 const fields = self.code.extra[extra.end..][0..extra.data.fields_len];
1365
1366 try stream.print("{s}, ", .{@tagName(name_strategy)});
1367
1368 try stream.writeAll("{\n");
1369 self.indent += 2;
1370 for (fields) |str_index| {
1371 const name = self.code.nullTerminatedString(str_index);
1372 try stream.writeByteNTimes(' ', self.indent);
1373 try stream.print("{},\n", .{std.zig.fmtId(name)});
1374 }
1375 self.indent -= 2;
1376 try stream.writeByteNTimes(' ', self.indent);
1377 try stream.writeAll("}) ");
1378
1379 try self.writeSrc(stream, inst_data.src());
1380 }
1381
1382 fn writePlNodeSwitchBr(
1383 self: *Writer,
1384 stream: anytype,
1385 inst: Zir.Inst.Index,
1386 special_prong: Zir.SpecialProng,
1387 ) !void {
1388 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1389 const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
1390 const special: struct {
1391 body: []const Zir.Inst.Index,
1392 end: usize,
1393 } = switch (special_prong) {
1394 .none => .{ .body = &.{}, .end = extra.end },
1395 .under, .@"else" => blk: {
1396 const body_len = self.code.extra[extra.end];
1397 const extra_body_start = extra.end + 1;
1398 break :blk .{
1399 .body = self.code.extra[extra_body_start..][0..body_len],
1400 .end = extra_body_start + body_len,
1401 };
1402 },
1403 };
1404
1405 try self.writeInstRef(stream, extra.data.operand);
1406
1407 if (special.body.len != 0) {
1408 const prong_name = switch (special_prong) {
1409 .@"else" => "else",
1410 .under => "_",
1411 else => unreachable,
1412 };
1413 try stream.print(", {s} => {{\n", .{prong_name});
1414 self.indent += 2;
1415 try self.writeBody(stream, special.body);
1416 self.indent -= 2;
1417 try stream.writeByteNTimes(' ', self.indent);
1418 try stream.writeAll("}");
1419 }
1420
1421 var extra_index: usize = special.end;
1422 {
1423 var scalar_i: usize = 0;
1424 while (scalar_i < extra.data.cases_len) : (scalar_i += 1) {
1425 const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1426 extra_index += 1;
1427 const body_len = self.code.extra[extra_index];
1428 extra_index += 1;
1429 const body = self.code.extra[extra_index..][0..body_len];
1430 extra_index += body_len;
1431
1432 try stream.writeAll(", ");
1433 try self.writeInstRef(stream, item_ref);
1434 try stream.writeAll(" => {\n");
1435 self.indent += 2;
1436 try self.writeBody(stream, body);
1437 self.indent -= 2;
1438 try stream.writeByteNTimes(' ', self.indent);
1439 try stream.writeAll("}");
1440 }
1441 }
1442 try stream.writeAll(") ");
1443 try self.writeSrc(stream, inst_data.src());
1444 }
1445
1446 fn writePlNodeSwitchBlockMulti(
1447 self: *Writer,
1448 stream: anytype,
1449 inst: Zir.Inst.Index,
1450 special_prong: Zir.SpecialProng,
1451 ) !void {
1452 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1453 const extra = self.code.extraData(Zir.Inst.SwitchBlockMulti, inst_data.payload_index);
1454 const special: struct {
1455 body: []const Zir.Inst.Index,
1456 end: usize,
1457 } = switch (special_prong) {
1458 .none => .{ .body = &.{}, .end = extra.end },
1459 .under, .@"else" => blk: {
1460 const body_len = self.code.extra[extra.end];
1461 const extra_body_start = extra.end + 1;
1462 break :blk .{
1463 .body = self.code.extra[extra_body_start..][0..body_len],
1464 .end = extra_body_start + body_len,
1465 };
1466 },
1467 };
1468
1469 try self.writeInstRef(stream, extra.data.operand);
1470
1471 if (special.body.len != 0) {
1472 const prong_name = switch (special_prong) {
1473 .@"else" => "else",
1474 .under => "_",
1475 else => unreachable,
1476 };
1477 try stream.print(", {s} => {{\n", .{prong_name});
1478 self.indent += 2;
1479 try self.writeBody(stream, special.body);
1480 self.indent -= 2;
1481 try stream.writeByteNTimes(' ', self.indent);
1482 try stream.writeAll("}");
1483 }
1484
1485 var extra_index: usize = special.end;
1486 {
1487 var scalar_i: usize = 0;
1488 while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) {
1489 const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1490 extra_index += 1;
1491 const body_len = self.code.extra[extra_index];
1492 extra_index += 1;
1493 const body = self.code.extra[extra_index..][0..body_len];
1494 extra_index += body_len;
1495
1496 try stream.writeAll(", ");
1497 try self.writeInstRef(stream, item_ref);
1498 try stream.writeAll(" => {\n");
1499 self.indent += 2;
1500 try self.writeBody(stream, body);
1501 self.indent -= 2;
1502 try stream.writeByteNTimes(' ', self.indent);
1503 try stream.writeAll("}");
1504 }
1505 }
1506 {
1507 var multi_i: usize = 0;
1508 while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) {
1509 const items_len = self.code.extra[extra_index];
1510 extra_index += 1;
1511 const ranges_len = self.code.extra[extra_index];
1512 extra_index += 1;
1513 const body_len = self.code.extra[extra_index];
1514 extra_index += 1;
1515 const items = self.code.refSlice(extra_index, items_len);
1516 extra_index += items_len;
1517
1518 for (items) |item_ref| {
1519 try stream.writeAll(", ");
1520 try self.writeInstRef(stream, item_ref);
1521 }
1522
1523 var range_i: usize = 0;
1524 while (range_i < ranges_len) : (range_i += 1) {
1525 const item_first = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1526 extra_index += 1;
1527 const item_last = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1528 extra_index += 1;
1529
1530 try stream.writeAll(", ");
1531 try self.writeInstRef(stream, item_first);
1532 try stream.writeAll("...");
1533 try self.writeInstRef(stream, item_last);
1534 }
1535
1536 const body = self.code.extra[extra_index..][0..body_len];
1537 extra_index += body_len;
1538 try stream.writeAll(" => {\n");
1539 self.indent += 2;
1540 try self.writeBody(stream, body);
1541 self.indent -= 2;
1542 try stream.writeByteNTimes(' ', self.indent);
1543 try stream.writeAll("}");
1544 }
1545 }
1546 try stream.writeAll(") ");
1547 try self.writeSrc(stream, inst_data.src());
1548 }
1549
1550 fn writePlNodeField(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1551 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1552 const extra = self.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
1553 const name = self.code.nullTerminatedString(extra.field_name_start);
1554 try self.writeInstRef(stream, extra.lhs);
1555 try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)});
1556 try self.writeSrc(stream, inst_data.src());
1557 }
1558
1559 fn writeAs(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1560 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1561 const extra = self.code.extraData(Zir.Inst.As, inst_data.payload_index).data;
1562 try self.writeInstRef(stream, extra.dest_type);
1563 try stream.writeAll(", ");
1564 try self.writeInstRef(stream, extra.operand);
1565 try stream.writeAll(") ");
1566 try self.writeSrc(stream, inst_data.src());
1567 }
1568
1569 fn writeNode(
1570 self: *Writer,
1571 stream: anytype,
1572 inst: Zir.Inst.Index,
1573 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1574 const src_node = self.code.instructions.items(.data)[inst].node;
1575 const src: LazySrcLoc = .{ .node_offset = src_node };
1576 try stream.writeAll(") ");
1577 try self.writeSrc(stream, src);
1578 }
1579
1580 fn writeStrTok(
1581 self: *Writer,
1582 stream: anytype,
1583 inst: Zir.Inst.Index,
1584 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1585 const inst_data = self.code.instructions.items(.data)[inst].str_tok;
1586 const str = inst_data.get(self.code);
1587 try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)});
1588 try self.writeSrc(stream, inst_data.src());
1589 }
1590
1591 fn writeFunc(
1592 self: *Writer,
1593 stream: anytype,
1594 inst: Zir.Inst.Index,
1595 inferred_error_set: bool,
1596 ) !void {
1597 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1598 const src = inst_data.src();
1599 const extra = self.code.extraData(Zir.Inst.Func, inst_data.payload_index);
1600 var extra_index = extra.end;
1601
1602 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
1603 extra_index += ret_ty_body.len;
1604
1605 const body = self.code.extra[extra_index..][0..extra.data.body_len];
1606 extra_index += body.len;
1607
1608 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
1609 if (body.len != 0) {
1610 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
1611 }
1612 return self.writeFuncCommon(
1613 stream,
1614 ret_ty_body,
1615 inferred_error_set,
1616 false,
1617 false,
1618 .none,
1619 .none,
1620 body,
1621 src,
1622 src_locs,
1623 );
1624 }
1625
1626 fn writeFuncExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1627 const extra = self.code.extraData(Zir.Inst.ExtendedFunc, extended.operand);
1628 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
1629 const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small);
1630
1631 var extra_index: usize = extra.end;
1632 if (small.has_lib_name) {
1633 const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
1634 extra_index += 1;
1635 try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)});
1636 }
1637 try self.writeFlag(stream, "test, ", small.is_test);
1638 const cc: Zir.Inst.Ref = if (!small.has_cc) .none else blk: {
1639 const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1640 extra_index += 1;
1641 break :blk cc;
1642 };
1643 const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: {
1644 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1645 extra_index += 1;
1646 break :blk align_inst;
1647 };
1648
1649 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
1650 extra_index += ret_ty_body.len;
1651
1652 const body = self.code.extra[extra_index..][0..extra.data.body_len];
1653 extra_index += body.len;
1654
1655 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
1656 if (body.len != 0) {
1657 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
1658 }
1659 return self.writeFuncCommon(
1660 stream,
1661 ret_ty_body,
1662 small.is_inferred_error,
1663 small.is_var_args,
1664 small.is_extern,
1665 cc,
1666 align_inst,
1667 body,
1668 src,
1669 src_locs,
1670 );
1671 }
1672
1673 fn writeVarExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1674 const extra = self.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
1675 const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
1676
1677 try self.writeInstRef(stream, extra.data.var_type);
1678
1679 var extra_index: usize = extra.end;
1680 if (small.has_lib_name) {
1681 const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
1682 extra_index += 1;
1683 try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)});
1684 }
1685 const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: {
1686 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1687 extra_index += 1;
1688 break :blk align_inst;
1689 };
1690 const init_inst: Zir.Inst.Ref = if (!small.has_init) .none else blk: {
1691 const init_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1692 extra_index += 1;
1693 break :blk init_inst;
1694 };
1695 try self.writeFlag(stream, ", is_extern", small.is_extern);
1696 try self.writeOptionalInstRef(stream, ", align=", align_inst);
1697 try self.writeOptionalInstRef(stream, ", init=", init_inst);
1698 try stream.writeAll("))");
1699 }
1700
1701 fn writeBoolBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1702 const inst_data = self.code.instructions.items(.data)[inst].bool_br;
1703 const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index);
1704 const body = self.code.extra[extra.end..][0..extra.data.body_len];
1705 try self.writeInstRef(stream, inst_data.lhs);
1706 try stream.writeAll(", {\n");
1707 self.indent += 2;
1708 try self.writeBody(stream, body);
1709 self.indent -= 2;
1710 try stream.writeByteNTimes(' ', self.indent);
1711 try stream.writeAll("})");
1712 }
1713
1714 fn writeIntType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1715 const int_type = self.code.instructions.items(.data)[inst].int_type;
1716 const prefix: u8 = switch (int_type.signedness) {
1717 .signed => 'i',
1718 .unsigned => 'u',
1719 };
1720 try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count });
1721 try self.writeSrc(stream, int_type.src());
1722 }
1723
1724 fn writeBreak(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1725 const inst_data = self.code.instructions.items(.data)[inst].@"break";
1726
1727 try self.writeInstIndex(stream, inst_data.block_inst);
1728 try stream.writeAll(", ");
1729 try self.writeInstRef(stream, inst_data.operand);
1730 try stream.writeAll(")");
1731 }
1732
1733 fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1734 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
1735 const safety_str = if (inst_data.safety) "safe" else "unsafe";
1736 try stream.print("{s}) ", .{safety_str});
1737 try self.writeSrc(stream, inst_data.src());
1738 }
1739
1740 fn writeFuncCommon(
1741 self: *Writer,
1742 stream: anytype,
1743 ret_ty_body: []const Zir.Inst.Index,
1744 inferred_error_set: bool,
1745 var_args: bool,
1746 is_extern: bool,
1747 cc: Zir.Inst.Ref,
1748 align_inst: Zir.Inst.Ref,
1749 body: []const Zir.Inst.Index,
1750 src: LazySrcLoc,
1751 src_locs: Zir.Inst.Func.SrcLocs,
1752 ) !void {
1753 if (ret_ty_body.len == 0) {
1754 try stream.writeAll("ret_ty=void");
1755 } else {
1756 try stream.writeAll("ret_ty={\n");
1757 self.indent += 2;
1758 try self.writeBody(stream, ret_ty_body);
1759 self.indent -= 2;
1760 try stream.writeByteNTimes(' ', self.indent);
1761 try stream.writeAll("}");
1762 }
1763
1764 try self.writeOptionalInstRef(stream, ", cc=", cc);
1765 try self.writeOptionalInstRef(stream, ", align=", align_inst);
1766 try self.writeFlag(stream, ", vargs", var_args);
1767 try self.writeFlag(stream, ", extern", is_extern);
1768 try self.writeFlag(stream, ", inferror", inferred_error_set);
1769
1770 if (body.len == 0) {
1771 try stream.writeAll(", body={}) ");
1772 } else {
1773 try stream.writeAll(", body={\n");
1774 self.indent += 2;
1775 try self.writeBody(stream, body);
1776 self.indent -= 2;
1777 try stream.writeByteNTimes(' ', self.indent);
1778 try stream.writeAll("}) ");
1779 }
1780 if (body.len != 0) {
1781 try stream.print("(lbrace={d}:{d},rbrace={d}:{d}) ", .{
1782 src_locs.lbrace_line, @truncate(u16, src_locs.columns),
1783 src_locs.rbrace_line, @truncate(u16, src_locs.columns >> 16),
1784 });
1785 }
1786 try self.writeSrc(stream, src);
1787 }
1788
1789 fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1790 const inst_data = self.code.instructions.items(.data)[inst].switch_capture;
1791 try self.writeInstIndex(stream, inst_data.switch_inst);
1792 try stream.print(", {d})", .{inst_data.prong_index});
1793 }
1794
1795 fn writeDbgStmt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1796 const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt;
1797 try stream.print("{d}, {d})", .{ inst_data.line, inst_data.column });
1798 }
1799
1800 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
1801 var i: usize = @enumToInt(ref);
1802
1803 if (i < Zir.Inst.Ref.typed_value_map.len) {
1804 return stream.print("@{}", .{ref});
1805 }
1806 i -= Zir.Inst.Ref.typed_value_map.len;
1807
1808 return self.writeInstIndex(stream, @intCast(Zir.Inst.Index, i));
1809 }
1810
1811 fn writeInstIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1812 _ = self;
1813 return stream.print("%{d}", .{inst});
1814 }
1815
1816 fn writeOptionalInstRef(
1817 self: *Writer,
1818 stream: anytype,
1819 prefix: []const u8,
1820 inst: Zir.Inst.Ref,
1821 ) !void {
1822 if (inst == .none) return;
1823 try stream.writeAll(prefix);
1824 try self.writeInstRef(stream, inst);
1825 }
1826
1827 fn writeFlag(
1828 self: *Writer,
1829 stream: anytype,
1830 name: []const u8,
1831 flag: bool,
1832 ) !void {
1833 _ = self;
1834 if (!flag) return;
1835 try stream.writeAll(name);
1836 }
1837
1838 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {
1839 const tree = self.file.tree;
1840 const src_loc: Module.SrcLoc = .{
1841 .file_scope = self.file,
1842 .parent_decl_node = self.parent_decl_node,
1843 .lazy = src,
1844 };
1845 // Caller must ensure AST tree is loaded.
1846 const abs_byte_off = src_loc.byteOffset(self.gpa) catch unreachable;
1847 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);
1848 try stream.print("{s}:{d}:{d}", .{
1849 @tagName(src), delta_line.line + 1, delta_line.column + 1,
1850 });
1851 }
1852
1853 fn writeSrcNode(self: *Writer, stream: anytype, src_node: ?i32) !void {
1854 const node_offset = src_node orelse return;
1855 const src: LazySrcLoc = .{ .node_offset = node_offset };
1856 try stream.writeAll(" ");
1857 return self.writeSrc(stream, src);
1858 }
1859
1860 fn writeBody(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void {
1861 for (body) |inst| {
1862 try stream.writeByteNTimes(' ', self.indent);
1863 try stream.print("%{d} ", .{inst});
1864 try self.writeInstToStream(stream, inst);
1865 try stream.writeByte('\n');
1866 }
1867 }
1868};