| ... | ... | @@ -6400,30 +6400,23 @@ fn callIntrinsic( |
| 6400 | 6400 | fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6401 | 6401 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 6402 | 6402 | if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{un_op}); |
| 6403 | | // const operand = try func.resolveInst(un_op); |
| 6403 | const operand = try func.resolveInst(un_op); |
| 6404 | 6404 | const enum_ty = func.air.typeOf(un_op); |
| 6405 | 6405 | |
| 6406 | | _ = try func.getTagNameFunction(enum_ty); |
| 6406 | const func_sym_index = try func.getTagNameFunction(enum_ty); |
| 6407 | 6407 | |
| 6408 | | func.finishAir(inst, .none, &.{un_op}); |
| 6408 | const result_ptr = try func.allocStack(func.air.typeOfIndex(inst)); |
| 6409 | try func.lowerToStack(result_ptr); |
| 6410 | try func.emitWValue(operand); |
| 6411 | try func.addLabel(.call, func_sym_index); |
| 6412 | |
| 6413 | return func.finishAir(inst, result_ptr, &.{un_op}); |
| 6409 | 6414 | } |
| 6410 | 6415 | |
| 6411 | 6416 | fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6412 | 6417 | const enum_decl_index = enum_ty.getOwnerDecl(); |
| 6413 | 6418 | const module = func.bin_file.base.options.module.?; |
| 6414 | 6419 | |
| 6415 | | // check if we already generated code for this. |
| 6416 | | if (func.bin_file.decls.get(enum_decl_index)) |decl_atom_index| { |
| 6417 | | std.debug.print("Found atom index for Enum decl! {d}\n", .{decl_atom_index}); |
| 6418 | | const atom = func.bin_file.getAtom(decl_atom_index); |
| 6419 | | return atom.getSymbolIndex().?; |
| 6420 | | } |
| 6421 | | |
| 6422 | | // Create an atom in which we will store all tag names. |
| 6423 | | const func_atom_index = try func.bin_file.getOrCreateAtomForDecl(enum_decl_index); |
| 6424 | | const func_atom = func.bin_file.getAtomPtr(func_atom_index); |
| 6425 | | std.debug.print("Generated a new atom! {d}\n", .{func_atom_index}); |
| 6426 | | |
| 6427 | 6420 | var arena_allocator = std.heap.ArenaAllocator.init(func.gpa); |
| 6428 | 6421 | defer arena_allocator.deinit(); |
| 6429 | 6422 | const arena = arena_allocator.allocator(); |
| ... | ... | @@ -6432,11 +6425,11 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6432 | 6425 | defer module.gpa.free(fqn); |
| 6433 | 6426 | const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); |
| 6434 | 6427 | |
| 6428 | // check if we already generated code for this. |
| 6435 | 6429 | if (func.bin_file.findGlobalSymbol(func_name)) |loc| { |
| 6436 | 6430 | return loc.index; |
| 6437 | 6431 | } |
| 6438 | 6432 | |
| 6439 | | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); |
| 6440 | 6433 | var int_tag_type_buffer: Type.Payload.Bits = undefined; |
| 6441 | 6434 | const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer); |
| 6442 | 6435 | |
| ... | ... | @@ -6444,118 +6437,120 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6444 | 6437 | return func.fail("TODO: Implement @tagName for enums with tag size larger than 64 bits", .{}); |
| 6445 | 6438 | } |
| 6446 | 6439 | |
| 6447 | | var func_type = try genFunctype(func.gpa, .Unspecified, &.{int_tag_ty}, slice_ty, func.target); |
| 6448 | | defer func_type.deinit(func.gpa); |
| 6449 | | try func.bin_file.storeDeclType(enum_decl_index, func_type); |
| 6440 | var relocs = std.ArrayList(link.File.Wasm.Relocation).init(func.gpa); |
| 6441 | defer relocs.deinit(); |
| 6450 | 6442 | |
| 6451 | | var body_list = std.ArrayList(u8).init(arena); |
| 6443 | var body_list = std.ArrayList(u8).init(func.gpa); |
| 6444 | defer body_list.deinit(); |
| 6452 | 6445 | var writer = body_list.writer(); |
| 6453 | 6446 | |
| 6454 | | // The locals of the function body (always 2) |
| 6455 | | try leb.writeULEB128(writer, @as(u32, 2)); |
| 6456 | | try leb.writeULEB128(writer, @as(u32, 1)); |
| 6457 | | try writer.writeByte(func.genValtype(slice_ty, func.target)); |
| 6458 | | try leb.writeULEB128(writer, @as(u32, 1)); |
| 6459 | | try writer.writeByte(func.genValtype(int_tag_ty, func.target)); |
| 6447 | // The locals of the function body (always 0) |
| 6448 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6460 | 6449 | |
| 6461 | 6450 | // outer block |
| 6462 | 6451 | try writer.writeByte(std.wasm.opcode(.block)); |
| 6452 | try writer.writeByte(std.wasm.block_empty); |
| 6463 | 6453 | |
| 6464 | 6454 | // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse. |
| 6465 | 6455 | // generate an if-else chain for each tag value as well as constant. |
| 6466 | 6456 | for (enum_ty.enumFields().keys(), 0..) |tag_name, field_index| { |
| 6467 | | // for each tag name, create an atom to store its name into, |
| 6457 | // for each tag name, create an unnamed const, |
| 6468 | 6458 | // and then get a pointer to its value. |
| 6469 | | const tag_atom_index = try func.bin_file.createAtom(); |
| 6470 | | const tag_atom = func.bin_file.getAtomPtr(tag_atom_index); |
| 6471 | | tag_atom.alignment = 1; |
| 6472 | | try func.bin_file.parseAtom(tag_atom_index, .read_only); |
| 6473 | | try tag_atom.code.appendSlice(func.gpa, tag_name); |
| 6459 | var name_ty_payload: Type.Payload.Len = .{ |
| 6460 | .base = .{ .tag = .array_u8 }, |
| 6461 | .data = @intCast(u64, tag_name.len), |
| 6462 | }; |
| 6463 | const name_ty = Type.initPayload(&name_ty_payload.base); |
| 6464 | var name_val_payload: Value.Payload.Bytes = .{ |
| 6465 | .base = .{ .tag = .bytes }, |
| 6466 | .data = tag_name, |
| 6467 | }; |
| 6468 | const name_val = Value.initPayload(&name_val_payload.base); |
| 6469 | const tag_sym_index = try func.bin_file.lowerUnnamedConst( |
| 6470 | .{ .ty = name_ty, .val = name_val }, |
| 6471 | enum_decl_index, |
| 6472 | ); |
| 6474 | 6473 | |
| 6475 | 6474 | // block for this if case |
| 6476 | 6475 | try writer.writeByte(std.wasm.opcode(.block)); |
| 6476 | try writer.writeByte(std.wasm.block_empty); |
| 6477 | 6477 | |
| 6478 | 6478 | // get actual tag value (stored in 2nd parameter); |
| 6479 | 6479 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6480 | 6480 | try leb.writeULEB128(writer, @as(u32, 1)); |
| 6481 | 6481 | |
| 6482 | | const tag_value = int: { |
| 6483 | | var tag_val_payload: Value.Payload.U32 = .{ |
| 6484 | | .base = .{ .tag = .enum_field_index }, |
| 6485 | | .data = @intCast(u32, field_index), |
| 6486 | | }; |
| 6487 | | break :int try func.lowerConstant(Value.initPayload(&tag_val_payload.base), enum_ty); |
| 6482 | var tag_val_payload: Value.Payload.U32 = .{ |
| 6483 | .base = .{ .tag = .enum_field_index }, |
| 6484 | .data = @intCast(u32, field_index), |
| 6488 | 6485 | }; |
| 6486 | const tag_value = try func.lowerConstant(Value.initPayload(&tag_val_payload.base), enum_ty); |
| 6489 | 6487 | |
| 6490 | 6488 | switch (tag_value) { |
| 6491 | 6489 | .imm32 => |value| { |
| 6492 | 6490 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 6493 | 6491 | try leb.writeULEB128(writer, value); |
| 6494 | | try writer.writeByte(std.wasm.opcode(.i32_neq)); |
| 6492 | try writer.writeByte(std.wasm.opcode(.i32_ne)); |
| 6495 | 6493 | }, |
| 6496 | 6494 | .imm64 => |value| { |
| 6497 | 6495 | try writer.writeByte(std.wasm.opcode(.i64_const)); |
| 6498 | 6496 | try leb.writeULEB128(writer, value); |
| 6499 | | try writer.writeByte(std.wasm.opcode(.i64_neq)); |
| 6497 | try writer.writeByte(std.wasm.opcode(.i64_ne)); |
| 6500 | 6498 | }, |
| 6501 | 6499 | else => unreachable, |
| 6502 | 6500 | } |
| 6503 | 6501 | // if they're not equal, break out of current branch |
| 6504 | 6502 | try writer.writeByte(std.wasm.opcode(.br_if)); |
| 6503 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6505 | 6504 | |
| 6506 | 6505 | // store the address of the tagname in the pointer field of the slice |
| 6506 | // get the address twice so we can also store the length. |
| 6507 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6508 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6507 | 6509 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6508 | 6510 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6509 | 6511 | |
| 6510 | | const is_wasm32 = func.arch() == .wasm32; |
| 6511 | 6512 | // get address of tagname and emit a relocation to it |
| 6512 | | { |
| 6513 | | if (is_wasm32) { |
| 6514 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 6515 | | var buf: [5]u8 = undefined; |
| 6516 | | leb.writeUnsignedFixed(5, &buf, mem.pointer); |
| 6517 | | try writer.writeAll(&buf); |
| 6518 | | } else { |
| 6519 | | try writer.writeByte(std.wasm.opcode(.i64_const)); |
| 6520 | | var buf: [10]u8 = undefined; |
| 6521 | | leb.writeUnsignedFixed(10, &buf, mem.pointer); |
| 6522 | | try writer.writeAll(&buf); |
| 6523 | | } |
| 6524 | | try func_atom.relocs.append(func.gpa, .{ |
| 6525 | | .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_LEB else .R_WASM_MEMORY_ADDR_LEB64, |
| 6513 | if (func.arch() == .wasm32) { |
| 6514 | const encoded_alignment = @ctz(@as(u32, 4)); |
| 6515 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 6516 | try relocs.append(.{ |
| 6517 | .relocation_type = .R_WASM_MEMORY_ADDR_LEB, |
| 6526 | 6518 | .offset = @intCast(u32, body_list.items.len), |
| 6527 | | .index = tag_atom.getSymbolIndex().?, |
| 6519 | .index = tag_sym_index, |
| 6528 | 6520 | }); |
| 6529 | | } |
| 6521 | try writer.writeAll(&[_]u8{0} ** 5); // will be relocated |
| 6530 | 6522 | |
| 6531 | | // call the actual store instructions |
| 6532 | | if (is_wasm32) { |
| 6533 | 6523 | // store pointer |
| 6534 | 6524 | try writer.writeByte(std.wasm.opcode(.i32_store)); |
| 6535 | | try leb.writeULEB128(writer, @as(u32, 4)); |
| 6525 | try leb.writeULEB128(writer, encoded_alignment); |
| 6536 | 6526 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6537 | 6527 | |
| 6538 | 6528 | // store length |
| 6539 | | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6540 | | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6541 | 6529 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 6542 | 6530 | try leb.writeULEB128(writer, @intCast(u32, tag_name.len)); |
| 6543 | 6531 | try writer.writeByte(std.wasm.opcode(.i32_store)); |
| 6544 | | try leb.writeULEB128(writer, @as(u32, 4)); |
| 6532 | try leb.writeULEB128(writer, encoded_alignment); |
| 6545 | 6533 | try leb.writeULEB128(writer, @as(u32, 4)); |
| 6546 | 6534 | } else { |
| 6535 | const encoded_alignment = @ctz(@as(u32, 8)); |
| 6536 | try writer.writeByte(std.wasm.opcode(.i64_const)); |
| 6537 | try relocs.append(.{ |
| 6538 | .relocation_type = .R_WASM_MEMORY_ADDR_LEB64, |
| 6539 | .offset = @intCast(u32, body_list.items.len), |
| 6540 | .index = tag_sym_index, |
| 6541 | }); |
| 6542 | try writer.writeAll(&[_]u8{0} ** 10); // will be relocated |
| 6543 | |
| 6547 | 6544 | // store pointer |
| 6548 | 6545 | try writer.writeByte(std.wasm.opcode(.i64_store)); |
| 6549 | | try leb.writeULEB128(writer, @as(u32, 8)); |
| 6546 | try leb.writeULEB128(writer, encoded_alignment); |
| 6550 | 6547 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6551 | 6548 | |
| 6552 | 6549 | // store length |
| 6553 | | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6554 | | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6555 | 6550 | try writer.writeByte(std.wasm.opcode(.i64_const)); |
| 6556 | 6551 | try leb.writeULEB128(writer, @intCast(u64, tag_name.len)); |
| 6557 | 6552 | try writer.writeByte(std.wasm.opcode(.i64_store)); |
| 6558 | | try leb.writeULEB128(writer, @as(u32, 8)); |
| 6553 | try leb.writeULEB128(writer, encoded_alignment); |
| 6559 | 6554 | try leb.writeULEB128(writer, @as(u32, 8)); |
| 6560 | 6555 | } |
| 6561 | 6556 | |
| ... | ... | @@ -6573,7 +6568,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6573 | 6568 | // finish function body |
| 6574 | 6569 | try writer.writeByte(std.wasm.opcode(.end)); |
| 6575 | 6570 | |
| 6576 | | try func_atom.code.appendSlice(func.gpa, body_list.items); |
| 6577 | | |
| 6578 | | return func_atom.sym_index; |
| 6571 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); |
| 6572 | const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty}, slice_ty, func.target); |
| 6573 | return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); |
| 6579 | 6574 | } |