| ... | @@ -39,6 +39,14 @@ const WValue = union(enum) { | ... | @@ -39,6 +39,14 @@ const WValue = union(enum) { |
| 39 | /// Note: The value contains the symbol index, rather than the actual address | 39 | /// Note: The value contains the symbol index, rather than the actual address |
| 40 | /// as we use this to perform the relocation. | 40 | /// as we use this to perform the relocation. |
| 41 | memory: u32, | 41 | memory: u32, |
| | 42 | /// A value that represents a parent pointer and an offset |
| | 43 | /// from that pointer. i.e. when slicing with constant values. |
| | 44 | memory_offset: struct { |
| | 45 | /// The symbol of the parent pointer |
| | 46 | pointer: u32, |
| | 47 | /// Offset will be set as 'addend' when relocating |
| | 48 | offset: u32, |
| | 49 | }, |
| 42 | /// Represents a function pointer | 50 | /// Represents a function pointer |
| 43 | /// In wasm function pointers are indexes into a function table, | 51 | /// In wasm function pointers are indexes into a function table, |
| 44 | /// rather than an address in the data section. | 52 | /// rather than an address in the data section. |
| ... | @@ -754,7 +762,14 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { | ... | @@ -754,7 +762,14 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { |
| 754 | .imm64 => |val| try self.addImm64(val), | 762 | .imm64 => |val| try self.addImm64(val), |
| 755 | .float32 => |val| try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }), | 763 | .float32 => |val| try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }), |
| 756 | .float64 => |val| try self.addFloat64(val), | 764 | .float64 => |val| try self.addFloat64(val), |
| 757 | .memory => |ptr| try self.addLabel(.memory_address, ptr), // write sybol address and generate relocation | 765 | .memory => |ptr| { |
| | 766 | const extra_index = try self.addExtra(Mir.Memory{ .pointer = ptr, .offset = 0 }); |
| | 767 | try self.addInst(.{ .tag = .memory_address, .data = .{ .payload = extra_index } }); |
| | 768 | }, |
| | 769 | .memory_offset => |mem_off| { |
| | 770 | const extra_index = try self.addExtra(Mir.Memory{ .pointer = mem_off.pointer, .offset = mem_off.offset }); |
| | 771 | try self.addInst(.{ .tag = .memory_address, .data = .{ .payload = extra_index } }); |
| | 772 | }, |
| 758 | .function_index => |index| try self.addLabel(.function_index, index), // write function index and generate relocation | 773 | .function_index => |index| try self.addLabel(.function_index, index), // write function index and generate relocation |
| 759 | } | 774 | } |
| 760 | } | 775 | } |
| ... | @@ -927,7 +942,7 @@ pub const DeclGen = struct { | ... | @@ -927,7 +942,7 @@ pub const DeclGen = struct { |
| 927 | .function => val.castTag(.function).?.data.owner_decl, | 942 | .function => val.castTag(.function).?.data.owner_decl, |
| 928 | else => unreachable, | 943 | else => unreachable, |
| 929 | }; | 944 | }; |
| 930 | return try self.lowerDeclRef(ty, val, fn_decl); | 945 | return try self.lowerDeclRefValue(ty, val, fn_decl, 0); |
| 931 | }, | 946 | }, |
| 932 | .Optional => { | 947 | .Optional => { |
| 933 | var opt_buf: Type.Payload.ElemType = undefined; | 948 | var opt_buf: Type.Payload.ElemType = undefined; |
| ... | @@ -1115,11 +1130,11 @@ pub const DeclGen = struct { | ... | @@ -1115,11 +1130,11 @@ pub const DeclGen = struct { |
| 1115 | .Pointer => switch (val.tag()) { | 1130 | .Pointer => switch (val.tag()) { |
| 1116 | .variable => { | 1131 | .variable => { |
| 1117 | const decl = val.castTag(.variable).?.data.owner_decl; | 1132 | const decl = val.castTag(.variable).?.data.owner_decl; |
| 1118 | return self.lowerDeclRef(ty, val, decl); | 1133 | return self.lowerDeclRefValue(ty, val, decl, 0); |
| 1119 | }, | 1134 | }, |
| 1120 | .decl_ref => { | 1135 | .decl_ref => { |
| 1121 | const decl = val.castTag(.decl_ref).?.data; | 1136 | const decl = val.castTag(.decl_ref).?.data; |
| 1122 | return self.lowerDeclRef(ty, val, decl); | 1137 | return self.lowerDeclRefValue(ty, val, decl, writer, 0); |
| 1123 | }, | 1138 | }, |
| 1124 | .slice => { | 1139 | .slice => { |
| 1125 | const slice = val.castTag(.slice).?.data; | 1140 | const slice = val.castTag(.slice).?.data; |
| ... | @@ -1139,6 +1154,13 @@ pub const DeclGen = struct { | ... | @@ -1139,6 +1154,13 @@ pub const DeclGen = struct { |
| 1139 | try writer.writeByteNTimes(0, @divExact(self.target().cpu.arch.ptrBitWidth(), 8)); | 1154 | try writer.writeByteNTimes(0, @divExact(self.target().cpu.arch.ptrBitWidth(), 8)); |
| 1140 | return Result{ .appended = {} }; | 1155 | return Result{ .appended = {} }; |
| 1141 | }, | 1156 | }, |
| | 1157 | .elem_ptr => { |
| | 1158 | const elem_ptr = val.castTag(.elem_ptr).?.data; |
| | 1159 | const elem_size = ty.childType().abiSize(self.target()); |
| | 1160 | const offset = elem_ptr.index * elem_size; |
| | 1161 | return self.lowerParentPtr(elem_ptr.array_ptr, writer, offset); |
| | 1162 | }, |
| | 1163 | .int_u64 => return self.genTypedValue(Type.usize, val, writer), |
| 1142 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), | 1164 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), |
| 1143 | }, | 1165 | }, |
| 1144 | .ErrorUnion => { | 1166 | .ErrorUnion => { |
| ... | @@ -1179,7 +1201,36 @@ pub const DeclGen = struct { | ... | @@ -1179,7 +1201,36 @@ pub const DeclGen = struct { |
| 1179 | } | 1201 | } |
| 1180 | } | 1202 | } |
| 1181 | | 1203 | |
| 1182 | fn lowerDeclRef(self: *DeclGen, ty: Type, val: Value, decl: *Module.Decl) InnerError!Result { | 1204 | fn lowerParentPtr(self: *DeclGen, ptr_value: Value, offset: usize) InnerError!Result { |
| | 1205 | switch (ptr_value.tag()) { |
| | 1206 | .decl_ref => { |
| | 1207 | const decl = ptr_value.castTag(.decl_ref).?.data; |
| | 1208 | return self.lowerParentPtrDecl(ptr_value, decl, offset); |
| | 1209 | }, |
| | 1210 | else => |tag| return self.fail("TODO: Implement lowerParentPtr for pointer value tag: {s}", .{tag}), |
| | 1211 | } |
| | 1212 | } |
| | 1213 | |
| | 1214 | fn lowerParentPtrDecl(self: *DeclGen, ptr_val: Value, decl: *Module.Decl, offset: usize) InnerError!Result { |
| | 1215 | decl.markAlive(); |
| | 1216 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| | 1217 | .base = .{ .tag = .single_mut_pointer }, |
| | 1218 | .data = decl.ty, |
| | 1219 | }; |
| | 1220 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); |
| | 1221 | return self.lowerDeclRefValue(ptr_ty, ptr_val, decl, offset); |
| | 1222 | } |
| | 1223 | |
| | 1224 | fn lowerDeclRefValue( |
| | 1225 | self: *DeclGen, |
| | 1226 | ty: Type, |
| | 1227 | val: Value, |
| | 1228 | /// The target decl that is being pointed to |
| | 1229 | decl: *Module.Decl, |
| | 1230 | /// When lowering to an indexed pointer, we can specify the offset |
| | 1231 | /// which will then be used as 'addend' to the relocation. |
| | 1232 | offset: usize, |
| | 1233 | ) InnerError!Result { |
| 1183 | const writer = self.code.writer(); | 1234 | const writer = self.code.writer(); |
| 1184 | if (ty.isSlice()) { | 1235 | if (ty.isSlice()) { |
| 1185 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1236 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| ... | @@ -1202,6 +1253,7 @@ pub const DeclGen = struct { | ... | @@ -1202,6 +1253,7 @@ pub const DeclGen = struct { |
| 1202 | self.symbol_index, // source symbol index | 1253 | self.symbol_index, // source symbol index |
| 1203 | decl.link.wasm.sym_index, // target symbol index | 1254 | decl.link.wasm.sym_index, // target symbol index |
| 1204 | @intCast(u32, self.code.items.len), // offset | 1255 | @intCast(u32, self.code.items.len), // offset |
| | 1256 | @intCast(u32, offset), // addend |
| 1205 | )); | 1257 | )); |
| 1206 | return Result{ .appended = {} }; | 1258 | return Result{ .appended = {} }; |
| 1207 | } | 1259 | } |
| ... | @@ -1974,6 +2026,17 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { | ... | @@ -1974,6 +2026,17 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1974 | return WValue{ .function_index = target_sym_index }; | 2026 | return WValue{ .function_index = target_sym_index }; |
| 1975 | } else return WValue{ .memory = target_sym_index }; | 2027 | } else return WValue{ .memory = target_sym_index }; |
| 1976 | }, | 2028 | }, |
| | 2029 | .elem_ptr => { |
| | 2030 | const elem_ptr = val.castTag(.elem_ptr).?.data; |
| | 2031 | const index = elem_ptr.index; |
| | 2032 | const offset = index * ty.childType().abiSize(self.target); |
| | 2033 | const array_ptr = try self.lowerConstant(elem_ptr.array_ptr, ty); |
| | 2034 | |
| | 2035 | return WValue{ .memory_offset = .{ |
| | 2036 | .pointer = array_ptr.memory, |
| | 2037 | .offset = @intCast(u32, offset), |
| | 2038 | } }; |
| | 2039 | }, |
| 1977 | .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, | 2040 | .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, |
| 1978 | .zero, .null_value => return WValue{ .imm32 = 0 }, | 2041 | .zero, .null_value => return WValue{ .imm32 = 0 }, |
| 1979 | else => return self.fail("Wasm TODO: lowerConstant for other const pointer tag {s}", .{val.tag()}), | 2042 | else => return self.fail("Wasm TODO: lowerConstant for other const pointer tag {s}", .{val.tag()}), |