| ... | ... | @@ -592,7 +592,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 592 | 592 | .ret_load => try self.airRetLoad(inst), |
| 593 | 593 | .store => try self.airStore(inst), |
| 594 | 594 | .struct_field_ptr=> @panic("TODO try self.airStructFieldPtr(inst)"), |
| 595 | | .struct_field_val=> @panic("TODO try self.airStructFieldVal(inst)"), |
| 595 | .struct_field_val=> try self.airStructFieldVal(inst), |
| 596 | 596 | .array_to_slice => @panic("TODO try self.airArrayToSlice(inst)"), |
| 597 | 597 | .int_to_float => @panic("TODO try self.airIntToFloat(inst)"), |
| 598 | 598 | .float_to_int => @panic("TODO try self.airFloatToInt(inst)"), |
| ... | ... | @@ -1598,6 +1598,75 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 1598 | 1598 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1599 | 1599 | } |
| 1600 | 1600 | |
| 1601 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1602 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1603 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 1604 | const operand = extra.struct_operand; |
| 1605 | const index = extra.field_index; |
| 1606 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1607 | const mcv = try self.resolveInst(operand); |
| 1608 | const struct_ty = self.air.typeOf(operand); |
| 1609 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| 1610 | |
| 1611 | switch (mcv) { |
| 1612 | .dead, .unreach => unreachable, |
| 1613 | .stack_offset => |off| { |
| 1614 | break :result MCValue{ .stack_offset = off - struct_field_offset }; |
| 1615 | }, |
| 1616 | .memory => |addr| { |
| 1617 | break :result MCValue{ .memory = addr + struct_field_offset }; |
| 1618 | }, |
| 1619 | .register_with_overflow => |rwo| { |
| 1620 | switch (index) { |
| 1621 | 0 => { |
| 1622 | // get wrapped value: return register |
| 1623 | break :result MCValue{ .register = rwo.reg }; |
| 1624 | }, |
| 1625 | 1 => { |
| 1626 | // TODO return special MCValue condition flags |
| 1627 | // get overflow bit: set register to C flag |
| 1628 | // resp. V flag |
| 1629 | const dest_reg = try self.register_manager.allocReg(null, gp); |
| 1630 | |
| 1631 | // TODO handle floating point CCRs |
| 1632 | assert(rwo.flag.ccr == .xcc or rwo.flag.ccr == .icc); |
| 1633 | |
| 1634 | _ = try self.addInst(.{ |
| 1635 | .tag = .mov, |
| 1636 | .data = .{ |
| 1637 | .arithmetic_2op = .{ |
| 1638 | .is_imm = false, |
| 1639 | .rs1 = dest_reg, |
| 1640 | .rs2_or_imm = .{ .rs2 = .g0 }, |
| 1641 | }, |
| 1642 | }, |
| 1643 | }); |
| 1644 | |
| 1645 | _ = try self.addInst(.{ |
| 1646 | .tag = .movcc, |
| 1647 | .data = .{ |
| 1648 | .conditional_move = .{ |
| 1649 | .ccr = rwo.flag.ccr, |
| 1650 | .cond = .{ .icond = rwo.flag.cond }, |
| 1651 | .is_imm = true, |
| 1652 | .rd = dest_reg, |
| 1653 | .rs2_or_imm = .{ .imm = 1 }, |
| 1654 | }, |
| 1655 | }, |
| 1656 | }); |
| 1657 | |
| 1658 | break :result MCValue{ .register = dest_reg }; |
| 1659 | }, |
| 1660 | else => unreachable, |
| 1661 | } |
| 1662 | }, |
| 1663 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), |
| 1664 | } |
| 1665 | }; |
| 1666 | |
| 1667 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 1668 | } |
| 1669 | |
| 1601 | 1670 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 1602 | 1671 | _ = self; |
| 1603 | 1672 | _ = inst; |
| ... | ... | @@ -1664,8 +1733,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 1664 | 1733 | if (abi_align > self.stack_align) |
| 1665 | 1734 | self.stack_align = abi_align; |
| 1666 | 1735 | // TODO find a free slot instead of always appending |
| 1667 | | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align); |
| 1668 | | self.next_stack_offset = offset + abi_size; |
| 1736 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; |
| 1737 | self.next_stack_offset = offset; |
| 1669 | 1738 | if (self.next_stack_offset > self.max_end_stack) |
| 1670 | 1739 | self.max_end_stack = self.next_stack_offset; |
| 1671 | 1740 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| ... | ... | @@ -2436,8 +2505,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2436 | 2505 | return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); |
| 2437 | 2506 | }, |
| 2438 | 2507 | .ptr_stack_offset => |off| { |
| 2439 | | const simm13 = math.cast(u12, off + abi.stack_bias + abi.stack_reserved_area) orelse |
| 2440 | | return self.fail("TODO larger stack offsets", .{}); |
| 2508 | const real_offset = off + abi.stack_bias + abi.stack_reserved_area; |
| 2509 | const simm13 = math.cast(i13, real_offset) orelse |
| 2510 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); |
| 2441 | 2511 | |
| 2442 | 2512 | _ = try self.addInst(.{ |
| 2443 | 2513 | .tag = .add, |
| ... | ... | @@ -2571,7 +2641,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2571 | 2641 | .stack_offset => |off| { |
| 2572 | 2642 | const real_offset = off + abi.stack_bias + abi.stack_reserved_area; |
| 2573 | 2643 | const simm13 = math.cast(i13, real_offset) orelse |
| 2574 | | return self.fail("TODO larger stack offsets", .{}); |
| 2644 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); |
| 2575 | 2645 | try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); |
| 2576 | 2646 | }, |
| 2577 | 2647 | } |
| ... | ... | @@ -2605,7 +2675,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2605 | 2675 | .register => |reg| { |
| 2606 | 2676 | const real_offset = stack_offset + abi.stack_bias + abi.stack_reserved_area; |
| 2607 | 2677 | const simm13 = math.cast(i13, real_offset) orelse |
| 2608 | | return self.fail("TODO larger stack offsets", .{}); |
| 2678 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); |
| 2609 | 2679 | return self.genStore(reg, .sp, i13, simm13, abi_size); |
| 2610 | 2680 | }, |
| 2611 | 2681 | .register_with_overflow => |rwo| { |
| ... | ... | @@ -3198,6 +3268,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 3198 | 3268 | .compare_flags_signed, |
| 3199 | 3269 | .compare_flags_unsigned, |
| 3200 | 3270 | => try self.allocRegOrMem(inst_to_save, true), |
| 3271 | .register_with_overflow => try self.allocRegOrMem(inst_to_save, false), |
| 3201 | 3272 | else => unreachable, // mcv doesn't occupy the compare flags |
| 3202 | 3273 | }; |
| 3203 | 3274 | |
| ... | ... | @@ -3208,6 +3279,13 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 3208 | 3279 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| 3209 | 3280 | |
| 3210 | 3281 | self.compare_flags_inst = null; |
| 3282 | |
| 3283 | // TODO consolidate with register manager and spillInstruction |
| 3284 | // this call should really belong in the register manager! |
| 3285 | switch (mcv) { |
| 3286 | .register_with_overflow => |rwo| self.register_manager.freeReg(rwo.reg), |
| 3287 | else => {}, |
| 3288 | } |
| 3211 | 3289 | } |
| 3212 | 3290 | } |
| 3213 | 3291 | |