| ... | @@ -105,7 +105,7 @@ const MCValue = union(enum) { | ... | @@ -105,7 +105,7 @@ const MCValue = union(enum) { |
| 105 | undef, | 105 | undef, |
| 106 | /// A pointer-sized integer that fits in a register. | 106 | /// A pointer-sized integer that fits in a register. |
| 107 | /// If the type is a pointer, this is the pointer address in virtual address space. | 107 | /// If the type is a pointer, this is the pointer address in virtual address space. |
| 108 | immediate: u64, | 108 | immediate: u32, |
| 109 | /// The constant was emitted into the code, at this offset. | 109 | /// The constant was emitted into the code, at this offset. |
| 110 | /// If the type is a pointer, it means the pointer address is embedded in the code. | 110 | /// If the type is a pointer, it means the pointer address is embedded in the code. |
| 111 | embedded_in_code: usize, | 111 | embedded_in_code: usize, |
| ... | @@ -783,7 +783,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -783,7 +783,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 783 | | 783 | |
| 784 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { | 784 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 785 | const stack_mcv = try self.allocRegOrMem(inst, false); | 785 | const stack_mcv = try self.allocRegOrMem(inst, false); |
| 786 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); | 786 | log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv }); |
| 787 | const reg_mcv = self.getResolvedInstValue(inst); | 787 | const reg_mcv = self.getResolvedInstValue(inst); |
| 788 | assert(reg == reg_mcv.register); | 788 | assert(reg == reg_mcv.register); |
| 789 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 789 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | @@ -1202,7 +1202,6 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1202,7 +1202,6 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1202 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1202 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1203 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { | 1203 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { |
| 1204 | const slice_mcv = try self.resolveInst(bin_op.lhs); | 1204 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 1205 | const index_mcv = try self.resolveInst(bin_op.rhs); | | |
| 1206 | | 1205 | |
| 1207 | const slice_ty = self.air.typeOf(bin_op.lhs); | 1206 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 1208 | const elem_ty = slice_ty.childType(); | 1207 | const elem_ty = slice_ty.childType(); |
| ... | @@ -1261,14 +1260,14 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1261,14 +1260,14 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1261 | | 1260 | |
| 1262 | break :result MCValue{ .register = dst_reg }; | 1261 | break :result MCValue{ .register = dst_reg }; |
| 1263 | } else { | 1262 | } else { |
| 1264 | // const dst_mcv = try self.allocRegOrMem(inst, false); | 1263 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1265 | return self.fail("TODO implement slice_elem_val for elem_size >= 4", .{}); | 1264 | const addr_reg = try self.register_manager.allocReg(null, &.{ base_mcv.register, offset_mcv.register }); |
| 1266 | } | 1265 | |
| | 1266 | try self.genArmBinOpCode(addr_reg, base_mcv, offset_mcv, false, .add, .unsigned); |
| | 1267 | try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); |
| 1267 | | 1268 | |
| 1268 | _ = offset_mcv; | 1269 | break :result dst_mcv; |
| 1269 | _ = slice_mcv; | 1270 | } |
| 1270 | _ = index_mcv; | | |
| 1271 | _ = offset_mcv; | | |
| 1272 | }; | 1271 | }; |
| 1273 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1272 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1274 | } | 1273 | } |
| ... | @@ -1402,7 +1401,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1402,7 +1401,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1402 | }, | 1401 | }, |
| 1403 | .stack_offset => |off| { | 1402 | .stack_offset => |off| { |
| 1404 | if (elem_ty.abiSize(self.target.*) <= 4) { | 1403 | if (elem_ty.abiSize(self.target.*) <= 4) { |
| 1405 | const tmp_reg = try self.register_manager.allocReg(null, &.{}); | 1404 | const tmp_reg = try self.register_manager.allocReg(null, &.{reg}); |
| 1406 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); | 1405 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); |
| 1407 | try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); | 1406 | try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); |
| 1408 | } else if (elem_ty.abiSize(self.target.*) == 8) { | 1407 | } else if (elem_ty.abiSize(self.target.*) == 8) { |
| ... | @@ -1413,7 +1412,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1413,7 +1412,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1413 | // larger | 1412 | // larger |
| 1414 | | 1413 | |
| 1415 | const usize_ty = Type.initTag(.usize); | 1414 | const usize_ty = Type.initTag(.usize); |
| 1416 | const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{}); | 1415 | const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{reg}); |
| 1417 | _ = try self.addInst(.{ | 1416 | _ = try self.addInst(.{ |
| 1418 | .tag = .ldr, | 1417 | .tag = .ldr, |
| 1419 | .cond = .al, | 1418 | .cond = .al, |
| ... | @@ -1435,7 +1434,46 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1435,7 +1434,46 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1435 | try self.genSetStack(usize_ty, off, MCValue{ .register = tmp_regs[0] }); | 1434 | try self.genSetStack(usize_ty, off, MCValue{ .register = tmp_regs[0] }); |
| 1436 | try self.genSetStack(usize_ty, off + 4, MCValue{ .register = tmp_regs[1] }); | 1435 | try self.genSetStack(usize_ty, off + 4, MCValue{ .register = tmp_regs[1] }); |
| 1437 | } else { | 1436 | } else { |
| 1438 | return self.fail("TODO implement memcpy", .{}); | 1437 | // TODO optimize the register allocation |
| | 1438 | const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, &.{reg}); |
| | 1439 | const src_reg = reg; |
| | 1440 | const dst_reg = regs[0]; |
| | 1441 | const len_reg = regs[1]; |
| | 1442 | const count_reg = regs[2]; |
| | 1443 | const tmp_reg = regs[3]; |
| | 1444 | |
| | 1445 | // sub dst_reg, fp, #off |
| | 1446 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); |
| | 1447 | const adj_off = off + elem_size; |
| | 1448 | const offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_off)) |x| x else { |
| | 1449 | return self.fail("TODO load: set reg to stack offset with all possible offsets", .{}); |
| | 1450 | }; |
| | 1451 | _ = try self.addInst(.{ |
| | 1452 | .tag = .sub, |
| | 1453 | .cond = .al, |
| | 1454 | .data = .{ .rr_op = .{ |
| | 1455 | .rd = dst_reg, |
| | 1456 | .rn = .fp, |
| | 1457 | .op = offset_op, |
| | 1458 | } }, |
| | 1459 | }); |
| | 1460 | |
| | 1461 | // mov len, #elem_size |
| | 1462 | const len_op: Instruction.Operand = if (Instruction.Operand.fromU32(elem_size)) |x| x else { |
| | 1463 | return self.fail("TODO load: set reg to elem_size with all possible sizes", .{}); |
| | 1464 | }; |
| | 1465 | _ = try self.addInst(.{ |
| | 1466 | .tag = .mov, |
| | 1467 | .cond = .al, |
| | 1468 | .data = .{ .rr_op = .{ |
| | 1469 | .rd = len_reg, |
| | 1470 | .rn = .r0, |
| | 1471 | .op = len_op, |
| | 1472 | } }, |
| | 1473 | }); |
| | 1474 | |
| | 1475 | // memcpy(src, dst, len) |
| | 1476 | try self.genArmInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 1439 | } | 1477 | } |
| 1440 | }, | 1478 | }, |
| 1441 | else => return self.fail("TODO load from register into {}", .{dst_mcv}), | 1479 | else => return self.fail("TODO load from register into {}", .{dst_mcv}), |
| ... | @@ -1553,28 +1591,54 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1553,28 +1591,54 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1553 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { | 1591 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1554 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1592 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1555 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 1593 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 1556 | return self.structFieldPtr(extra.struct_operand, ty_pl.ty, extra.field_index); | 1594 | const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index); |
| | 1595 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 1557 | } | 1596 | } |
| 1558 | | 1597 | |
| 1559 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { | 1598 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 1560 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1599 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1561 | return self.structFieldPtr(ty_op.operand, ty_op.ty, index); | 1600 | const result = try self.structFieldPtr(inst, ty_op.operand, index); |
| | 1601 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1562 | } | 1602 | } |
| 1563 | fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void { | 1603 | |
| 1564 | _ = self; | 1604 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 1565 | _ = operand; | 1605 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 1566 | _ = ty; | 1606 | const mcv = try self.resolveInst(operand); |
| 1567 | _ = index; | 1607 | const struct_ty = self.air.typeOf(operand).childType(); |
| 1568 | return self.fail("TODO implement codegen struct_field_ptr", .{}); | 1608 | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| 1569 | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); | 1609 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| | 1610 | const struct_field_ty = struct_ty.structFieldType(index); |
| | 1611 | const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); |
| | 1612 | switch (mcv) { |
| | 1613 | .ptr_stack_offset => |off| { |
| | 1614 | break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size }; |
| | 1615 | }, |
| | 1616 | else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}), |
| | 1617 | } |
| | 1618 | }; |
| 1570 | } | 1619 | } |
| 1571 | | 1620 | |
| 1572 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | 1621 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1573 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1622 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1574 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 1623 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 1575 | _ = extra; | 1624 | const operand = extra.struct_operand; |
| 1576 | return self.fail("TODO implement codegen struct_field_val", .{}); | 1625 | const index = extra.field_index; |
| 1577 | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); | 1626 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1627 | const mcv = try self.resolveInst(operand); |
| | 1628 | const struct_ty = self.air.typeOf(operand); |
| | 1629 | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| | 1630 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| | 1631 | const struct_field_ty = struct_ty.structFieldType(index); |
| | 1632 | const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); |
| | 1633 | switch (mcv) { |
| | 1634 | .stack_offset => |off| { |
| | 1635 | break :result MCValue{ .stack_offset = off + struct_size - struct_field_offset - struct_field_size }; |
| | 1636 | }, |
| | 1637 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), |
| | 1638 | } |
| | 1639 | }; |
| | 1640 | |
| | 1641 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 1578 | } | 1642 | } |
| 1579 | | 1643 | |
| 1580 | fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool { | 1644 | fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool { |
| ... | @@ -1947,11 +2011,11 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind | ... | @@ -1947,11 +2011,11 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind |
| 1947 | // Allocate 1 or 2 registers | 2011 | // Allocate 1 or 2 registers |
| 1948 | if (lhs_is_register) { | 2012 | if (lhs_is_register) { |
| 1949 | // Move RHS to register | 2013 | // Move RHS to register |
| 1950 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{mcv.register}) }; | 2014 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{mcv.register}) }; |
| 1951 | rhs_mcv = dst_mcv; | 2015 | rhs_mcv = dst_mcv; |
| 1952 | } else { | 2016 | } else { |
| 1953 | // Move LHS and RHS to register | 2017 | // Move LHS and RHS to register |
| 1954 | const regs = try self.register_manager.allocRegs(2, .{ inst, null }, &.{}); | 2018 | const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{}); |
| 1955 | lhs_mcv = MCValue{ .register = regs[0] }; | 2019 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 1956 | rhs_mcv = MCValue{ .register = regs[1] }; | 2020 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 1957 | dst_mcv = lhs_mcv; | 2021 | dst_mcv = lhs_mcv; |
| ... | @@ -1976,6 +2040,87 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind | ... | @@ -1976,6 +2040,87 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind |
| 1976 | return dst_mcv; | 2040 | return dst_mcv; |
| 1977 | } | 2041 | } |
| 1978 | | 2042 | |
| | 2043 | fn genArmInlineMemcpy( |
| | 2044 | self: *Self, |
| | 2045 | src: Register, |
| | 2046 | dst: Register, |
| | 2047 | len: Register, |
| | 2048 | count: Register, |
| | 2049 | tmp: Register, |
| | 2050 | ) !void { |
| | 2051 | // mov count, #0 |
| | 2052 | _ = try self.addInst(.{ |
| | 2053 | .tag = .mov, |
| | 2054 | .cond = .al, |
| | 2055 | .data = .{ .rr_op = .{ |
| | 2056 | .rd = count, |
| | 2057 | .rn = .r0, |
| | 2058 | .op = Instruction.Operand.imm(0, 0), |
| | 2059 | } }, |
| | 2060 | }); |
| | 2061 | |
| | 2062 | // loop: |
| | 2063 | // cmp count, len |
| | 2064 | _ = try self.addInst(.{ |
| | 2065 | .tag = .cmp, |
| | 2066 | .cond = .al, |
| | 2067 | .data = .{ .rr_op = .{ |
| | 2068 | .rd = .r0, |
| | 2069 | .rn = count, |
| | 2070 | .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none), |
| | 2071 | } }, |
| | 2072 | }); |
| | 2073 | |
| | 2074 | // bge end |
| | 2075 | _ = try self.addInst(.{ |
| | 2076 | .tag = .b, |
| | 2077 | .cond = .ge, |
| | 2078 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len + 5) }, |
| | 2079 | }); |
| | 2080 | |
| | 2081 | // ldrb tmp, [src, count] |
| | 2082 | _ = try self.addInst(.{ |
| | 2083 | .tag = .ldrb, |
| | 2084 | .cond = .al, |
| | 2085 | .data = .{ .rr_offset = .{ |
| | 2086 | .rt = tmp, |
| | 2087 | .rn = src, |
| | 2088 | .offset = .{ .offset = Instruction.Offset.reg(count, 0) }, |
| | 2089 | } }, |
| | 2090 | }); |
| | 2091 | |
| | 2092 | // strb tmp, [src, count] |
| | 2093 | _ = try self.addInst(.{ |
| | 2094 | .tag = .strb, |
| | 2095 | .cond = .al, |
| | 2096 | .data = .{ .rr_offset = .{ |
| | 2097 | .rt = tmp, |
| | 2098 | .rn = dst, |
| | 2099 | .offset = .{ .offset = Instruction.Offset.reg(count, 0) }, |
| | 2100 | } }, |
| | 2101 | }); |
| | 2102 | |
| | 2103 | // add count, count, #1 |
| | 2104 | _ = try self.addInst(.{ |
| | 2105 | .tag = .add, |
| | 2106 | .cond = .al, |
| | 2107 | .data = .{ .rr_op = .{ |
| | 2108 | .rd = count, |
| | 2109 | .rn = count, |
| | 2110 | .op = Instruction.Operand.imm(1, 0), |
| | 2111 | } }, |
| | 2112 | }); |
| | 2113 | |
| | 2114 | // b loop |
| | 2115 | _ = try self.addInst(.{ |
| | 2116 | .tag = .b, |
| | 2117 | .cond = .al, |
| | 2118 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 5) }, |
| | 2119 | }); |
| | 2120 | |
| | 2121 | // end: |
| | 2122 | } |
| | 2123 | |
| 1979 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void { | 2124 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void { |
| 1980 | const ty_str = self.air.instructions.items(.data)[inst].ty_str; | 2125 | const ty_str = self.air.instructions.items(.data)[inst].ty_str; |
| 1981 | const zir = &self.mod_fn.owner_decl.getFileScope().zir; | 2126 | const zir = &self.mod_fn.owner_decl.getFileScope().zir; |
| ... | @@ -2282,16 +2427,22 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -2282,16 +2427,22 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2282 | if (rhs_should_be_register) { | 2427 | if (rhs_should_be_register) { |
| 2283 | if (!lhs_is_register and !rhs_is_register) { | 2428 | if (!lhs_is_register and !rhs_is_register) { |
| 2284 | const regs = try self.register_manager.allocRegs(2, .{ | 2429 | const regs = try self.register_manager.allocRegs(2, .{ |
| 2285 | Air.refToIndex(bin_op.rhs).?, Air.refToIndex(bin_op.lhs).?, | 2430 | Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?, |
| 2286 | }, &.{}); | 2431 | }, &.{}); |
| 2287 | lhs_mcv = MCValue{ .register = regs[0] }; | 2432 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 2288 | rhs_mcv = MCValue{ .register = regs[1] }; | 2433 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 2289 | } else if (!rhs_is_register) { | 2434 | } else if (!rhs_is_register) { |
| 2290 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?, &.{}) }; | 2435 | const track_inst = if (self.liveness.operandDies(inst, 1)) null else Air.refToIndex(bin_op.rhs).?; |
| | 2436 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; |
| | 2437 | } else if (!lhs_is_register) { |
| | 2438 | const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?; |
| | 2439 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; |
| | 2440 | } |
| | 2441 | } else { |
| | 2442 | if (!lhs_is_register) { |
| | 2443 | const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?; |
| | 2444 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; |
| 2291 | } | 2445 | } |
| 2292 | } | | |
| 2293 | if (!lhs_is_register) { | | |
| 2294 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?, &.{}) }; | | |
| 2295 | } | 2446 | } |
| 2296 | | 2447 | |
| 2297 | // Move the operands to the newly allocated registers | 2448 | // Move the operands to the newly allocated registers |
| ... | @@ -2921,7 +3072,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -2921,7 +3072,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2921 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), | 3072 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 2922 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 3073 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 2923 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 3074 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 2924 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), | | |
| 2925 | else => return self.fail("TODO implement memset", .{}), | 3075 | else => return self.fail("TODO implement memset", .{}), |
| 2926 | } | 3076 | } |
| 2927 | }, | 3077 | }, |
| ... | @@ -2937,7 +3087,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -2937,7 +3087,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2937 | return self.fail("TODO implement set stack variable from embedded_in_code", .{}); | 3087 | return self.fail("TODO implement set stack variable from embedded_in_code", .{}); |
| 2938 | }, | 3088 | }, |
| 2939 | .register => |reg| { | 3089 | .register => |reg| { |
| 2940 | const abi_size = ty.abiSize(self.target.*); | 3090 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 2941 | const adj_off = stack_offset + abi_size; | 3091 | const adj_off = stack_offset + abi_size; |
| 2942 | | 3092 | |
| 2943 | switch (abi_size) { | 3093 | switch (abi_size) { |
| ... | @@ -3004,7 +3154,60 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3004,7 +3154,60 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3004 | const reg = try self.copyToTmpRegister(ty, mcv); | 3154 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3005 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3155 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3006 | } else { | 3156 | } else { |
| 3007 | return self.fail("TODO implement memcpy", .{}); | 3157 | // TODO optimize the register allocation |
| | 3158 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, &.{}); |
| | 3159 | const src_reg = regs[0]; |
| | 3160 | const dst_reg = regs[2]; |
| | 3161 | const len_reg = regs[2]; |
| | 3162 | const count_reg = regs[3]; |
| | 3163 | const tmp_reg = regs[4]; |
| | 3164 | |
| | 3165 | // add src_reg, fp, #off |
| | 3166 | const src_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(off)) |x| x else { |
| | 3167 | return self.fail("TODO load: set reg to stack offset with all possible offsets", .{}); |
| | 3168 | }; |
| | 3169 | _ = try self.addInst(.{ |
| | 3170 | .tag = .add, |
| | 3171 | .cond = .al, |
| | 3172 | .data = .{ .rr_op = .{ |
| | 3173 | .rd = src_reg, |
| | 3174 | .rn = .fp, |
| | 3175 | .op = src_offset_op, |
| | 3176 | } }, |
| | 3177 | }); |
| | 3178 | |
| | 3179 | // sub dst_reg, fp, #stack_offset |
| | 3180 | const adj_stack_offset = stack_offset + @intCast(u32, ty.abiSize(self.target.*)); |
| | 3181 | const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_stack_offset)) |x| x else { |
| | 3182 | return self.fail("TODO load: set reg to stack offset with all possible offsets", .{}); |
| | 3183 | }; |
| | 3184 | _ = try self.addInst(.{ |
| | 3185 | .tag = .sub, |
| | 3186 | .cond = .al, |
| | 3187 | .data = .{ .rr_op = .{ |
| | 3188 | .rd = dst_reg, |
| | 3189 | .rn = .fp, |
| | 3190 | .op = dst_offset_op, |
| | 3191 | } }, |
| | 3192 | }); |
| | 3193 | |
| | 3194 | // mov len, #elem_size |
| | 3195 | const elem_size = @intCast(u32, ty.abiSize(self.target.*)); |
| | 3196 | const len_op: Instruction.Operand = if (Instruction.Operand.fromU32(elem_size)) |x| x else { |
| | 3197 | return self.fail("TODO load: set reg to elem_size with all possible sizes", .{}); |
| | 3198 | }; |
| | 3199 | _ = try self.addInst(.{ |
| | 3200 | .tag = .mov, |
| | 3201 | .cond = .al, |
| | 3202 | .data = .{ .rr_op = .{ |
| | 3203 | .rd = len_reg, |
| | 3204 | .rn = .r0, |
| | 3205 | .op = len_op, |
| | 3206 | } }, |
| | 3207 | }); |
| | 3208 | |
| | 3209 | // memcpy(src, dst, len) |
| | 3210 | try self.genArmInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 3008 | } | 3211 | } |
| 3009 | }, | 3212 | }, |
| 3010 | } | 3213 | } |
| ... | @@ -3196,7 +3399,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3196,7 +3399,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3196 | .memory => |addr| { | 3399 | .memory => |addr| { |
| 3197 | // The value is in memory at a hard-coded address. | 3400 | // The value is in memory at a hard-coded address. |
| 3198 | // If the type is a pointer, it means the pointer address is at this memory location. | 3401 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3199 | try self.genSetReg(ty, reg, .{ .immediate = addr }); | 3402 | try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) }); |
| 3200 | _ = try self.addInst(.{ | 3403 | _ = try self.addInst(.{ |
| 3201 | .tag = .ldr, | 3404 | .tag = .ldr, |
| 3202 | .cond = .al, | 3405 | .cond = .al, |
| ... | @@ -3209,7 +3412,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3209,7 +3412,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3209 | }, | 3412 | }, |
| 3210 | .stack_offset => |unadjusted_off| { | 3413 | .stack_offset => |unadjusted_off| { |
| 3211 | // TODO: maybe addressing from sp instead of fp | 3414 | // TODO: maybe addressing from sp instead of fp |
| 3212 | const abi_size = ty.abiSize(self.target.*); | 3415 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 3213 | const adj_off = unadjusted_off + abi_size; | 3416 | const adj_off = unadjusted_off + abi_size; |
| 3214 | | 3417 | |
| 3215 | switch (abi_size) { | 3418 | switch (abi_size) { |
| ... | @@ -3295,12 +3498,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -3295,12 +3498,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 3295 | 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), | 3498 | 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), |
| 3296 | 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), | 3499 | 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 3297 | 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 3500 | 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 3298 | 8 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), | | |
| 3299 | else => return self.fail("TODO implement memset", .{}), | 3501 | else => return self.fail("TODO implement memset", .{}), |
| 3300 | } | 3502 | } |
| 3301 | }, | 3503 | }, |
| 3302 | .register => |reg| { | 3504 | .register => |reg| { |
| 3303 | const abi_size = ty.abiSize(self.target.*); | 3505 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 3304 | const adj_off = stack_offset - abi_size; | 3506 | const adj_off = stack_offset - abi_size; |
| 3305 | | 3507 | |
| 3306 | switch (abi_size) { | 3508 | switch (abi_size) { |
| ... | @@ -3541,7 +3743,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -3541,7 +3743,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3541 | } | 3743 | } |
| 3542 | } | 3744 | } |
| 3543 | if (typed_value.val.tag() == .int_u64) { | 3745 | if (typed_value.val.tag() == .int_u64) { |
| 3544 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; | 3746 | return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) }; |
| 3545 | } | 3747 | } |
| 3546 | return self.fail("TODO codegen more kinds of const pointers", .{}); | 3748 | return self.fail("TODO codegen more kinds of const pointers", .{}); |
| 3547 | }, | 3749 | }, |
| ... | @@ -3551,7 +3753,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -3551,7 +3753,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3551 | if (info.bits > ptr_bits or info.signedness == .signed) { | 3753 | if (info.bits > ptr_bits or info.signedness == .signed) { |
| 3552 | return self.fail("TODO const int bigger than ptr and signed int", .{}); | 3754 | return self.fail("TODO const int bigger than ptr and signed int", .{}); |
| 3553 | } | 3755 | } |
| 3554 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; | 3756 | return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) }; |
| 3555 | }, | 3757 | }, |
| 3556 | .Bool => { | 3758 | .Bool => { |
| 3557 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | 3759 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; |