authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-30 15:25:36-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-12-30 15:25:36-05:00
log4645ec89f7e858121a22e3d6107cfa74151437a3
treee7cbe3a0dfd2ffd1af3594888b41383fd9878e0f
parent2f53406ad821c6fd8239551d3b812cd4100929bd
parent69d03d3a297809d1bc91ed5848501c64666244a1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10455 from joachimschmidt557/stage2-arm

stage2 ARM: basic slice + basic struct support

4 files changed, 316 insertions(+), 43 deletions(-)

src/arch/arm/CodeGen.zig+243-41
...@@ -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 {
783783
784pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {784pub 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);
12061205
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 {
12611260
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);
12671268
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 // larger1412 // larger
14141413
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 {
1553fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {1591fn 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}
15581597
1559fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {1598fn 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}
1563fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void {1603
1564 _ = self;1604fn 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}
15711620
1572fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {1621fn 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}
15791643
1580fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {1644fn 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 registers2011 // Allocate 1 or 2 registers
1948 if (lhs_is_register) {2012 if (lhs_is_register) {
1949 // Move RHS to register2013 // 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 register2017 // 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}
19782042
2043fn 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
1979fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void {2124fn 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 }
22962447
2297 // Move the operands to the newly allocated registers2448 // 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;
29423092
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 fp3414 // 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;
32143417
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;
33053507
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()) };
src/codegen.zig+22-1
...@@ -372,11 +372,32 @@ pub fn generateSymbol(...@@ -372,11 +372,32 @@ pub fn generateSymbol(
372 return Result{ .appended = {} };372 return Result{ .appended = {} };
373 },373 },
374 .Struct => {374 .Struct => {
375 // TODO debug info
376 // TODO padding of struct members
375 const field_vals = typed_value.val.castTag(.@"struct").?.data;377 const field_vals = typed_value.val.castTag(.@"struct").?.data;
376 _ = field_vals; // TODO write the fields for real378 for (field_vals) |field_val, index| {
379 const field_ty = typed_value.ty.structFieldType(index);
380 if (!field_ty.hasCodeGenBits()) continue;
381 switch (try generateSymbol(bin_file, src_loc, .{
382 .ty = field_ty,
383 .val = field_val,
384 }, code, debug_output)) {
385 .appended => {},
386 .externally_managed => |external_slice| {
387 code.appendSliceAssumeCapacity(external_slice);
388 },
389 .fail => |em| return Result{ .fail = em },
390 }
391 }
392
393 return Result{ .appended = {} };
394 },
395 .Union => {
396 // TODO generateSymbol for unions
377 const target = bin_file.options.target;397 const target = bin_file.options.target;
378 const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));398 const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));
379 try code.writer().writeByteNTimes(0xaa, abi_size);399 try code.writer().writeByteNTimes(0xaa, abi_size);
400
380 return Result{ .appended = {} };401 return Result{ .appended = {} };
381 },402 },
382 else => |t| {403 else => |t| {
src/register_manager.zig+5-1
...@@ -129,7 +129,7 @@ pub fn RegisterManager(...@@ -129,7 +129,7 @@ pub fn RegisterManager(
129 comptime assert(count > 0 and count <= callee_preserved_regs.len);129 comptime assert(count > 0 and count <= callee_preserved_regs.len);
130 assert(count + exceptions.len <= callee_preserved_regs.len);130 assert(count + exceptions.len <= callee_preserved_regs.len);
131131
132 return self.tryAllocRegs(count, insts, exceptions) orelse blk: {132 const result = self.tryAllocRegs(count, insts, exceptions) orelse blk: {
133 // We'll take over the first count registers. Spill133 // We'll take over the first count registers. Spill
134 // the instructions that were previously there to a134 // the instructions that were previously there to a
135 // stack allocations.135 // stack allocations.
...@@ -164,6 +164,9 @@ pub fn RegisterManager(...@@ -164,6 +164,9 @@ pub fn RegisterManager(
164164
165 break :blk regs;165 break :blk regs;
166 };166 };
167
168 log.debug("allocated registers {any} for insts {any}", .{ result, insts });
169 return result;
167 }170 }
168171
169 /// Allocates a register and optionally tracks it with a172 /// Allocates a register and optionally tracks it with a
...@@ -213,6 +216,7 @@ pub fn RegisterManager(...@@ -213,6 +216,7 @@ pub fn RegisterManager(
213 /// Marks the specified register as free216 /// Marks the specified register as free
214 pub fn freeReg(self: *Self, reg: Register) void {217 pub fn freeReg(self: *Self, reg: Register) void {
215 const index = reg.allocIndex() orelse return;218 const index = reg.allocIndex() orelse return;
219 log.debug("freeing register {}", .{reg});
216220
217 self.registers[index] = null;221 self.registers[index] = null;
218 self.markRegFree(reg);222 self.markRegFree(reg);
test/stage2/arm.zig+46
...@@ -658,4 +658,50 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -658,4 +658,50 @@ pub fn addCases(ctx: *TestContext) !void {
658 "",658 "",
659 );659 );
660 }660 }
661
662 {
663 var case = ctx.exe("structs", linux_arm);
664 case.addCompareOutput(
665 \\var array = [_]SomeStruct{
666 \\ .{ .a = 0, .b = 42, .c = 69 },
667 \\ .{ .a = 1, .b = 2, .c = 3 },
668 \\ .{ .a = 123, .b = 456, .c = 789 },
669 \\};
670 \\var s: []const SomeStruct = &array;
671 \\
672 \\var some_struct: SomeStruct = .{
673 \\ .a = 0,
674 \\ .b = 42,
675 \\ .c = 69,
676 \\};
677 \\
678 \\const SomeStruct = struct {
679 \\ a: u32,
680 \\ b: u32,
681 \\ c: u32,
682 \\};
683 \\
684 \\pub fn main() void {
685 \\ assert(some_struct.a == 0);
686 \\ assert(some_struct.b == 42);
687 \\ assert(some_struct.c == 69);
688 \\
689 \\ assert(s[0].a == 0);
690 \\ assert(s[0].b == 42);
691 \\ assert(s[0].c == 69);
692 \\ assert(s[1].a == 1);
693 \\ assert(s[1].b == 2);
694 \\ assert(s[1].c == 3);
695 \\ assert(s[2].a == 123);
696 \\ assert(s[2].b == 456);
697 \\ assert(s[2].c == 789);
698 \\}
699 \\
700 \\fn assert(ok: bool) void {
701 \\ if (!ok) unreachable;
702 \\}
703 ,
704 "",
705 );
706 }
661}707}