| ... | ... | @@ -105,7 +105,7 @@ const MCValue = union(enum) { |
| 105 | 105 | undef, |
| 106 | 106 | /// A pointer-sized integer that fits in a register. |
| 107 | 107 | /// If the type is a pointer, this is the pointer address in virtual address space. |
| 108 | | immediate: u64, |
| 108 | immediate: u32, |
| 109 | 109 | /// The constant was emitted into the code, at this offset. |
| 110 | 110 | /// If the type is a pointer, it means the pointer address is embedded in the code. |
| 111 | 111 | embedded_in_code: usize, |
| ... | ... | @@ -783,7 +783,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 783 | 783 | |
| 784 | 784 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 785 | 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 | 787 | const reg_mcv = self.getResolvedInstValue(inst); |
| 788 | 788 | assert(reg == reg_mcv.register); |
| 789 | 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 | 1202 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1203 | 1203 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { |
| 1204 | 1204 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 1205 | | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 1206 | 1205 | |
| 1207 | 1206 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 1208 | 1207 | const elem_ty = slice_ty.childType(); |
| ... | ... | @@ -1261,14 +1260,14 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1261 | 1260 | |
| 1262 | 1261 | break :result MCValue{ .register = dst_reg }; |
| 1263 | 1262 | } else { |
| 1264 | | // const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1265 | | return self.fail("TODO implement slice_elem_val for elem_size >= 4", .{}); |
| 1266 | | } |
| 1263 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1264 | const addr_reg = try self.register_manager.allocReg(null, &.{ base_mcv.register, offset_mcv.register }); |
| 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 | | _ = slice_mcv; |
| 1270 | | _ = index_mcv; |
| 1271 | | _ = offset_mcv; |
| 1269 | break :result dst_mcv; |
| 1270 | } |
| 1272 | 1271 | }; |
| 1273 | 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 | 1401 | }, |
| 1403 | 1402 | .stack_offset => |off| { |
| 1404 | 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 | 1405 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); |
| 1407 | 1406 | try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); |
| 1408 | 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 | 1412 | // larger |
| 1414 | 1413 | |
| 1415 | 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 | 1416 | _ = try self.addInst(.{ |
| 1418 | 1417 | .tag = .ldr, |
| 1419 | 1418 | .cond = .al, |
| ... | ... | @@ -1435,7 +1434,46 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1435 | 1434 | try self.genSetStack(usize_ty, off, MCValue{ .register = tmp_regs[0] }); |
| 1436 | 1435 | try self.genSetStack(usize_ty, off + 4, MCValue{ .register = tmp_regs[1] }); |
| 1437 | 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 | 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 | 1591 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1554 | 1592 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1555 | 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 | 1598 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 1560 | 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 { |
| 1564 | | _ = self; |
| 1565 | | _ = operand; |
| 1566 | | _ = ty; |
| 1567 | | _ = index; |
| 1568 | | return self.fail("TODO implement codegen struct_field_ptr", .{}); |
| 1569 | | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); |
| 1603 | |
| 1604 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 1605 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 1606 | const mcv = try self.resolveInst(operand); |
| 1607 | const struct_ty = self.air.typeOf(operand).childType(); |
| 1608 | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| 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 | 1621 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1573 | 1622 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1574 | 1623 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 1575 | | _ = extra; |
| 1576 | | return self.fail("TODO implement codegen struct_field_val", .{}); |
| 1577 | | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); |
| 1624 | const operand = extra.struct_operand; |
| 1625 | const index = extra.field_index; |
| 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 | 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 | 2011 | // Allocate 1 or 2 registers |
| 1948 | 2012 | if (lhs_is_register) { |
| 1949 | 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 | 2015 | rhs_mcv = dst_mcv; |
| 1952 | 2016 | } else { |
| 1953 | 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 | 2019 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 1956 | 2020 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 1957 | 2021 | dst_mcv = lhs_mcv; |
| ... | ... | @@ -1976,6 +2040,87 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind |
| 1976 | 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 | 2124 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void { |
| 1980 | 2125 | const ty_str = self.air.instructions.items(.data)[inst].ty_str; |
| 1981 | 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 | 2427 | if (rhs_should_be_register) { |
| 2283 | 2428 | if (!lhs_is_register and !rhs_is_register) { |
| 2284 | 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 | 2432 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 2288 | 2433 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 2289 | 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 | 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 | 3072 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 2922 | 3073 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 2923 | 3074 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 2924 | | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 2925 | 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 | 3087 | return self.fail("TODO implement set stack variable from embedded_in_code", .{}); |
| 2938 | 3088 | }, |
| 2939 | 3089 | .register => |reg| { |
| 2940 | | const abi_size = ty.abiSize(self.target.*); |
| 3090 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 2941 | 3091 | const adj_off = stack_offset + abi_size; |
| 2942 | 3092 | |
| 2943 | 3093 | switch (abi_size) { |
| ... | ... | @@ -3004,7 +3154,60 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3004 | 3154 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3005 | 3155 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3006 | 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 | 3399 | .memory => |addr| { |
| 3197 | 3400 | // The value is in memory at a hard-coded address. |
| 3198 | 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 | 3403 | _ = try self.addInst(.{ |
| 3201 | 3404 | .tag = .ldr, |
| 3202 | 3405 | .cond = .al, |
| ... | ... | @@ -3209,7 +3412,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3209 | 3412 | }, |
| 3210 | 3413 | .stack_offset => |unadjusted_off| { |
| 3211 | 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 | 3416 | const adj_off = unadjusted_off + abi_size; |
| 3214 | 3417 | |
| 3215 | 3418 | switch (abi_size) { |
| ... | ... | @@ -3295,12 +3498,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 3295 | 3498 | 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), |
| 3296 | 3499 | 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 3297 | 3500 | 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 3298 | | 8 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 3299 | 3501 | else => return self.fail("TODO implement memset", .{}), |
| 3300 | 3502 | } |
| 3301 | 3503 | }, |
| 3302 | 3504 | .register => |reg| { |
| 3303 | | const abi_size = ty.abiSize(self.target.*); |
| 3505 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 3304 | 3506 | const adj_off = stack_offset - abi_size; |
| 3305 | 3507 | |
| 3306 | 3508 | switch (abi_size) { |
| ... | ... | @@ -3541,7 +3743,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3541 | 3743 | } |
| 3542 | 3744 | } |
| 3543 | 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 | 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 | 3753 | if (info.bits > ptr_bits or info.signedness == .signed) { |
| 3552 | 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 | 3758 | .Bool => { |
| 3557 | 3759 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; |