| ... | @@ -2506,6 +2506,70 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2506,6 +2506,70 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 2506 | return self.finishAirBookkeeping(); | 2506 | return self.finishAirBookkeeping(); |
| 2507 | } | 2507 | } |
| 2508 | | 2508 | |
| | 2509 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { |
| | 2510 | const abi_size = ty.abiSize(self.target.*); |
| | 2511 | switch (mcv) { |
| | 2512 | .compare_flags_unsigned, |
| | 2513 | .compare_flags_signed, |
| | 2514 | => |cmp_op| { |
| | 2515 | // Here we map the opposites since the jump is to the false branch. |
| | 2516 | const flags: u2 = switch (cmp_op) { |
| | 2517 | .gte => 0b10, |
| | 2518 | .gt => 0b11, |
| | 2519 | .neq => 0b01, |
| | 2520 | .lt => 0b00, |
| | 2521 | .lte => 0b01, |
| | 2522 | .eq => 0b00, |
| | 2523 | }; |
| | 2524 | const tag: Mir.Inst.Tag = if (cmp_op == .neq or cmp_op == .eq) |
| | 2525 | .cond_jmp_eq_ne |
| | 2526 | else if (mcv == .compare_flags_unsigned) |
| | 2527 | Mir.Inst.Tag.cond_jmp_above_below |
| | 2528 | else |
| | 2529 | Mir.Inst.Tag.cond_jmp_greater_less; |
| | 2530 | return self.addInst(.{ |
| | 2531 | .tag = tag, |
| | 2532 | .ops = (Mir.Ops{ |
| | 2533 | .flags = flags, |
| | 2534 | }).encode(), |
| | 2535 | .data = .{ .inst = undefined }, |
| | 2536 | }); |
| | 2537 | }, |
| | 2538 | .register => |reg| { |
| | 2539 | _ = try self.addInst(.{ |
| | 2540 | .tag = .@"test", |
| | 2541 | .ops = (Mir.Ops{ |
| | 2542 | .reg1 = reg, |
| | 2543 | .flags = 0b00, |
| | 2544 | }).encode(), |
| | 2545 | .data = .{ .imm = 1 }, |
| | 2546 | }); |
| | 2547 | return self.addInst(.{ |
| | 2548 | .tag = .cond_jmp_eq_ne, |
| | 2549 | .ops = (Mir.Ops{ |
| | 2550 | .flags = 0b01, |
| | 2551 | }).encode(), |
| | 2552 | .data = .{ .inst = undefined }, |
| | 2553 | }); |
| | 2554 | }, |
| | 2555 | .immediate => { |
| | 2556 | if (abi_size <= 8) { |
| | 2557 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 2558 | return self.genCondBrMir(ty, .{ .register = reg }); |
| | 2559 | } |
| | 2560 | return self.fail("TODO implement condbr when condition is immediate larger than 4 bytes", .{}); |
| | 2561 | }, |
| | 2562 | .stack_offset => { |
| | 2563 | if (abi_size <= 8) { |
| | 2564 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 2565 | return self.genCondBrMir(ty, .{ .register = reg }); |
| | 2566 | } |
| | 2567 | return self.fail("TODO implement condbr when condition is stack offset with abi larger than 8 bytes", .{}); |
| | 2568 | }, |
| | 2569 | else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}), |
| | 2570 | } |
| | 2571 | } |
| | 2572 | |
| 2509 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | 2573 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2510 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 2574 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2511 | const cond = try self.resolveInst(pl_op.operand); | 2575 | const cond = try self.resolveInst(pl_op.operand); |
| ... | @@ -2515,97 +2579,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2515,97 +2579,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2515 | const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | 2579 | const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| 2516 | const liveness_condbr = self.liveness.getCondBr(inst); | 2580 | const liveness_condbr = self.liveness.getCondBr(inst); |
| 2517 | | 2581 | |
| 2518 | const reloc: Mir.Inst.Index = reloc: { | 2582 | const reloc = try self.genCondBrMir(cond_ty, cond); |
| 2519 | switch (cond) { | | |
| 2520 | .compare_flags_signed => |cmp_op| { | | |
| 2521 | // Here we map the opposites since the jump is to the false branch. | | |
| 2522 | const flags: u2 = switch (cmp_op) { | | |
| 2523 | .gte => 0b10, | | |
| 2524 | .gt => 0b11, | | |
| 2525 | .neq => 0b01, | | |
| 2526 | .lt => 0b00, | | |
| 2527 | .lte => 0b01, | | |
| 2528 | .eq => 0b00, | | |
| 2529 | }; | | |
| 2530 | const tag: Mir.Inst.Tag = if (cmp_op == .neq or cmp_op == .eq) | | |
| 2531 | .cond_jmp_eq_ne | | |
| 2532 | else | | |
| 2533 | .cond_jmp_greater_less; | | |
| 2534 | const reloc = try self.addInst(.{ | | |
| 2535 | .tag = tag, | | |
| 2536 | .ops = (Mir.Ops{ | | |
| 2537 | .flags = flags, | | |
| 2538 | }).encode(), | | |
| 2539 | .data = .{ .inst = undefined }, | | |
| 2540 | }); | | |
| 2541 | break :reloc reloc; | | |
| 2542 | }, | | |
| 2543 | .compare_flags_unsigned => |cmp_op| { | | |
| 2544 | // Here we map the opposites since the jump is to the false branch. | | |
| 2545 | const flags: u2 = switch (cmp_op) { | | |
| 2546 | .gte => 0b10, | | |
| 2547 | .gt => 0b11, | | |
| 2548 | .neq => 0b01, | | |
| 2549 | .lt => 0b00, | | |
| 2550 | .lte => 0b01, | | |
| 2551 | .eq => 0b00, | | |
| 2552 | }; | | |
| 2553 | const tag: Mir.Inst.Tag = if (cmp_op == .neq or cmp_op == .eq) | | |
| 2554 | .cond_jmp_eq_ne | | |
| 2555 | else | | |
| 2556 | .cond_jmp_above_below; | | |
| 2557 | const reloc = try self.addInst(.{ | | |
| 2558 | .tag = tag, | | |
| 2559 | .ops = (Mir.Ops{ | | |
| 2560 | .flags = flags, | | |
| 2561 | }).encode(), | | |
| 2562 | .data = .{ .inst = undefined }, | | |
| 2563 | }); | | |
| 2564 | break :reloc reloc; | | |
| 2565 | }, | | |
| 2566 | .register => |reg| { | | |
| 2567 | _ = try self.addInst(.{ | | |
| 2568 | .tag = .@"test", | | |
| 2569 | .ops = (Mir.Ops{ | | |
| 2570 | .reg1 = reg, | | |
| 2571 | .flags = 0b00, | | |
| 2572 | }).encode(), | | |
| 2573 | .data = .{ .imm = 1 }, | | |
| 2574 | }); | | |
| 2575 | const reloc = try self.addInst(.{ | | |
| 2576 | .tag = .cond_jmp_eq_ne, | | |
| 2577 | .ops = (Mir.Ops{ | | |
| 2578 | .flags = 0b01, | | |
| 2579 | }).encode(), | | |
| 2580 | .data = .{ .inst = undefined }, | | |
| 2581 | }); | | |
| 2582 | break :reloc reloc; | | |
| 2583 | }, | | |
| 2584 | .immediate => |imm| { | | |
| 2585 | if (cond_ty.abiSize(self.target.*) <= 4) { | | |
| 2586 | const reg = try self.copyToTmpRegister(cond_ty, .{ .immediate = imm }); | | |
| 2587 | _ = try self.addInst(.{ | | |
| 2588 | .tag = .@"test", | | |
| 2589 | .ops = (Mir.Ops{ | | |
| 2590 | .reg1 = reg, | | |
| 2591 | .flags = 0b00, | | |
| 2592 | }).encode(), | | |
| 2593 | .data = .{ .imm = 1 }, | | |
| 2594 | }); | | |
| 2595 | const reloc = try self.addInst(.{ | | |
| 2596 | .tag = .cond_jmp_eq_ne, | | |
| 2597 | .ops = (Mir.Ops{ | | |
| 2598 | .flags = 0b01, | | |
| 2599 | }).encode(), | | |
| 2600 | .data = .{ .inst = undefined }, | | |
| 2601 | }); | | |
| 2602 | break :reloc reloc; | | |
| 2603 | } | | |
| 2604 | return self.fail("TODO implement condbr when condition is immediate larger than 4 bytes", .{}); | | |
| 2605 | }, | | |
| 2606 | else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(cond)}), | | |
| 2607 | } | | |
| 2608 | }; | | |
| 2609 | | 2583 | |
| 2610 | // Capture the state of register and stack allocation state so that we can revert to it. | 2584 | // Capture the state of register and stack allocation state so that we can revert to it. |
| 2611 | const parent_next_stack_offset = self.next_stack_offset; | 2585 | const parent_next_stack_offset = self.next_stack_offset; |
| ... | @@ -3158,6 +3132,53 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3158,6 +3132,53 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3158 | .dead => unreachable, | 3132 | .dead => unreachable, |
| 3159 | .ptr_embedded_in_code => unreachable, | 3133 | .ptr_embedded_in_code => unreachable, |
| 3160 | .unreach, .none => return, | 3134 | .unreach, .none => return, |
| | 3135 | .compare_flags_unsigned, |
| | 3136 | .compare_flags_signed, |
| | 3137 | => { |
| | 3138 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 3139 | return self.genSetStackArg(ty, stack_offset, .{ .register = reg }); |
| | 3140 | }, |
| | 3141 | .immediate => |imm| { |
| | 3142 | const off = stack_offset + @intCast(i32, abi_size); |
| | 3143 | switch (abi_size) { |
| | 3144 | 1, 2, 4 => { |
| | 3145 | // We have a positive stack offset value but we want a twos complement negative |
| | 3146 | // offset from rbp, which is at the top of the stack frame. |
| | 3147 | // mov [rbp+offset], immediate |
| | 3148 | const payload = try self.addExtra(Mir.ImmPair{ |
| | 3149 | .dest_off = @bitCast(u32, -off), |
| | 3150 | .operand = @truncate(u32, imm), |
| | 3151 | }); |
| | 3152 | _ = try self.addInst(.{ |
| | 3153 | .tag = .mov_mem_imm, |
| | 3154 | .ops = (Mir.Ops{ |
| | 3155 | .reg1 = .rsp, |
| | 3156 | .flags = switch (abi_size) { |
| | 3157 | 1 => 0b00, |
| | 3158 | 2 => 0b01, |
| | 3159 | 4 => 0b10, |
| | 3160 | else => unreachable, |
| | 3161 | }, |
| | 3162 | }).encode(), |
| | 3163 | .data = .{ .payload = payload }, |
| | 3164 | }); |
| | 3165 | }, |
| | 3166 | 8 => { |
| | 3167 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 3168 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| | 3169 | }, |
| | 3170 | else => return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv}), |
| | 3171 | } |
| | 3172 | }, |
| | 3173 | .memory, |
| | 3174 | .embedded_in_code, |
| | 3175 | => { |
| | 3176 | if (abi_size <= 8) { |
| | 3177 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 3178 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| | 3179 | } |
| | 3180 | return self.fail("TODO implement memcpy for setting args on stack from {}", .{mcv}); |
| | 3181 | }, |
| 3161 | .register => |reg| { | 3182 | .register => |reg| { |
| 3162 | _ = try self.addInst(.{ | 3183 | _ = try self.addInst(.{ |
| 3163 | .tag = .mov, | 3184 | .tag = .mov, |
| ... | @@ -3227,13 +3248,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3227,13 +3248,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3227 | else => return self.genInlineMemset(ty, stack_offset, .{ .immediate = 0xaa }), | 3248 | else => return self.genInlineMemset(ty, stack_offset, .{ .immediate = 0xaa }), |
| 3228 | } | 3249 | } |
| 3229 | }, | 3250 | }, |
| 3230 | .compare_flags_unsigned => |op| { | 3251 | .compare_flags_unsigned, |
| 3231 | _ = op; | 3252 | .compare_flags_signed, |
| 3232 | return self.fail("TODO implement set stack variable with compare flags value (unsigned)", .{}); | 3253 | => { |
| 3233 | }, | 3254 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3234 | .compare_flags_signed => |op| { | 3255 | return self.genSetStack(ty, stack_offset, .{ .register = reg }); |
| 3235 | _ = op; | | |
| 3236 | return self.fail("TODO implement set stack variable with compare flags value (signed)", .{}); | | |
| 3237 | }, | 3256 | }, |
| 3238 | .immediate => |x_big| { | 3257 | .immediate => |x_big| { |
| 3239 | const abi_size = ty.abiSize(self.target.*); | 3258 | const abi_size = ty.abiSize(self.target.*); |
| ... | @@ -3321,7 +3340,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3321,7 +3340,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3321 | .data = .{ .imm = @bitCast(u32, -adj_off) }, | 3340 | .data = .{ .imm = @bitCast(u32, -adj_off) }, |
| 3322 | }); | 3341 | }); |
| 3323 | }, | 3342 | }, |
| 3324 | .memory, .embedded_in_code => { | 3343 | .memory, |
| | 3344 | .embedded_in_code, |
| | 3345 | => { |
| 3325 | if (ty.abiSize(self.target.*) <= 8) { | 3346 | if (ty.abiSize(self.target.*) <= 8) { |
| 3326 | const reg = try self.copyToTmpRegister(ty, mcv); | 3347 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3327 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3348 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| ... | @@ -3605,7 +3626,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3605,7 +3626,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3605 | .compare_flags_signed, | 3626 | .compare_flags_signed, |
| 3606 | => |op| { | 3627 | => |op| { |
| 3607 | const tag: Mir.Inst.Tag = switch (op) { | 3628 | const tag: Mir.Inst.Tag = switch (op) { |
| 3608 | .gte, .gt, .lt, .lte => .cond_set_byte_above_below, | 3629 | .gte, .gt, .lt, .lte => if (mcv == .compare_flags_unsigned) |
| | 3630 | Mir.Inst.Tag.cond_set_byte_above_below |
| | 3631 | else |
| | 3632 | Mir.Inst.Tag.cond_set_byte_greater_less, |
| 3609 | .eq, .neq => .cond_set_byte_eq_ne, | 3633 | .eq, .neq => .cond_set_byte_eq_ne, |
| 3610 | }; | 3634 | }; |
| 3611 | const flags: u2 = switch (op) { | 3635 | const flags: u2 = switch (op) { |