mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
stage2: Air and Liveness are passed ephemerally
to the link infrastructure, instead of being stored with Module.Fn. This moves towards a strategy to make more efficient use of memory by not storing Air or Liveness data in the Fn struct, but computing it on demand, immediately sending it to the backend, and then immediately freeing it. Backends which want to defer codegen until flush() such as SPIR-V must move the Air/Liveness data upon `updateFunc` being called and keep track of that data in the backend implementation itself.
This commit is contained in:
parent
0ffc6b5cc3
commit
0f38f68696
@ -690,3 +690,8 @@ pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void {
|
||||
}
|
||||
}
|
||||
|
||||
/// For debugging purposes.
|
||||
pub fn dump(func: *Fn, mod: Module) void {
|
||||
ir.dumpFn(mod, func);
|
||||
}
|
||||
|
||||
|
||||
@ -2027,7 +2027,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
|
||||
defer liveness.deinit(gpa);
|
||||
|
||||
if (std.builtin.mode == .Debug and self.verbose_air) {
|
||||
func.dump(module.*);
|
||||
@panic("TODO implement dumping AIR and liveness");
|
||||
}
|
||||
|
||||
assert(decl.ty.hasCodeGenBits());
|
||||
|
||||
@ -50,7 +50,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness {
|
||||
|
||||
var a: Analysis = .{
|
||||
.gpa = gpa,
|
||||
.air = &air,
|
||||
.air = air,
|
||||
.table = .{},
|
||||
.tomb_bits = try gpa.alloc(
|
||||
usize,
|
||||
@ -65,7 +65,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness {
|
||||
defer a.table.deinit(gpa);
|
||||
|
||||
const main_body = air.getMainBody();
|
||||
try a.table.ensureTotalCapacity(main_body.len);
|
||||
try a.table.ensureTotalCapacity(gpa, @intCast(u32, main_body.len));
|
||||
try analyzeWithContext(&a, null, main_body);
|
||||
return Liveness{
|
||||
.tomb_bits = a.tomb_bits,
|
||||
@ -108,9 +108,10 @@ const OperandInt = std.math.Log2Int(Bpi);
|
||||
/// In-progress data; on successful analysis converted into `Liveness`.
|
||||
const Analysis = struct {
|
||||
gpa: *Allocator,
|
||||
air: *const Air,
|
||||
air: Air,
|
||||
table: std.AutoHashMapUnmanaged(Air.Inst.Index, void),
|
||||
tomb_bits: []usize,
|
||||
special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
|
||||
extra: std.ArrayListUnmanaged(u32),
|
||||
|
||||
fn storeTombBits(a: *Analysis, inst: Air.Inst.Index, tomb_bits: Bpi) void {
|
||||
@ -165,7 +166,7 @@ fn analyzeWithContext(
|
||||
|
||||
fn analyzeInst(
|
||||
a: *Analysis,
|
||||
new_set: ?*std.AutoHashMap(Air.Inst.Index, void),
|
||||
new_set: ?*std.AutoHashMapUnmanaged(Air.Inst.Index, void),
|
||||
inst: Air.Inst.Index,
|
||||
) Allocator.Error!void {
|
||||
const gpa = a.gpa;
|
||||
|
||||
@ -769,11 +769,6 @@ pub const Fn = struct {
|
||||
success,
|
||||
};
|
||||
|
||||
/// For debugging purposes.
|
||||
pub fn dump(func: *Fn, mod: Module) void {
|
||||
ir.dumpFn(mod, func);
|
||||
}
|
||||
|
||||
pub fn deinit(func: *Fn, gpa: *Allocator) void {
|
||||
if (func.getInferredErrorSet()) |map| {
|
||||
map.deinit(gpa);
|
||||
|
||||
752
src/Sema.zig
752
src/Sema.zig
@ -69,7 +69,7 @@ const LazySrcLoc = Module.LazySrcLoc;
|
||||
const RangeSet = @import("RangeSet.zig");
|
||||
const target_util = @import("target.zig");
|
||||
|
||||
pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Index);
|
||||
pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
|
||||
|
||||
pub fn deinit(sema: *Sema) void {
|
||||
const gpa = sema.gpa;
|
||||
@ -158,344 +158,344 @@ pub fn analyzeBody(
|
||||
var i: usize = 0;
|
||||
while (true) {
|
||||
const inst = body[i];
|
||||
const air_inst = switch (tags[inst]) {
|
||||
const air_inst: Air.Inst.Ref = switch (tags[inst]) {
|
||||
// zig fmt: off
|
||||
.arg => try sema.zirArg(block, inst),
|
||||
.alloc => try sema.zirAlloc(block, inst),
|
||||
.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
|
||||
.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
|
||||
.alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
|
||||
.alloc_mut => try sema.zirAllocMut(block, inst),
|
||||
.alloc_comptime => try sema.zirAllocComptime(block, inst),
|
||||
.anyframe_type => try sema.zirAnyframeType(block, inst),
|
||||
.array_cat => try sema.zirArrayCat(block, inst),
|
||||
.array_mul => try sema.zirArrayMul(block, inst),
|
||||
.array_type => try sema.zirArrayType(block, inst),
|
||||
.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
|
||||
.vector_type => try sema.zirVectorType(block, inst),
|
||||
.as => try sema.zirAs(block, inst),
|
||||
.as_node => try sema.zirAsNode(block, inst),
|
||||
.bit_and => try sema.zirBitwise(block, inst, .bit_and),
|
||||
.bit_not => try sema.zirBitNot(block, inst),
|
||||
.bit_or => try sema.zirBitwise(block, inst, .bit_or),
|
||||
.bitcast => try sema.zirBitcast(block, inst),
|
||||
.bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
|
||||
.block => try sema.zirBlock(block, inst),
|
||||
.suspend_block => try sema.zirSuspendBlock(block, inst),
|
||||
.bool_not => try sema.zirBoolNot(block, inst),
|
||||
.bool_and => try sema.zirBoolOp(block, inst, false),
|
||||
.bool_or => try sema.zirBoolOp(block, inst, true),
|
||||
.bool_br_and => try sema.zirBoolBr(block, inst, false),
|
||||
.bool_br_or => try sema.zirBoolBr(block, inst, true),
|
||||
.c_import => try sema.zirCImport(block, inst),
|
||||
.call => try sema.zirCall(block, inst, .auto, false),
|
||||
.call_chkused => try sema.zirCall(block, inst, .auto, true),
|
||||
.call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
|
||||
.call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
|
||||
.call_async => try sema.zirCall(block, inst, .async_kw, false),
|
||||
.cmp_eq => try sema.zirCmp(block, inst, .eq),
|
||||
.cmp_gt => try sema.zirCmp(block, inst, .gt),
|
||||
.cmp_gte => try sema.zirCmp(block, inst, .gte),
|
||||
.cmp_lt => try sema.zirCmp(block, inst, .lt),
|
||||
.cmp_lte => try sema.zirCmp(block, inst, .lte),
|
||||
.cmp_neq => try sema.zirCmp(block, inst, .neq),
|
||||
.coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
|
||||
.decl_ref => try sema.zirDeclRef(block, inst),
|
||||
.decl_val => try sema.zirDeclVal(block, inst),
|
||||
.load => try sema.zirLoad(block, inst),
|
||||
.elem_ptr => try sema.zirElemPtr(block, inst),
|
||||
.elem_ptr_node => try sema.zirElemPtrNode(block, inst),
|
||||
.elem_val => try sema.zirElemVal(block, inst),
|
||||
.elem_val_node => try sema.zirElemValNode(block, inst),
|
||||
.elem_type => try sema.zirElemType(block, inst),
|
||||
.enum_literal => try sema.zirEnumLiteral(block, inst),
|
||||
.enum_to_int => try sema.zirEnumToInt(block, inst),
|
||||
.int_to_enum => try sema.zirIntToEnum(block, inst),
|
||||
.err_union_code => try sema.zirErrUnionCode(block, inst),
|
||||
.err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
|
||||
.err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
|
||||
.err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
|
||||
.err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
|
||||
.err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
|
||||
.error_union_type => try sema.zirErrorUnionType(block, inst),
|
||||
.error_value => try sema.zirErrorValue(block, inst),
|
||||
.error_to_int => try sema.zirErrorToInt(block, inst),
|
||||
.int_to_error => try sema.zirIntToError(block, inst),
|
||||
.field_ptr => try sema.zirFieldPtr(block, inst),
|
||||
.field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
|
||||
.field_val => try sema.zirFieldVal(block, inst),
|
||||
.field_val_named => try sema.zirFieldValNamed(block, inst),
|
||||
.func => try sema.zirFunc(block, inst, false),
|
||||
.func_inferred => try sema.zirFunc(block, inst, true),
|
||||
.import => try sema.zirImport(block, inst),
|
||||
.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
|
||||
.int => try sema.zirInt(block, inst),
|
||||
.int_big => try sema.zirIntBig(block, inst),
|
||||
.float => try sema.zirFloat(block, inst),
|
||||
.float128 => try sema.zirFloat128(block, inst),
|
||||
.int_type => try sema.zirIntType(block, inst),
|
||||
.is_non_err => try sema.zirIsNonErr(block, inst),
|
||||
.is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
|
||||
.is_non_null => try sema.zirIsNonNull(block, inst),
|
||||
.is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst),
|
||||
.loop => try sema.zirLoop(block, inst),
|
||||
.merge_error_sets => try sema.zirMergeErrorSets(block, inst),
|
||||
.negate => try sema.zirNegate(block, inst, .sub),
|
||||
.negate_wrap => try sema.zirNegate(block, inst, .subwrap),
|
||||
.optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
|
||||
.optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
|
||||
.optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
|
||||
.optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
|
||||
.optional_type => try sema.zirOptionalType(block, inst),
|
||||
.param_type => try sema.zirParamType(block, inst),
|
||||
.ptr_type => try sema.zirPtrType(block, inst),
|
||||
.ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
|
||||
.ref => try sema.zirRef(block, inst),
|
||||
.ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
|
||||
.shl => try sema.zirShl(block, inst),
|
||||
.shr => try sema.zirShr(block, inst),
|
||||
.slice_end => try sema.zirSliceEnd(block, inst),
|
||||
.slice_sentinel => try sema.zirSliceSentinel(block, inst),
|
||||
.slice_start => try sema.zirSliceStart(block, inst),
|
||||
.str => try sema.zirStr(block, inst),
|
||||
.switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
|
||||
.switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
|
||||
.switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
|
||||
.switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
|
||||
.switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
|
||||
.switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
|
||||
.switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
|
||||
.switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
|
||||
.switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
|
||||
.switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
|
||||
.switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
|
||||
.switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
|
||||
.switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
|
||||
.switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
|
||||
.switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
|
||||
.switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
|
||||
.switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
|
||||
.switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
|
||||
.type_info => try sema.zirTypeInfo(block, inst),
|
||||
.size_of => try sema.zirSizeOf(block, inst),
|
||||
.bit_size_of => try sema.zirBitSizeOf(block, inst),
|
||||
.typeof => try sema.zirTypeof(block, inst),
|
||||
.typeof_elem => try sema.zirTypeofElem(block, inst),
|
||||
.log2_int_type => try sema.zirLog2IntType(block, inst),
|
||||
.typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
|
||||
.xor => try sema.zirBitwise(block, inst, .xor),
|
||||
.struct_init_empty => try sema.zirStructInitEmpty(block, inst),
|
||||
.struct_init => try sema.zirStructInit(block, inst, false),
|
||||
.struct_init_ref => try sema.zirStructInit(block, inst, true),
|
||||
.struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
|
||||
.struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
|
||||
.array_init => try sema.zirArrayInit(block, inst, false),
|
||||
.array_init_ref => try sema.zirArrayInit(block, inst, true),
|
||||
.array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
|
||||
.array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
|
||||
.union_init_ptr => try sema.zirUnionInitPtr(block, inst),
|
||||
.field_type => try sema.zirFieldType(block, inst),
|
||||
.field_type_ref => try sema.zirFieldTypeRef(block, inst),
|
||||
.ptr_to_int => try sema.zirPtrToInt(block, inst),
|
||||
.align_of => try sema.zirAlignOf(block, inst),
|
||||
.bool_to_int => try sema.zirBoolToInt(block, inst),
|
||||
.embed_file => try sema.zirEmbedFile(block, inst),
|
||||
.error_name => try sema.zirErrorName(block, inst),
|
||||
.tag_name => try sema.zirTagName(block, inst),
|
||||
.reify => try sema.zirReify(block, inst),
|
||||
.type_name => try sema.zirTypeName(block, inst),
|
||||
.frame_type => try sema.zirFrameType(block, inst),
|
||||
.frame_size => try sema.zirFrameSize(block, inst),
|
||||
.float_to_int => try sema.zirFloatToInt(block, inst),
|
||||
.int_to_float => try sema.zirIntToFloat(block, inst),
|
||||
.int_to_ptr => try sema.zirIntToPtr(block, inst),
|
||||
.float_cast => try sema.zirFloatCast(block, inst),
|
||||
.int_cast => try sema.zirIntCast(block, inst),
|
||||
.err_set_cast => try sema.zirErrSetCast(block, inst),
|
||||
.ptr_cast => try sema.zirPtrCast(block, inst),
|
||||
.truncate => try sema.zirTruncate(block, inst),
|
||||
.align_cast => try sema.zirAlignCast(block, inst),
|
||||
.has_decl => try sema.zirHasDecl(block, inst),
|
||||
.has_field => try sema.zirHasField(block, inst),
|
||||
.clz => try sema.zirClz(block, inst),
|
||||
.ctz => try sema.zirCtz(block, inst),
|
||||
.pop_count => try sema.zirPopCount(block, inst),
|
||||
.byte_swap => try sema.zirByteSwap(block, inst),
|
||||
.bit_reverse => try sema.zirBitReverse(block, inst),
|
||||
.div_exact => try sema.zirDivExact(block, inst),
|
||||
.div_floor => try sema.zirDivFloor(block, inst),
|
||||
.div_trunc => try sema.zirDivTrunc(block, inst),
|
||||
.mod => try sema.zirMod(block, inst),
|
||||
.rem => try sema.zirRem(block, inst),
|
||||
.shl_exact => try sema.zirShlExact(block, inst),
|
||||
.shr_exact => try sema.zirShrExact(block, inst),
|
||||
.bit_offset_of => try sema.zirBitOffsetOf(block, inst),
|
||||
.offset_of => try sema.zirOffsetOf(block, inst),
|
||||
.cmpxchg_strong => try sema.zirCmpxchg(block, inst),
|
||||
.cmpxchg_weak => try sema.zirCmpxchg(block, inst),
|
||||
.splat => try sema.zirSplat(block, inst),
|
||||
.reduce => try sema.zirReduce(block, inst),
|
||||
.shuffle => try sema.zirShuffle(block, inst),
|
||||
.atomic_load => try sema.zirAtomicLoad(block, inst),
|
||||
.atomic_rmw => try sema.zirAtomicRmw(block, inst),
|
||||
.atomic_store => try sema.zirAtomicStore(block, inst),
|
||||
.mul_add => try sema.zirMulAdd(block, inst),
|
||||
.builtin_call => try sema.zirBuiltinCall(block, inst),
|
||||
.field_ptr_type => try sema.zirFieldPtrType(block, inst),
|
||||
.field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
|
||||
.memcpy => try sema.zirMemcpy(block, inst),
|
||||
.memset => try sema.zirMemset(block, inst),
|
||||
.builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
|
||||
.@"resume" => try sema.zirResume(block, inst),
|
||||
.@"await" => try sema.zirAwait(block, inst, false),
|
||||
.await_nosuspend => try sema.zirAwait(block, inst, true),
|
||||
.extended => try sema.zirExtended(block, inst),
|
||||
//.alloc => try sema.zirAlloc(block, inst),
|
||||
//.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
|
||||
//.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
|
||||
//.alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
|
||||
//.alloc_mut => try sema.zirAllocMut(block, inst),
|
||||
//.alloc_comptime => try sema.zirAllocComptime(block, inst),
|
||||
//.anyframe_type => try sema.zirAnyframeType(block, inst),
|
||||
//.array_cat => try sema.zirArrayCat(block, inst),
|
||||
//.array_mul => try sema.zirArrayMul(block, inst),
|
||||
//.array_type => try sema.zirArrayType(block, inst),
|
||||
//.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
|
||||
//.vector_type => try sema.zirVectorType(block, inst),
|
||||
//.as => try sema.zirAs(block, inst),
|
||||
//.as_node => try sema.zirAsNode(block, inst),
|
||||
//.bit_and => try sema.zirBitwise(block, inst, .bit_and),
|
||||
//.bit_not => try sema.zirBitNot(block, inst),
|
||||
//.bit_or => try sema.zirBitwise(block, inst, .bit_or),
|
||||
//.bitcast => try sema.zirBitcast(block, inst),
|
||||
//.bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
|
||||
//.block => try sema.zirBlock(block, inst),
|
||||
//.suspend_block => try sema.zirSuspendBlock(block, inst),
|
||||
//.bool_not => try sema.zirBoolNot(block, inst),
|
||||
//.bool_and => try sema.zirBoolOp(block, inst, false),
|
||||
//.bool_or => try sema.zirBoolOp(block, inst, true),
|
||||
//.bool_br_and => try sema.zirBoolBr(block, inst, false),
|
||||
//.bool_br_or => try sema.zirBoolBr(block, inst, true),
|
||||
//.c_import => try sema.zirCImport(block, inst),
|
||||
//.call => try sema.zirCall(block, inst, .auto, false),
|
||||
//.call_chkused => try sema.zirCall(block, inst, .auto, true),
|
||||
//.call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
|
||||
//.call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
|
||||
//.call_async => try sema.zirCall(block, inst, .async_kw, false),
|
||||
//.cmp_eq => try sema.zirCmp(block, inst, .eq),
|
||||
//.cmp_gt => try sema.zirCmp(block, inst, .gt),
|
||||
//.cmp_gte => try sema.zirCmp(block, inst, .gte),
|
||||
//.cmp_lt => try sema.zirCmp(block, inst, .lt),
|
||||
//.cmp_lte => try sema.zirCmp(block, inst, .lte),
|
||||
//.cmp_neq => try sema.zirCmp(block, inst, .neq),
|
||||
//.coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
|
||||
//.decl_ref => try sema.zirDeclRef(block, inst),
|
||||
//.decl_val => try sema.zirDeclVal(block, inst),
|
||||
//.load => try sema.zirLoad(block, inst),
|
||||
//.elem_ptr => try sema.zirElemPtr(block, inst),
|
||||
//.elem_ptr_node => try sema.zirElemPtrNode(block, inst),
|
||||
//.elem_val => try sema.zirElemVal(block, inst),
|
||||
//.elem_val_node => try sema.zirElemValNode(block, inst),
|
||||
//.elem_type => try sema.zirElemType(block, inst),
|
||||
//.enum_literal => try sema.zirEnumLiteral(block, inst),
|
||||
//.enum_to_int => try sema.zirEnumToInt(block, inst),
|
||||
//.int_to_enum => try sema.zirIntToEnum(block, inst),
|
||||
//.err_union_code => try sema.zirErrUnionCode(block, inst),
|
||||
//.err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
|
||||
//.err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
|
||||
//.err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
|
||||
//.err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
|
||||
//.err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
|
||||
//.error_union_type => try sema.zirErrorUnionType(block, inst),
|
||||
//.error_value => try sema.zirErrorValue(block, inst),
|
||||
//.error_to_int => try sema.zirErrorToInt(block, inst),
|
||||
//.int_to_error => try sema.zirIntToError(block, inst),
|
||||
//.field_ptr => try sema.zirFieldPtr(block, inst),
|
||||
//.field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
|
||||
//.field_val => try sema.zirFieldVal(block, inst),
|
||||
//.field_val_named => try sema.zirFieldValNamed(block, inst),
|
||||
//.func => try sema.zirFunc(block, inst, false),
|
||||
//.func_inferred => try sema.zirFunc(block, inst, true),
|
||||
//.import => try sema.zirImport(block, inst),
|
||||
//.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
|
||||
//.int => try sema.zirInt(block, inst),
|
||||
//.int_big => try sema.zirIntBig(block, inst),
|
||||
//.float => try sema.zirFloat(block, inst),
|
||||
//.float128 => try sema.zirFloat128(block, inst),
|
||||
//.int_type => try sema.zirIntType(block, inst),
|
||||
//.is_non_err => try sema.zirIsNonErr(block, inst),
|
||||
//.is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
|
||||
//.is_non_null => try sema.zirIsNonNull(block, inst),
|
||||
//.is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst),
|
||||
//.loop => try sema.zirLoop(block, inst),
|
||||
//.merge_error_sets => try sema.zirMergeErrorSets(block, inst),
|
||||
//.negate => try sema.zirNegate(block, inst, .sub),
|
||||
//.negate_wrap => try sema.zirNegate(block, inst, .subwrap),
|
||||
//.optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
|
||||
//.optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
|
||||
//.optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
|
||||
//.optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
|
||||
//.optional_type => try sema.zirOptionalType(block, inst),
|
||||
//.param_type => try sema.zirParamType(block, inst),
|
||||
//.ptr_type => try sema.zirPtrType(block, inst),
|
||||
//.ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
|
||||
//.ref => try sema.zirRef(block, inst),
|
||||
//.ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
|
||||
//.shl => try sema.zirShl(block, inst),
|
||||
//.shr => try sema.zirShr(block, inst),
|
||||
//.slice_end => try sema.zirSliceEnd(block, inst),
|
||||
//.slice_sentinel => try sema.zirSliceSentinel(block, inst),
|
||||
//.slice_start => try sema.zirSliceStart(block, inst),
|
||||
//.str => try sema.zirStr(block, inst),
|
||||
//.switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
|
||||
//.switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
|
||||
//.switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
|
||||
//.switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
|
||||
//.switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
|
||||
//.switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
|
||||
//.switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
|
||||
//.switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
|
||||
//.switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
|
||||
//.switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
|
||||
//.switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
|
||||
//.switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
|
||||
//.switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
|
||||
//.switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
|
||||
//.switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
|
||||
//.switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
|
||||
//.switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
|
||||
//.switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
|
||||
//.type_info => try sema.zirTypeInfo(block, inst),
|
||||
//.size_of => try sema.zirSizeOf(block, inst),
|
||||
//.bit_size_of => try sema.zirBitSizeOf(block, inst),
|
||||
//.typeof => try sema.zirTypeof(block, inst),
|
||||
//.typeof_elem => try sema.zirTypeofElem(block, inst),
|
||||
//.log2_int_type => try sema.zirLog2IntType(block, inst),
|
||||
//.typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
|
||||
//.xor => try sema.zirBitwise(block, inst, .xor),
|
||||
//.struct_init_empty => try sema.zirStructInitEmpty(block, inst),
|
||||
//.struct_init => try sema.zirStructInit(block, inst, false),
|
||||
//.struct_init_ref => try sema.zirStructInit(block, inst, true),
|
||||
//.struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
|
||||
//.struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
|
||||
//.array_init => try sema.zirArrayInit(block, inst, false),
|
||||
//.array_init_ref => try sema.zirArrayInit(block, inst, true),
|
||||
//.array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
|
||||
//.array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
|
||||
//.union_init_ptr => try sema.zirUnionInitPtr(block, inst),
|
||||
//.field_type => try sema.zirFieldType(block, inst),
|
||||
//.field_type_ref => try sema.zirFieldTypeRef(block, inst),
|
||||
//.ptr_to_int => try sema.zirPtrToInt(block, inst),
|
||||
//.align_of => try sema.zirAlignOf(block, inst),
|
||||
//.bool_to_int => try sema.zirBoolToInt(block, inst),
|
||||
//.embed_file => try sema.zirEmbedFile(block, inst),
|
||||
//.error_name => try sema.zirErrorName(block, inst),
|
||||
//.tag_name => try sema.zirTagName(block, inst),
|
||||
//.reify => try sema.zirReify(block, inst),
|
||||
//.type_name => try sema.zirTypeName(block, inst),
|
||||
//.frame_type => try sema.zirFrameType(block, inst),
|
||||
//.frame_size => try sema.zirFrameSize(block, inst),
|
||||
//.float_to_int => try sema.zirFloatToInt(block, inst),
|
||||
//.int_to_float => try sema.zirIntToFloat(block, inst),
|
||||
//.int_to_ptr => try sema.zirIntToPtr(block, inst),
|
||||
//.float_cast => try sema.zirFloatCast(block, inst),
|
||||
//.int_cast => try sema.zirIntCast(block, inst),
|
||||
//.err_set_cast => try sema.zirErrSetCast(block, inst),
|
||||
//.ptr_cast => try sema.zirPtrCast(block, inst),
|
||||
//.truncate => try sema.zirTruncate(block, inst),
|
||||
//.align_cast => try sema.zirAlignCast(block, inst),
|
||||
//.has_decl => try sema.zirHasDecl(block, inst),
|
||||
//.has_field => try sema.zirHasField(block, inst),
|
||||
//.clz => try sema.zirClz(block, inst),
|
||||
//.ctz => try sema.zirCtz(block, inst),
|
||||
//.pop_count => try sema.zirPopCount(block, inst),
|
||||
//.byte_swap => try sema.zirByteSwap(block, inst),
|
||||
//.bit_reverse => try sema.zirBitReverse(block, inst),
|
||||
//.div_exact => try sema.zirDivExact(block, inst),
|
||||
//.div_floor => try sema.zirDivFloor(block, inst),
|
||||
//.div_trunc => try sema.zirDivTrunc(block, inst),
|
||||
//.mod => try sema.zirMod(block, inst),
|
||||
//.rem => try sema.zirRem(block, inst),
|
||||
//.shl_exact => try sema.zirShlExact(block, inst),
|
||||
//.shr_exact => try sema.zirShrExact(block, inst),
|
||||
//.bit_offset_of => try sema.zirBitOffsetOf(block, inst),
|
||||
//.offset_of => try sema.zirOffsetOf(block, inst),
|
||||
//.cmpxchg_strong => try sema.zirCmpxchg(block, inst),
|
||||
//.cmpxchg_weak => try sema.zirCmpxchg(block, inst),
|
||||
//.splat => try sema.zirSplat(block, inst),
|
||||
//.reduce => try sema.zirReduce(block, inst),
|
||||
//.shuffle => try sema.zirShuffle(block, inst),
|
||||
//.atomic_load => try sema.zirAtomicLoad(block, inst),
|
||||
//.atomic_rmw => try sema.zirAtomicRmw(block, inst),
|
||||
//.atomic_store => try sema.zirAtomicStore(block, inst),
|
||||
//.mul_add => try sema.zirMulAdd(block, inst),
|
||||
//.builtin_call => try sema.zirBuiltinCall(block, inst),
|
||||
//.field_ptr_type => try sema.zirFieldPtrType(block, inst),
|
||||
//.field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
|
||||
//.memcpy => try sema.zirMemcpy(block, inst),
|
||||
//.memset => try sema.zirMemset(block, inst),
|
||||
//.builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
|
||||
//.@"resume" => try sema.zirResume(block, inst),
|
||||
//.@"await" => try sema.zirAwait(block, inst, false),
|
||||
//.await_nosuspend => try sema.zirAwait(block, inst, true),
|
||||
//.extended => try sema.zirExtended(block, inst),
|
||||
|
||||
.sqrt => try sema.zirUnaryMath(block, inst),
|
||||
.sin => try sema.zirUnaryMath(block, inst),
|
||||
.cos => try sema.zirUnaryMath(block, inst),
|
||||
.exp => try sema.zirUnaryMath(block, inst),
|
||||
.exp2 => try sema.zirUnaryMath(block, inst),
|
||||
.log => try sema.zirUnaryMath(block, inst),
|
||||
.log2 => try sema.zirUnaryMath(block, inst),
|
||||
.log10 => try sema.zirUnaryMath(block, inst),
|
||||
.fabs => try sema.zirUnaryMath(block, inst),
|
||||
.floor => try sema.zirUnaryMath(block, inst),
|
||||
.ceil => try sema.zirUnaryMath(block, inst),
|
||||
.trunc => try sema.zirUnaryMath(block, inst),
|
||||
.round => try sema.zirUnaryMath(block, inst),
|
||||
//.sqrt => try sema.zirUnaryMath(block, inst),
|
||||
//.sin => try sema.zirUnaryMath(block, inst),
|
||||
//.cos => try sema.zirUnaryMath(block, inst),
|
||||
//.exp => try sema.zirUnaryMath(block, inst),
|
||||
//.exp2 => try sema.zirUnaryMath(block, inst),
|
||||
//.log => try sema.zirUnaryMath(block, inst),
|
||||
//.log2 => try sema.zirUnaryMath(block, inst),
|
||||
//.log10 => try sema.zirUnaryMath(block, inst),
|
||||
//.fabs => try sema.zirUnaryMath(block, inst),
|
||||
//.floor => try sema.zirUnaryMath(block, inst),
|
||||
//.ceil => try sema.zirUnaryMath(block, inst),
|
||||
//.trunc => try sema.zirUnaryMath(block, inst),
|
||||
//.round => try sema.zirUnaryMath(block, inst),
|
||||
|
||||
.opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
|
||||
.opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
|
||||
.opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
|
||||
.error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
|
||||
.error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
|
||||
.error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
|
||||
//.opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
|
||||
//.opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
|
||||
//.opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
|
||||
//.error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
|
||||
//.error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
|
||||
//.error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
|
||||
|
||||
.add => try sema.zirArithmetic(block, inst),
|
||||
.addwrap => try sema.zirArithmetic(block, inst),
|
||||
.div => try sema.zirArithmetic(block, inst),
|
||||
.mod_rem => try sema.zirArithmetic(block, inst),
|
||||
.mul => try sema.zirArithmetic(block, inst),
|
||||
.mulwrap => try sema.zirArithmetic(block, inst),
|
||||
.sub => try sema.zirArithmetic(block, inst),
|
||||
.subwrap => try sema.zirArithmetic(block, inst),
|
||||
//.add => try sema.zirArithmetic(block, inst),
|
||||
//.addwrap => try sema.zirArithmetic(block, inst),
|
||||
//.div => try sema.zirArithmetic(block, inst),
|
||||
//.mod_rem => try sema.zirArithmetic(block, inst),
|
||||
//.mul => try sema.zirArithmetic(block, inst),
|
||||
//.mulwrap => try sema.zirArithmetic(block, inst),
|
||||
//.sub => try sema.zirArithmetic(block, inst),
|
||||
//.subwrap => try sema.zirArithmetic(block, inst),
|
||||
|
||||
// Instructions that we know to *always* be noreturn based solely on their tag.
|
||||
// These functions match the return type of analyzeBody so that we can
|
||||
// tail call them here.
|
||||
.break_inline => return inst,
|
||||
.condbr => return sema.zirCondbr(block, inst),
|
||||
.@"break" => return sema.zirBreak(block, inst),
|
||||
.compile_error => return sema.zirCompileError(block, inst),
|
||||
.ret_coerce => return sema.zirRetCoerce(block, inst, true),
|
||||
.ret_node => return sema.zirRetNode(block, inst),
|
||||
.ret_err_value => return sema.zirRetErrValue(block, inst),
|
||||
.@"unreachable" => return sema.zirUnreachable(block, inst),
|
||||
.repeat => return sema.zirRepeat(block, inst),
|
||||
.panic => return sema.zirPanic(block, inst),
|
||||
// zig fmt: on
|
||||
//// Instructions that we know to *always* be noreturn based solely on their tag.
|
||||
//// These functions match the return type of analyzeBody so that we can
|
||||
//// tail call them here.
|
||||
//.break_inline => return inst,
|
||||
//.condbr => return sema.zirCondbr(block, inst),
|
||||
//.@"break" => return sema.zirBreak(block, inst),
|
||||
//.compile_error => return sema.zirCompileError(block, inst),
|
||||
//.ret_coerce => return sema.zirRetCoerce(block, inst, true),
|
||||
//.ret_node => return sema.zirRetNode(block, inst),
|
||||
//.ret_err_value => return sema.zirRetErrValue(block, inst),
|
||||
//.@"unreachable" => return sema.zirUnreachable(block, inst),
|
||||
//.repeat => return sema.zirRepeat(block, inst),
|
||||
//.panic => return sema.zirPanic(block, inst),
|
||||
//// zig fmt: on
|
||||
|
||||
// Instructions that we know can *never* be noreturn based solely on
|
||||
// their tag. We avoid needlessly checking if they are noreturn and
|
||||
// continue the loop.
|
||||
// We also know that they cannot be referenced later, so we avoid
|
||||
// putting them into the map.
|
||||
.breakpoint => {
|
||||
try sema.zirBreakpoint(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.fence => {
|
||||
try sema.zirFence(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.dbg_stmt => {
|
||||
try sema.zirDbgStmt(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.ensure_err_payload_void => {
|
||||
try sema.zirEnsureErrPayloadVoid(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.ensure_result_non_error => {
|
||||
try sema.zirEnsureResultNonError(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.ensure_result_used => {
|
||||
try sema.zirEnsureResultUsed(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.set_eval_branch_quota => {
|
||||
try sema.zirSetEvalBranchQuota(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.store => {
|
||||
try sema.zirStore(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.store_node => {
|
||||
try sema.zirStoreNode(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.store_to_block_ptr => {
|
||||
try sema.zirStoreToBlockPtr(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.store_to_inferred_ptr => {
|
||||
try sema.zirStoreToInferredPtr(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.resolve_inferred_alloc => {
|
||||
try sema.zirResolveInferredAlloc(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.validate_struct_init_ptr => {
|
||||
try sema.zirValidateStructInitPtr(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.validate_array_init_ptr => {
|
||||
try sema.zirValidateArrayInitPtr(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.@"export" => {
|
||||
try sema.zirExport(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.set_align_stack => {
|
||||
try sema.zirSetAlignStack(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.set_cold => {
|
||||
try sema.zirSetCold(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.set_float_mode => {
|
||||
try sema.zirSetFloatMode(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.set_runtime_safety => {
|
||||
try sema.zirSetRuntimeSafety(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
//// Instructions that we know can *never* be noreturn based solely on
|
||||
//// their tag. We avoid needlessly checking if they are noreturn and
|
||||
//// continue the loop.
|
||||
//// We also know that they cannot be referenced later, so we avoid
|
||||
//// putting them into the map.
|
||||
//.breakpoint => {
|
||||
// try sema.zirBreakpoint(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.fence => {
|
||||
// try sema.zirFence(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.dbg_stmt => {
|
||||
// try sema.zirDbgStmt(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.ensure_err_payload_void => {
|
||||
// try sema.zirEnsureErrPayloadVoid(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.ensure_result_non_error => {
|
||||
// try sema.zirEnsureResultNonError(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.ensure_result_used => {
|
||||
// try sema.zirEnsureResultUsed(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.set_eval_branch_quota => {
|
||||
// try sema.zirSetEvalBranchQuota(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.store => {
|
||||
// try sema.zirStore(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.store_node => {
|
||||
// try sema.zirStoreNode(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.store_to_block_ptr => {
|
||||
// try sema.zirStoreToBlockPtr(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.store_to_inferred_ptr => {
|
||||
// try sema.zirStoreToInferredPtr(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.resolve_inferred_alloc => {
|
||||
// try sema.zirResolveInferredAlloc(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.validate_struct_init_ptr => {
|
||||
// try sema.zirValidateStructInitPtr(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.validate_array_init_ptr => {
|
||||
// try sema.zirValidateArrayInitPtr(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.@"export" => {
|
||||
// try sema.zirExport(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.set_align_stack => {
|
||||
// try sema.zirSetAlignStack(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.set_cold => {
|
||||
// try sema.zirSetCold(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.set_float_mode => {
|
||||
// try sema.zirSetFloatMode(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
//.set_runtime_safety => {
|
||||
// try sema.zirSetRuntimeSafety(block, inst);
|
||||
// i += 1;
|
||||
// continue;
|
||||
//},
|
||||
|
||||
// Special case instructions to handle comptime control flow.
|
||||
.repeat_inline => {
|
||||
@ -505,37 +505,38 @@ pub fn analyzeBody(
|
||||
i = 0;
|
||||
continue;
|
||||
},
|
||||
.block_inline => blk: {
|
||||
// Directly analyze the block body without introducing a new block.
|
||||
const inst_data = datas[inst].pl_node;
|
||||
const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
|
||||
const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
|
||||
const break_inst = try sema.analyzeBody(block, inline_body);
|
||||
const break_data = datas[break_inst].@"break";
|
||||
if (inst == break_data.block_inst) {
|
||||
break :blk try sema.resolveInst(break_data.operand);
|
||||
} else {
|
||||
return break_inst;
|
||||
}
|
||||
},
|
||||
.condbr_inline => blk: {
|
||||
const inst_data = datas[inst].pl_node;
|
||||
const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
|
||||
const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
|
||||
const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
|
||||
const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
|
||||
const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
|
||||
const inline_body = if (cond.val.toBool()) then_body else else_body;
|
||||
const break_inst = try sema.analyzeBody(block, inline_body);
|
||||
const break_data = datas[break_inst].@"break";
|
||||
if (inst == break_data.block_inst) {
|
||||
break :blk try sema.resolveInst(break_data.operand);
|
||||
} else {
|
||||
return break_inst;
|
||||
}
|
||||
},
|
||||
//.block_inline => blk: {
|
||||
// // Directly analyze the block body without introducing a new block.
|
||||
// const inst_data = datas[inst].pl_node;
|
||||
// const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
|
||||
// const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
|
||||
// const break_inst = try sema.analyzeBody(block, inline_body);
|
||||
// const break_data = datas[break_inst].@"break";
|
||||
// if (inst == break_data.block_inst) {
|
||||
// break :blk try sema.resolveInst(break_data.operand);
|
||||
// } else {
|
||||
// return break_inst;
|
||||
// }
|
||||
//},
|
||||
//.condbr_inline => blk: {
|
||||
// const inst_data = datas[inst].pl_node;
|
||||
// const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
|
||||
// const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
|
||||
// const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
|
||||
// const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
|
||||
// const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
|
||||
// const inline_body = if (cond.val.toBool()) then_body else else_body;
|
||||
// const break_inst = try sema.analyzeBody(block, inline_body);
|
||||
// const break_data = datas[break_inst].@"break";
|
||||
// if (inst == break_data.block_inst) {
|
||||
// break :blk try sema.resolveInst(break_data.operand);
|
||||
// } else {
|
||||
// return break_inst;
|
||||
// }
|
||||
//},
|
||||
else => @panic("TODO remove else prong"),
|
||||
};
|
||||
if (air_inst.ty.isNoReturn())
|
||||
if (sema.getAirType(air_inst).isNoReturn())
|
||||
return always_noreturn;
|
||||
try map.put(sema.gpa, inst, air_inst);
|
||||
i += 1;
|
||||
@ -577,18 +578,13 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO when we rework AIR memory layout, this function will no longer have a possible error.
|
||||
pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!Air.Inst.Index {
|
||||
pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) Air.Inst.Ref {
|
||||
var i: usize = @enumToInt(zir_ref);
|
||||
|
||||
// First section of indexes correspond to a set number of constant values.
|
||||
if (i < Zir.Inst.Ref.typed_value_map.len) {
|
||||
// TODO when we rework AIR memory layout, this function can be as simple as:
|
||||
// if (zir_ref < Zir.const_inst_list.len + sema.param_count)
|
||||
// return zir_ref;
|
||||
// Until then we allocate memory for a new, mutable `ir.Inst` to match what
|
||||
// AIR expects.
|
||||
return sema.mod.constInst(sema.arena, .unneeded, Zir.Inst.Ref.typed_value_map[i]);
|
||||
// We intentionally map the same indexes to the same values between ZIR and AIR.
|
||||
return zir_ref;
|
||||
}
|
||||
i -= Zir.Inst.Ref.typed_value_map.len;
|
||||
|
||||
@ -1256,7 +1252,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
|
||||
return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
|
||||
}
|
||||
|
||||
fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air.Inst.Index {
|
||||
fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air.Inst.Ref {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
|
||||
const arg_name = inst_data.get(sema.code);
|
||||
const arg_index = sema.next_arg_index;
|
||||
@ -1271,7 +1267,7 @@ fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air
|
||||
|
||||
// Set the name of the Air.Arg instruction for use by codegen debug info.
|
||||
const air_arg = sema.param_inst_list[arg_index];
|
||||
sema.air.instructions.items(.data)[air_arg].ty_str.str = inst_data.start;
|
||||
sema.air_instructions.items(.data)[air_arg].ty_str.str = inst_data.start;
|
||||
return air_arg;
|
||||
}
|
||||
|
||||
@ -7942,6 +7938,18 @@ fn enumFieldSrcLoc(
|
||||
} else unreachable;
|
||||
}
|
||||
|
||||
fn getAirType(sema: *Sema, air_ref: Air.Inst.Ref) Type {
|
||||
var i: usize = @enumToInt(air_ref);
|
||||
if (i < Air.Inst.Ref.typed_value_map.len) {
|
||||
return Air.Inst.Ref.typed_value_map[i].val.toType(undefined) catch unreachable;
|
||||
}
|
||||
i -= Air.Inst.Ref.typed_value_map.len;
|
||||
const air_tags = sema.air_instructions.items(.tag);
|
||||
const air_datas = sema.air_instructions.items(.data);
|
||||
assert(air_tags[i] == .const_ty);
|
||||
return air_datas[i].ty;
|
||||
}
|
||||
|
||||
pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
|
||||
switch (ty.tag()) {
|
||||
.u8 => return .u8_type,
|
||||
|
||||
@ -282,7 +282,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
|
||||
return struct {
|
||||
gpa: *Allocator,
|
||||
air: *const Air,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
bin_file: *link.File,
|
||||
target: *const std.Target,
|
||||
mod_fn: *const Module.Fn,
|
||||
@ -468,8 +469,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
|
||||
var function = Self{
|
||||
.gpa = bin_file.allocator,
|
||||
.air = &air,
|
||||
.liveness = &liveness,
|
||||
.air = air,
|
||||
.liveness = liveness,
|
||||
.target = &bin_file.options.target,
|
||||
.bin_file = bin_file,
|
||||
.mod_fn = module_fn,
|
||||
|
||||
@ -6,7 +6,6 @@ const log = std.log.scoped(.c);
|
||||
const link = @import("../link.zig");
|
||||
const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const Air = @import("../Air.zig");
|
||||
const Value = @import("../value.zig").Value;
|
||||
const Type = @import("../type.zig").Type;
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
@ -14,6 +13,8 @@ const C = link.File.C;
|
||||
const Decl = Module.Decl;
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
const Mutability = enum { Const, Mut };
|
||||
|
||||
@ -37,7 +38,7 @@ const BlockData = struct {
|
||||
result: CValue,
|
||||
};
|
||||
|
||||
pub const CValueMap = std.AutoHashMap(*Inst, CValue);
|
||||
pub const CValueMap = std.AutoHashMap(Air.Inst.Index, CValue);
|
||||
pub const TypedefMap = std.ArrayHashMap(
|
||||
Type,
|
||||
struct { name: []const u8, rendered: []u8 },
|
||||
@ -93,6 +94,8 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
|
||||
/// It is not available when generating .h file.
|
||||
pub const Object = struct {
|
||||
dg: DeclGen,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
gpa: *mem.Allocator,
|
||||
code: std.ArrayList(u8),
|
||||
value_map: CValueMap,
|
||||
@ -102,7 +105,7 @@ pub const Object = struct {
|
||||
next_block_index: usize = 0,
|
||||
indent_writer: IndentWriter(std.ArrayList(u8).Writer),
|
||||
|
||||
fn resolveInst(o: *Object, inst: *Inst) !CValue {
|
||||
fn resolveInst(o: *Object, inst: Air.Inst.Index) !CValue {
|
||||
if (inst.value()) |_| {
|
||||
return CValue{ .constant = inst };
|
||||
}
|
||||
|
||||
@ -277,6 +277,9 @@ pub const Object = struct {
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
var dg: DeclGen = .{
|
||||
.object = self,
|
||||
.module = module,
|
||||
|
||||
@ -159,7 +159,8 @@ pub const DeclGen = struct {
|
||||
/// The SPIR-V module code should be put in.
|
||||
spv: *SPIRVModule,
|
||||
|
||||
air: *const Air,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
|
||||
/// An array of function argument result-ids. Each index corresponds with the
|
||||
/// function argument of the same index.
|
||||
|
||||
@ -9,13 +9,14 @@ const wasm = std.wasm;
|
||||
|
||||
const Module = @import("../Module.zig");
|
||||
const Decl = Module.Decl;
|
||||
const Air = @import("../Air.zig");
|
||||
const Type = @import("../type.zig").Type;
|
||||
const Value = @import("../value.zig").Value;
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const link = @import("../link.zig");
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
/// Wasm Value, created when generating an instruction
|
||||
const WValue = union(enum) {
|
||||
@ -491,6 +492,8 @@ pub const Context = struct {
|
||||
/// Reference to the function declaration the code
|
||||
/// section belongs to
|
||||
decl: *Decl,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
gpa: *mem.Allocator,
|
||||
/// Table to save `WValue`'s generated by an `Inst`
|
||||
values: ValueTable,
|
||||
@ -710,52 +713,53 @@ pub const Context = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result {
|
||||
try self.genFunctype();
|
||||
|
||||
// Write instructions
|
||||
// TODO: check for and handle death of instructions
|
||||
|
||||
// Reserve space to write the size after generating the code as well as space for locals count
|
||||
try self.code.resize(10);
|
||||
|
||||
try self.genBody(func.body);
|
||||
|
||||
// finally, write our local types at the 'offset' position
|
||||
{
|
||||
leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
|
||||
|
||||
// offset into 'code' section where we will put our locals types
|
||||
var local_offset: usize = 10;
|
||||
|
||||
// emit the actual locals amount
|
||||
for (self.locals.items) |local| {
|
||||
var buf: [6]u8 = undefined;
|
||||
leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
|
||||
buf[5] = local;
|
||||
try self.code.insertSlice(local_offset, &buf);
|
||||
local_offset += 6;
|
||||
}
|
||||
}
|
||||
|
||||
const writer = self.code.writer();
|
||||
try writer.writeByte(wasm.opcode(.end));
|
||||
|
||||
// Fill in the size of the generated code to the reserved space at the
|
||||
// beginning of the buffer.
|
||||
const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5;
|
||||
leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
|
||||
|
||||
// codegen data has been appended to `code`
|
||||
return Result.appended;
|
||||
}
|
||||
|
||||
/// Generates the wasm bytecode for the function declaration belonging to `Context`
|
||||
pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Fn => {
|
||||
try self.genFunctype();
|
||||
|
||||
// Write instructions
|
||||
// TODO: check for and handle death of instructions
|
||||
const mod_fn = blk: {
|
||||
if (typed_value.val.castTag(.function)) |func| break :blk func.data;
|
||||
if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions
|
||||
unreachable;
|
||||
};
|
||||
|
||||
// Reserve space to write the size after generating the code as well as space for locals count
|
||||
try self.code.resize(10);
|
||||
|
||||
try self.genBody(mod_fn.body);
|
||||
|
||||
// finally, write our local types at the 'offset' position
|
||||
{
|
||||
leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
|
||||
|
||||
// offset into 'code' section where we will put our locals types
|
||||
var local_offset: usize = 10;
|
||||
|
||||
// emit the actual locals amount
|
||||
for (self.locals.items) |local| {
|
||||
var buf: [6]u8 = undefined;
|
||||
leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
|
||||
buf[5] = local;
|
||||
try self.code.insertSlice(local_offset, &buf);
|
||||
local_offset += 6;
|
||||
}
|
||||
}
|
||||
|
||||
const writer = self.code.writer();
|
||||
try writer.writeByte(wasm.opcode(.end));
|
||||
|
||||
// Fill in the size of the generated code to the reserved space at the
|
||||
// beginning of the buffer.
|
||||
const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5;
|
||||
leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
|
||||
|
||||
// codegen data has been appended to `code`
|
||||
return Result.appended;
|
||||
if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions
|
||||
return self.fail("TODO implement wasm codegen for function pointers", .{});
|
||||
},
|
||||
.Array => {
|
||||
if (typed_value.val.castTag(.bytes)) |payload| {
|
||||
|
||||
34
src/link.zig
34
src/link.zig
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const mem = std.mem;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const fs = std.fs;
|
||||
@ -14,8 +15,10 @@ const Cache = @import("Cache.zig");
|
||||
const build_options = @import("build_options");
|
||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
const wasi_libc = @import("wasi_libc.zig");
|
||||
const Air = @import("Air.zig");
|
||||
const Liveness = @import("Liveness.zig");
|
||||
|
||||
pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
|
||||
pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;
|
||||
|
||||
pub const Emit = struct {
|
||||
/// Where the output will go.
|
||||
@ -313,13 +316,34 @@ pub const File = struct {
|
||||
log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty });
|
||||
assert(decl.has_tv);
|
||||
switch (base.tag) {
|
||||
.coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl),
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
|
||||
// zig fmt: off
|
||||
.coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl),
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl),
|
||||
// zig fmt: on
|
||||
}
|
||||
}
|
||||
|
||||
/// May be called before or after updateDeclExports but must be called
|
||||
/// after allocateDeclIndexes for any given Decl.
|
||||
pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
|
||||
log.debug("updateFunc {*} ({s}), type={}", .{
|
||||
func.owner_decl, func.owner_decl.name, func.owner_decl.ty,
|
||||
});
|
||||
switch (base.tag) {
|
||||
// zig fmt: off
|
||||
.coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func, air, liveness),
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func, air, liveness),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func, air, liveness),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness),
|
||||
// zig fmt: on
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,14 +2,17 @@ const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const fs = std.fs;
|
||||
|
||||
const C = @This();
|
||||
const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const fs = std.fs;
|
||||
const codegen = @import("../codegen/c.zig");
|
||||
const link = @import("../link.zig");
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const C = @This();
|
||||
const Type = @import("../type.zig").Type;
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
pub const base_tag: link.File.Tag = .c;
|
||||
pub const zig_h = @embedFile("C/zig.h");
|
||||
@ -95,10 +98,7 @@ fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void {
|
||||
decl.fn_link.c.typedefs.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air, liveness: Liveness) !void {
|
||||
// Keep track of all decls so we can iterate over them on flush().
|
||||
_ = try self.decl_table.getOrPut(self.base.allocator, decl);
|
||||
|
||||
@ -126,6 +126,8 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
|
||||
.code = code.toManaged(module.gpa),
|
||||
.value_map = codegen.CValueMap.init(module.gpa),
|
||||
.indent_writer = undefined, // set later so we can get a pointer to object.code
|
||||
.air = air,
|
||||
.liveness = liveness,
|
||||
};
|
||||
object.indent_writer = .{ .underlying_writer = object.code.writer() };
|
||||
defer {
|
||||
@ -157,6 +159,20 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
|
||||
code.shrinkAndFree(module.gpa, code.items.len);
|
||||
}
|
||||
|
||||
pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
return self.finishUpdateDecl(module, func.owner_decl, air, liveness);
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
return self.finishUpdateDecl(module, decl, undefined, undefined);
|
||||
}
|
||||
|
||||
pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void {
|
||||
// The C backend does not have the ability to fix line numbers without re-generating
|
||||
// the entire Decl.
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
const Coff = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const log = std.log.scoped(.link);
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
@ -17,6 +18,8 @@ const build_options = @import("build_options");
|
||||
const Cache = @import("../Cache.zig");
|
||||
const mingw = @import("../mingw.zig");
|
||||
const llvm_backend = @import("../codegen/llvm.zig");
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
const allocation_padding = 4 / 3;
|
||||
const minimum_text_block_size = 64 * allocation_padding;
|
||||
@ -653,19 +656,58 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
|
||||
// TODO COFF/PE debug information
|
||||
// TODO Implement exports
|
||||
pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
|
||||
}
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
if (build_options.have_llvm)
|
||||
if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl);
|
||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
const res = try codegen.generateFunction(
|
||||
&self.base,
|
||||
decl.srcLoc(),
|
||||
func,
|
||||
air,
|
||||
liveness,
|
||||
&code_buffer,
|
||||
.none,
|
||||
);
|
||||
const code = switch (res) {
|
||||
.externally_managed => |x| x,
|
||||
.appended => code_buffer.items,
|
||||
.fail => |em| {
|
||||
decl.analysis = .codegen_failure;
|
||||
try module.failed_decls.put(module.gpa, decl, em);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
return self.finishUpdateDecl(module, func.owner_decl, code);
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
|
||||
}
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
if (decl.val.tag() == .extern_fn) {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
}
|
||||
|
||||
// TODO COFF/PE debug information
|
||||
// TODO Implement exports
|
||||
|
||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
@ -683,6 +725,10 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
|
||||
},
|
||||
};
|
||||
|
||||
return self.finishUpdateDecl(module, func.owner_decl, code);
|
||||
}
|
||||
|
||||
fn finishUpdateDecl(self: *Coff, decl: *Module.Decl, code: []const u8) !void {
|
||||
const required_alignment = decl.ty.abiAlignment(self.base.options.target);
|
||||
const curr_size = decl.link.coff.size;
|
||||
if (curr_size != 0) {
|
||||
|
||||
558
src/link/Elf.zig
558
src/link/Elf.zig
@ -1,6 +1,7 @@
|
||||
const Elf = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const mem = std.mem;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -10,7 +11,6 @@ const log = std.log.scoped(.link);
|
||||
const DW = std.dwarf;
|
||||
const leb128 = std.leb;
|
||||
|
||||
const Air = @import("../Air.zig");
|
||||
const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const codegen = @import("../codegen.zig");
|
||||
@ -26,6 +26,8 @@ const glibc = @import("../glibc.zig");
|
||||
const musl = @import("../musl.zig");
|
||||
const Cache = @import("../Cache.zig");
|
||||
const llvm_backend = @import("../codegen/llvm.zig");
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
const default_entry_addr = 0x8000000;
|
||||
|
||||
@ -2155,138 +2157,17 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
if (build_options.have_llvm)
|
||||
if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl);
|
||||
|
||||
if (decl.val.tag() == .extern_fn) {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
}
|
||||
if (decl.val.castTag(.variable)) |payload| {
|
||||
const variable = payload.data;
|
||||
if (variable.is_extern) {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
}
|
||||
fn deinitRelocs(gpa: *Allocator, table: *File.DbgInfoTypeRelocsTable) void {
|
||||
var it = table.valueIterator();
|
||||
while (it.next()) |value| {
|
||||
value.relocs.deinit(gpa);
|
||||
}
|
||||
table.deinit(gpa);
|
||||
}
|
||||
|
||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer dbg_line_buffer.deinit();
|
||||
|
||||
var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer dbg_info_buffer.deinit();
|
||||
|
||||
var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
|
||||
defer {
|
||||
var it = dbg_info_type_relocs.valueIterator();
|
||||
while (it.next()) |value| {
|
||||
value.relocs.deinit(self.base.allocator);
|
||||
}
|
||||
dbg_info_type_relocs.deinit(self.base.allocator);
|
||||
}
|
||||
|
||||
const is_fn: bool = switch (decl.ty.zigTypeTag()) {
|
||||
.Fn => true,
|
||||
else => false,
|
||||
};
|
||||
if (is_fn) {
|
||||
// For functions we need to add a prologue to the debug line program.
|
||||
try dbg_line_buffer.ensureCapacity(26);
|
||||
|
||||
const func = decl.val.castTag(.function).?.data;
|
||||
const line_off = @intCast(u28, decl.src_line + func.lbrace_line);
|
||||
|
||||
const ptr_width_bytes = self.ptrWidthBytes();
|
||||
dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
|
||||
DW.LNS_extended_op,
|
||||
ptr_width_bytes + 1,
|
||||
DW.LNE_set_address,
|
||||
});
|
||||
// This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
|
||||
assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
|
||||
dbg_line_buffer.items.len += ptr_width_bytes;
|
||||
|
||||
dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line);
|
||||
// This is the "relocatable" relative line offset from the previous function's end curly
|
||||
// to this function's begin curly.
|
||||
assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
|
||||
// Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
|
||||
leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);
|
||||
|
||||
dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file);
|
||||
assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
|
||||
// Once we support more than one source file, this will have the ability to be more
|
||||
// than one possible value.
|
||||
const file_index = 1;
|
||||
leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
|
||||
|
||||
// Emit a line for the begin curly with prologue_end=false. The codegen will
|
||||
// do the work of setting prologue_end=true and epilogue_begin=true.
|
||||
dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
|
||||
|
||||
// .debug_info subprogram
|
||||
const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1];
|
||||
try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
|
||||
|
||||
const fn_ret_type = decl.ty.fnReturnType();
|
||||
const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
|
||||
if (fn_ret_has_bits) {
|
||||
dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
|
||||
} else {
|
||||
dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
|
||||
}
|
||||
// These get overwritten after generating the machine code. These values are
|
||||
// "relocations" and have to be in this fixed place so that functions can be
|
||||
// moved in virtual address space.
|
||||
assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
|
||||
dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
|
||||
assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
|
||||
dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
|
||||
if (fn_ret_has_bits) {
|
||||
const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{
|
||||
.off = undefined,
|
||||
.relocs = .{},
|
||||
};
|
||||
}
|
||||
try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
|
||||
dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
|
||||
}
|
||||
dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
|
||||
} else {
|
||||
// TODO implement .debug_info for global variables
|
||||
}
|
||||
const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
|
||||
const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
|
||||
.ty = decl.ty,
|
||||
.val = decl_val,
|
||||
}, &code_buffer, .{
|
||||
.dwarf = .{
|
||||
.dbg_line = &dbg_line_buffer,
|
||||
.dbg_info = &dbg_info_buffer,
|
||||
.dbg_info_type_relocs = &dbg_info_type_relocs,
|
||||
},
|
||||
});
|
||||
const code = switch (res) {
|
||||
.externally_managed => |x| x,
|
||||
.appended => code_buffer.items,
|
||||
.fail => |em| {
|
||||
decl.analysis = .codegen_failure;
|
||||
try module.failed_decls.put(module.gpa, decl, em);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
|
||||
const required_alignment = decl.ty.abiAlignment(self.base.options.target);
|
||||
|
||||
const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT;
|
||||
|
||||
assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
|
||||
const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
|
||||
if (local_sym.st_size != 0) {
|
||||
@ -2338,128 +2219,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||
const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
|
||||
try self.base.file.?.pwriteAll(code, file_offset);
|
||||
|
||||
const target_endian = self.base.options.target.cpu.arch.endian();
|
||||
|
||||
const text_block = &decl.link.elf;
|
||||
|
||||
// If the Decl is a function, we need to update the .debug_line program.
|
||||
if (is_fn) {
|
||||
// Perform the relocations based on vaddr.
|
||||
switch (self.ptr_width) {
|
||||
.p32 => {
|
||||
{
|
||||
const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
|
||||
mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
|
||||
}
|
||||
{
|
||||
const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
|
||||
mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
|
||||
}
|
||||
},
|
||||
.p64 => {
|
||||
{
|
||||
const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
|
||||
mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
|
||||
}
|
||||
{
|
||||
const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
|
||||
mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
|
||||
}
|
||||
},
|
||||
}
|
||||
{
|
||||
const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
|
||||
mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
|
||||
}
|
||||
|
||||
try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
|
||||
|
||||
// Now we have the full contents and may allocate a region to store it.
|
||||
|
||||
// This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for
|
||||
// `TextBlock` and the .debug_info. If you are editing this logic, you
|
||||
// probably need to edit that logic too.
|
||||
|
||||
const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
|
||||
const src_fn = &decl.fn_link.elf;
|
||||
src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
|
||||
if (self.dbg_line_fn_last) |last| not_first: {
|
||||
if (src_fn.next) |next| {
|
||||
// Update existing function - non-last item.
|
||||
if (src_fn.off + src_fn.len + min_nop_size > next.off) {
|
||||
// It grew too big, so we move it to a new location.
|
||||
if (src_fn.prev) |prev| {
|
||||
self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
prev.next = src_fn.next;
|
||||
}
|
||||
assert(src_fn.prev != next);
|
||||
next.prev = src_fn.prev;
|
||||
src_fn.next = null;
|
||||
// Populate where it used to be with NOPs.
|
||||
const file_pos = debug_line_sect.sh_offset + src_fn.off;
|
||||
try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
|
||||
// TODO Look at the free list before appending at the end.
|
||||
src_fn.prev = last;
|
||||
last.next = src_fn;
|
||||
self.dbg_line_fn_last = src_fn;
|
||||
|
||||
src_fn.off = last.off + padToIdeal(last.len);
|
||||
}
|
||||
} else if (src_fn.prev == null) {
|
||||
if (src_fn == last) {
|
||||
// Special case: there is only 1 function and it is being updated.
|
||||
// In this case there is nothing to do. The function's length has
|
||||
// already been updated, and the logic below takes care of
|
||||
// resizing the .debug_line section.
|
||||
break :not_first;
|
||||
}
|
||||
// Append new function.
|
||||
// TODO Look at the free list before appending at the end.
|
||||
src_fn.prev = last;
|
||||
last.next = src_fn;
|
||||
self.dbg_line_fn_last = src_fn;
|
||||
|
||||
src_fn.off = last.off + padToIdeal(last.len);
|
||||
}
|
||||
} else {
|
||||
// This is the first function of the Line Number Program.
|
||||
self.dbg_line_fn_first = src_fn;
|
||||
self.dbg_line_fn_last = src_fn;
|
||||
|
||||
src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes());
|
||||
}
|
||||
|
||||
const last_src_fn = self.dbg_line_fn_last.?;
|
||||
const needed_size = last_src_fn.off + last_src_fn.len;
|
||||
if (needed_size != debug_line_sect.sh_size) {
|
||||
if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) {
|
||||
const new_offset = self.findFreeSpace(needed_size, 1);
|
||||
const existing_size = last_src_fn.off;
|
||||
log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{
|
||||
existing_size,
|
||||
debug_line_sect.sh_offset,
|
||||
new_offset,
|
||||
});
|
||||
const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
|
||||
if (amt != existing_size) return error.InputOutput;
|
||||
debug_line_sect.sh_offset = new_offset;
|
||||
}
|
||||
debug_line_sect.sh_size = needed_size;
|
||||
self.shdr_table_dirty = true; // TODO look into making only the one section dirty
|
||||
self.debug_line_header_dirty = true;
|
||||
}
|
||||
const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
|
||||
const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
|
||||
|
||||
// We only have support for one compilation unit so far, so the offsets are directly
|
||||
// from the .debug_line section.
|
||||
const file_pos = debug_line_sect.sh_offset + src_fn.off;
|
||||
try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
|
||||
|
||||
// .debug_info - End the TAG_subprogram children.
|
||||
try dbg_info_buffer.append(0);
|
||||
}
|
||||
return local_sym;
|
||||
}
|
||||
|
||||
fn finishUpdateDecl(
|
||||
self: *Elf,
|
||||
module: *Module,
|
||||
decl: *Module.Decl,
|
||||
dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
|
||||
dbg_info_buffer: *std.ArrayList(u8),
|
||||
) !void {
|
||||
// Now we emit the .debug_info types of the Decl. These will count towards the size of
|
||||
// the buffer, so we have to do it before computing the offset, and we can't perform the actual
|
||||
// relocations yet.
|
||||
@ -2467,12 +2236,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||
var it = dbg_info_type_relocs.iterator();
|
||||
while (it.next()) |entry| {
|
||||
entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
|
||||
try self.addDbgInfoType(entry.key_ptr.*, &dbg_info_buffer);
|
||||
try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
const text_block = &decl.link.elf;
|
||||
try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len));
|
||||
|
||||
const target_endian = self.base.options.target.cpu.arch.endian();
|
||||
|
||||
{
|
||||
// Now that we have the offset assigned we can finally perform type relocations.
|
||||
var it = dbg_info_type_relocs.valueIterator();
|
||||
@ -2495,6 +2267,290 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||
return self.updateDeclExports(module, decl, decl_exports);
|
||||
}
|
||||
|
||||
pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .elf) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
|
||||
}
|
||||
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer dbg_line_buffer.deinit();
|
||||
|
||||
var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer dbg_info_buffer.deinit();
|
||||
|
||||
var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
|
||||
defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs);
|
||||
|
||||
// For functions we need to add a prologue to the debug line program.
|
||||
try dbg_line_buffer.ensureCapacity(26);
|
||||
|
||||
const decl = func.owner_decl;
|
||||
const line_off = @intCast(u28, decl.src_line + func.lbrace_line);
|
||||
|
||||
const ptr_width_bytes = self.ptrWidthBytes();
|
||||
dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
|
||||
DW.LNS_extended_op,
|
||||
ptr_width_bytes + 1,
|
||||
DW.LNE_set_address,
|
||||
});
|
||||
// This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
|
||||
assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
|
||||
dbg_line_buffer.items.len += ptr_width_bytes;
|
||||
|
||||
dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line);
|
||||
// This is the "relocatable" relative line offset from the previous function's end curly
|
||||
// to this function's begin curly.
|
||||
assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
|
||||
// Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
|
||||
leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);
|
||||
|
||||
dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file);
|
||||
assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
|
||||
// Once we support more than one source file, this will have the ability to be more
|
||||
// than one possible value.
|
||||
const file_index = 1;
|
||||
leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
|
||||
|
||||
// Emit a line for the begin curly with prologue_end=false. The codegen will
|
||||
// do the work of setting prologue_end=true and epilogue_begin=true.
|
||||
dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
|
||||
|
||||
// .debug_info subprogram
|
||||
const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1];
|
||||
try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
|
||||
|
||||
const fn_ret_type = decl.ty.fnReturnType();
|
||||
const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
|
||||
if (fn_ret_has_bits) {
|
||||
dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
|
||||
} else {
|
||||
dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
|
||||
}
|
||||
// These get overwritten after generating the machine code. These values are
|
||||
// "relocations" and have to be in this fixed place so that functions can be
|
||||
// moved in virtual address space.
|
||||
assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
|
||||
dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
|
||||
assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
|
||||
dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
|
||||
if (fn_ret_has_bits) {
|
||||
const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{
|
||||
.off = undefined,
|
||||
.relocs = .{},
|
||||
};
|
||||
}
|
||||
try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
|
||||
dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
|
||||
}
|
||||
dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
|
||||
|
||||
const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
|
||||
.dwarf = .{
|
||||
.dbg_line = &dbg_line_buffer,
|
||||
.dbg_info = &dbg_info_buffer,
|
||||
.dbg_info_type_relocs = &dbg_info_type_relocs,
|
||||
},
|
||||
});
|
||||
const code = switch (res) {
|
||||
.externally_managed => |x| x,
|
||||
.appended => code_buffer.items,
|
||||
.fail => |em| {
|
||||
decl.analysis = .codegen_failure;
|
||||
try module.failed_decls.put(module.gpa, decl, em);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC);
|
||||
|
||||
const target_endian = self.base.options.target.cpu.arch.endian();
|
||||
|
||||
// Since the Decl is a function, we need to update the .debug_line program.
|
||||
// Perform the relocations based on vaddr.
|
||||
switch (self.ptr_width) {
|
||||
.p32 => {
|
||||
{
|
||||
const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
|
||||
mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
|
||||
}
|
||||
{
|
||||
const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
|
||||
mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
|
||||
}
|
||||
},
|
||||
.p64 => {
|
||||
{
|
||||
const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
|
||||
mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
|
||||
}
|
||||
{
|
||||
const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
|
||||
mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
|
||||
}
|
||||
},
|
||||
}
|
||||
{
|
||||
const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
|
||||
mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
|
||||
}
|
||||
|
||||
try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
|
||||
|
||||
// Now we have the full contents and may allocate a region to store it.
|
||||
|
||||
// This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for
|
||||
// `TextBlock` and the .debug_info. If you are editing this logic, you
|
||||
// probably need to edit that logic too.
|
||||
|
||||
const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
|
||||
const src_fn = &decl.fn_link.elf;
|
||||
src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
|
||||
if (self.dbg_line_fn_last) |last| not_first: {
|
||||
if (src_fn.next) |next| {
|
||||
// Update existing function - non-last item.
|
||||
if (src_fn.off + src_fn.len + min_nop_size > next.off) {
|
||||
// It grew too big, so we move it to a new location.
|
||||
if (src_fn.prev) |prev| {
|
||||
self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
prev.next = src_fn.next;
|
||||
}
|
||||
assert(src_fn.prev != next);
|
||||
next.prev = src_fn.prev;
|
||||
src_fn.next = null;
|
||||
// Populate where it used to be with NOPs.
|
||||
const file_pos = debug_line_sect.sh_offset + src_fn.off;
|
||||
try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
|
||||
// TODO Look at the free list before appending at the end.
|
||||
src_fn.prev = last;
|
||||
last.next = src_fn;
|
||||
self.dbg_line_fn_last = src_fn;
|
||||
|
||||
src_fn.off = last.off + padToIdeal(last.len);
|
||||
}
|
||||
} else if (src_fn.prev == null) {
|
||||
if (src_fn == last) {
|
||||
// Special case: there is only 1 function and it is being updated.
|
||||
// In this case there is nothing to do. The function's length has
|
||||
// already been updated, and the logic below takes care of
|
||||
// resizing the .debug_line section.
|
||||
break :not_first;
|
||||
}
|
||||
// Append new function.
|
||||
// TODO Look at the free list before appending at the end.
|
||||
src_fn.prev = last;
|
||||
last.next = src_fn;
|
||||
self.dbg_line_fn_last = src_fn;
|
||||
|
||||
src_fn.off = last.off + padToIdeal(last.len);
|
||||
}
|
||||
} else {
|
||||
// This is the first function of the Line Number Program.
|
||||
self.dbg_line_fn_first = src_fn;
|
||||
self.dbg_line_fn_last = src_fn;
|
||||
|
||||
src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes());
|
||||
}
|
||||
|
||||
const last_src_fn = self.dbg_line_fn_last.?;
|
||||
const needed_size = last_src_fn.off + last_src_fn.len;
|
||||
if (needed_size != debug_line_sect.sh_size) {
|
||||
if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) {
|
||||
const new_offset = self.findFreeSpace(needed_size, 1);
|
||||
const existing_size = last_src_fn.off;
|
||||
log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{
|
||||
existing_size,
|
||||
debug_line_sect.sh_offset,
|
||||
new_offset,
|
||||
});
|
||||
const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
|
||||
if (amt != existing_size) return error.InputOutput;
|
||||
debug_line_sect.sh_offset = new_offset;
|
||||
}
|
||||
debug_line_sect.sh_size = needed_size;
|
||||
self.shdr_table_dirty = true; // TODO look into making only the one section dirty
|
||||
self.debug_line_header_dirty = true;
|
||||
}
|
||||
const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
|
||||
const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
|
||||
|
||||
// We only have support for one compilation unit so far, so the offsets are directly
|
||||
// from the .debug_line section.
|
||||
const file_pos = debug_line_sect.sh_offset + src_fn.off;
|
||||
try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
|
||||
|
||||
// .debug_info - End the TAG_subprogram children.
|
||||
try dbg_info_buffer.append(0);
|
||||
|
||||
return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer);
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .elf) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
|
||||
}
|
||||
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
if (decl.val.tag() == .extern_fn) {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
}
|
||||
if (decl.val.castTag(.variable)) |payload| {
|
||||
const variable = payload.data;
|
||||
if (variable.is_extern) {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
}
|
||||
}
|
||||
|
||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer dbg_info_buffer.deinit();
|
||||
|
||||
var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
|
||||
defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs);
|
||||
|
||||
// TODO implement .debug_info for global variables
|
||||
const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
|
||||
const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
|
||||
.ty = decl.ty,
|
||||
.val = decl_val,
|
||||
}, &code_buffer, .{
|
||||
.dwarf = .{
|
||||
.dbg_line = &dbg_line_buffer,
|
||||
.dbg_info = &dbg_info_buffer,
|
||||
.dbg_info_type_relocs = &dbg_info_type_relocs,
|
||||
},
|
||||
});
|
||||
const code = switch (res) {
|
||||
.externally_managed => |x| x,
|
||||
.appended => code_buffer.items,
|
||||
.fail => |em| {
|
||||
decl.analysis = .codegen_failure;
|
||||
try module.failed_decls.put(module.gpa, decl, em);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
_ = try self.updateDeclCode(decl, code, elf.STT_OBJECT);
|
||||
return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer);
|
||||
}
|
||||
|
||||
/// Asserts the type has codegen bits.
|
||||
fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
|
||||
switch (ty.zigTypeTag()) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
const MachO = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const fmt = std.fmt;
|
||||
@ -22,6 +23,8 @@ const link = @import("../link.zig");
|
||||
const File = link.File;
|
||||
const Cache = @import("../Cache.zig");
|
||||
const target_util = @import("../target.zig");
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
const DebugSymbols = @import("MachO/DebugSymbols.zig");
|
||||
const Trie = @import("MachO/Trie.zig");
|
||||
@ -1132,7 +1135,55 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .macho) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
|
||||
}
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const decl = func.owner_decl;
|
||||
|
||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
var debug_buffers = if (self.d_sym) |*ds| try ds.initDeclDebugBuffers(self.base.allocator, module, decl) else null;
|
||||
defer {
|
||||
if (debug_buffers) |*dbg| {
|
||||
dbg.dbg_line_buffer.deinit();
|
||||
dbg.dbg_info_buffer.deinit();
|
||||
var it = dbg.dbg_info_type_relocs.valueIterator();
|
||||
while (it.next()) |value| {
|
||||
value.relocs.deinit(self.base.allocator);
|
||||
}
|
||||
dbg.dbg_info_type_relocs.deinit(self.base.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
const res = if (debug_buffers) |*dbg|
|
||||
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
|
||||
.dwarf = .{
|
||||
.dbg_line = &dbg.dbg_line_buffer,
|
||||
.dbg_info = &dbg.dbg_info_buffer,
|
||||
.dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
|
||||
},
|
||||
})
|
||||
else
|
||||
try codegen.generateSymbol(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
|
||||
|
||||
return self.finishUpdateDecl(module, decl, res);
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .macho) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
|
||||
}
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -1173,6 +1224,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
|
||||
.val = decl.val,
|
||||
}, &code_buffer, .none);
|
||||
|
||||
return self.finishUpdateDecl(module, decl, res);
|
||||
}
|
||||
|
||||
fn finishUpdateDecl(self: *MachO, module: *Module, decl: *Module.Decl, res: codegen.Result) !void {
|
||||
const code = switch (res) {
|
||||
.externally_managed => |x| x,
|
||||
.appended => code_buffer.items,
|
||||
|
||||
@ -2,18 +2,21 @@
|
||||
//! would be to add incremental linking in a similar way as ELF does.
|
||||
|
||||
const Plan9 = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const link = @import("../link.zig");
|
||||
const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const aout = @import("Plan9/aout.zig");
|
||||
const codegen = @import("../codegen.zig");
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const mem = std.mem;
|
||||
const File = link.File;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const build_options = @import("build_options");
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const mem = std.mem;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const log = std.log.scoped(.link);
|
||||
const assert = std.debug.assert;
|
||||
|
||||
@ -120,6 +123,19 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .plan9) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
_ = module;
|
||||
// Keep track of all decls so we can iterate over them on flush().
|
||||
_ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
|
||||
|
||||
_ = air;
|
||||
_ = liveness;
|
||||
@panic("TODO Plan9 needs to keep track of Air and Liveness so it can use them later");
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {
|
||||
_ = module;
|
||||
_ = try self.decl_table.getOrPut(self.base.allocator, decl);
|
||||
@ -138,6 +154,9 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .plan9) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
_ = comp;
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
@ -199,7 +218,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
|
||||
}
|
||||
}
|
||||
if (std.mem.eql(u8, exp.options.name, "_start")) {
|
||||
std.debug.assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry
|
||||
assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry
|
||||
self.entry_decl = decl;
|
||||
}
|
||||
if (exp.link.plan9) |i| {
|
||||
|
||||
@ -36,6 +36,8 @@ const ResultId = codegen.ResultId;
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const build_options = @import("build_options");
|
||||
const spec = @import("../codegen/spirv/spec.zig");
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
// TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl?
|
||||
pub const FnData = struct {
|
||||
@ -101,7 +103,23 @@ pub fn deinit(self: *SpirV) void {
|
||||
self.decl_table.deinit(self.base.allocator);
|
||||
}
|
||||
|
||||
pub fn updateFunc(self: *SpirV, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
|
||||
if (build_options.skip_non_native) {
|
||||
@panic("Attempted to compile for architecture that was disabled by build configuration");
|
||||
}
|
||||
_ = module;
|
||||
// Keep track of all decls so we can iterate over them on flush().
|
||||
_ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
|
||||
|
||||
_ = air;
|
||||
_ = liveness;
|
||||
@panic("TODO SPIR-V needs to keep track of Air and Liveness so it can use them later");
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void {
|
||||
if (build_options.skip_non_native) {
|
||||
@panic("Attempted to compile for architecture that was disabled by build configuration");
|
||||
}
|
||||
_ = module;
|
||||
// Keep track of all decls so we can iterate over them on flush().
|
||||
_ = try self.decl_table.getOrPut(self.base.allocator, decl);
|
||||
@ -132,13 +150,13 @@ pub fn flush(self: *SpirV, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
if (build_options.skip_non_native) {
|
||||
@panic("Attempted to compile for architecture that was disabled by build configuration");
|
||||
}
|
||||
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const module = self.base.options.module.?;
|
||||
const target = comp.getTarget();
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
const Wasm = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const mem = std.mem;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
@ -18,6 +19,8 @@ const build_options = @import("build_options");
|
||||
const wasi_libc = @import("../wasi_libc.zig");
|
||||
const Cache = @import("../Cache.zig");
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
|
||||
pub const base_tag = link.File.Tag.wasm;
|
||||
|
||||
@ -186,11 +189,60 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .wasm) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
|
||||
}
|
||||
const decl = func.owner_decl;
|
||||
assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
|
||||
|
||||
const fn_data = &decl.fn_link.wasm;
|
||||
fn_data.functype.items.len = 0;
|
||||
fn_data.code.items.len = 0;
|
||||
fn_data.idx_refs.items.len = 0;
|
||||
|
||||
var context = codegen.Context{
|
||||
.gpa = self.base.allocator,
|
||||
.air = air,
|
||||
.liveness = liveness,
|
||||
.values = .{},
|
||||
.code = fn_data.code.toManaged(self.base.allocator),
|
||||
.func_type_data = fn_data.functype.toManaged(self.base.allocator),
|
||||
.decl = decl,
|
||||
.err_msg = undefined,
|
||||
.locals = .{},
|
||||
.target = self.base.options.target,
|
||||
.global_error_set = self.base.options.module.?.global_error_set,
|
||||
};
|
||||
defer context.deinit();
|
||||
|
||||
// generate the 'code' section for the function declaration
|
||||
const result = context.genFunc(func) catch |err| switch (err) {
|
||||
error.CodegenFail => {
|
||||
decl.analysis = .codegen_failure;
|
||||
try module.failed_decls.put(module.gpa, decl, context.err_msg);
|
||||
return;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
return self.finishUpdateDecl(decl, result);
|
||||
}
|
||||
|
||||
// Generate code for the Decl, storing it in memory to be later written to
|
||||
// the file on flush().
|
||||
pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
|
||||
std.debug.assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
|
||||
if (build_options.skip_non_native and builtin.object_format != .wasm) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (build_options.have_llvm) {
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
|
||||
}
|
||||
assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
|
||||
|
||||
// TODO don't use this for non-functions
|
||||
const fn_data = &decl.fn_link.wasm;
|
||||
fn_data.functype.items.len = 0;
|
||||
fn_data.code.items.len = 0;
|
||||
@ -218,7 +270,10 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
return self.finishUpdateDecl(decl, result);
|
||||
}
|
||||
|
||||
fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result) !void {
|
||||
const code: []const u8 = switch (result) {
|
||||
.appended => @as([]const u8, context.code.items),
|
||||
.externally_managed => |payload| payload,
|
||||
@ -521,7 +576,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
|
||||
var data_offset = offset_table_size;
|
||||
while (cur) |cur_block| : (cur = cur_block.next) {
|
||||
if (cur_block.size == 0) continue;
|
||||
std.debug.assert(cur_block.init);
|
||||
assert(cur_block.init);
|
||||
|
||||
const offset = (cur_block.offset_index) * ptr_width;
|
||||
var buf: [4]u8 = undefined;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user