| ... | @@ -6400,30 +6400,23 @@ fn callIntrinsic( | ... | @@ -6400,30 +6400,23 @@ fn callIntrinsic( |
| 6400 | fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6400 | fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6401 | const un_op = func.air.instructions.items(.data)[inst].un_op; | 6401 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 6402 | if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{un_op}); | 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 | const enum_ty = func.air.typeOf(un_op); | 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 | fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { | 6416 | fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6412 | const enum_decl_index = enum_ty.getOwnerDecl(); | 6417 | const enum_decl_index = enum_ty.getOwnerDecl(); |
| 6413 | const module = func.bin_file.base.options.module.?; | 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 | var arena_allocator = std.heap.ArenaAllocator.init(func.gpa); | 6420 | var arena_allocator = std.heap.ArenaAllocator.init(func.gpa); |
| 6428 | defer arena_allocator.deinit(); | 6421 | defer arena_allocator.deinit(); |
| 6429 | const arena = arena_allocator.allocator(); | 6422 | const arena = arena_allocator.allocator(); |
| ... | @@ -6432,11 +6425,11 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { | ... | @@ -6432,11 +6425,11 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6432 | defer module.gpa.free(fqn); | 6425 | defer module.gpa.free(fqn); |
| 6433 | const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); | 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 | if (func.bin_file.findGlobalSymbol(func_name)) |loc| { | 6429 | if (func.bin_file.findGlobalSymbol(func_name)) |loc| { |
| 6436 | return loc.index; | 6430 | return loc.index; |
| 6437 | } | 6431 | } |
| 6438 | | 6432 | |
| 6439 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | | |
| 6440 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | 6433 | var int_tag_type_buffer: Type.Payload.Bits = undefined; |
| 6441 | const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer); | 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,118 +6437,120 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6444 | return func.fail("TODO: Implement @tagName for enums with tag size larger than 64 bits", .{}); | 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); | 6440 | var relocs = std.ArrayList(link.File.Wasm.Relocation).init(func.gpa); |
| 6448 | defer func_type.deinit(func.gpa); | 6441 | defer relocs.deinit(); |
| 6449 | try func.bin_file.storeDeclType(enum_decl_index, func_type); | | |
| 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 | var writer = body_list.writer(); | 6445 | var writer = body_list.writer(); |
| 6453 | | 6446 | |
| 6454 | // The locals of the function body (always 2) | 6447 | // The locals of the function body (always 0) |
| 6455 | try leb.writeULEB128(writer, @as(u32, 2)); | 6448 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 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)); | | |
| 6460 | | 6449 | |
| 6461 | // outer block | 6450 | // outer block |
| 6462 | try writer.writeByte(std.wasm.opcode(.block)); | 6451 | try writer.writeByte(std.wasm.opcode(.block)); |
| | 6452 | try writer.writeByte(std.wasm.block_empty); |
| 6463 | | 6453 | |
| 6464 | // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse. | 6454 | // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse. |
| 6465 | // generate an if-else chain for each tag value as well as constant. | 6455 | // generate an if-else chain for each tag value as well as constant. |
| 6466 | for (enum_ty.enumFields().keys(), 0..) |tag_name, field_index| { | 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 | // and then get a pointer to its value. | 6458 | // and then get a pointer to its value. |
| 6469 | const tag_atom_index = try func.bin_file.createAtom(); | 6459 | var name_ty_payload: Type.Payload.Len = .{ |
| 6470 | const tag_atom = func.bin_file.getAtomPtr(tag_atom_index); | 6460 | .base = .{ .tag = .array_u8 }, |
| 6471 | tag_atom.alignment = 1; | 6461 | .data = @intCast(u64, tag_name.len), |
| 6472 | try func.bin_file.parseAtom(tag_atom_index, .read_only); | 6462 | }; |
| 6473 | try tag_atom.code.appendSlice(func.gpa, tag_name); | 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 | // block for this if case | 6474 | // block for this if case |
| 6476 | try writer.writeByte(std.wasm.opcode(.block)); | 6475 | try writer.writeByte(std.wasm.opcode(.block)); |
| | 6476 | try writer.writeByte(std.wasm.block_empty); |
| 6477 | | 6477 | |
| 6478 | // get actual tag value (stored in 2nd parameter); | 6478 | // get actual tag value (stored in 2nd parameter); |
| 6479 | try writer.writeByte(std.wasm.opcode(.local_get)); | 6479 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6480 | try leb.writeULEB128(writer, @as(u32, 1)); | 6480 | try leb.writeULEB128(writer, @as(u32, 1)); |
| 6481 | | 6481 | |
| 6482 | const tag_value = int: { | 6482 | var tag_val_payload: Value.Payload.U32 = .{ |
| 6483 | var tag_val_payload: Value.Payload.U32 = .{ | 6483 | .base = .{ .tag = .enum_field_index }, |
| 6484 | .base = .{ .tag = .enum_field_index }, | 6484 | .data = @intCast(u32, field_index), |
| 6485 | .data = @intCast(u32, field_index), | | |
| 6486 | }; | | |
| 6487 | break :int try func.lowerConstant(Value.initPayload(&tag_val_payload.base), enum_ty); | | |
| 6488 | }; | 6485 | }; |
| | 6486 | const tag_value = try func.lowerConstant(Value.initPayload(&tag_val_payload.base), enum_ty); |
| 6489 | | 6487 | |
| 6490 | switch (tag_value) { | 6488 | switch (tag_value) { |
| 6491 | .imm32 => |value| { | 6489 | .imm32 => |value| { |
| 6492 | try writer.writeByte(std.wasm.opcode(.i32_const)); | 6490 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 6493 | try leb.writeULEB128(writer, value); | 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 | .imm64 => |value| { | 6494 | .imm64 => |value| { |
| 6497 | try writer.writeByte(std.wasm.opcode(.i64_const)); | 6495 | try writer.writeByte(std.wasm.opcode(.i64_const)); |
| 6498 | try leb.writeULEB128(writer, value); | 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 | else => unreachable, | 6499 | else => unreachable, |
| 6502 | } | 6500 | } |
| 6503 | // if they're not equal, break out of current branch | 6501 | // if they're not equal, break out of current branch |
| 6504 | try writer.writeByte(std.wasm.opcode(.br_if)); | 6502 | try writer.writeByte(std.wasm.opcode(.br_if)); |
| | 6503 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6505 | | 6504 | |
| 6506 | // store the address of the tagname in the pointer field of the slice | 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 | try writer.writeByte(std.wasm.opcode(.local_get)); | 6509 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6508 | try leb.writeULEB128(writer, @as(u32, 0)); | 6510 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6509 | | 6511 | |
| 6510 | const is_wasm32 = func.arch() == .wasm32; | | |
| 6511 | // get address of tagname and emit a relocation to it | 6512 | // get address of tagname and emit a relocation to it |
| 6512 | { | 6513 | if (func.arch() == .wasm32) { |
| 6513 | if (is_wasm32) { | 6514 | const encoded_alignment = @ctz(@as(u32, 4)); |
| 6514 | try writer.writeByte(std.wasm.opcode(.i32_const)); | 6515 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 6515 | var buf: [5]u8 = undefined; | 6516 | try relocs.append(.{ |
| 6516 | leb.writeUnsignedFixed(5, &buf, mem.pointer); | 6517 | .relocation_type = .R_WASM_MEMORY_ADDR_LEB, |
| 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, | | |
| 6526 | .offset = @intCast(u32, body_list.items.len), | 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 | // store pointer | 6523 | // store pointer |
| 6534 | try writer.writeByte(std.wasm.opcode(.i32_store)); | 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 | try leb.writeULEB128(writer, @as(u32, 0)); | 6526 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6537 | | 6527 | |
| 6538 | // store length | 6528 | // store length |
| 6539 | try writer.writeByte(std.wasm.opcode(.local_get)); | | |
| 6540 | try leb.writeULEB128(writer, @as(u32, 0)); | | |
| 6541 | try writer.writeByte(std.wasm.opcode(.i32_const)); | 6529 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 6542 | try leb.writeULEB128(writer, @intCast(u32, tag_name.len)); | 6530 | try leb.writeULEB128(writer, @intCast(u32, tag_name.len)); |
| 6543 | try writer.writeByte(std.wasm.opcode(.i32_store)); | 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 | try leb.writeULEB128(writer, @as(u32, 4)); | 6533 | try leb.writeULEB128(writer, @as(u32, 4)); |
| 6546 | } else { | 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 | // store pointer | 6544 | // store pointer |
| 6548 | try writer.writeByte(std.wasm.opcode(.i64_store)); | 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 | try leb.writeULEB128(writer, @as(u32, 0)); | 6547 | try leb.writeULEB128(writer, @as(u32, 0)); |
| 6551 | | 6548 | |
| 6552 | // store length | 6549 | // store length |
| 6553 | try writer.writeByte(std.wasm.opcode(.local_get)); | | |
| 6554 | try leb.writeULEB128(writer, @as(u32, 0)); | | |
| 6555 | try writer.writeByte(std.wasm.opcode(.i64_const)); | 6550 | try writer.writeByte(std.wasm.opcode(.i64_const)); |
| 6556 | try leb.writeULEB128(writer, @intCast(u64, tag_name.len)); | 6551 | try leb.writeULEB128(writer, @intCast(u64, tag_name.len)); |
| 6557 | try writer.writeByte(std.wasm.opcode(.i64_store)); | 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 | try leb.writeULEB128(writer, @as(u32, 8)); | 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,7 +6568,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6573 | // finish function body | 6568 | // finish function body |
| 6574 | try writer.writeByte(std.wasm.opcode(.end)); | 6569 | try writer.writeByte(std.wasm.opcode(.end)); |
| 6575 | | 6570 | |
| 6576 | try func_atom.code.appendSlice(func.gpa, body_list.items); | 6571 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); |
| 6577 | | 6572 | const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty}, slice_ty, func.target); |
| 6578 | return func_atom.sym_index; | 6573 | return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); |
| 6579 | } | 6574 | } |