authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-06 16:54:56+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-06 19:38:53+01:00
log2faba4092a3c730c4062e0e82b967daa9638b129
tree0faf160bbdfb8d8d305e9293362d03bba61aae46
parent70fc6e37766c3c0b7d75854055fa3f862d4025f7
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Remove old DeclGen/genTypedValue


1 files changed, 1 insertions(+), 429 deletions(-)

src/arch/wasm/CodeGen.zig+1-429
...@@ -639,7 +639,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {...@@ -639,7 +639,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
639 }639 }
640640
641 // When we need to pass the value by reference (such as a struct), we will641 // When we need to pass the value by reference (such as a struct), we will
642 // leverage `genTypedValue` to lower the constant to bytes and emit it642 // leverage `generateSymbol` to lower the constant to bytes and emit it
643 // to the 'rodata' section. We then return the index into the section as `WValue`.643 // to the 'rodata' section. We then return the index into the section as `WValue`.
644 //644 //
645 // In the other cases, we will simply lower the constant to a value that fits645 // In the other cases, we will simply lower the constant to a value that fits
...@@ -903,434 +903,6 @@ pub fn genFunc(self: *Self) InnerError!void {...@@ -903,434 +903,6 @@ pub fn genFunc(self: *Self) InnerError!void {
903 };903 };
904}904}
905905
906pub const DeclGen = struct {
907 /// The decl we are generating code for.
908 decl: *Decl,
909 /// The symbol we're generating code for.
910 /// This can either be the symbol of the Decl itself,
911 /// or one of its locals.
912 symbol_index: u32,
913 gpa: Allocator,
914 /// A reference to the linker, that will process the decl's
915 /// code and create any relocations it deems neccesary.
916 bin_file: *link.File.Wasm,
917 /// This will be set when `InnerError` has been returned.
918 /// In any other case, this will be 'undefined'.
919 err_msg: *Module.ErrorMsg,
920 /// Reference to the Module that is being compiled.
921 /// Used to find the error value of an error.
922 module: *Module,
923 /// The list of bytes that have been generated so far,
924 /// can be used to calculate the offset into a section.
925 code: *std.ArrayList(u8),
926
927 /// Sets `err_msg` on `DeclGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
928 fn fail(self: *DeclGen, comptime fmt: []const u8, args: anytype) InnerError {
929 const src: LazySrcLoc = .{ .node_offset = 0 };
930 const src_loc = src.toSrcLoc(self.decl);
931 self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args);
932 return error.CodegenFail;
933 }
934
935 fn target(self: *const DeclGen) std.Target {
936 return self.bin_file.base.options.target;
937 }
938
939 pub fn genDecl(self: *DeclGen) InnerError!Result {
940 const decl = self.decl;
941 assert(decl.has_tv);
942
943 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val });
944
945 if (decl.val.castTag(.function)) |func_payload| {
946 _ = func_payload;
947 return self.fail("TODO wasm backend genDecl function pointer", .{});
948 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
949 const ext_decl = extern_fn.data.owner_decl;
950 var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target());
951 defer func_type.deinit(self.gpa);
952 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
953 return Result{ .appended = {} };
954 } else {
955 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
956 break :init_val payload.data.init;
957 } else decl.val;
958 if (init_val.tag() != .unreachable_value) {
959 return self.genTypedValue(decl.ty, init_val);
960 }
961 return Result{ .appended = {} };
962 }
963 }
964
965 /// Generates the wasm bytecode for the declaration belonging to `Context`
966 pub fn genTypedValue(self: *DeclGen, ty: Type, val: Value) InnerError!Result {
967 log.debug("genTypedValue: ty = {}, val = {}", .{ ty, val });
968
969 const writer = self.code.writer();
970 if (val.isUndef()) {
971 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
972 return Result{ .appended = {} };
973 }
974 switch (ty.zigTypeTag()) {
975 .Fn => {
976 const fn_decl = switch (val.tag()) {
977 .extern_fn => val.castTag(.extern_fn).?.data.owner_decl,
978 .function => val.castTag(.function).?.data.owner_decl,
979 else => unreachable,
980 };
981 return try self.lowerDeclRefValue(ty, val, fn_decl, 0);
982 },
983 .Optional => {
984 var opt_buf: Type.Payload.ElemType = undefined;
985 const payload_type = ty.optionalChild(&opt_buf);
986 const is_pl = !val.isNull();
987 const abi_size = @intCast(usize, ty.abiSize(self.target()));
988 const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target()));
989
990 if (!payload_type.hasRuntimeBits()) {
991 try writer.writeByteNTimes(@boolToInt(is_pl), abi_size);
992 return Result{ .appended = {} };
993 }
994
995 if (ty.isPtrLikeOptional()) {
996 if (val.castTag(.opt_payload)) |payload| {
997 return self.genTypedValue(payload_type, payload.data);
998 } else if (!val.isNull()) {
999 return self.genTypedValue(payload_type, val);
1000 } else {
1001 try writer.writeByteNTimes(0, abi_size);
1002 return Result{ .appended = {} };
1003 }
1004 }
1005
1006 // `null-tag` bytes
1007 try writer.writeByteNTimes(@boolToInt(is_pl), offset);
1008 switch (try self.genTypedValue(
1009 payload_type,
1010 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
1011 )) {
1012 .appended => {},
1013 .externally_managed => |payload| try writer.writeAll(payload),
1014 }
1015 return Result{ .appended = {} };
1016 },
1017 .Array => switch (val.tag()) {
1018 .bytes => {
1019 const payload = val.castTag(.bytes).?;
1020 return Result{ .externally_managed = payload.data };
1021 },
1022 .array => {
1023 const elem_vals = val.castTag(.array).?.data;
1024 const elem_ty = ty.childType();
1025 for (elem_vals) |elem_val| {
1026 switch (try self.genTypedValue(elem_ty, elem_val)) {
1027 .appended => {},
1028 .externally_managed => |data| try writer.writeAll(data),
1029 }
1030 }
1031 return Result{ .appended = {} };
1032 },
1033 .repeated => {
1034 const array = val.castTag(.repeated).?.data;
1035 const elem_ty = ty.childType();
1036 const sentinel = ty.sentinel();
1037 const len = ty.arrayLen();
1038
1039 var index: u32 = 0;
1040 while (index < len) : (index += 1) {
1041 switch (try self.genTypedValue(elem_ty, array)) {
1042 .externally_managed => |data| try writer.writeAll(data),
1043 .appended => {},
1044 }
1045 }
1046 if (sentinel) |sentinel_value| {
1047 return self.genTypedValue(elem_ty, sentinel_value);
1048 }
1049 return Result{ .appended = {} };
1050 },
1051 .empty_array_sentinel => {
1052 const elem_ty = ty.childType();
1053 const sent_val = ty.sentinel().?;
1054 return self.genTypedValue(elem_ty, sent_val);
1055 },
1056 else => unreachable,
1057 },
1058 .Int => {
1059 const info = ty.intInfo(self.target());
1060 const abi_size = @intCast(usize, ty.abiSize(self.target()));
1061 if (info.bits <= 64) {
1062 var buf: [8]u8 = undefined;
1063 if (info.signedness == .unsigned) {
1064 std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt());
1065 } else std.mem.writeIntLittle(i64, &buf, val.toSignedInt());
1066 try writer.writeAll(buf[0..abi_size]);
1067 return Result{ .appended = {} };
1068 }
1069 var space: Value.BigIntSpace = undefined;
1070 const bigint = val.toBigInt(&space);
1071 const iterations = @divExact(abi_size, @sizeOf(usize));
1072 for (bigint.limbs) |_, index| {
1073 const limb = bigint.limbs[bigint.limbs.len - index - 1];
1074 try writer.writeIntLittle(usize, limb);
1075 } else if (bigint.limbs.len < iterations) {
1076 // When the value is saved in less limbs than the required
1077 // abi size, we fill the remaining parts with 0's.
1078 var it_left = iterations - bigint.limbs.len;
1079 while (it_left > 0) {
1080 it_left -= 1;
1081 try writer.writeIntLittle(usize, 0);
1082 }
1083 }
1084 return Result{ .appended = {} };
1085 },
1086 .Float => {
1087 const float_bits = ty.floatBits(self.target());
1088 if (float_bits > 64) {
1089 return self.fail("Wasm TODO: Implement f80 and f128", .{});
1090 }
1091
1092 switch (float_bits) {
1093 16, 32 => try writer.writeIntLittle(u32, @bitCast(u32, val.toFloat(f32))),
1094 64 => try writer.writeIntLittle(u64, @bitCast(u64, val.toFloat(f64))),
1095 else => unreachable,
1096 }
1097
1098 return Result{ .appended = {} };
1099 },
1100 .Enum => {
1101 var int_buffer: Value.Payload.U64 = undefined;
1102 const int_val = val.enumToInt(ty, &int_buffer);
1103 var buf: Type.Payload.Bits = undefined;
1104 const int_ty = ty.intTagType(&buf);
1105 return self.genTypedValue(int_ty, int_val);
1106 },
1107 .Bool => {
1108 try writer.writeByte(@boolToInt(val.toBool()));
1109 return Result{ .appended = {} };
1110 },
1111 .Struct => {
1112 const struct_obj = ty.castTag(.@"struct").?.data;
1113 if (struct_obj.layout == .Packed) {
1114 return self.fail("TODO: Packed structs for wasm", .{});
1115 }
1116
1117 const struct_begin = self.code.items.len;
1118 const field_vals = val.castTag(.@"struct").?.data;
1119 for (field_vals) |field_val, index| {
1120 const field_ty = ty.structFieldType(index);
1121 if (!field_ty.hasRuntimeBits()) continue;
1122
1123 switch (try self.genTypedValue(field_ty, field_val)) {
1124 .appended => {},
1125 .externally_managed => |payload| try writer.writeAll(payload),
1126 }
1127 const unpadded_field_len = self.code.items.len - struct_begin;
1128
1129 // Pad struct members if required
1130 const padded_field_end = ty.structFieldOffset(index + 1, self.target());
1131 const padding = try std.math.cast(usize, padded_field_end - unpadded_field_len);
1132
1133 if (padding > 0) {
1134 try writer.writeByteNTimes(0, padding);
1135 }
1136 }
1137 return Result{ .appended = {} };
1138 },
1139 .Union => {
1140 const union_val = val.castTag(.@"union").?.data;
1141 const layout = ty.unionGetLayout(self.target());
1142
1143 if (layout.payload_size == 0) {
1144 return self.genTypedValue(ty.unionTagType().?, union_val.tag);
1145 }
1146
1147 // Check if we should store the tag first, in which case, do so now:
1148 if (layout.tag_align >= layout.payload_align) {
1149 switch (try self.genTypedValue(ty.unionTagType().?, union_val.tag)) {
1150 .appended => {},
1151 .externally_managed => |payload| try writer.writeAll(payload),
1152 }
1153 }
1154
1155 const union_ty = ty.cast(Type.Payload.Union).?.data;
1156 const field_index = union_ty.tag_ty.enumTagFieldIndex(union_val.tag).?;
1157 assert(union_ty.haveFieldTypes());
1158 const field_ty = union_ty.fields.values()[field_index].ty;
1159 if (!field_ty.hasRuntimeBits()) {
1160 try writer.writeByteNTimes(0xaa, @intCast(usize, layout.payload_size));
1161 } else {
1162 switch (try self.genTypedValue(field_ty, union_val.val)) {
1163 .appended => {},
1164 .externally_managed => |payload| try writer.writeAll(payload),
1165 }
1166
1167 // Unions have the size of the largest field, so we must pad
1168 // whenever the active field has a smaller size.
1169 const diff = layout.payload_size - field_ty.abiSize(self.target());
1170 if (diff > 0) {
1171 try writer.writeByteNTimes(0xaa, @intCast(usize, diff));
1172 }
1173 }
1174
1175 if (layout.tag_size == 0) {
1176 return Result{ .appended = {} };
1177 }
1178 return self.genTypedValue(union_ty.tag_ty, union_val.tag);
1179 },
1180 .Pointer => switch (val.tag()) {
1181 .variable => {
1182 const decl = val.castTag(.variable).?.data.owner_decl;
1183 return self.lowerDeclRefValue(ty, val, decl, 0);
1184 },
1185 .decl_ref => {
1186 const decl = val.castTag(.decl_ref).?.data;
1187 return self.lowerDeclRefValue(ty, val, decl, 0);
1188 },
1189 .slice => {
1190 const slice = val.castTag(.slice).?.data;
1191 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1192 const ptr_ty = ty.slicePtrFieldType(&buf);
1193 switch (try self.genTypedValue(ptr_ty, slice.ptr)) {
1194 .externally_managed => |data| try writer.writeAll(data),
1195 .appended => {},
1196 }
1197 switch (try self.genTypedValue(Type.usize, slice.len)) {
1198 .externally_managed => |data| try writer.writeAll(data),
1199 .appended => {},
1200 }
1201 return Result{ .appended = {} };
1202 },
1203 .zero => {
1204 try writer.writeByteNTimes(0, @divExact(self.target().cpu.arch.ptrBitWidth(), 8));
1205 return Result{ .appended = {} };
1206 },
1207 .elem_ptr => {
1208 const elem_ptr = val.castTag(.elem_ptr).?.data;
1209 const elem_size = ty.childType().abiSize(self.target());
1210 const offset = elem_ptr.index * elem_size;
1211 return self.lowerParentPtr(elem_ptr.array_ptr, @intCast(usize, offset));
1212 },
1213 .int_u64 => return self.genTypedValue(Type.usize, val),
1214 else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}),
1215 },
1216 .ErrorUnion => {
1217 const error_ty = ty.errorUnionSet();
1218 const payload_ty = ty.errorUnionPayload();
1219 const is_pl = val.errorUnionIsPayload();
1220 const abi_align = ty.abiAlignment(self.target());
1221
1222 {
1223 const err_val = if (!is_pl) val else Value.initTag(.zero);
1224 const start = self.code.items.len;
1225 switch (try self.genTypedValue(error_ty, err_val)) {
1226 .externally_managed => |data| try writer.writeAll(data),
1227 .appended => {},
1228 }
1229 const unpadded_end = self.code.items.len - start;
1230 const padded_end = mem.alignForwardGeneric(usize, unpadded_end, abi_align);
1231 const padding = padded_end - unpadded_end;
1232 if (padding > 0) {
1233 try writer.writeByteNTimes(0, padding);
1234 }
1235 }
1236
1237 if (payload_ty.hasRuntimeBits()) {
1238 const start = self.code.items.len;
1239 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
1240 switch (try self.genTypedValue(payload_ty, pl_val)) {
1241 .externally_managed => |data| try writer.writeAll(data),
1242 .appended => {},
1243 }
1244
1245 const unpadded_end = self.code.items.len - start;
1246 const padded_end = mem.alignForwardGeneric(usize, unpadded_end, abi_align);
1247 const padding = padded_end - unpadded_end;
1248 if (padding > 0) {
1249 try writer.writeByteNTimes(0, padding);
1250 }
1251 }
1252
1253 return Result{ .appended = {} };
1254 },
1255 .ErrorSet => {
1256 switch (val.tag()) {
1257 .@"error" => {
1258 const name = val.castTag(.@"error").?.data.name;
1259 const kv = try self.module.getErrorValue(name);
1260 try writer.writeIntLittle(u32, kv.value);
1261 },
1262 else => {
1263 try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target())));
1264 },
1265 }
1266 return Result{ .appended = {} };
1267 },
1268 else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
1269 }
1270 }
1271
1272 fn lowerParentPtr(self: *DeclGen, ptr_value: Value, offset: usize) InnerError!Result {
1273 switch (ptr_value.tag()) {
1274 .decl_ref => {
1275 const decl = ptr_value.castTag(.decl_ref).?.data;
1276 return self.lowerParentPtrDecl(ptr_value, decl, offset);
1277 },
1278 else => |tag| return self.fail("TODO: Implement lowerParentPtr for pointer value tag: {s}", .{tag}),
1279 }
1280 }
1281
1282 fn lowerParentPtrDecl(self: *DeclGen, ptr_val: Value, decl: *Module.Decl, offset: usize) InnerError!Result {
1283 decl.markAlive();
1284 var ptr_ty_payload: Type.Payload.ElemType = .{
1285 .base = .{ .tag = .single_mut_pointer },
1286 .data = decl.ty,
1287 };
1288 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
1289 return self.lowerDeclRefValue(ptr_ty, ptr_val, decl, offset);
1290 }
1291
1292 fn lowerDeclRefValue(
1293 self: *DeclGen,
1294 ty: Type,
1295 val: Value,
1296 /// The target decl that is being pointed to
1297 decl: *Module.Decl,
1298 /// When lowering to an indexed pointer, we can specify the offset
1299 /// which will then be used as 'addend' to the relocation.
1300 offset: usize,
1301 ) InnerError!Result {
1302 const writer = self.code.writer();
1303 if (ty.isSlice()) {
1304 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1305 const slice_ty = ty.slicePtrFieldType(&buf);
1306 switch (try self.genTypedValue(slice_ty, val)) {
1307 .appended => {},
1308 .externally_managed => |payload| try writer.writeAll(payload),
1309 }
1310 var slice_len: Value.Payload.U64 = .{
1311 .base = .{ .tag = .int_u64 },
1312 .data = val.sliceLen(),
1313 };
1314 return self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base));
1315 }
1316
1317 decl.markAlive();
1318 if (decl.link.wasm.sym_index == 0) {
1319 try writer.writeIntLittle(u32, 0);
1320 } else {
1321 try writer.writeIntLittle(u32, @intCast(u32, try self.bin_file.getDeclVAddr(
1322 decl,
1323 .{
1324 .parent_atom_index = self.symbol_index,
1325 .offset = self.code.items.len,
1326 .addend = @intCast(u32, offset),
1327 },
1328 )));
1329 }
1330 return Result{ .appended = {} };
1331 }
1332};
1333
1334const CallWValues = struct {906const CallWValues = struct {
1335 args: []WValue,907 args: []WValue,
1336 return_value: WValue,908 return_value: WValue,