| ... | @@ -453,7 +453,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -453,7 +453,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 453 | .bitcast => @panic("TODO try self.airBitCast(inst)"), | 453 | .bitcast => @panic("TODO try self.airBitCast(inst)"), |
| 454 | .block => try self.airBlock(inst), | 454 | .block => try self.airBlock(inst), |
| 455 | .br => @panic("TODO try self.airBr(inst)"), | 455 | .br => @panic("TODO try self.airBr(inst)"), |
| 456 | .breakpoint => @panic("TODO try self.airBreakpoint()"), | 456 | .breakpoint => try self.airBreakpoint(), |
| 457 | .ret_addr => @panic("TODO try self.airRetAddr(inst)"), | 457 | .ret_addr => @panic("TODO try self.airRetAddr(inst)"), |
| 458 | .frame_addr => @panic("TODO try self.airFrameAddress(inst)"), | 458 | .frame_addr => @panic("TODO try self.airFrameAddress(inst)"), |
| 459 | .fence => @panic("TODO try self.airFence()"), | 459 | .fence => @panic("TODO try self.airFence()"), |
| ... | @@ -476,7 +476,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -476,7 +476,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 476 | .loop => @panic("TODO try self.airLoop(inst)"), | 476 | .loop => @panic("TODO try self.airLoop(inst)"), |
| 477 | .not => @panic("TODO try self.airNot(inst)"), | 477 | .not => @panic("TODO try self.airNot(inst)"), |
| 478 | .ptrtoint => @panic("TODO try self.airPtrToInt(inst)"), | 478 | .ptrtoint => @panic("TODO try self.airPtrToInt(inst)"), |
| 479 | .ret => @panic("TODO try self.airRet(inst)"), | 479 | .ret => try self.airRet(inst), |
| 480 | .ret_load => try self.airRetLoad(inst), | 480 | .ret_load => try self.airRetLoad(inst), |
| 481 | .store => try self.airStore(inst), | 481 | .store => try self.airStore(inst), |
| 482 | .struct_field_ptr=> @panic("TODO try self.airStructFieldPtr(inst)"), | 482 | .struct_field_ptr=> @panic("TODO try self.airStructFieldPtr(inst)"), |
| ... | @@ -667,6 +667,21 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -667,6 +667,21 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 667 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 667 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 668 | } | 668 | } |
| 669 | | 669 | |
| | 670 | fn airBreakpoint(self: *Self) !void { |
| | 671 | // ta 0x01 |
| | 672 | _ = try self.addInst(.{ |
| | 673 | .tag = .tcc, |
| | 674 | .data = .{ |
| | 675 | .trap = .{ |
| | 676 | .is_imm = true, |
| | 677 | .cond = 0b1000, // TODO need to look into changing this into an enum |
| | 678 | .rs2_or_imm = .{ .imm = 0x01 }, |
| | 679 | }, |
| | 680 | }, |
| | 681 | }); |
| | 682 | return self.finishAirBookkeeping(); |
| | 683 | } |
| | 684 | |
| 670 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void { | 685 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void { |
| 671 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch}); | 686 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch}); |
| 672 | | 687 | |
| ... | @@ -695,10 +710,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -695,10 +710,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 695 | .unreach => unreachable, | 710 | .unreach => unreachable, |
| 696 | .dead => unreachable, | 711 | .dead => unreachable, |
| 697 | .memory => unreachable, | 712 | .memory => unreachable, |
| 698 | .compare_flags_signed => unreachable, | | |
| 699 | .compare_flags_unsigned => unreachable, | | |
| 700 | .got_load => unreachable, | | |
| 701 | .direct_load => unreachable, | | |
| 702 | .register => |reg| { | 713 | .register => |reg| { |
| 703 | try self.register_manager.getReg(reg, null); | 714 | try self.register_manager.getReg(reg, null); |
| 704 | try self.genSetReg(arg_ty, reg, arg_mcv); | 715 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| ... | @@ -712,6 +723,44 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -712,6 +723,44 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 712 | } | 723 | } |
| 713 | } | 724 | } |
| 714 | | 725 | |
| | 726 | // Due to incremental compilation, how function calls are generated depends |
| | 727 | // on linking. |
| | 728 | if (self.air.value(callee)) |func_value| { |
| | 729 | if (self.bin_file.tag == link.File.Elf.base_tag) { |
| | 730 | if (func_value.castTag(.function)) |func_payload| { |
| | 731 | const func = func_payload.data; |
| | 732 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| | 733 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| | 734 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| | 735 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; |
| | 736 | break :blk @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); |
| | 737 | } else unreachable; |
| | 738 | |
| | 739 | try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr }); |
| | 740 | |
| | 741 | _ = try self.addInst(.{ |
| | 742 | .tag = .jmpl, |
| | 743 | .data = .{ .branch_link_indirect = .{ .reg = .o7 } }, |
| | 744 | }); |
| | 745 | } else if (func_value.castTag(.extern_fn)) |_| { |
| | 746 | return self.fail("TODO implement calling extern functions", .{}); |
| | 747 | } else { |
| | 748 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| | 749 | } |
| | 750 | } else @panic("TODO SPARCv9 currently does not support non-ELF binaries"); |
| | 751 | } else { |
| | 752 | assert(ty.zigTypeTag() == .Pointer); |
| | 753 | const mcv = try self.resolveInst(callee); |
| | 754 | try self.genSetReg(ty, .o7, mcv); |
| | 755 | |
| | 756 | _ = try self.addInst(.{ |
| | 757 | .tag = .jmpl, |
| | 758 | .data = .{ .branch_link_indirect = .{ .reg = .o7 } }, |
| | 759 | }); |
| | 760 | } |
| | 761 | |
| | 762 | // TODO handle return value |
| | 763 | |
| 715 | return self.fail("TODO implement call for {}", .{self.target.cpu.arch}); | 764 | return self.fail("TODO implement call for {}", .{self.target.cpu.arch}); |
| 716 | } | 765 | } |
| 717 | | 766 | |
| ... | @@ -759,8 +808,17 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -759,8 +808,17 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 759 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 808 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 760 | } | 809 | } |
| 761 | | 810 | |
| | 811 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| | 812 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 813 | const operand = try self.resolveInst(un_op); |
| | 814 | try self.ret(operand); |
| | 815 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| | 816 | } |
| | 817 | |
| 762 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | 818 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 763 | _ = inst; | 819 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 820 | const ptr = try self.resolveInst(un_op); |
| | 821 | _ = ptr; |
| 764 | return self.fail("TODO implement airRetLoad for {}", .{self.target.cpu.arch}); | 822 | return self.fail("TODO implement airRetLoad for {}", .{self.target.cpu.arch}); |
| 765 | //return self.finishAir(inst, .dead, .{ un_op, .none, .none }); | 823 | //return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 766 | } | 824 | } |
| ... | @@ -832,6 +890,37 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | ... | @@ -832,6 +890,37 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 832 | return self.allocMem(inst, abi_size, abi_align); | 890 | return self.allocMem(inst, abi_size, abi_align); |
| 833 | } | 891 | } |
| 834 | | 892 | |
| | 893 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| | 894 | const elem_ty = self.air.typeOfIndex(inst); |
| | 895 | const target = self.target.*; |
| | 896 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { |
| | 897 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(target)}); |
| | 898 | }; |
| | 899 | const abi_align = elem_ty.abiAlignment(self.target.*); |
| | 900 | if (abi_align > self.stack_align) |
| | 901 | self.stack_align = abi_align; |
| | 902 | |
| | 903 | if (reg_ok) { |
| | 904 | // Make sure the type can fit in a register before we try to allocate one. |
| | 905 | if (abi_size <= 8) { |
| | 906 | if (self.register_manager.tryAllocReg(inst)) |reg| { |
| | 907 | return MCValue{ .register = reg }; |
| | 908 | } |
| | 909 | } |
| | 910 | } |
| | 911 | const stack_offset = try self.allocMem(inst, abi_size, abi_align); |
| | 912 | return MCValue{ .stack_offset = stack_offset }; |
| | 913 | } |
| | 914 | |
| | 915 | /// Copies a value to a register without tracking the register. The register is not considered |
| | 916 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| | 917 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| | 918 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| | 919 | const reg = try self.register_manager.allocReg(null); |
| | 920 | try self.genSetReg(ty, reg, mcv); |
| | 921 | return reg; |
| | 922 | } |
| | 923 | |
| 835 | fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | 924 | fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 836 | const table = &self.branch_stack.items[self.branch_stack.items.len - 1].inst_table; | 925 | const table = &self.branch_stack.items[self.branch_stack.items.len - 1].inst_table; |
| 837 | try table.ensureUnusedCapacity(self.gpa, additional_count); | 926 | try table.ensureUnusedCapacity(self.gpa, additional_count); |
| ... | @@ -885,37 +974,216 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -885,37 +974,216 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 885 | self.finishAirBookkeeping(); | 974 | self.finishAirBookkeeping(); |
| 886 | } | 975 | } |
| 887 | | 976 | |
| | 977 | fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, off: i13, abi_size: u64) !void { |
| | 978 | _ = value_reg; |
| | 979 | _ = addr_reg; |
| | 980 | _ = off; |
| | 981 | |
| | 982 | switch (abi_size) { |
| | 983 | 1, 2, 4, 8 => return self.fail("TODO: A.27 Load Integer", .{}), |
| | 984 | 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), |
| | 985 | else => unreachable, |
| | 986 | } |
| | 987 | } |
| | 988 | |
| | 989 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| | 990 | switch (mcv) { |
| | 991 | .dead => unreachable, |
| | 992 | .unreach, .none => return, // Nothing to do. |
| | 993 | .undef => { |
| | 994 | if (!self.wantSafety()) |
| | 995 | return; // The already existing value will do just fine. |
| | 996 | // Write the debug undefined value. |
| | 997 | return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); |
| | 998 | }, |
| | 999 | .ptr_stack_offset => |off| { |
| | 1000 | const simm13 = math.cast(u12, off) catch |
| | 1001 | return self.fail("TODO larger stack offsets", .{}); |
| | 1002 | |
| | 1003 | _ = try self.addInst(.{ |
| | 1004 | .tag = .add, |
| | 1005 | .data = .{ |
| | 1006 | .arithmetic_3op = .{ |
| | 1007 | .is_imm = true, |
| | 1008 | .rd = reg, |
| | 1009 | .rs1 = .sp, |
| | 1010 | .rs2_or_imm = .{ .imm = simm13 }, |
| | 1011 | }, |
| | 1012 | }, |
| | 1013 | }); |
| | 1014 | }, |
| | 1015 | .immediate => |x| { |
| | 1016 | if (x <= math.maxInt(u12)) { |
| | 1017 | _ = try self.addInst(.{ |
| | 1018 | .tag = .@"or", |
| | 1019 | .data = .{ |
| | 1020 | .arithmetic_3op = .{ |
| | 1021 | .is_imm = true, |
| | 1022 | .rd = reg, |
| | 1023 | .rs1 = .g0, |
| | 1024 | .rs2_or_imm = .{ .imm = @truncate(u12, x) }, |
| | 1025 | }, |
| | 1026 | }, |
| | 1027 | }); |
| | 1028 | } else if (x <= math.maxInt(u32)) { |
| | 1029 | _ = try self.addInst(.{ |
| | 1030 | .tag = .sethi, |
| | 1031 | .data = .{ |
| | 1032 | .sethi = .{ |
| | 1033 | .rd = reg, |
| | 1034 | .imm = @truncate(u22, x >> 10), |
| | 1035 | }, |
| | 1036 | }, |
| | 1037 | }); |
| | 1038 | |
| | 1039 | _ = try self.addInst(.{ |
| | 1040 | .tag = .@"or", |
| | 1041 | .data = .{ |
| | 1042 | .arithmetic_3op = .{ |
| | 1043 | .is_imm = true, |
| | 1044 | .rd = reg, |
| | 1045 | .rs1 = reg, |
| | 1046 | .rs2_or_imm = .{ .imm = @truncate(u10, x) }, |
| | 1047 | }, |
| | 1048 | }, |
| | 1049 | }); |
| | 1050 | } else if (x <= math.maxInt(u44)) { |
| | 1051 | try self.genSetReg(ty, reg, .{ .immediate = @truncate(u32, x >> 12) }); |
| | 1052 | |
| | 1053 | _ = try self.addInst(.{ |
| | 1054 | .tag = .sllx, |
| | 1055 | .data = .{ |
| | 1056 | .shift = .{ |
| | 1057 | .is_imm = true, |
| | 1058 | .width = .shift64, |
| | 1059 | .rd = reg, |
| | 1060 | .rs1 = reg, |
| | 1061 | .rs2_or_imm = .{ .imm = 12 }, |
| | 1062 | }, |
| | 1063 | }, |
| | 1064 | }); |
| | 1065 | |
| | 1066 | _ = try self.addInst(.{ |
| | 1067 | .tag = .@"or", |
| | 1068 | .data = .{ |
| | 1069 | .arithmetic_3op = .{ |
| | 1070 | .is_imm = true, |
| | 1071 | .rd = reg, |
| | 1072 | .rs1 = reg, |
| | 1073 | .rs2_or_imm = .{ .imm = @truncate(u12, x) }, |
| | 1074 | }, |
| | 1075 | }, |
| | 1076 | }); |
| | 1077 | } else { |
| | 1078 | // Need to allocate a temporary register to load 64-bit immediates. |
| | 1079 | const tmp_reg = try self.register_manager.allocReg(null); |
| | 1080 | |
| | 1081 | try self.genSetReg(ty, tmp_reg, .{ .immediate = @truncate(u32, x) }); |
| | 1082 | try self.genSetReg(ty, reg, .{ .immediate = @truncate(u32, x >> 32) }); |
| | 1083 | |
| | 1084 | _ = try self.addInst(.{ |
| | 1085 | .tag = .sllx, |
| | 1086 | .data = .{ |
| | 1087 | .shift = .{ |
| | 1088 | .is_imm = true, |
| | 1089 | .width = .shift64, |
| | 1090 | .rd = reg, |
| | 1091 | .rs1 = reg, |
| | 1092 | .rs2_or_imm = .{ .imm = 32 }, |
| | 1093 | }, |
| | 1094 | }, |
| | 1095 | }); |
| | 1096 | |
| | 1097 | _ = try self.addInst(.{ |
| | 1098 | .tag = .@"or", |
| | 1099 | .data = .{ |
| | 1100 | .arithmetic_3op = .{ |
| | 1101 | .is_imm = false, |
| | 1102 | .rd = reg, |
| | 1103 | .rs1 = reg, |
| | 1104 | .rs2_or_imm = .{ .rs2 = tmp_reg }, |
| | 1105 | }, |
| | 1106 | }, |
| | 1107 | }); |
| | 1108 | } |
| | 1109 | }, |
| | 1110 | .register => |src_reg| { |
| | 1111 | // If the registers are the same, nothing to do. |
| | 1112 | if (src_reg.id() == reg.id()) |
| | 1113 | return; |
| | 1114 | |
| | 1115 | // or %g0, src, dst (aka mov src, dst) |
| | 1116 | _ = try self.addInst(.{ |
| | 1117 | .tag = .@"or", |
| | 1118 | .data = .{ |
| | 1119 | .arithmetic_3op = .{ |
| | 1120 | .is_imm = false, |
| | 1121 | .rd = reg, |
| | 1122 | .rs1 = .g0, |
| | 1123 | .rs2_or_imm = .{ .rs2 = src_reg }, |
| | 1124 | }, |
| | 1125 | }, |
| | 1126 | }); |
| | 1127 | }, |
| | 1128 | .memory => |addr| { |
| | 1129 | // The value is in memory at a hard-coded address. |
| | 1130 | // If the type is a pointer, it means the pointer address is at this memory location. |
| | 1131 | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| | 1132 | try self.genLoad(reg, reg, 0, ty.abiSize(self.target.*)); |
| | 1133 | }, |
| | 1134 | .stack_offset => |off| { |
| | 1135 | const simm13 = math.cast(u12, off) catch |
| | 1136 | return self.fail("TODO larger stack offsets", .{}); |
| | 1137 | try self.genLoad(reg, .sp, simm13, ty.abiSize(self.target.*)); |
| | 1138 | }, |
| | 1139 | } |
| | 1140 | } |
| | 1141 | |
| | 1142 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| | 1143 | const abi_size = ty.abiSize(self.target.*); |
| | 1144 | switch (mcv) { |
| | 1145 | .dead => unreachable, |
| | 1146 | .unreach, .none => return, // Nothing to do. |
| | 1147 | .undef => { |
| | 1148 | if (!self.wantSafety()) |
| | 1149 | return; // The already existing value will do just fine. |
| | 1150 | // TODO Upgrade this to a memset call when we have that available. |
| | 1151 | switch (ty.abiSize(self.target.*)) { |
| | 1152 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| | 1153 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| | 1154 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| | 1155 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| | 1156 | else => return self.fail("TODO implement memset", .{}), |
| | 1157 | } |
| | 1158 | }, |
| | 1159 | .immediate, |
| | 1160 | .ptr_stack_offset, |
| | 1161 | => { |
| | 1162 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 1163 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| | 1164 | }, |
| | 1165 | .register => return self.fail("TODO implement storing types abi_size={}", .{abi_size}), |
| | 1166 | .memory, .stack_offset => return self.fail("TODO implement memcpy", .{}), |
| | 1167 | } |
| | 1168 | } |
| | 1169 | |
| 888 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | 1170 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 889 | if (typed_value.val.isUndef()) | 1171 | if (typed_value.val.isUndef()) |
| 890 | return MCValue{ .undef = {} }; | 1172 | return MCValue{ .undef = {} }; |
| 891 | | 1173 | |
| 892 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 1174 | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 893 | return self.lowerDeclRef(typed_value, payload.data); | 1175 | _ = payload; |
| | 1176 | return self.fail("TODO implement lowerDeclRef", .{}); |
| | 1177 | // return self.lowerDeclRef(typed_value, payload.data); |
| 894 | } | 1178 | } |
| 895 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | 1179 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { |
| 896 | return self.lowerDeclRef(typed_value, payload.data.decl); | 1180 | _ = payload; |
| | 1181 | return self.fail("TODO implement lowerDeclRef", .{}); |
| | 1182 | // return self.lowerDeclRef(typed_value, payload.data.decl); |
| 897 | } | 1183 | } |
| 898 | const target = self.target.*; | 1184 | const target = self.target.*; |
| 899 | | 1185 | |
| 900 | switch (typed_value.ty.zigTypeTag()) { | 1186 | switch (typed_value.ty.zigTypeTag()) { |
| 901 | .Pointer => switch (typed_value.ty.ptrSize()) { | | |
| 902 | .Slice => { | | |
| 903 | return self.lowerUnnamedConst(typed_value); | | |
| 904 | }, | | |
| 905 | else => { | | |
| 906 | switch (typed_value.val.tag()) { | | |
| 907 | .int_u64 => { | | |
| 908 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | | |
| 909 | }, | | |
| 910 | .slice => { | | |
| 911 | return self.lowerUnnamedConst(typed_value); | | |
| 912 | }, | | |
| 913 | else => { | | |
| 914 | return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()}); | | |
| 915 | }, | | |
| 916 | } | | |
| 917 | }, | | |
| 918 | }, | | |
| 919 | .Int => { | 1187 | .Int => { |
| 920 | const info = typed_value.ty.intInfo(self.target.*); | 1188 | const info = typed_value.ty.intInfo(self.target.*); |
| 921 | if (info.bits <= 64) { | 1189 | if (info.bits <= 64) { |
| ... | @@ -929,83 +1197,11 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -929,83 +1197,11 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 929 | | 1197 | |
| 930 | return MCValue{ .immediate = unsigned }; | 1198 | return MCValue{ .immediate = unsigned }; |
| 931 | } else { | 1199 | } else { |
| 932 | return self.lowerUnnamedConst(typed_value); | 1200 | return self.fail("TODO implement int genTypedValue of > 64 bits", .{}); |
| 933 | } | 1201 | } |
| 934 | }, | 1202 | }, |
| 935 | .Bool => { | | |
| 936 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | | |
| 937 | }, | | |
| 938 | .ComptimeInt => unreachable, // semantic analysis prevents this | 1203 | .ComptimeInt => unreachable, // semantic analysis prevents this |
| 939 | .ComptimeFloat => unreachable, // semantic analysis prevents this | 1204 | .ComptimeFloat => unreachable, // semantic analysis prevents this |
| 940 | .Optional => { | | |
| 941 | if (typed_value.ty.isPtrLikeOptional()) { | | |
| 942 | if (typed_value.val.isNull()) | | |
| 943 | return MCValue{ .immediate = 0 }; | | |
| 944 | | | |
| 945 | var buf: Type.Payload.ElemType = undefined; | | |
| 946 | return self.genTypedValue(.{ | | |
| 947 | .ty = typed_value.ty.optionalChild(&buf), | | |
| 948 | .val = typed_value.val, | | |
| 949 | }); | | |
| 950 | } else if (typed_value.ty.abiSize(self.target.*) == 1) { | | |
| 951 | return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; | | |
| 952 | } | | |
| 953 | return self.fail("TODO non pointer optionals", .{}); | | |
| 954 | }, | | |
| 955 | .Enum => { | | |
| 956 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | | |
| 957 | switch (typed_value.ty.tag()) { | | |
| 958 | .enum_simple => { | | |
| 959 | return MCValue{ .immediate = field_index.data }; | | |
| 960 | }, | | |
| 961 | .enum_full, .enum_nonexhaustive => { | | |
| 962 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | | |
| 963 | if (enum_full.values.count() != 0) { | | |
| 964 | const tag_val = enum_full.values.keys()[field_index.data]; | | |
| 965 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | | |
| 966 | } else { | | |
| 967 | return MCValue{ .immediate = field_index.data }; | | |
| 968 | } | | |
| 969 | }, | | |
| 970 | else => unreachable, | | |
| 971 | } | | |
| 972 | } else { | | |
| 973 | var int_tag_buffer: Type.Payload.Bits = undefined; | | |
| 974 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | | |
| 975 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); | | |
| 976 | } | | |
| 977 | }, | | |
| 978 | .ErrorSet => { | | |
| 979 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | | |
| 980 | const module = self.bin_file.options.module.?; | | |
| 981 | const global_error_set = module.global_error_set; | | |
| 982 | const error_index = global_error_set.get(err_name).?; | | |
| 983 | return MCValue{ .immediate = error_index }; | | |
| 984 | }, | | |
| 985 | .ErrorUnion => { | | |
| 986 | const error_type = typed_value.ty.errorUnionSet(); | | |
| 987 | const payload_type = typed_value.ty.errorUnionPayload(); | | |
| 988 | | | |
| 989 | if (typed_value.val.castTag(.eu_payload)) |pl| { | | |
| 990 | if (!payload_type.hasRuntimeBits()) { | | |
| 991 | // We use the error type directly as the type. | | |
| 992 | return MCValue{ .immediate = 0 }; | | |
| 993 | } | | |
| 994 | | | |
| 995 | _ = pl; | | |
| 996 | return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty.fmtDebug()}); | | |
| 997 | } else { | | |
| 998 | if (!payload_type.hasRuntimeBits()) { | | |
| 999 | // We use the error type directly as the type. | | |
| 1000 | return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); | | |
| 1001 | } | | |
| 1002 | | | |
| 1003 | return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty.fmtDebug()}); | | |
| 1004 | } | | |
| 1005 | }, | | |
| 1006 | .Struct => { | | |
| 1007 | return self.lowerUnnamedConst(typed_value); | | |
| 1008 | }, | | |
| 1009 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), | 1205 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), |
| 1010 | } | 1206 | } |
| 1011 | } | 1207 | } |
| ... | @@ -1171,6 +1367,18 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | ... | @@ -1171,6 +1367,18 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 1171 | } | 1367 | } |
| 1172 | } | 1368 | } |
| 1173 | | 1369 | |
| | 1370 | fn ret(self: *Self, mcv: MCValue) !void { |
| | 1371 | const ret_ty = self.fn_type.fnReturnType(); |
| | 1372 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| | 1373 | |
| | 1374 | // Just add space for an instruction, patch this later |
| | 1375 | const index = try self.addInst(.{ |
| | 1376 | .tag = .nop, |
| | 1377 | .data = .{ .nop = {} }, |
| | 1378 | }); |
| | 1379 | try self.exitlude_jump_relocs.append(self.gpa, index); |
| | 1380 | } |
| | 1381 | |
| 1174 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { | 1382 | fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { |
| 1175 | if (!self.liveness.operandDies(inst, op_index)) | 1383 | if (!self.liveness.operandDies(inst, op_index)) |
| 1176 | return false; | 1384 | return false; |
| ... | @@ -1201,3 +1409,36 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind | ... | @@ -1201,3 +1409,36 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind |
| 1201 | | 1409 | |
| 1202 | return true; | 1410 | return true; |
| 1203 | } | 1411 | } |
| | 1412 | |
| | 1413 | /// Sets the value without any modifications to register allocation metadata or stack allocation metadata. |
| | 1414 | fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { |
| | 1415 | switch (loc) { |
| | 1416 | .none => return, |
| | 1417 | .register => |reg| return self.genSetReg(ty, reg, val), |
| | 1418 | .stack_offset => |off| return self.genSetStack(ty, off, val), |
| | 1419 | .memory => { |
| | 1420 | return self.fail("TODO implement setRegOrMem for memory", .{}); |
| | 1421 | }, |
| | 1422 | else => unreachable, |
| | 1423 | } |
| | 1424 | } |
| | 1425 | |
| | 1426 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| | 1427 | const stack_mcv = try self.allocRegOrMem(inst, false); |
| | 1428 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); |
| | 1429 | const reg_mcv = self.getResolvedInstValue(inst); |
| | 1430 | assert(reg == reg_mcv.register); |
| | 1431 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| | 1432 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| | 1433 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); |
| | 1434 | } |
| | 1435 | |
| | 1436 | /// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`. |
| | 1437 | fn wantSafety(self: *Self) bool { |
| | 1438 | return switch (self.bin_file.options.optimize_mode) { |
| | 1439 | .Debug => true, |
| | 1440 | .ReleaseSafe => true, |
| | 1441 | .ReleaseFast => false, |
| | 1442 | .ReleaseSmall => false, |
| | 1443 | }; |
| | 1444 | } |