| author | |
| committer | |
| log | bffa14860078fe466e9f005dfc56869e195281b5 |
| tree | 43e22f8708b784ea5d1f5f2e7415761ff56014c4 |
| parent | e521879e4730fd85a92081c0040db7dc5daad8a3 |
5 files changed, 161 insertions(+), 106 deletions(-)
src/Zcu.zig+11| ... | @@ -4120,3 +4120,14 @@ pub fn codegenFailTypeMsg(zcu: *Zcu, ty_index: InternPool.Index, msg: *ErrorMsg) | ... | @@ -4120,3 +4120,14 @@ pub fn codegenFailTypeMsg(zcu: *Zcu, ty_index: InternPool.Index, msg: *ErrorMsg) |
| 4120 | zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg); | 4120 | zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg); |
| 4121 | return error.CodegenFail; | 4121 | return error.CodegenFail; |
| 4122 | } | 4122 | } |
| 4123 | |||
| 4124 | /// Check if nav is an alias to a function, in which case we want to lower the | ||
| 4125 | /// actual nav, rather than the alias itself. | ||
| 4126 | pub fn chaseNav(zcu: *const Zcu, nav: InternPool.Nav.Index) InternPool.Nav.Index { | ||
| 4127 | return switch (zcu.intern_pool.indexToKey(zcu.navValue(nav).toIntern())) { | ||
| 4128 | .func => |f| f.owner_nav, | ||
| 4129 | .variable => |variable| variable.owner_nav, | ||
| 4130 | .@"extern" => |@"extern"| @"extern".owner_nav, | ||
| 4131 | else => nav, | ||
| 4132 | }; | ||
| 4133 | } |
src/arch/wasm/CodeGen.zig+44-77| ... | @@ -146,19 +146,14 @@ const WValue = union(enum) { | ... | @@ -146,19 +146,14 @@ const WValue = union(enum) { |
| 146 | float32: f32, | 146 | float32: f32, |
| 147 | /// A constant 64bit float value | 147 | /// A constant 64bit float value |
| 148 | float64: f64, | 148 | float64: f64, |
| 149 | /// A value that represents a pointer to the data section. | 149 | nav_ref: struct { |
| 150 | memory: InternPool.Index, | 150 | nav_index: InternPool.Nav.Index, |
| 151 | /// A value that represents a parent pointer and an offset | 151 | offset: i32 = 0, |
| 152 | /// from that pointer. i.e. when slicing with constant values. | 152 | }, |
| 153 | memory_offset: struct { | 153 | uav_ref: struct { |
| 154 | pointer: InternPool.Index, | 154 | ip_index: InternPool.Index, |
| 155 | /// Offset will be set as addend when relocating | 155 | offset: i32 = 0, |
| 156 | offset: u32, | ||
| 157 | }, | 156 | }, |
| 158 | /// Represents a function pointer | ||
| 159 | /// In wasm function pointers are indexes into a function table, | ||
| 160 | /// rather than an address in the data section. | ||
| 161 | function_index: InternPool.Index, | ||
| 162 | /// Offset from the bottom of the virtual stack, with the offset | 157 | /// Offset from the bottom of the virtual stack, with the offset |
| 163 | /// pointing to where the value lives. | 158 | /// pointing to where the value lives. |
| 164 | stack_offset: struct { | 159 | stack_offset: struct { |
| ... | @@ -752,7 +747,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { | ... | @@ -752,7 +747,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { |
| 752 | const ty = func.typeOf(ref); | 747 | const ty = func.typeOf(ref); |
| 753 | if (!ty.hasRuntimeBitsIgnoreComptime(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) { | 748 | if (!ty.hasRuntimeBitsIgnoreComptime(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) { |
| 754 | gop.value_ptr.* = .none; | 749 | gop.value_ptr.* = .none; |
| 755 | return gop.value_ptr.*; | 750 | return .none; |
| 756 | } | 751 | } |
| 757 | 752 | ||
| 758 | // When we need to pass the value by reference (such as a struct), we will | 753 | // When we need to pass the value by reference (such as a struct), we will |
| ... | @@ -762,7 +757,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { | ... | @@ -762,7 +757,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { |
| 762 | // In the other cases, we will simply lower the constant to a value that fits | 757 | // In the other cases, we will simply lower the constant to a value that fits |
| 763 | // into a single local (such as a pointer, integer, bool, etc). | 758 | // into a single local (such as a pointer, integer, bool, etc). |
| 764 | const result: WValue = if (isByRef(ty, pt, func.target)) | 759 | const result: WValue = if (isByRef(ty, pt, func.target)) |
| 765 | .{ .memory = val.toIntern() } | 760 | .{ .uav_ref = .{ .ip_index = val.toIntern() } } |
| 766 | else | 761 | else |
| 767 | try func.lowerConstant(val, ty); | 762 | try func.lowerConstant(val, ty); |
| 768 | 763 | ||
| ... | @@ -956,6 +951,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 | ... | @@ -956,6 +951,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 |
| 956 | u32 => @field(extra, field.name), | 951 | u32 => @field(extra, field.name), |
| 957 | i32 => @bitCast(@field(extra, field.name)), | 952 | i32 => @bitCast(@field(extra, field.name)), |
| 958 | InternPool.Index => @intFromEnum(@field(extra, field.name)), | 953 | InternPool.Index => @intFromEnum(@field(extra, field.name)), |
| 954 | InternPool.Nav.Index => @intFromEnum(@field(extra, field.name)), | ||
| 959 | else => |field_type| @compileError("Unsupported field type " ++ @typeName(field_type)), | 955 | else => |field_type| @compileError("Unsupported field type " ++ @typeName(field_type)), |
| 960 | }); | 956 | }); |
| 961 | } | 957 | } |
| ... | @@ -1028,17 +1024,36 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void { | ... | @@ -1028,17 +1024,36 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void { |
| 1028 | .imm128 => |val| try func.addImm128(val), | 1024 | .imm128 => |val| try func.addImm128(val), |
| 1029 | .float32 => |val| try func.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }), | 1025 | .float32 => |val| try func.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }), |
| 1030 | .float64 => |val| try func.addFloat64(val), | 1026 | .float64 => |val| try func.addFloat64(val), |
| 1031 | .memory => |ptr| try func.addInst(.{ .tag = .uav_ref, .data = .{ .ip_index = ptr } }), | 1027 | .nav_ref => |nav_ref| { |
| 1032 | .memory_offset => |mo| try func.addInst(.{ | 1028 | if (nav_ref.offset == 0) { |
| 1033 | .tag = .uav_ref_off, | 1029 | try func.addInst(.{ .tag = .nav_ref, .data = .{ .nav_index = nav_ref.nav_index } }); |
| 1034 | .data = .{ | 1030 | } else { |
| 1035 | .payload = try func.addExtra(Mir.UavRefOff{ | 1031 | try func.addInst(.{ |
| 1036 | .ip_index = mo.pointer, | 1032 | .tag = .nav_ref_off, |
| 1037 | .offset = @intCast(mo.offset), // TODO should not be an assert | 1033 | .data = .{ |
| 1038 | }), | 1034 | .payload = try func.addExtra(Mir.NavRefOff{ |
| 1039 | }, | 1035 | .nav_index = nav_ref.nav_index, |
| 1040 | }), | 1036 | .offset = nav_ref.offset, |
| 1041 | .function_index => |index| try func.addIpIndex(.function_index, index), | 1037 | }), |
| 1038 | }, | ||
| 1039 | }); | ||
| 1040 | } | ||
| 1041 | }, | ||
| 1042 | .uav_ref => |uav| { | ||
| 1043 | if (uav.offset == 0) { | ||
| 1044 | try func.addInst(.{ .tag = .uav_ref, .data = .{ .ip_index = uav.ip_index } }); | ||
| 1045 | } else { | ||
| 1046 | try func.addInst(.{ | ||
| 1047 | .tag = .uav_ref_off, | ||
| 1048 | .data = .{ | ||
| 1049 | .payload = try func.addExtra(Mir.UavRefOff{ | ||
| 1050 | .ip_index = uav.ip_index, | ||
| 1051 | .offset = uav.offset, | ||
| 1052 | }), | ||
| 1053 | }, | ||
| 1054 | }); | ||
| 1055 | } | ||
| 1056 | }, | ||
| 1042 | .stack_offset => try func.addLabel(.local_get, func.bottom_stack_value.local.value), // caller must ensure to address the offset | 1057 | .stack_offset => try func.addLabel(.local_get, func.bottom_stack_value.local.value), // caller must ensure to address the offset |
| 1043 | } | 1058 | } |
| 1044 | } | 1059 | } |
| ... | @@ -1466,10 +1481,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: | ... | @@ -1466,10 +1481,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: |
| 1466 | assert(ty_classes[0] == .direct); | 1481 | assert(ty_classes[0] == .direct); |
| 1467 | const scalar_type = abi.scalarType(ty, zcu); | 1482 | const scalar_type = abi.scalarType(ty, zcu); |
| 1468 | switch (value) { | 1483 | switch (value) { |
| 1469 | .memory, | 1484 | .nav_ref, .stack_offset => _ = try func.load(value, scalar_type, 0), |
| 1470 | .memory_offset, | ||
| 1471 | .stack_offset, | ||
| 1472 | => _ = try func.load(value, scalar_type, 0), | ||
| 1473 | .dead => unreachable, | 1485 | .dead => unreachable, |
| 1474 | else => try func.emitWValue(value), | 1486 | else => try func.emitWValue(value), |
| 1475 | } | 1487 | } |
| ... | @@ -3117,8 +3129,8 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr | ... | @@ -3117,8 +3129,8 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr |
| 3117 | const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; | 3129 | const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; |
| 3118 | const offset: u64 = prev_offset + ptr.byte_offset; | 3130 | const offset: u64 = prev_offset + ptr.byte_offset; |
| 3119 | return switch (ptr.base_addr) { | 3131 | return switch (ptr.base_addr) { |
| 3120 | .nav => |nav| return func.lowerNavRef(nav, @intCast(offset)), | 3132 | .nav => |nav| return .{ .nav_ref = .{ .nav_index = zcu.chaseNav(nav), .offset = @intCast(offset) } }, |
| 3121 | .uav => |uav| return func.lowerUavRef(uav, @intCast(offset)), | 3133 | .uav => |uav| return .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset) } }, |
| 3122 | .int => return func.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize), | 3134 | .int => return func.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize), |
| 3123 | .eu_payload => return func.fail("Wasm TODO: lower error union payload pointer", .{}), | 3135 | .eu_payload => return func.fail("Wasm TODO: lower error union payload pointer", .{}), |
| 3124 | .opt_payload => |opt_ptr| return func.lowerPtr(opt_ptr, offset), | 3136 | .opt_payload => |opt_ptr| return func.lowerPtr(opt_ptr, offset), |
| ... | @@ -3162,51 +3174,6 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr | ... | @@ -3162,51 +3174,6 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr |
| 3162 | }; | 3174 | }; |
| 3163 | } | 3175 | } |
| 3164 | 3176 | ||
| 3165 | fn lowerUavRef( | ||
| 3166 | func: *CodeGen, | ||
| 3167 | uav: InternPool.Key.Ptr.BaseAddr.Uav, | ||
| 3168 | offset: u32, | ||
| 3169 | ) InnerError!WValue { | ||
| 3170 | const pt = func.pt; | ||
| 3171 | const zcu = pt.zcu; | ||
| 3172 | const ty = Type.fromInterned(zcu.intern_pool.typeOf(uav.val)); | ||
| 3173 | |||
| 3174 | const is_fn_body = ty.zigTypeTag(zcu) == .@"fn"; | ||
| 3175 | if (!is_fn_body and !ty.hasRuntimeBitsIgnoreComptime(zcu)) { | ||
| 3176 | return .{ .imm32 = 0xaaaaaaaa }; | ||
| 3177 | } | ||
| 3178 | |||
| 3179 | return if (is_fn_body) .{ | ||
| 3180 | .function_index = uav.val, | ||
| 3181 | } else if (offset == 0) .{ | ||
| 3182 | .memory = uav.val, | ||
| 3183 | } else .{ .memory_offset = .{ | ||
| 3184 | .pointer = uav.val, | ||
| 3185 | .offset = offset, | ||
| 3186 | } }; | ||
| 3187 | } | ||
| 3188 | |||
| 3189 | fn lowerNavRef(func: *CodeGen, nav_index: InternPool.Nav.Index, offset: u32) InnerError!WValue { | ||
| 3190 | const pt = func.pt; | ||
| 3191 | const zcu = pt.zcu; | ||
| 3192 | const ip = &zcu.intern_pool; | ||
| 3193 | |||
| 3194 | const nav_ty = ip.getNav(nav_index).typeOf(ip); | ||
| 3195 | if (!ip.isFunctionType(nav_ty) and !Type.fromInterned(nav_ty).hasRuntimeBitsIgnoreComptime(zcu)) { | ||
| 3196 | return .{ .imm32 = 0xaaaaaaaa }; | ||
| 3197 | } | ||
| 3198 | |||
| 3199 | const atom_index = try func.wasm.getOrCreateAtomForNav(pt, nav_index); | ||
| 3200 | const atom = func.wasm.getAtom(atom_index); | ||
| 3201 | |||
| 3202 | const target_sym_index = @intFromEnum(atom.sym_index); | ||
| 3203 | if (ip.isFunctionType(nav_ty)) { | ||
| 3204 | return .{ .function_index = target_sym_index }; | ||
| 3205 | } else if (offset == 0) { | ||
| 3206 | return .{ .memory = target_sym_index }; | ||
| 3207 | } else return .{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } }; | ||
| 3208 | } | ||
| 3209 | |||
| 3210 | /// Asserts that `isByRef` returns `false` for `ty`. | 3177 | /// Asserts that `isByRef` returns `false` for `ty`. |
| 3211 | fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { | 3178 | fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3212 | const pt = func.pt; | 3179 | const pt = func.pt; |
| ... | @@ -3307,7 +3274,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { | ... | @@ -3307,7 +3274,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3307 | .f64 => |f64_val| return .{ .float64 = f64_val }, | 3274 | .f64 => |f64_val| return .{ .float64 = f64_val }, |
| 3308 | else => unreachable, | 3275 | else => unreachable, |
| 3309 | }, | 3276 | }, |
| 3310 | .slice => return .{ .memory = val.toIntern() }, | 3277 | .slice => unreachable, // isByRef == true |
| 3311 | .ptr => return func.lowerPtr(val.toIntern(), 0), | 3278 | .ptr => return func.lowerPtr(val.toIntern(), 0), |
| 3312 | .opt => if (ty.optionalReprIsPayload(zcu)) { | 3279 | .opt => if (ty.optionalReprIsPayload(zcu)) { |
| 3313 | const pl_ty = ty.optionalChild(zcu); | 3280 | const pl_ty = ty.optionalChild(zcu); |
src/arch/wasm/Emit.zig+63-12| ... | @@ -33,6 +33,9 @@ pub fn lowerToCode(emit: *Emit) Error!void { | ... | @@ -33,6 +33,9 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 33 | var inst: u32 = 0; | 33 | var inst: u32 = 0; |
| 34 | 34 | ||
| 35 | loop: switch (tags[inst]) { | 35 | loop: switch (tags[inst]) { |
| 36 | .dbg_epilogue_begin => { | ||
| 37 | return; | ||
| 38 | }, | ||
| 36 | .block, .loop => { | 39 | .block, .loop => { |
| 37 | const block_type = datas[inst].block_type; | 40 | const block_type = datas[inst].block_type; |
| 38 | try code.ensureUnusedCapacity(gpa, 2); | 41 | try code.ensureUnusedCapacity(gpa, 2); |
| ... | @@ -42,28 +45,31 @@ pub fn lowerToCode(emit: *Emit) Error!void { | ... | @@ -42,28 +45,31 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 42 | inst += 1; | 45 | inst += 1; |
| 43 | continue :loop tags[inst]; | 46 | continue :loop tags[inst]; |
| 44 | }, | 47 | }, |
| 45 | |||
| 46 | .uav_ref => { | 48 | .uav_ref => { |
| 47 | try uavRefOff(wasm, code, .{ .ip_index = datas[inst].ip_index, .offset = 0 }); | 49 | try uavRefOff(wasm, code, .{ .ip_index = datas[inst].ip_index, .offset = 0 }); |
| 48 | |||
| 49 | inst += 1; | 50 | inst += 1; |
| 50 | continue :loop tags[inst]; | 51 | continue :loop tags[inst]; |
| 51 | }, | 52 | }, |
| 52 | .uav_ref_off => { | 53 | .uav_ref_off => { |
| 53 | try uavRefOff(wasm, code, mir.extraData(Mir.UavRefOff, datas[inst].payload).data); | 54 | try uavRefOff(wasm, code, mir.extraData(Mir.UavRefOff, datas[inst].payload).data); |
| 54 | |||
| 55 | inst += 1; | 55 | inst += 1; |
| 56 | continue :loop tags[inst]; | 56 | continue :loop tags[inst]; |
| 57 | }, | 57 | }, |
| 58 | 58 | .nav_ref => { | |
| 59 | .dbg_line => { | 59 | try navRefOff(wasm, code, .{ .ip_index = datas[inst].ip_index, .offset = 0 }); |
| 60 | inst += 1; | 60 | inst += 1; |
| 61 | continue :loop tags[inst]; | 61 | continue :loop tags[inst]; |
| 62 | }, | 62 | }, |
| 63 | .dbg_epilogue_begin => { | 63 | .nav_ref_off => { |
| 64 | return; | 64 | try navRefOff(wasm, code, mir.extraData(Mir.NavRefOff, datas[inst].payload).data); |
| 65 | inst += 1; | ||
| 66 | continue :loop tags[inst]; | ||
| 65 | }, | 67 | }, |
| 66 | 68 | ||
| 69 | .dbg_line => { | ||
| 70 | inst += 1; | ||
| 71 | continue :loop tags[inst]; | ||
| 72 | }, | ||
| 67 | .br_if, .br, .memory_grow, .memory_size => { | 73 | .br_if, .br, .memory_grow, .memory_size => { |
| 68 | try code.ensureUnusedCapacity(gpa, 11); | 74 | try code.ensureUnusedCapacity(gpa, 11); |
| 69 | code.appendAssumeCapacity(@intFromEnum(tags[inst])); | 75 | code.appendAssumeCapacity(@intFromEnum(tags[inst])); |
| ... | @@ -431,7 +437,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { | ... | @@ -431,7 +437,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 431 | 437 | ||
| 432 | _ => unreachable, | 438 | _ => unreachable, |
| 433 | } | 439 | } |
| 434 | unreachable; | 440 | comptime unreachable; |
| 435 | }, | 441 | }, |
| 436 | .simd_prefix => { | 442 | .simd_prefix => { |
| 437 | try code.ensureUnusedCapacity(gpa, 6 + 20); | 443 | try code.ensureUnusedCapacity(gpa, 6 + 20); |
| ... | @@ -487,7 +493,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { | ... | @@ -487,7 +493,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 487 | }, | 493 | }, |
| 488 | _ => unreachable, | 494 | _ => unreachable, |
| 489 | } | 495 | } |
| 490 | unreachable; | 496 | comptime unreachable; |
| 491 | }, | 497 | }, |
| 492 | .atomics_prefix => { | 498 | .atomics_prefix => { |
| 493 | try code.ensureUnusedCapacity(gpa, 6 + 20); | 499 | try code.ensureUnusedCapacity(gpa, 6 + 20); |
| ... | @@ -576,13 +582,13 @@ pub fn lowerToCode(emit: *Emit) Error!void { | ... | @@ -576,13 +582,13 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 576 | continue :loop tags[inst]; | 582 | continue :loop tags[inst]; |
| 577 | }, | 583 | }, |
| 578 | } | 584 | } |
| 579 | unreachable; | 585 | comptime unreachable; |
| 580 | }, | 586 | }, |
| 581 | } | 587 | } |
| 582 | unreachable; | 588 | comptime unreachable; |
| 583 | } | 589 | } |
| 584 | 590 | ||
| 585 | /// Assert 20 unused capacity. | 591 | /// Asserts 20 unused capacity. |
| 586 | fn encodeMemArg(code: *std.ArrayListUnmanaged(u8), mem_arg: Mir.MemArg) void { | 592 | fn encodeMemArg(code: *std.ArrayListUnmanaged(u8), mem_arg: Mir.MemArg) void { |
| 587 | assert(code.unusedCapacitySlice().len >= 20); | 593 | assert(code.unusedCapacitySlice().len >= 20); |
| 588 | // Wasm encodes alignment as power of 2, rather than natural alignment. | 594 | // Wasm encodes alignment as power of 2, rather than natural alignment. |
| ... | @@ -619,3 +625,48 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir | ... | @@ -619,3 +625,48 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir |
| 619 | const addr: i64 = try wasm.uavAddr(data.ip_index); | 625 | const addr: i64 = try wasm.uavAddr(data.ip_index); |
| 620 | leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable; | 626 | leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable; |
| 621 | } | 627 | } |
| 628 | |||
| 629 | fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff) !void { | ||
| 630 | const comp = wasm.base.comp; | ||
| 631 | const zcu = comp.zcu.?; | ||
| 632 | const ip = &zcu.intern_pool; | ||
| 633 | const gpa = comp.gpa; | ||
| 634 | const is_obj = comp.config.output_mode == .Obj; | ||
| 635 | const target = &comp.root_mod.resolved_target.result; | ||
| 636 | const nav_ty = ip.getNav(data.nav_index).typeOf(ip); | ||
| 637 | |||
| 638 | try code.ensureUnusedCapacity(gpa, 11); | ||
| 639 | |||
| 640 | if (ip.isFunctionType(nav_ty)) { | ||
| 641 | code.appendAssumeCapacity(std.wasm.Opcode.i32_const); | ||
| 642 | assert(data.offset == 0); | ||
| 643 | if (is_obj) { | ||
| 644 | try wasm.out_relocs.append(gpa, .{ | ||
| 645 | .offset = @intCast(code.items.len), | ||
| 646 | .index = try wasm.navSymbolIndex(data.nav_index), | ||
| 647 | .tag = .TABLE_INDEX_SLEB, | ||
| 648 | .addend = data.offset, | ||
| 649 | }); | ||
| 650 | code.appendNTimesAssumeCapacity(0, 5); | ||
| 651 | } else { | ||
| 652 | const addr: i64 = try wasm.navAddr(data.nav_index); | ||
| 653 | leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable; | ||
| 654 | } | ||
| 655 | } else { | ||
| 656 | const is_wasm32 = target.cpu.arch == .wasm32; | ||
| 657 | const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; | ||
| 658 | code.appendAssumeCapacity(@intFromEnum(opcode)); | ||
| 659 | if (is_obj) { | ||
| 660 | try wasm.out_relocs.append(gpa, .{ | ||
| 661 | .offset = @intCast(code.items.len), | ||
| 662 | .index = try wasm.navSymbolIndex(data.nav_index), | ||
| 663 | .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64, | ||
| 664 | .addend = data.offset, | ||
| 665 | }); | ||
| 666 | code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); | ||
| 667 | } else { | ||
| 668 | const addr: i64 = try wasm.navAddr(data.nav_index); | ||
| 669 | leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable; | ||
| 670 | } | ||
| 671 | } | ||
| 672 | } |
src/arch/wasm/Mir.zig+38-16| ... | @@ -32,8 +32,12 @@ pub const Inst = struct { | ... | @@ -32,8 +32,12 @@ pub const Inst = struct { |
| 32 | 32 | ||
| 33 | /// Some tags match wasm opcode values to facilitate trivial lowering. | 33 | /// Some tags match wasm opcode values to facilitate trivial lowering. |
| 34 | pub const Tag = enum(u8) { | 34 | pub const Tag = enum(u8) { |
| 35 | /// Uses `nop` | 35 | /// Uses `tag`. |
| 36 | @"unreachable" = 0x00, | 36 | @"unreachable" = 0x00, |
| 37 | /// Emits epilogue begin debug information. Marks the end of the function. | ||
| 38 | /// | ||
| 39 | /// Uses `tag` (no additional data). | ||
| 40 | dbg_epilogue_begin, | ||
| 37 | /// Creates a new block that can be jump from. | 41 | /// Creates a new block that can be jump from. |
| 38 | /// | 42 | /// |
| 39 | /// Type of the block is given in data `block_type` | 43 | /// Type of the block is given in data `block_type` |
| ... | @@ -46,34 +50,51 @@ pub const Inst = struct { | ... | @@ -46,34 +50,51 @@ pub const Inst = struct { |
| 46 | /// memory address of an unnamed constant. When emitting an object | 50 | /// memory address of an unnamed constant. When emitting an object |
| 47 | /// file, this adds a relocation. | 51 | /// file, this adds a relocation. |
| 48 | /// | 52 | /// |
| 49 | /// Data is `ip_index`. | 53 | /// This may not refer to a function. |
| 54 | /// | ||
| 55 | /// Uses `ip_index`. | ||
| 50 | uav_ref, | 56 | uav_ref, |
| 51 | /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the | 57 | /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the |
| 52 | /// memory address of an unnamed constant, offset by an integer value. | 58 | /// memory address of an unnamed constant, offset by an integer value. |
| 53 | /// When emitting an object file, this adds a relocation. | 59 | /// When emitting an object file, this adds a relocation. |
| 54 | /// | 60 | /// |
| 55 | /// Data is `payload` pointing to a `UavRefOff`. | 61 | /// This may not refer to a function. |
| 62 | /// | ||
| 63 | /// Uses `payload` pointing to a `UavRefOff`. | ||
| 56 | uav_ref_off, | 64 | uav_ref_off, |
| 65 | /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the | ||
| 66 | /// memory address of a named constant. | ||
| 67 | /// | ||
| 68 | /// When this refers to a function, this always lowers to an i32_const | ||
| 69 | /// which is the function index. When emitting an object file, this | ||
| 70 | /// adds a `Wasm.Relocation.Tag.TABLE_INDEX_SLEB` relocation. | ||
| 71 | /// | ||
| 72 | /// Uses `nav_index`. | ||
| 73 | nav_ref, | ||
| 74 | /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the | ||
| 75 | /// memory address of named constant, offset by an integer value. | ||
| 76 | /// When emitting an object file, this adds a relocation. | ||
| 77 | /// | ||
| 78 | /// This may not refer to a function. | ||
| 79 | /// | ||
| 80 | /// Uses `payload` pointing to a `NavRefOff`. | ||
| 81 | nav_ref_off, | ||
| 57 | /// Inserts debug information about the current line and column | 82 | /// Inserts debug information about the current line and column |
| 58 | /// of the source code | 83 | /// of the source code |
| 59 | /// | 84 | /// |
| 60 | /// Uses `payload` of which the payload type is `DbgLineColumn` | 85 | /// Uses `payload` of which the payload type is `DbgLineColumn` |
| 61 | dbg_line = 0x06, | 86 | dbg_line, |
| 62 | /// Emits epilogue begin debug information. Marks the end of the function. | ||
| 63 | /// | ||
| 64 | /// Uses `nop` | ||
| 65 | dbg_epilogue_begin = 0x07, | ||
| 66 | /// Represents the end of a function body or an initialization expression | 87 | /// Represents the end of a function body or an initialization expression |
| 67 | /// | 88 | /// |
| 68 | /// Payload is `nop` | 89 | /// Uses `tag` (no additional data). |
| 69 | end = 0x0B, | 90 | end = 0x0B, |
| 70 | /// Breaks from the current block to a label | 91 | /// Breaks from the current block to a label |
| 71 | /// | 92 | /// |
| 72 | /// Data is `label` where index represents the label to jump to | 93 | /// Uses `label` where index represents the label to jump to |
| 73 | br = 0x0C, | 94 | br = 0x0C, |
| 74 | /// Breaks from the current block if the stack value is non-zero | 95 | /// Breaks from the current block if the stack value is non-zero |
| 75 | /// | 96 | /// |
| 76 | /// Data is `label` where index represents the label to jump to | 97 | /// Uses `label` where index represents the label to jump to |
| 77 | br_if = 0x0D, | 98 | br_if = 0x0D, |
| 78 | /// Jump table that takes the stack value as an index where each value | 99 | /// Jump table that takes the stack value as an index where each value |
| 79 | /// represents the label to jump to. | 100 | /// represents the label to jump to. |
| ... | @@ -82,7 +103,7 @@ pub const Inst = struct { | ... | @@ -82,7 +103,7 @@ pub const Inst = struct { |
| 82 | br_table = 0x0E, | 103 | br_table = 0x0E, |
| 83 | /// Returns from the function | 104 | /// Returns from the function |
| 84 | /// | 105 | /// |
| 85 | /// Uses `nop` | 106 | /// Uses `tag`. |
| 86 | @"return" = 0x0F, | 107 | @"return" = 0x0F, |
| 87 | /// Calls a function using `nav_index`. | 108 | /// Calls a function using `nav_index`. |
| 88 | call_nav, | 109 | call_nav, |
| ... | @@ -98,10 +119,6 @@ pub const Inst = struct { | ... | @@ -98,10 +119,6 @@ pub const Inst = struct { |
| 98 | /// The function is the auto-generated tag name function for the type | 119 | /// The function is the auto-generated tag name function for the type |
| 99 | /// provided in `ip_index`. | 120 | /// provided in `ip_index`. |
| 100 | call_tag_name, | 121 | call_tag_name, |
| 101 | /// Lowers to an i32_const containing the index of a function. | ||
| 102 | /// When emitting an object file, this adds a relocation. | ||
| 103 | /// Uses `ip_index`. | ||
| 104 | function_index, | ||
| 105 | 122 | ||
| 106 | /// Pops three values from the stack and pushes | 123 | /// Pops three values from the stack and pushes |
| 107 | /// the first or second value dependent on the third value. | 124 | /// the first or second value dependent on the third value. |
| ... | @@ -663,6 +680,11 @@ pub const UavRefOff = struct { | ... | @@ -663,6 +680,11 @@ pub const UavRefOff = struct { |
| 663 | offset: i32, | 680 | offset: i32, |
| 664 | }; | 681 | }; |
| 665 | 682 | ||
| 683 | pub const NavRefOff = struct { | ||
| 684 | nav_index: InternPool.Nav.Index, | ||
| 685 | offset: i32, | ||
| 686 | }; | ||
| 687 | |||
| 666 | /// Maps a source line with wasm bytecode | 688 | /// Maps a source line with wasm bytecode |
| 667 | pub const DbgLineColumn = struct { | 689 | pub const DbgLineColumn = struct { |
| 668 | line: u32, | 690 | line: u32, |
src/link/Wasm.zig+5-1| ... | @@ -1508,6 +1508,10 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, | ... | @@ -1508,6 +1508,10 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, |
| 1508 | 1508 | ||
| 1509 | dev.check(.wasm_backend); | 1509 | dev.check(.wasm_backend); |
| 1510 | 1510 | ||
| 1511 | // This converts AIR to MIR but does not yet lower to wasm code. | ||
| 1512 | // That lowering happens during `flush`, after garbage collection, which | ||
| 1513 | // can affect function and global indexes, which affects the LEB integer | ||
| 1514 | // encoding, which affects the output binary size. | ||
| 1511 | try wasm.zcu_funcs.put(pt.zcu.gpa, func_index, .{ | 1515 | try wasm.zcu_funcs.put(pt.zcu.gpa, func_index, .{ |
| 1512 | .function = try CodeGen.function(wasm, pt, func_index, air, liveness), | 1516 | .function = try CodeGen.function(wasm, pt, func_index, air, liveness), |
| 1513 | }); | 1517 | }); |
| ... | @@ -1729,7 +1733,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v | ... | @@ -1729,7 +1733,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v |
| 1729 | continue; | 1733 | continue; |
| 1730 | } | 1734 | } |
| 1731 | } | 1735 | } |
| 1732 | wasm.functions_len = @intCast(wasm.functions.items.len); | 1736 | wasm.functions_len = @intCast(wasm.functions.entries.len); |
| 1733 | wasm.function_imports_init_keys = try gpa.dupe(String, wasm.function_imports.keys()); | 1737 | wasm.function_imports_init_keys = try gpa.dupe(String, wasm.function_imports.keys()); |
| 1734 | wasm.function_imports_init_vals = try gpa.dupe(FunctionImportId, wasm.function_imports.vals()); | 1738 | wasm.function_imports_init_vals = try gpa.dupe(FunctionImportId, wasm.function_imports.vals()); |
| 1735 | wasm.function_exports_len = @intCast(wasm.function_exports.items.len); | 1739 | wasm.function_exports_len = @intCast(wasm.function_exports.items.len); |