| ... | @@ -105,9 +105,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, | ... | @@ -105,9 +105,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, |
| 105 | const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; | 105 | const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; |
| 106 | | 106 | |
| 107 | const MCValue = union(enum) { | 107 | const MCValue = union(enum) { |
| 108 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. | 108 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 |
| 109 | /// TODO Look into deleting this tag and using `dead` instead, since every use | 109 | /// tag, etc. |
| 110 | /// of MCValue.none should be instead looking at the type and noticing it is 0 bits. | 110 | /// |
| | 111 | /// TODO Look into deleting this tag and using `dead` instead, |
| | 112 | /// since every use of MCValue.none should be instead looking at |
| | 113 | /// the type and noticing it is 0 bits. |
| 111 | none, | 114 | none, |
| 112 | /// Control flow will not allow this value to be observed. | 115 | /// Control flow will not allow this value to be observed. |
| 113 | unreach, | 116 | unreach, |
| ... | @@ -116,20 +119,41 @@ const MCValue = union(enum) { | ... | @@ -116,20 +119,41 @@ const MCValue = union(enum) { |
| 116 | /// The value is undefined. | 119 | /// The value is undefined. |
| 117 | undef, | 120 | undef, |
| 118 | /// A pointer-sized integer that fits in a register. | 121 | /// A pointer-sized integer that fits in a register. |
| 119 | /// If the type is a pointer, this is the pointer address in virtual address space. | 122 | /// |
| | 123 | /// If the type is a pointer, this is the pointer address in |
| | 124 | /// virtual address space. |
| 120 | immediate: u32, | 125 | immediate: u32, |
| 121 | /// The value is in a target-specific register. | 126 | /// The value is in a target-specific register. |
| 122 | register: Register, | 127 | register: Register, |
| | 128 | /// The value is a tuple { wrapped: u32, overflow: u1 } where |
| | 129 | /// wrapped is stored in the register and the overflow bit is |
| | 130 | /// stored in the C flag of the CPSR. |
| | 131 | /// |
| | 132 | /// This MCValue is only generated by a add_with_overflow or |
| | 133 | /// sub_with_overflow instruction operating on u32. |
| | 134 | register_c_flag: Register, |
| | 135 | /// The value is a tuple { wrapped: i32, overflow: u1 } where |
| | 136 | /// wrapped is stored in the register and the overflow bit is |
| | 137 | /// stored in the V flag of the CPSR. |
| | 138 | /// |
| | 139 | /// This MCValue is only generated by a add_with_overflow or |
| | 140 | /// sub_with_overflow instruction operating on i32. |
| | 141 | register_v_flag: Register, |
| 123 | /// The value is in memory at a hard-coded address. | 142 | /// The value is in memory at a hard-coded address. |
| 124 | /// If the type is a pointer, it means the pointer address is at this memory location. | 143 | /// |
| | 144 | /// If the type is a pointer, it means the pointer address is at |
| | 145 | /// this memory location. |
| 125 | memory: u64, | 146 | memory: u64, |
| 126 | /// The value is one of the stack variables. | 147 | /// The value is one of the stack variables. |
| 127 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. | 148 | /// |
| | 149 | /// If the type is a pointer, it means the pointer address is in |
| | 150 | /// the stack at this offset. |
| 128 | stack_offset: u32, | 151 | stack_offset: u32, |
| 129 | /// The value is a pointer to one of the stack variables (payload is stack offset). | 152 | /// The value is a pointer to one of the stack variables (payload |
| | 153 | /// is stack offset). |
| 130 | ptr_stack_offset: u32, | 154 | ptr_stack_offset: u32, |
| 131 | /// The value is in the compare flags assuming an unsigned operation, | 155 | /// The value is in the compare flags assuming an unsigned |
| 132 | /// with this operator applied on top of it. | 156 | /// operation, with this operator applied on top of it. |
| 133 | compare_flags_unsigned: math.CompareOperator, | 157 | compare_flags_unsigned: math.CompareOperator, |
| 134 | /// The value is in the compare flags assuming a signed operation, | 158 | /// The value is in the compare flags assuming a signed operation, |
| 135 | /// with this operator applied on top of it. | 159 | /// with this operator applied on top of it. |
| ... | @@ -554,8 +578,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -554,8 +578,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 554 | .trunc_float, | 578 | .trunc_float, |
| 555 | => try self.airUnaryMath(inst), | 579 | => try self.airUnaryMath(inst), |
| 556 | | 580 | |
| 557 | .add_with_overflow => try self.airAddWithOverflow(inst), | 581 | .add_with_overflow => try self.airOverflow(inst), |
| 558 | .sub_with_overflow => try self.airSubWithOverflow(inst), | 582 | .sub_with_overflow => try self.airOverflow(inst), |
| 559 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 583 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 560 | .shl_with_overflow => try self.airShlWithOverflow(inst), | 584 | .shl_with_overflow => try self.airShlWithOverflow(inst), |
| 561 | | 585 | |
| ... | @@ -726,6 +750,12 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -726,6 +750,12 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 726 | .register => |reg| { | 750 | .register => |reg| { |
| 727 | self.register_manager.freeReg(reg); | 751 | self.register_manager.freeReg(reg); |
| 728 | }, | 752 | }, |
| | 753 | .register_c_flag, |
| | 754 | .register_v_flag, |
| | 755 | => |reg| { |
| | 756 | self.register_manager.freeReg(reg); |
| | 757 | self.compare_flags_inst = null; |
| | 758 | }, |
| 729 | .compare_flags_signed, .compare_flags_unsigned => { | 759 | .compare_flags_signed, .compare_flags_unsigned => { |
| 730 | self.compare_flags_inst = null; | 760 | self.compare_flags_inst = null; |
| 731 | }, | 761 | }, |
| ... | @@ -841,8 +871,16 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -841,8 +871,16 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 841 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { | 871 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 842 | const stack_mcv = try self.allocRegOrMem(inst, false); | 872 | const stack_mcv = try self.allocRegOrMem(inst, false); |
| 843 | log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv }); | 873 | log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv }); |
| | 874 | |
| 844 | const reg_mcv = self.getResolvedInstValue(inst); | 875 | const reg_mcv = self.getResolvedInstValue(inst); |
| 845 | assert(reg == reg_mcv.register); | 876 | switch (reg_mcv) { |
| | 877 | .register, |
| | 878 | .register_c_flag, |
| | 879 | .register_v_flag, |
| | 880 | => |r| assert(r == reg), |
| | 881 | else => unreachable, // not a register |
| | 882 | } |
| | 883 | |
| 846 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 884 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 847 | try branch.inst_table.put(self.gpa, inst, stack_mcv); | 885 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 848 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); | 886 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); |
| ... | @@ -853,7 +891,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -853,7 +891,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 853 | fn spillCompareFlagsIfOccupied(self: *Self) !void { | 891 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 854 | if (self.compare_flags_inst) |inst_to_save| { | 892 | if (self.compare_flags_inst) |inst_to_save| { |
| 855 | const mcv = self.getResolvedInstValue(inst_to_save); | 893 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 856 | assert(mcv == .compare_flags_signed or mcv == .compare_flags_unsigned); | 894 | switch (mcv) { |
| | 895 | .compare_flags_signed, |
| | 896 | .compare_flags_unsigned, |
| | 897 | .register_c_flag, |
| | 898 | .register_v_flag, |
| | 899 | => {}, |
| | 900 | else => unreachable, // mcv doesn't occupy the compare flags |
| | 901 | } |
| 857 | | 902 | |
| 858 | const new_mcv = try self.allocRegOrMem(inst_to_save, true); | 903 | const new_mcv = try self.allocRegOrMem(inst_to_save, true); |
| 859 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); | 904 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); |
| ... | @@ -1268,7 +1313,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1268,7 +1313,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1268 | const len = try self.resolveInst(bin_op.rhs); | 1313 | const len = try self.resolveInst(bin_op.rhs); |
| 1269 | const len_ty = self.air.typeOf(bin_op.rhs); | 1314 | const len_ty = self.air.typeOf(bin_op.rhs); |
| 1270 | | 1315 | |
| 1271 | const stack_offset = try self.allocMem(inst, 8, 8); | 1316 | const stack_offset = try self.allocMem(inst, 8, 4); |
| 1272 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 1317 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1273 | try self.genSetStack(len_ty, stack_offset - 4, len); | 1318 | try self.genSetStack(len_ty, stack_offset - 4, len); |
| 1274 | break :result MCValue{ .stack_offset = stack_offset }; | 1319 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -1306,14 +1351,71 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1306,14 +1351,71 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1306 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1351 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1307 | } | 1352 | } |
| 1308 | | 1353 | |
| 1309 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1354 | fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1310 | _ = inst; | 1355 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1311 | return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); | 1356 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1312 | } | 1357 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1358 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1359 | const lhs = try self.resolveInst(extra.lhs); |
| | 1360 | const rhs = try self.resolveInst(extra.rhs); |
| | 1361 | const lhs_ty = self.air.typeOf(extra.lhs); |
| | 1362 | const rhs_ty = self.air.typeOf(extra.rhs); |
| | 1363 | |
| | 1364 | switch (lhs_ty.zigTypeTag()) { |
| | 1365 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), |
| | 1366 | .Int => { |
| | 1367 | assert(lhs_ty.eql(rhs_ty, self.target.*)); |
| | 1368 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1369 | if (int_info.bits < 32) { |
| | 1370 | return self.fail("TODO ARM overflow operations on integers < u32/i32", .{}); |
| | 1371 | } else if (int_info.bits == 32) { |
| | 1372 | // Only say yes if the operation is |
| | 1373 | // commutative, i.e. we can swap both of the |
| | 1374 | // operands |
| | 1375 | const lhs_immediate_ok = switch (tag) { |
| | 1376 | .add_with_overflow => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null, |
| | 1377 | .sub_with_overflow => false, |
| | 1378 | else => unreachable, |
| | 1379 | }; |
| | 1380 | const rhs_immediate_ok = switch (tag) { |
| | 1381 | .add_with_overflow, |
| | 1382 | .sub_with_overflow, |
| | 1383 | => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null, |
| | 1384 | else => unreachable, |
| | 1385 | }; |
| 1313 | | 1386 | |
| 1314 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1387 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1315 | _ = inst; | 1388 | .add_with_overflow => .adds, |
| 1316 | return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch}); | 1389 | .sub_with_overflow => .subs, |
| | 1390 | else => unreachable, |
| | 1391 | }; |
| | 1392 | |
| | 1393 | try self.spillCompareFlagsIfOccupied(); |
| | 1394 | self.compare_flags_inst = inst; |
| | 1395 | |
| | 1396 | const dest = blk: { |
| | 1397 | if (rhs_immediate_ok) { |
| | 1398 | break :blk try self.binOpImmediate(mir_tag, null, lhs, rhs, lhs_ty, false); |
| | 1399 | } else if (lhs_immediate_ok) { |
| | 1400 | // swap lhs and rhs |
| | 1401 | break :blk try self.binOpImmediate(mir_tag, null, rhs, lhs, rhs_ty, true); |
| | 1402 | } else { |
| | 1403 | break :blk try self.binOpRegister(mir_tag, null, lhs, rhs, lhs_ty, rhs_ty); |
| | 1404 | } |
| | 1405 | }; |
| | 1406 | |
| | 1407 | switch (int_info.signedness) { |
| | 1408 | .unsigned => break :result MCValue{ .register_c_flag = dest.register }, |
| | 1409 | .signed => break :result MCValue{ .register_v_flag = dest.register }, |
| | 1410 | } |
| | 1411 | } else { |
| | 1412 | return self.fail("TODO ARM overflow operations on integers > u32/i32", .{}); |
| | 1413 | } |
| | 1414 | }, |
| | 1415 | else => unreachable, |
| | 1416 | } |
| | 1417 | }; |
| | 1418 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1317 | } | 1419 | } |
| 1318 | | 1420 | |
| 1319 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1421 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1424,7 +1526,6 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) | ... | @@ -1424,7 +1526,6 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) |
| 1424 | const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*)); | 1526 | const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*)); |
| 1425 | const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align); | 1527 | const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align); |
| 1426 | | 1528 | |
| 1427 | // TODO optimization for small error unions: put into register | | |
| 1428 | switch (error_union_mcv) { | 1529 | switch (error_union_mcv) { |
| 1429 | .register => return self.fail("TODO errUnionPayload for registers", .{}), | 1530 | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| 1430 | .stack_argument_offset => |off| { | 1531 | .stack_argument_offset => |off| { |
| ... | @@ -1791,8 +1892,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1791,8 +1892,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1791 | .undef => unreachable, | 1892 | .undef => unreachable, |
| 1792 | .unreach => unreachable, | 1893 | .unreach => unreachable, |
| 1793 | .dead => unreachable, | 1894 | .dead => unreachable, |
| 1794 | .compare_flags_unsigned => unreachable, | 1895 | .compare_flags_unsigned, |
| 1795 | .compare_flags_signed => unreachable, | 1896 | .compare_flags_signed, |
| | 1897 | .register_c_flag, |
| | 1898 | .register_v_flag, |
| | 1899 | => unreachable, // cannot hold an address |
| 1796 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 1900 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 1797 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), | 1901 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 1798 | .register => |reg| { | 1902 | .register => |reg| { |
| ... | @@ -1887,8 +1991,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1887,8 +1991,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1887 | .undef => unreachable, | 1991 | .undef => unreachable, |
| 1888 | .unreach => unreachable, | 1992 | .unreach => unreachable, |
| 1889 | .dead => unreachable, | 1993 | .dead => unreachable, |
| 1890 | .compare_flags_unsigned => unreachable, | 1994 | .compare_flags_unsigned, |
| 1891 | .compare_flags_signed => unreachable, | 1995 | .compare_flags_signed, |
| | 1996 | .register_c_flag, |
| | 1997 | .register_v_flag, |
| | 1998 | => unreachable, // cannot hold an address |
| 1892 | .immediate => |imm| { | 1999 | .immediate => |imm| { |
| 1893 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); | 2000 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); |
| 1894 | }, | 2001 | }, |
| ... | @@ -2043,6 +2150,50 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2043,6 +2150,50 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2043 | .memory => |addr| { | 2150 | .memory => |addr| { |
| 2044 | break :result MCValue{ .memory = addr + struct_field_offset }; | 2151 | break :result MCValue{ .memory = addr + struct_field_offset }; |
| 2045 | }, | 2152 | }, |
| | 2153 | .register_c_flag, |
| | 2154 | .register_v_flag, |
| | 2155 | => |reg| { |
| | 2156 | switch (index) { |
| | 2157 | 0 => { |
| | 2158 | // get wrapped value: return register |
| | 2159 | break :result MCValue{ .register = reg }; |
| | 2160 | }, |
| | 2161 | 1 => { |
| | 2162 | // get overflow bit: set register to C flag |
| | 2163 | // resp. V flag |
| | 2164 | const dest_reg = try self.register_manager.allocReg(null); |
| | 2165 | |
| | 2166 | // mov reg, #0 |
| | 2167 | _ = try self.addInst(.{ |
| | 2168 | .tag = .mov, |
| | 2169 | .data = .{ .rr_op = .{ |
| | 2170 | .rd = dest_reg, |
| | 2171 | .rn = .r0, |
| | 2172 | .op = Instruction.Operand.fromU32(0).?, |
| | 2173 | } }, |
| | 2174 | }); |
| | 2175 | |
| | 2176 | // C flag: movcs reg, #1 |
| | 2177 | // V flag: movvs reg, #1 |
| | 2178 | _ = try self.addInst(.{ |
| | 2179 | .tag = .mov, |
| | 2180 | .cond = switch (mcv) { |
| | 2181 | .register_c_flag => .cs, |
| | 2182 | .register_v_flag => .vs, |
| | 2183 | else => unreachable, |
| | 2184 | }, |
| | 2185 | .data = .{ .rr_op = .{ |
| | 2186 | .rd = dest_reg, |
| | 2187 | .rn = .r0, |
| | 2188 | .op = Instruction.Operand.fromU32(1).?, |
| | 2189 | } }, |
| | 2190 | }); |
| | 2191 | |
| | 2192 | break :result MCValue{ .register = dest_reg }; |
| | 2193 | }, |
| | 2194 | else => unreachable, |
| | 2195 | } |
| | 2196 | }, |
| 2046 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), | 2197 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), |
| 2047 | } | 2198 | } |
| 2048 | }; | 2199 | }; |
| ... | @@ -2132,7 +2283,9 @@ fn binOpRegister( | ... | @@ -2132,7 +2283,9 @@ fn binOpRegister( |
| 2132 | | 2283 | |
| 2133 | const mir_data: Mir.Inst.Data = switch (mir_tag) { | 2284 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 2134 | .add, | 2285 | .add, |
| | 2286 | .adds, |
| 2135 | .sub, | 2287 | .sub, |
| | 2288 | .subs, |
| 2136 | .cmp, | 2289 | .cmp, |
| 2137 | .@"and", | 2290 | .@"and", |
| 2138 | .orr, | 2291 | .orr, |
| ... | @@ -2232,7 +2385,9 @@ fn binOpImmediate( | ... | @@ -2232,7 +2385,9 @@ fn binOpImmediate( |
| 2232 | | 2385 | |
| 2233 | const mir_data: Mir.Inst.Data = switch (mir_tag) { | 2386 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 2234 | .add, | 2387 | .add, |
| | 2388 | .adds, |
| 2235 | .sub, | 2389 | .sub, |
| | 2390 | .subs, |
| 2236 | .cmp, | 2391 | .cmp, |
| 2237 | .@"and", | 2392 | .@"and", |
| 2238 | .orr, | 2393 | .orr, |
| ... | @@ -2814,14 +2969,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -2814,14 +2969,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 2814 | | 2969 | |
| 2815 | switch (mc_arg) { | 2970 | switch (mc_arg) { |
| 2816 | .none => continue, | 2971 | .none => continue, |
| 2817 | .undef => unreachable, | | |
| 2818 | .immediate => unreachable, | | |
| 2819 | .unreach => unreachable, | | |
| 2820 | .dead => unreachable, | | |
| 2821 | .memory => unreachable, | | |
| 2822 | .compare_flags_signed => unreachable, | | |
| 2823 | .compare_flags_unsigned => unreachable, | | |
| 2824 | .ptr_stack_offset => unreachable, | | |
| 2825 | .register => |reg| { | 2972 | .register => |reg| { |
| 2826 | try self.register_manager.getReg(reg, null); | 2973 | try self.register_manager.getReg(reg, null); |
| 2827 | try self.genSetReg(arg_ty, reg, arg_mcv); | 2974 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| ... | @@ -2832,6 +2979,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -2832,6 +2979,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 2832 | info.stack_byte_count - offset, | 2979 | info.stack_byte_count - offset, |
| 2833 | arg_mcv, | 2980 | arg_mcv, |
| 2834 | ), | 2981 | ), |
| | 2982 | else => unreachable, |
| 2835 | } | 2983 | } |
| 2836 | } | 2984 | } |
| 2837 | | 2985 | |
| ... | @@ -3774,6 +3922,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3774,6 +3922,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3774 | else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}), | 3922 | else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}), |
| 3775 | } | 3923 | } |
| 3776 | }, | 3924 | }, |
| | 3925 | .register_c_flag, |
| | 3926 | .register_v_flag, |
| | 3927 | => { |
| | 3928 | return self.fail("TODO implement genSetStack {}", .{mcv}); |
| | 3929 | }, |
| 3777 | .memory, | 3930 | .memory, |
| 3778 | .stack_argument_offset, | 3931 | .stack_argument_offset, |
| 3779 | .stack_offset, | 3932 | .stack_offset, |
| ... | @@ -4015,6 +4168,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -4015,6 +4168,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4015 | } }, | 4168 | } }, |
| 4016 | }); | 4169 | }); |
| 4017 | }, | 4170 | }, |
| | 4171 | .register_c_flag => unreachable, // doesn't fit into a register |
| | 4172 | .register_v_flag => unreachable, // doesn't fit into a register |
| 4018 | .memory => |addr| { | 4173 | .memory => |addr| { |
| 4019 | // The value is in memory at a hard-coded address. | 4174 | // The value is in memory at a hard-coded address. |
| 4020 | // If the type is a pointer, it means the pointer address is at this memory location. | 4175 | // If the type is a pointer, it means the pointer address is at this memory location. |
| ... | @@ -4149,6 +4304,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -4149,6 +4304,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 4149 | else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}), | 4304 | else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}), |
| 4150 | } | 4305 | } |
| 4151 | }, | 4306 | }, |
| | 4307 | .register_c_flag, |
| | 4308 | .register_v_flag, |
| | 4309 | => { |
| | 4310 | return self.fail("TODO implement genSetStack {}", .{mcv}); |
| | 4311 | }, |
| 4152 | .stack_offset, | 4312 | .stack_offset, |
| 4153 | .memory, | 4313 | .memory, |
| 4154 | .stack_argument_offset, | 4314 | .stack_argument_offset, |