| ... | @@ -1261,7 +1261,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1261,7 +1261,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1261 | break :result MCValue{ .register = dst_reg }; | 1261 | break :result MCValue{ .register = dst_reg }; |
| 1262 | } else { | 1262 | } else { |
| 1263 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1263 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1264 | const addr_reg = try self.register_manager.allocReg(inst, &.{ base_mcv.register, offset_mcv.register }); | 1264 | const addr_reg = try self.register_manager.allocReg(null, &.{ base_mcv.register, offset_mcv.register }); |
| 1265 | | 1265 | |
| 1266 | try self.genArmBinOpCode(addr_reg, base_mcv, offset_mcv, false, .add, .unsigned); | 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 | try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); |
| ... | @@ -1401,7 +1401,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1401,7 +1401,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1401 | }, | 1401 | }, |
| 1402 | .stack_offset => |off| { | 1402 | .stack_offset => |off| { |
| 1403 | if (elem_ty.abiSize(self.target.*) <= 4) { | 1403 | if (elem_ty.abiSize(self.target.*) <= 4) { |
| 1404 | const tmp_reg = try self.register_manager.allocReg(null, &.{}); | 1404 | const tmp_reg = try self.register_manager.allocReg(null, &.{reg}); |
| 1405 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); | 1405 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); |
| 1406 | try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); | 1406 | try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); |
| 1407 | } else if (elem_ty.abiSize(self.target.*) == 8) { | 1407 | } else if (elem_ty.abiSize(self.target.*) == 8) { |
| ... | @@ -1412,7 +1412,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1412,7 +1412,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1412 | // larger | 1412 | // larger |
| 1413 | | 1413 | |
| 1414 | const usize_ty = Type.initTag(.usize); | 1414 | const usize_ty = Type.initTag(.usize); |
| 1415 | const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{}); | 1415 | const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{reg}); |
| 1416 | _ = try self.addInst(.{ | 1416 | _ = try self.addInst(.{ |
| 1417 | .tag = .ldr, | 1417 | .tag = .ldr, |
| 1418 | .cond = .al, | 1418 | .cond = .al, |
| ... | @@ -1434,7 +1434,46 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1434,7 +1434,46 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1434 | try self.genSetStack(usize_ty, off, MCValue{ .register = tmp_regs[0] }); | 1434 | try self.genSetStack(usize_ty, off, MCValue{ .register = tmp_regs[0] }); |
| 1435 | 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] }); |
| 1436 | } else { | 1436 | } else { |
| 1437 | 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); |
| 1438 | } | 1477 | } |
| 1439 | }, | 1478 | }, |
| 1440 | else => return self.fail("TODO load from register into {}", .{dst_mcv}), | 1479 | else => return self.fail("TODO load from register into {}", .{dst_mcv}), |
| ... | @@ -1975,6 +2014,87 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind | ... | @@ -1975,6 +2014,87 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind |
| 1975 | return dst_mcv; | 2014 | return dst_mcv; |
| 1976 | } | 2015 | } |
| 1977 | | 2016 | |
| | 2017 | fn genArmInlineMemcpy( |
| | 2018 | self: *Self, |
| | 2019 | src: Register, |
| | 2020 | dst: Register, |
| | 2021 | len: Register, |
| | 2022 | count: Register, |
| | 2023 | tmp: Register, |
| | 2024 | ) !void { |
| | 2025 | // mov count, #0 |
| | 2026 | _ = try self.addInst(.{ |
| | 2027 | .tag = .mov, |
| | 2028 | .cond = .al, |
| | 2029 | .data = .{ .rr_op = .{ |
| | 2030 | .rd = count, |
| | 2031 | .rn = .r0, |
| | 2032 | .op = Instruction.Operand.imm(0, 0), |
| | 2033 | } }, |
| | 2034 | }); |
| | 2035 | |
| | 2036 | // loop: |
| | 2037 | // cmp count, len |
| | 2038 | _ = try self.addInst(.{ |
| | 2039 | .tag = .cmp, |
| | 2040 | .cond = .al, |
| | 2041 | .data = .{ .rr_op = .{ |
| | 2042 | .rd = .r0, |
| | 2043 | .rn = count, |
| | 2044 | .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none), |
| | 2045 | } }, |
| | 2046 | }); |
| | 2047 | |
| | 2048 | // bge end |
| | 2049 | _ = try self.addInst(.{ |
| | 2050 | .tag = .b, |
| | 2051 | .cond = .ge, |
| | 2052 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len + 5) }, |
| | 2053 | }); |
| | 2054 | |
| | 2055 | // ldrb tmp, [src, count] |
| | 2056 | _ = try self.addInst(.{ |
| | 2057 | .tag = .ldrb, |
| | 2058 | .cond = .al, |
| | 2059 | .data = .{ .rr_offset = .{ |
| | 2060 | .rt = tmp, |
| | 2061 | .rn = src, |
| | 2062 | .offset = .{ .offset = Instruction.Offset.reg(count, 0) }, |
| | 2063 | } }, |
| | 2064 | }); |
| | 2065 | |
| | 2066 | // strb tmp, [src, count] |
| | 2067 | _ = try self.addInst(.{ |
| | 2068 | .tag = .strb, |
| | 2069 | .cond = .al, |
| | 2070 | .data = .{ .rr_offset = .{ |
| | 2071 | .rt = tmp, |
| | 2072 | .rn = dst, |
| | 2073 | .offset = .{ .offset = Instruction.Offset.reg(count, 0) }, |
| | 2074 | } }, |
| | 2075 | }); |
| | 2076 | |
| | 2077 | // add count, count, #1 |
| | 2078 | _ = try self.addInst(.{ |
| | 2079 | .tag = .add, |
| | 2080 | .cond = .al, |
| | 2081 | .data = .{ .rr_op = .{ |
| | 2082 | .rd = count, |
| | 2083 | .rn = count, |
| | 2084 | .op = Instruction.Operand.imm(1, 0), |
| | 2085 | } }, |
| | 2086 | }); |
| | 2087 | |
| | 2088 | // b loop |
| | 2089 | _ = try self.addInst(.{ |
| | 2090 | .tag = .b, |
| | 2091 | .cond = .al, |
| | 2092 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 5) }, |
| | 2093 | }); |
| | 2094 | |
| | 2095 | // end: |
| | 2096 | } |
| | 2097 | |
| 1978 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void { | 2098 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void { |
| 1979 | const ty_str = self.air.instructions.items(.data)[inst].ty_str; | 2099 | const ty_str = self.air.instructions.items(.data)[inst].ty_str; |
| 1980 | const zir = &self.mod_fn.owner_decl.getFileScope().zir; | 2100 | const zir = &self.mod_fn.owner_decl.getFileScope().zir; |
| ... | @@ -3002,7 +3122,60 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3002,7 +3122,60 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3002 | const reg = try self.copyToTmpRegister(ty, mcv); | 3122 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3003 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3123 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3004 | } else { | 3124 | } else { |
| 3005 | return self.fail("TODO implement memcpy", .{}); | 3125 | // TODO optimize the register allocation |
| | 3126 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, &.{}); |
| | 3127 | const src_reg = regs[0]; |
| | 3128 | const dst_reg = regs[2]; |
| | 3129 | const len_reg = regs[2]; |
| | 3130 | const count_reg = regs[3]; |
| | 3131 | const tmp_reg = regs[4]; |
| | 3132 | |
| | 3133 | // add src_reg, fp, #off |
| | 3134 | const src_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(off)) |x| x else { |
| | 3135 | return self.fail("TODO load: set reg to stack offset with all possible offsets", .{}); |
| | 3136 | }; |
| | 3137 | _ = try self.addInst(.{ |
| | 3138 | .tag = .add, |
| | 3139 | .cond = .al, |
| | 3140 | .data = .{ .rr_op = .{ |
| | 3141 | .rd = src_reg, |
| | 3142 | .rn = .fp, |
| | 3143 | .op = src_offset_op, |
| | 3144 | } }, |
| | 3145 | }); |
| | 3146 | |
| | 3147 | // sub dst_reg, fp, #stack_offset |
| | 3148 | const adj_stack_offset = stack_offset + @intCast(u32, ty.abiSize(self.target.*)); |
| | 3149 | const dst_offset_op: Instruction.Operand = if (Instruction.Operand.fromU32(adj_stack_offset)) |x| x else { |
| | 3150 | return self.fail("TODO load: set reg to stack offset with all possible offsets", .{}); |
| | 3151 | }; |
| | 3152 | _ = try self.addInst(.{ |
| | 3153 | .tag = .sub, |
| | 3154 | .cond = .al, |
| | 3155 | .data = .{ .rr_op = .{ |
| | 3156 | .rd = dst_reg, |
| | 3157 | .rn = .fp, |
| | 3158 | .op = dst_offset_op, |
| | 3159 | } }, |
| | 3160 | }); |
| | 3161 | |
| | 3162 | // mov len, #elem_size |
| | 3163 | const elem_size = @intCast(u32, ty.abiSize(self.target.*)); |
| | 3164 | const len_op: Instruction.Operand = if (Instruction.Operand.fromU32(elem_size)) |x| x else { |
| | 3165 | return self.fail("TODO load: set reg to elem_size with all possible sizes", .{}); |
| | 3166 | }; |
| | 3167 | _ = try self.addInst(.{ |
| | 3168 | .tag = .mov, |
| | 3169 | .cond = .al, |
| | 3170 | .data = .{ .rr_op = .{ |
| | 3171 | .rd = len_reg, |
| | 3172 | .rn = .r0, |
| | 3173 | .op = len_op, |
| | 3174 | } }, |
| | 3175 | }); |
| | 3176 | |
| | 3177 | // memcpy(src, dst, len) |
| | 3178 | try self.genArmInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 3006 | } | 3179 | } |
| 3007 | }, | 3180 | }, |
| 3008 | } | 3181 | } |