| ... | ... | @@ -247,6 +247,31 @@ const BigTomb = struct { |
| 247 | 247 | log.debug("%{d} => {}", .{ bt.inst, result }); |
| 248 | 248 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; |
| 249 | 249 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); |
| 250 | |
| 251 | switch (result) { |
| 252 | .register => |reg| { |
| 253 | // In some cases (such as bitcast), an operand |
| 254 | // may be the same MCValue as the result. If |
| 255 | // that operand died and was a register, it |
| 256 | // was freed by processDeath. We have to |
| 257 | // "re-allocate" the register. |
| 258 | if (bt.function.register_manager.isRegFree(reg)) { |
| 259 | bt.function.register_manager.getRegAssumeFree(reg, bt.inst); |
| 260 | } |
| 261 | }, |
| 262 | .register_c_flag, |
| 263 | .register_v_flag, |
| 264 | => |reg| { |
| 265 | if (bt.function.register_manager.isRegFree(reg)) { |
| 266 | bt.function.register_manager.getRegAssumeFree(reg, bt.inst); |
| 267 | } |
| 268 | bt.function.cpsr_flags_inst = bt.inst; |
| 269 | }, |
| 270 | .cpsr_flags => { |
| 271 | bt.function.cpsr_flags_inst = bt.inst; |
| 272 | }, |
| 273 | else => {}, |
| 274 | } |
| 250 | 275 | } |
| 251 | 276 | bt.function.finishAirBookkeeping(); |
| 252 | 277 | } |
| ... | ... | @@ -332,7 +357,7 @@ pub fn generate( |
| 332 | 357 | }; |
| 333 | 358 | |
| 334 | 359 | for (function.dbg_arg_relocs.items) |reloc| { |
| 335 | | try function.genArgDbgInfo(reloc.inst, reloc.index, call_info.stack_byte_count); |
| 360 | try function.genArgDbgInfo(reloc.inst, reloc.index); |
| 336 | 361 | } |
| 337 | 362 | |
| 338 | 363 | var mir = Mir{ |
| ... | ... | @@ -351,7 +376,8 @@ pub fn generate( |
| 351 | 376 | .prev_di_pc = 0, |
| 352 | 377 | .prev_di_line = module_fn.lbrace_line, |
| 353 | 378 | .prev_di_column = module_fn.lbrace_column, |
| 354 | | .prologue_stack_space = call_info.stack_byte_count + function.saved_regs_stack_space, |
| 379 | .stack_size = function.max_end_stack, |
| 380 | .saved_regs_stack_space = function.saved_regs_stack_space, |
| 355 | 381 | }; |
| 356 | 382 | defer emit.deinit(); |
| 357 | 383 | |
| ... | ... | @@ -464,6 +490,7 @@ fn gen(self: *Self) !void { |
| 464 | 490 | const total_stack_size = self.max_end_stack + self.saved_regs_stack_space; |
| 465 | 491 | const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align); |
| 466 | 492 | const stack_size = aligned_total_stack_end - self.saved_regs_stack_space; |
| 493 | self.max_end_stack = stack_size; |
| 467 | 494 | if (Instruction.Operand.fromU32(stack_size)) |op| { |
| 468 | 495 | self.mir_instructions.set(sub_reloc, .{ |
| 469 | 496 | .tag = .sub, |
| ... | ... | @@ -1812,7 +1839,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV |
| 1812 | 1839 | switch (error_union_mcv) { |
| 1813 | 1840 | .register => return self.fail("TODO errUnionErr for registers", .{}), |
| 1814 | 1841 | .stack_argument_offset => |off| { |
| 1815 | | return MCValue{ .stack_argument_offset = off - err_offset }; |
| 1842 | return MCValue{ .stack_argument_offset = off + err_offset }; |
| 1816 | 1843 | }, |
| 1817 | 1844 | .stack_offset => |off| { |
| 1818 | 1845 | return MCValue{ .stack_offset = off - err_offset }; |
| ... | ... | @@ -1849,7 +1876,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) |
| 1849 | 1876 | switch (error_union_mcv) { |
| 1850 | 1877 | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| 1851 | 1878 | .stack_argument_offset => |off| { |
| 1852 | | return MCValue{ .stack_argument_offset = off - payload_offset }; |
| 1879 | return MCValue{ .stack_argument_offset = off + payload_offset }; |
| 1853 | 1880 | }, |
| 1854 | 1881 | .stack_offset => |off| { |
| 1855 | 1882 | return MCValue{ .stack_offset = off - payload_offset }; |
| ... | ... | @@ -1983,7 +2010,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1983 | 2010 | .dead, .unreach => unreachable, |
| 1984 | 2011 | .register => unreachable, // a slice doesn't fit in one register |
| 1985 | 2012 | .stack_argument_offset => |off| { |
| 1986 | | break :result MCValue{ .stack_argument_offset = off - 4 }; |
| 2013 | break :result MCValue{ .stack_argument_offset = off + 4 }; |
| 1987 | 2014 | }, |
| 1988 | 2015 | .stack_offset => |off| { |
| 1989 | 2016 | break :result MCValue{ .stack_offset = off - 4 }; |
| ... | ... | @@ -2259,16 +2286,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2259 | 2286 | .register_c_flag, |
| 2260 | 2287 | .register_v_flag, |
| 2261 | 2288 | => unreachable, // cannot hold an address |
| 2262 | | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 2263 | | .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 | }, |
| 2264 | 2295 | .register => |reg| { |
| 2265 | 2296 | const reg_lock = self.register_manager.lockReg(reg); |
| 2266 | 2297 | defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); |
| 2267 | 2298 | |
| 2268 | 2299 | switch (dst_mcv) { |
| 2269 | | .dead => unreachable, |
| 2270 | | .undef => unreachable, |
| 2271 | | .cpsr_flags => unreachable, |
| 2272 | 2300 | .register => |dst_reg| { |
| 2273 | 2301 | try self.genLdrRegister(dst_reg, reg, elem_ty); |
| 2274 | 2302 | }, |
| ... | ... | @@ -2304,7 +2332,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2304 | 2332 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 2305 | 2333 | } |
| 2306 | 2334 | }, |
| 2307 | | else => return self.fail("TODO load from register into {}", .{dst_mcv}), |
| 2335 | else => unreachable, // attempting to load into non-register or non-stack MCValue |
| 2308 | 2336 | } |
| 2309 | 2337 | }, |
| 2310 | 2338 | .memory, |
| ... | ... | @@ -2401,7 +2429,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2401 | 2429 | // sub src_reg, fp, #off |
| 2402 | 2430 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 2403 | 2431 | }, |
| 2404 | | .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) }), |
| 2405 | 2433 | .stack_argument_offset => |off| { |
| 2406 | 2434 | _ = try self.addInst(.{ |
| 2407 | 2435 | .tag = .ldr_ptr_stack_argument, |
| ... | ... | @@ -2507,7 +2535,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2507 | 2535 | switch (mcv) { |
| 2508 | 2536 | .dead, .unreach => unreachable, |
| 2509 | 2537 | .stack_argument_offset => |off| { |
| 2510 | | break :result MCValue{ .stack_argument_offset = off - struct_field_offset }; |
| 2538 | break :result MCValue{ .stack_argument_offset = off + struct_field_offset }; |
| 2511 | 2539 | }, |
| 2512 | 2540 | .stack_offset => |off| { |
| 2513 | 2541 | break :result MCValue{ .stack_offset = off - struct_field_offset }; |
| ... | ... | @@ -3347,6 +3375,102 @@ fn genInlineMemcpy( |
| 3347 | 3375 | // end: |
| 3348 | 3376 | } |
| 3349 | 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 | |
| 3350 | 3474 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 3351 | 3475 | /// after codegen for this symbol is done. |
| 3352 | 3476 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { |
| ... | ... | @@ -3369,9 +3493,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { |
| 3369 | 3493 | } |
| 3370 | 3494 | } |
| 3371 | 3495 | |
| 3372 | | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_count: u32) error{OutOfMemory}!void { |
| 3373 | | const prologue_stack_space = stack_byte_count + self.saved_regs_stack_space; |
| 3374 | | |
| 3496 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void { |
| 3375 | 3497 | const mcv = self.args[arg_index]; |
| 3376 | 3498 | const ty = self.air.instructions.items(.data)[inst].ty; |
| 3377 | 3499 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); |
| ... | ... | @@ -3404,7 +3526,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_c |
| 3404 | 3526 | // const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 3405 | 3527 | const adjusted_stack_offset = switch (mcv) { |
| 3406 | 3528 | .stack_offset => |offset| -@intCast(i32, offset), |
| 3407 | | .stack_argument_offset => |offset| @intCast(i32, prologue_stack_space - offset), |
| 3529 | .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset), |
| 3408 | 3530 | else => unreachable, |
| 3409 | 3531 | }; |
| 3410 | 3532 | |
| ... | ... | @@ -3524,7 +3646,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3524 | 3646 | try self.register_manager.getReg(reg, null); |
| 3525 | 3647 | } |
| 3526 | 3648 | |
| 3527 | | if (info.return_value == .stack_offset) { |
| 3649 | // If returning by reference, r0 will contain the address of where |
| 3650 | // to put the result into. In that case, make sure that r0 remains |
| 3651 | // untouched by the parameter passing code |
| 3652 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { |
| 3528 | 3653 | log.debug("airCall: return by reference", .{}); |
| 3529 | 3654 | const ret_ty = fn_ty.fnReturnType(); |
| 3530 | 3655 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| ... | ... | @@ -3540,7 +3665,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3540 | 3665 | try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset }); |
| 3541 | 3666 | |
| 3542 | 3667 | info.return_value = .{ .stack_offset = stack_offset }; |
| 3543 | | } |
| 3668 | |
| 3669 | break :blk self.register_manager.lockRegAssumeUnused(.r0); |
| 3670 | } else null; |
| 3671 | defer if (r0_lock) |reg| self.register_manager.unlockReg(reg); |
| 3544 | 3672 | |
| 3545 | 3673 | // Make space for the arguments passed via the stack |
| 3546 | 3674 | self.max_end_stack += info.stack_byte_count; |
| ... | ... | @@ -3559,7 +3687,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3559 | 3687 | .stack_offset => unreachable, |
| 3560 | 3688 | .stack_argument_offset => |offset| try self.genSetStackArgument( |
| 3561 | 3689 | arg_ty, |
| 3562 | | info.stack_byte_count - offset, |
| 3690 | offset, |
| 3563 | 3691 | arg_mcv, |
| 3564 | 3692 | ), |
| 3565 | 3693 | else => unreachable, |
| ... | ... | @@ -4621,11 +4749,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4621 | 4749 | if (!self.wantSafety()) |
| 4622 | 4750 | return; // The already existing value will do just fine. |
| 4623 | 4751 | // TODO Upgrade this to a memset call when we have that available. |
| 4624 | | switch (ty.abiSize(self.target.*)) { |
| 4625 | | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 4626 | | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 4627 | | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 4628 | | 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 | ), |
| 4629 | 4761 | } |
| 4630 | 4762 | }, |
| 4631 | 4763 | .cpsr_flags, |
| ... | ... | @@ -5037,9 +5169,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5037 | 5169 | return; // The already existing value will do just fine. |
| 5038 | 5170 | // TODO Upgrade this to a memset call when we have that available. |
| 5039 | 5171 | switch (abi_size) { |
| 5040 | | 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), |
| 5041 | | 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 5042 | | 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 }), |
| 5043 | 5175 | else => return self.fail("TODO implement memset", .{}), |
| 5044 | 5176 | } |
| 5045 | 5177 | }, |
| ... | ... | @@ -5653,8 +5785,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5653 | 5785 | if (ty.abiAlignment(self.target.*) == 8) |
| 5654 | 5786 | nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8); |
| 5655 | 5787 | |
| 5656 | | nsaa += param_size; |
| 5657 | 5788 | result.args[i] = .{ .stack_argument_offset = nsaa }; |
| 5789 | nsaa += param_size; |
| 5658 | 5790 | } |
| 5659 | 5791 | } |
| 5660 | 5792 | |
| ... | ... | @@ -5687,9 +5819,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5687 | 5819 | for (param_types) |ty, i| { |
| 5688 | 5820 | if (ty.abiSize(self.target.*) > 0) { |
| 5689 | 5821 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 5822 | const param_alignment = ty.abiAlignment(self.target.*); |
| 5690 | 5823 | |
| 5691 | | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, ty.abiAlignment(self.target.*)) + param_size; |
| 5824 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); |
| 5692 | 5825 | result.args[i] = .{ .stack_argument_offset = stack_offset }; |
| 5826 | stack_offset += param_size; |
| 5693 | 5827 | } else { |
| 5694 | 5828 | result.args[i] = .{ .none = {} }; |
| 5695 | 5829 | } |