| 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,12 +923,12 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 923 | }; | 923 | }; |
| 924 | break :result r; | 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 | fn airMin(self: *Self, inst: Air.Inst.Index) !void { | 934 | fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1411,7 +1411,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1411,7 +1411,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1411 | .dead, .unreach => unreachable, | 1411 | .dead, .unreach => unreachable, |
| 1412 | .register => unreachable, // a slice doesn't fit in one register | 1412 | .register => unreachable, // a slice doesn't fit in one register |
| 1413 | .stack_offset => |off| { | 1413 | .stack_offset => |off| { |
| 1414 | break :result MCValue{ .stack_offset = off + 8 }; | 1414 | break :result MCValue{ .stack_offset = off }; |
| 1415 | }, | 1415 | }, |
| 1416 | .memory => |addr| { | 1416 | .memory => |addr| { |
| 1417 | break :result MCValue{ .memory = addr + 8 }; | 1417 | break :result MCValue{ .memory = addr + 8 }; |
| ... | @@ -2425,7 +2425,22 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -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 | // Capture the state of register and stack allocation state so that we can revert to it. | 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,8 +2785,9 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 2770 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { | 2785 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| 2771 | const tag = self.mir_instructions.items(.tag)[inst]; | 2786 | const tag = self.mir_instructions.items(.tag)[inst]; |
| 2772 | switch (tag) { | 2787 | switch (tag) { |
| 2773 | .b_cond => self.mir_instructions.items(.data)[inst].inst_cond.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), |
| 2774 | .b => self.mir_instructions.items(.data)[inst].inst = @intCast(Air.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 | else => unreachable, | 2791 | else => unreachable, |
| 2776 | } | 2792 | } |
| 2777 | } | 2793 | } |
src/arch/aarch64/Emit.zig+41-6| ... | @@ -50,11 +50,13 @@ const InnerError = error{ | ... | @@ -50,11 +50,13 @@ const InnerError = error{ |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | const BranchType = enum { | 52 | const BranchType = enum { |
| 53 | cbz, | ||
| 53 | b_cond, | 54 | b_cond, |
| 54 | unconditional_branch_immediate, | 55 | unconditional_branch_immediate, |
| 55 | 56 | ||
| 56 | fn default(tag: Mir.Inst.Tag) BranchType { | 57 | fn default(tag: Mir.Inst.Tag) BranchType { |
| 57 | return switch (tag) { | 58 | return switch (tag) { |
| 59 | .cbz => .cbz, | ||
| 58 | .b, .bl => .unconditional_branch_immediate, | 60 | .b, .bl => .unconditional_branch_immediate, |
| 59 | .b_cond => .b_cond, | 61 | .b_cond => .b_cond, |
| 60 | else => unreachable, | 62 | else => unreachable, |
| ... | @@ -83,6 +85,8 @@ pub fn emitMir( | ... | @@ -83,6 +85,8 @@ pub fn emitMir( |
| 83 | .b => try emit.mirBranch(inst), | 85 | .b => try emit.mirBranch(inst), |
| 84 | .bl => try emit.mirBranch(inst), | 86 | .bl => try emit.mirBranch(inst), |
| 85 | 87 | ||
| 88 | .cbz => try emit.mirCompareAndBranch(inst), | ||
| 89 | |||
| 86 | .blr => try emit.mirUnconditionalBranchRegister(inst), | 90 | .blr => try emit.mirUnconditionalBranchRegister(inst), |
| 87 | .ret => try emit.mirUnconditionalBranchRegister(inst), | 91 | .ret => try emit.mirUnconditionalBranchRegister(inst), |
| 88 | 92 | ||
| ... | @@ -160,15 +164,22 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType { | ... | @@ -160,15 +164,22 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType { |
| 160 | assert(offset & 0b11 == 0); | 164 | assert(offset & 0b11 == 0); |
| 161 | 165 | ||
| 162 | switch (tag) { | 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 | .b, .bl => { | 174 | .b, .bl => { |
| 164 | if (std.math.cast(i26, offset >> 2)) |_| { | 175 | if (std.math.cast(i26, @shrExact(offset, 2))) |_| { |
| 165 | return BranchType.unconditional_branch_immediate; | 176 | return BranchType.unconditional_branch_immediate; |
| 166 | } else |_| { | 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 | .b_cond => { | 181 | .b_cond => { |
| 171 | if (std.math.cast(i19, offset >> 2)) |_| { | 182 | if (std.math.cast(i19, @shrExact(offset, 2))) |_| { |
| 172 | return BranchType.b_cond; | 183 | return BranchType.b_cond; |
| 173 | } else |_| { | 184 | } else |_| { |
| 174 | return emit.fail("TODO support conditional branches larger than +-1 MiB", .{}); | 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,8 +194,10 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { |
| 183 | 194 | ||
| 184 | if (isBranch(tag)) { | 195 | if (isBranch(tag)) { |
| 185 | switch (emit.branch_types.get(inst).?) { | 196 | switch (emit.branch_types.get(inst).?) { |
| 186 | .unconditional_branch_immediate => return 4, | 197 | .cbz, |
| 187 | .b_cond => return 4, | 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,7 +235,11 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { |
| 222 | 235 | ||
| 223 | fn isBranch(tag: Mir.Inst.Tag) bool { | 236 | fn isBranch(tag: Mir.Inst.Tag) bool { |
| 224 | return switch (tag) { | 237 | return switch (tag) { |
| 225 | .b, .bl, .b_cond => true, | 238 | .cbz, |
| 239 | .b, | ||
| 240 | .bl, | ||
| 241 | .b_cond, | ||
| 242 | => true, | ||
| 226 | else => false, | 243 | else => false, |
| 227 | }; | 244 | }; |
| 228 | } | 245 | } |
| ... | @@ -231,6 +248,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { | ... | @@ -231,6 +248,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { |
| 231 | const tag = emit.mir.instructions.items(.tag)[inst]; | 248 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 232 | 249 | ||
| 233 | switch (tag) { | 250 | switch (tag) { |
| 251 | .cbz => return emit.mir.instructions.items(.data)[inst].r_inst.inst, | ||
| 234 | .b, .bl => return emit.mir.instructions.items(.data)[inst].inst, | 252 | .b, .bl => return emit.mir.instructions.items(.data)[inst].inst, |
| 235 | .b_cond => return emit.mir.instructions.items(.data)[inst].inst_cond.inst, | 253 | .b_cond => return emit.mir.instructions.items(.data)[inst].inst_cond.inst, |
| 236 | else => unreachable, | 254 | else => unreachable, |
| ... | @@ -494,6 +512,23 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -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 | fn mirUnconditionalBranchRegister(emit: *Emit, inst: Mir.Inst.Index) !void { | 532 | fn mirUnconditionalBranchRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 498 | const tag = emit.mir.instructions.items(.tag)[inst]; | 533 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 499 | const reg = emit.mir.instructions.items(.data)[inst].reg; | 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,6 +40,8 @@ pub const Inst = struct { |
| 40 | brk, | 40 | brk, |
| 41 | /// Pseudo-instruction: Call extern | 41 | /// Pseudo-instruction: Call extern |
| 42 | call_extern, | 42 | call_extern, |
| 43 | /// Compare and Branch on Zero | ||
| 44 | cbz, | ||
| 43 | /// Compare (immediate) | 45 | /// Compare (immediate) |
| 44 | cmp_immediate, | 46 | cmp_immediate, |
| 45 | /// Compare (shifted register) | 47 | /// Compare (shifted register) |
| ... | @@ -184,6 +186,13 @@ pub const Inst = struct { | ... | @@ -184,6 +186,13 @@ pub const Inst = struct { |
| 184 | rd: Register, | 186 | rd: Register, |
| 185 | cond: bits.Instruction.Condition, | 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 | /// Two registers | 196 | /// Two registers |
| 188 | /// | 197 | /// |
| 189 | /// Used by e.g. mov_register | 198 | /// Used by e.g. mov_register |
test/stage2/aarch64.zig+25| ... | @@ -102,6 +102,31 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -102,6 +102,31 @@ pub fn addCases(ctx: *TestContext) !void { |
| 102 | , | 102 | , |
| 103 | "Hello, World!\n", | 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 | // macOS tests | 132 | // macOS tests |