| author | |
| committer | |
| log | 3a33f313347f3fa151ba3a90c1c3b14eee3d1d1e |
| tree | 364f538c243c4e9f7af05770d535c7e84ab947df |
| parent | edb2a75982a011dc883678ca57efa8c3f6be5466 |
| signature |
4 files changed, 99 insertions(+), 14 deletions(-)
src/arch/aarch64/CodeGen.zig+24-8| ... | ... | @@ -923,12 +923,12 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 923 | 923 | }; |
| 924 | 924 | break :result r; |
| 925 | 925 | }, |
| 926 | else => {}, | |
| 926 | else => { | |
| 927 | return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch}); | |
| 928 | }, | |
| 927 | 929 | } |
| 928 | ||
| 929 | return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch}); | |
| 930 | 930 | }; |
| 931 | _ = result; | |
| 931 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 932 | 932 | } |
| 933 | 933 | |
| 934 | 934 | fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1411,7 +1411,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1411 | 1411 | .dead, .unreach => unreachable, |
| 1412 | 1412 | .register => unreachable, // a slice doesn't fit in one register |
| 1413 | 1413 | .stack_offset => |off| { |
| 1414 | break :result MCValue{ .stack_offset = off + 8 }; | |
| 1414 | break :result MCValue{ .stack_offset = off }; | |
| 1415 | 1415 | }, |
| 1416 | 1416 | .memory => |addr| { |
| 1417 | 1417 | break :result MCValue{ .memory = addr + 8 }; |
| ... | ... | @@ -2425,7 +2425,22 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2425 | 2425 | }, |
| 2426 | 2426 | }, |
| 2427 | 2427 | }), |
| 2428 | else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(cond)}), | |
| 2428 | else => blk: { | |
| 2429 | const reg = switch (cond) { | |
| 2430 | .register => |r| r, | |
| 2431 | else => try self.copyToTmpRegister(Type.bool, cond), | |
| 2432 | }; | |
| 2433 | ||
| 2434 | break :blk try self.addInst(.{ | |
| 2435 | .tag = .cbz, | |
| 2436 | .data = .{ | |
| 2437 | .r_inst = .{ | |
| 2438 | .rt = reg, | |
| 2439 | .inst = undefined, // populated later through performReloc | |
| 2440 | }, | |
| 2441 | }, | |
| 2442 | }); | |
| 2443 | }, | |
| 2429 | 2444 | }; |
| 2430 | 2445 | |
| 2431 | 2446 | // Capture the state of register and stack allocation state so that we can revert to it. |
| ... | ... | @@ -2770,8 +2785,9 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 2770 | 2785 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| 2771 | 2786 | const tag = self.mir_instructions.items(.tag)[inst]; |
| 2772 | 2787 | switch (tag) { |
| 2773 | .b_cond => self.mir_instructions.items(.data)[inst].inst_cond.inst = @intCast(Air.Inst.Index, self.mir_instructions.len), | |
| 2774 | .b => self.mir_instructions.items(.data)[inst].inst = @intCast(Air.Inst.Index, self.mir_instructions.len), | |
| 2788 | .cbz => self.mir_instructions.items(.data)[inst].r_inst.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len), | |
| 2789 | .b_cond => self.mir_instructions.items(.data)[inst].inst_cond.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len), | |
| 2790 | .b => self.mir_instructions.items(.data)[inst].inst = @intCast(Mir.Inst.Index, self.mir_instructions.len), | |
| 2775 | 2791 | else => unreachable, |
| 2776 | 2792 | } |
| 2777 | 2793 | } |
src/arch/aarch64/Emit.zig+41-6| ... | ... | @@ -50,11 +50,13 @@ const InnerError = error{ |
| 50 | 50 | }; |
| 51 | 51 | |
| 52 | 52 | const BranchType = enum { |
| 53 | cbz, | |
| 53 | 54 | b_cond, |
| 54 | 55 | unconditional_branch_immediate, |
| 55 | 56 | |
| 56 | 57 | fn default(tag: Mir.Inst.Tag) BranchType { |
| 57 | 58 | return switch (tag) { |
| 59 | .cbz => .cbz, | |
| 58 | 60 | .b, .bl => .unconditional_branch_immediate, |
| 59 | 61 | .b_cond => .b_cond, |
| 60 | 62 | else => unreachable, |
| ... | ... | @@ -83,6 +85,8 @@ pub fn emitMir( |
| 83 | 85 | .b => try emit.mirBranch(inst), |
| 84 | 86 | .bl => try emit.mirBranch(inst), |
| 85 | 87 | |
| 88 | .cbz => try emit.mirCompareAndBranch(inst), | |
| 89 | ||
| 86 | 90 | .blr => try emit.mirUnconditionalBranchRegister(inst), |
| 87 | 91 | .ret => try emit.mirUnconditionalBranchRegister(inst), |
| 88 | 92 | |
| ... | ... | @@ -160,15 +164,22 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType { |
| 160 | 164 | assert(offset & 0b11 == 0); |
| 161 | 165 | |
| 162 | 166 | switch (tag) { |
| 167 | .cbz => { | |
| 168 | if (std.math.cast(i19, @shrExact(offset, 2))) |_| { | |
| 169 | return BranchType.cbz; | |
| 170 | } else |_| { | |
| 171 | return emit.fail("TODO support cbz branches larger than +-1 MiB", .{}); | |
| 172 | } | |
| 173 | }, | |
| 163 | 174 | .b, .bl => { |
| 164 | if (std.math.cast(i26, offset >> 2)) |_| { | |
| 175 | if (std.math.cast(i26, @shrExact(offset, 2))) |_| { | |
| 165 | 176 | return BranchType.unconditional_branch_immediate; |
| 166 | 177 | } else |_| { |
| 167 | return emit.fail("TODO support branches larger than +-128 MiB", .{}); | |
| 178 | return emit.fail("TODO support unconditional branches larger than +-128 MiB", .{}); | |
| 168 | 179 | } |
| 169 | 180 | }, |
| 170 | 181 | .b_cond => { |
| 171 | if (std.math.cast(i19, offset >> 2)) |_| { | |
| 182 | if (std.math.cast(i19, @shrExact(offset, 2))) |_| { | |
| 172 | 183 | return BranchType.b_cond; |
| 173 | 184 | } else |_| { |
| 174 | 185 | return emit.fail("TODO support conditional branches larger than +-1 MiB", .{}); |
| ... | ... | @@ -183,8 +194,10 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { |
| 183 | 194 | |
| 184 | 195 | if (isBranch(tag)) { |
| 185 | 196 | switch (emit.branch_types.get(inst).?) { |
| 186 | .unconditional_branch_immediate => return 4, | |
| 187 | .b_cond => return 4, | |
| 197 | .cbz, | |
| 198 | .unconditional_branch_immediate, | |
| 199 | .b_cond, | |
| 200 | => return 4, | |
| 188 | 201 | } |
| 189 | 202 | } |
| 190 | 203 | |
| ... | ... | @@ -222,7 +235,11 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { |
| 222 | 235 | |
| 223 | 236 | fn isBranch(tag: Mir.Inst.Tag) bool { |
| 224 | 237 | return switch (tag) { |
| 225 | .b, .bl, .b_cond => true, | |
| 238 | .cbz, | |
| 239 | .b, | |
| 240 | .bl, | |
| 241 | .b_cond, | |
| 242 | => true, | |
| 226 | 243 | else => false, |
| 227 | 244 | }; |
| 228 | 245 | } |
| ... | ... | @@ -231,6 +248,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { |
| 231 | 248 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 232 | 249 | |
| 233 | 250 | switch (tag) { |
| 251 | .cbz => return emit.mir.instructions.items(.data)[inst].r_inst.inst, | |
| 234 | 252 | .b, .bl => return emit.mir.instructions.items(.data)[inst].inst, |
| 235 | 253 | .b_cond => return emit.mir.instructions.items(.data)[inst].inst_cond.inst, |
| 236 | 254 | else => unreachable, |
| ... | ... | @@ -494,6 +512,23 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 494 | 512 | } |
| 495 | 513 | } |
| 496 | 514 | |
| 515 | fn mirCompareAndBranch(emit: *Emit, inst: Mir.Inst.Index) !void { | |
| 516 | const tag = emit.mir.instructions.items(.tag)[inst]; | |
| 517 | const r_inst = emit.mir.instructions.items(.data)[inst].r_inst; | |
| 518 | ||
| 519 | const offset = @intCast(i64, emit.code_offset_mapping.get(r_inst.inst).?) - @intCast(i64, emit.code.items.len); | |
| 520 | const branch_type = emit.branch_types.get(inst).?; | |
| 521 | log.debug("mirCompareAndBranch: {} offset={}", .{ inst, offset }); | |
| 522 | ||
| 523 | switch (branch_type) { | |
| 524 | .cbz => switch (tag) { | |
| 525 | .cbz => try emit.writeInstruction(Instruction.cbz(r_inst.rt, @intCast(i21, offset))), | |
| 526 | else => unreachable, | |
| 527 | }, | |
| 528 | else => unreachable, | |
| 529 | } | |
| 530 | } | |
| 531 | ||
| 497 | 532 | fn mirUnconditionalBranchRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 498 | 533 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 499 | 534 | const reg = emit.mir.instructions.items(.data)[inst].reg; |
src/arch/aarch64/Mir.zig+9| ... | ... | @@ -40,6 +40,8 @@ pub const Inst = struct { |
| 40 | 40 | brk, |
| 41 | 41 | /// Pseudo-instruction: Call extern |
| 42 | 42 | call_extern, |
| 43 | /// Compare and Branch on Zero | |
| 44 | cbz, | |
| 43 | 45 | /// Compare (immediate) |
| 44 | 46 | cmp_immediate, |
| 45 | 47 | /// Compare (shifted register) |
| ... | ... | @@ -184,6 +186,13 @@ pub const Inst = struct { |
| 184 | 186 | rd: Register, |
| 185 | 187 | cond: bits.Instruction.Condition, |
| 186 | 188 | }, |
| 189 | /// A register and another instruction | |
| 190 | /// | |
| 191 | /// Used by e.g. cbz | |
| 192 | r_inst: struct { | |
| 193 | rt: Register, | |
| 194 | inst: Index, | |
| 195 | }, | |
| 187 | 196 | /// Two registers |
| 188 | 197 | /// |
| 189 | 198 | /// Used by e.g. mov_register |
test/stage2/aarch64.zig+25| ... | ... | @@ -102,6 +102,31 @@ pub fn addCases(ctx: *TestContext) !void { |
| 102 | 102 | , |
| 103 | 103 | "Hello, World!\n", |
| 104 | 104 | ); |
| 105 | ||
| 106 | case.addCompareOutput( | |
| 107 | \\pub fn main() void { | |
| 108 | \\ foo(true); | |
| 109 | \\} | |
| 110 | \\ | |
| 111 | \\fn foo(x: bool) void { | |
| 112 | \\ if (x) { | |
| 113 | \\ print(); | |
| 114 | \\ } | |
| 115 | \\} | |
| 116 | \\ | |
| 117 | \\fn print() void { | |
| 118 | \\ asm volatile ("svc #0" | |
| 119 | \\ : | |
| 120 | \\ : [number] "{x8}" (64), | |
| 121 | \\ [arg1] "{x0}" (1), | |
| 122 | \\ [arg2] "{x1}" (@ptrToInt("Hello, World!\n")), | |
| 123 | \\ [arg3] "{x2}" ("Hello, World!\n".len), | |
| 124 | \\ : "memory", "cc" | |
| 125 | \\ ); | |
| 126 | \\} | |
| 127 | , | |
| 128 | "Hello, World!\n", | |
| 129 | ); | |
| 105 | 130 | } |
| 106 | 131 | |
| 107 | 132 | // macOS tests |