| ... | ... | @@ -2286,16 +2286,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2286 | 2286 | .register_c_flag, |
| 2287 | 2287 | .register_v_flag, |
| 2288 | 2288 | => unreachable, // cannot hold an address |
| 2289 | | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 2290 | | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 2289 | .immediate => |imm| { |
| 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 | 2295 | .register => |reg| { |
| 2292 | 2296 | const reg_lock = self.register_manager.lockReg(reg); |
| 2293 | 2297 | defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); |
| 2294 | 2298 | |
| 2295 | 2299 | switch (dst_mcv) { |
| 2296 | | .dead => unreachable, |
| 2297 | | .undef => unreachable, |
| 2298 | | .cpsr_flags => unreachable, |
| 2299 | 2300 | .register => |dst_reg| { |
| 2300 | 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 | 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 | 2338 | .memory, |
| ... | ... | @@ -2428,7 +2429,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2428 | 2429 | // sub src_reg, fp, #off |
| 2429 | 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 | 2433 | .stack_argument_offset => |off| { |
| 2433 | 2434 | _ = try self.addInst(.{ |
| 2434 | 2435 | .tag = .ldr_ptr_stack_argument, |
| ... | ... | @@ -3374,6 +3375,102 @@ fn genInlineMemcpy( |
| 3374 | 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 | 3474 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 3378 | 3475 | /// after codegen for this symbol is done. |
| 3379 | 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 | 4749 | if (!self.wantSafety()) |
| 4653 | 4750 | return; // The already existing value will do just fine. |
| 4654 | 4751 | // TODO Upgrade this to a memset call when we have that available. |
| 4655 | | switch (ty.abiSize(self.target.*)) { |
| 4656 | | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 4657 | | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 4658 | | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 4659 | | else => return self.fail("TODO implement memset", .{}), |
| 4752 | switch (abi_size) { |
| 4753 | 1 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 4754 | 2 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 4755 | 4 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 4756 | else => try self.genInlineMemset( |
| 4757 | .{ .ptr_stack_offset = stack_offset }, |
| 4758 | .{ .immediate = 0xaa }, |
| 4759 | .{ .immediate = abi_size }, |
| 4760 | ), |
| 4660 | 4761 | } |
| 4661 | 4762 | }, |
| 4662 | 4763 | .cpsr_flags, |
| ... | ... | @@ -5068,9 +5169,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5068 | 5169 | return; // The already existing value will do just fine. |
| 5069 | 5170 | // TODO Upgrade this to a memset call when we have that available. |
| 5070 | 5171 | switch (abi_size) { |
| 5071 | | 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), |
| 5072 | | 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 5073 | | 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 5172 | 1 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), |
| 5173 | 2 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 5174 | 4 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 5074 | 5175 | else => return self.fail("TODO implement memset", .{}), |
| 5075 | 5176 | } |
| 5076 | 5177 | }, |