authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-12 14:31:25+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-14 22:09:44+01:00
log3a33f313347f3fa151ba3a90c1c3b14eee3d1d1e
tree364f538c243c4e9f7af05770d535c7e84ab947df
parentedb2a75982a011dc883678ca57efa8c3f6be5466
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement cond_br for other MCValues


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}
933933
934fn airMin(self: *Self, inst: Air.Inst.Index) !void {934fn 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 register1412 .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 };
24302445
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 {
2770fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {2785fn 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};
5151
52const BranchType = enum {52const BranchType = enum {
53 cbz,
53 b_cond,54 b_cond,
54 unconditional_branch_immediate,55 unconditional_branch_immediate,
5556
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),
8587
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),
8892
...@@ -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);
161165
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 {
183194
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 }
190203
...@@ -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 {
222235
223fn isBranch(tag: Mir.Inst.Tag) bool {236fn 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];
232249
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}
496514
515fn 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
497fn mirUnconditionalBranchRegister(emit: *Emit, inst: Mir.Inst.Index) !void {532fn 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 extern41 /// 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 registers196 /// Two registers
188 ///197 ///
189 /// Used by e.g. mov_register198 /// 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 }
106131
107 // macOS tests132 // macOS tests