| ... | @@ -2286,16 +2286,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2286,16 +2286,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2286 | .register_c_flag, | 2286 | .register_c_flag, |
| 2287 | .register_v_flag, | 2287 | .register_v_flag, |
| 2288 | => unreachable, // cannot hold an address | 2288 | => unreachable, // cannot hold an address |
| 2289 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 2289 | .immediate => |imm| { |
| 2290 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), | 2290 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }); |
| | 2291 | }, |
| | 2292 | .ptr_stack_offset => |off| { |
| | 2293 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }); |
| | 2294 | }, |
| 2291 | .register => |reg| { | 2295 | .register => |reg| { |
| 2292 | const reg_lock = self.register_manager.lockReg(reg); | 2296 | const reg_lock = self.register_manager.lockReg(reg); |
| 2293 | defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); | 2297 | defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); |
| 2294 | | 2298 | |
| 2295 | switch (dst_mcv) { | 2299 | switch (dst_mcv) { |
| 2296 | .dead => unreachable, | | |
| 2297 | .undef => unreachable, | | |
| 2298 | .cpsr_flags => unreachable, | | |
| 2299 | .register => |dst_reg| { | 2300 | .register => |dst_reg| { |
| 2300 | try self.genLdrRegister(dst_reg, reg, elem_ty); | 2301 | try self.genLdrRegister(dst_reg, reg, elem_ty); |
| 2301 | }, | 2302 | }, |
| ... | @@ -2331,7 +2332,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2331,7 +2332,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2331 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); | 2332 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 2332 | } | 2333 | } |
| 2333 | }, | 2334 | }, |
| 2334 | else => return self.fail("TODO load from register into {}", .{dst_mcv}), | 2335 | else => unreachable, // attempting to load into non-register or non-stack MCValue |
| 2335 | } | 2336 | } |
| 2336 | }, | 2337 | }, |
| 2337 | .memory, | 2338 | .memory, |
| ... | @@ -2428,7 +2429,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2428,7 +2429,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2428 | // sub src_reg, fp, #off | 2429 | // sub src_reg, fp, #off |
| 2429 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); | 2430 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 2430 | }, | 2431 | }, |
| 2431 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }), | 2432 | .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }), |
| 2432 | .stack_argument_offset => |off| { | 2433 | .stack_argument_offset => |off| { |
| 2433 | _ = try self.addInst(.{ | 2434 | _ = try self.addInst(.{ |
| 2434 | .tag = .ldr_ptr_stack_argument, | 2435 | .tag = .ldr_ptr_stack_argument, |
| ... | @@ -3374,6 +3375,102 @@ fn genInlineMemcpy( | ... | @@ -3374,6 +3375,102 @@ fn genInlineMemcpy( |
| 3374 | // end: | 3375 | // end: |
| 3375 | } | 3376 | } |
| 3376 | | 3377 | |
| | 3378 | fn genInlineMemset( |
| | 3379 | self: *Self, |
| | 3380 | dst: MCValue, |
| | 3381 | val: MCValue, |
| | 3382 | len: MCValue, |
| | 3383 | ) !void { |
| | 3384 | const dst_reg = switch (dst) { |
| | 3385 | .register => |r| r, |
| | 3386 | else => try self.copyToTmpRegister(Type.initTag(.manyptr_u8), dst), |
| | 3387 | }; |
| | 3388 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| | 3389 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3390 | |
| | 3391 | const val_reg = switch (val) { |
| | 3392 | .register => |r| r, |
| | 3393 | else => try self.copyToTmpRegister(Type.initTag(.u8), val), |
| | 3394 | }; |
| | 3395 | const val_reg_lock = self.register_manager.lockReg(val_reg); |
| | 3396 | defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3397 | |
| | 3398 | const len_reg = switch (len) { |
| | 3399 | .register => |r| r, |
| | 3400 | else => try self.copyToTmpRegister(Type.usize, len), |
| | 3401 | }; |
| | 3402 | const len_reg_lock = self.register_manager.lockReg(len_reg); |
| | 3403 | defer if (len_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3404 | |
| | 3405 | const count_reg = try self.register_manager.allocReg(null, gp); |
| | 3406 | |
| | 3407 | try self.genInlineMemsetCode(dst_reg, val_reg, len_reg, count_reg); |
| | 3408 | } |
| | 3409 | |
| | 3410 | fn genInlineMemsetCode( |
| | 3411 | self: *Self, |
| | 3412 | dst: Register, |
| | 3413 | val: Register, |
| | 3414 | len: Register, |
| | 3415 | count: Register, |
| | 3416 | ) !void { |
| | 3417 | // mov count, #0 |
| | 3418 | _ = try self.addInst(.{ |
| | 3419 | .tag = .mov, |
| | 3420 | .data = .{ .rr_op = .{ |
| | 3421 | .rd = count, |
| | 3422 | .rn = .r0, |
| | 3423 | .op = Instruction.Operand.imm(0, 0), |
| | 3424 | } }, |
| | 3425 | }); |
| | 3426 | |
| | 3427 | // loop: |
| | 3428 | // cmp count, len |
| | 3429 | _ = try self.addInst(.{ |
| | 3430 | .tag = .cmp, |
| | 3431 | .data = .{ .rr_op = .{ |
| | 3432 | .rd = .r0, |
| | 3433 | .rn = count, |
| | 3434 | .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none), |
| | 3435 | } }, |
| | 3436 | }); |
| | 3437 | |
| | 3438 | // bge end |
| | 3439 | _ = try self.addInst(.{ |
| | 3440 | .tag = .b, |
| | 3441 | .cond = .ge, |
| | 3442 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len + 4) }, |
| | 3443 | }); |
| | 3444 | |
| | 3445 | // strb val, [src, count] |
| | 3446 | _ = try self.addInst(.{ |
| | 3447 | .tag = .strb, |
| | 3448 | .data = .{ .rr_offset = .{ |
| | 3449 | .rt = val, |
| | 3450 | .rn = dst, |
| | 3451 | .offset = .{ .offset = Instruction.Offset.reg(count, .none) }, |
| | 3452 | } }, |
| | 3453 | }); |
| | 3454 | |
| | 3455 | // add count, count, #1 |
| | 3456 | _ = try self.addInst(.{ |
| | 3457 | .tag = .add, |
| | 3458 | .data = .{ .rr_op = .{ |
| | 3459 | .rd = count, |
| | 3460 | .rn = count, |
| | 3461 | .op = Instruction.Operand.imm(1, 0), |
| | 3462 | } }, |
| | 3463 | }); |
| | 3464 | |
| | 3465 | // b loop |
| | 3466 | _ = try self.addInst(.{ |
| | 3467 | .tag = .b, |
| | 3468 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 4) }, |
| | 3469 | }); |
| | 3470 | |
| | 3471 | // end: |
| | 3472 | } |
| | 3473 | |
| 3377 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | 3474 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 3378 | /// after codegen for this symbol is done. | 3475 | /// after codegen for this symbol is done. |
| 3379 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { | 3476 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { |
| ... | @@ -4652,11 +4749,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4652,11 +4749,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4652 | if (!self.wantSafety()) | 4749 | if (!self.wantSafety()) |
| 4653 | return; // The already existing value will do just fine. | 4750 | return; // The already existing value will do just fine. |
| 4654 | // TODO Upgrade this to a memset call when we have that available. | 4751 | // TODO Upgrade this to a memset call when we have that available. |
| 4655 | switch (ty.abiSize(self.target.*)) { | 4752 | switch (abi_size) { |
| 4656 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), | 4753 | 1 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 4657 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 4754 | 2 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 4658 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 4755 | 4 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 4659 | else => return self.fail("TODO implement memset", .{}), | 4756 | else => try self.genInlineMemset( |
| | 4757 | .{ .ptr_stack_offset = stack_offset }, |
| | 4758 | .{ .immediate = 0xaa }, |
| | 4759 | .{ .immediate = abi_size }, |
| | 4760 | ), |
| 4660 | } | 4761 | } |
| 4661 | }, | 4762 | }, |
| 4662 | .cpsr_flags, | 4763 | .cpsr_flags, |
| ... | @@ -5068,9 +5169,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5068,9 +5169,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5068 | return; // The already existing value will do just fine. | 5169 | return; // The already existing value will do just fine. |
| 5069 | // TODO Upgrade this to a memset call when we have that available. | 5170 | // TODO Upgrade this to a memset call when we have that available. |
| 5070 | switch (abi_size) { | 5171 | switch (abi_size) { |
| 5071 | 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), | 5172 | 1 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), |
| 5072 | 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), | 5173 | 2 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 5073 | 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 5174 | 4 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 5074 | else => return self.fail("TODO implement memset", .{}), | 5175 | else => return self.fail("TODO implement memset", .{}), |
| 5075 | } | 5176 | } |
| 5076 | }, | 5177 | }, |