| ... | ... | @@ -39,6 +39,14 @@ const WValue = union(enum) { |
| 39 | 39 | /// Note: The value contains the symbol index, rather than the actual address |
| 40 | 40 | /// as we use this to perform the relocation. |
| 41 | 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 | 50 | /// Represents a function pointer |
| 43 | 51 | /// In wasm function pointers are indexes into a function table, |
| 44 | 52 | /// rather than an address in the data section. |
| ... | ... | @@ -754,7 +762,14 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { |
| 754 | 762 | .imm64 => |val| try self.addImm64(val), |
| 755 | 763 | .float32 => |val| try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }), |
| 756 | 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 | 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 | 942 | .function => val.castTag(.function).?.data.owner_decl, |
| 928 | 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 | 947 | .Optional => { |
| 933 | 948 | var opt_buf: Type.Payload.ElemType = undefined; |
| ... | ... | @@ -1115,11 +1130,11 @@ pub const DeclGen = struct { |
| 1115 | 1130 | .Pointer => switch (val.tag()) { |
| 1116 | 1131 | .variable => { |
| 1117 | 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 | 1135 | .decl_ref => { |
| 1121 | 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 | 1139 | .slice => { |
| 1125 | 1140 | const slice = val.castTag(.slice).?.data; |
| ... | ... | @@ -1139,6 +1154,13 @@ pub const DeclGen = struct { |
| 1139 | 1154 | try writer.writeByteNTimes(0, @divExact(self.target().cpu.arch.ptrBitWidth(), 8)); |
| 1140 | 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 | 1164 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), |
| 1143 | 1165 | }, |
| 1144 | 1166 | .ErrorUnion => { |
| ... | ... | @@ -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 | 1234 | const writer = self.code.writer(); |
| 1184 | 1235 | if (ty.isSlice()) { |
| 1185 | 1236 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| ... | ... | @@ -1202,6 +1253,7 @@ pub const DeclGen = struct { |
| 1202 | 1253 | self.symbol_index, // source symbol index |
| 1203 | 1254 | decl.link.wasm.sym_index, // target symbol index |
| 1204 | 1255 | @intCast(u32, self.code.items.len), // offset |
| 1256 | @intCast(u32, offset), // addend |
| 1205 | 1257 | )); |
| 1206 | 1258 | return Result{ .appended = {} }; |
| 1207 | 1259 | } |
| ... | ... | @@ -1974,6 +2026,17 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1974 | 2026 | return WValue{ .function_index = target_sym_index }; |
| 1975 | 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 | 2040 | .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, |
| 1978 | 2041 | .zero, .null_value => return WValue{ .imm32 = 0 }, |
| 1979 | 2042 | else => return self.fail("Wasm TODO: lowerConstant for other const pointer tag {s}", .{val.tag()}), |