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 {
923923 };
924924 break :result r;
925925 },
926 else => {},
926 else => {
927 return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch});
928 },
927929 }
928
929 return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch});
930930 };
931 _ = result;
931 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
932932}
933933
934934fn airMin(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1411,7 +1411,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
14111411 .dead, .unreach => unreachable,
14121412 .register => unreachable, // a slice doesn't fit in one register
14131413 .stack_offset => |off| {
1414 break :result MCValue{ .stack_offset = off + 8 };
1414 break :result MCValue{ .stack_offset = off };
14151415 },
14161416 .memory => |addr| {
14171417 break :result MCValue{ .memory = addr + 8 };
......@@ -2425,7 +2425,22 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
24252425 },
24262426 },
24272427 }),
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 },
24292444 };
24302445
24312446 // 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 {
27702785fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
27712786 const tag = self.mir_instructions.items(.tag)[inst];
27722787 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),
27752791 else => unreachable,
27762792 }
27772793}
src/arch/aarch64/Emit.zig+41-6
......@@ -50,11 +50,13 @@ const InnerError = error{
5050};
5151
5252const BranchType = enum {
53 cbz,
5354 b_cond,
5455 unconditional_branch_immediate,
5556
5657 fn default(tag: Mir.Inst.Tag) BranchType {
5758 return switch (tag) {
59 .cbz => .cbz,
5860 .b, .bl => .unconditional_branch_immediate,
5961 .b_cond => .b_cond,
6062 else => unreachable,
......@@ -83,6 +85,8 @@ pub fn emitMir(
8385 .b => try emit.mirBranch(inst),
8486 .bl => try emit.mirBranch(inst),
8587
88 .cbz => try emit.mirCompareAndBranch(inst),
89
8690 .blr => try emit.mirUnconditionalBranchRegister(inst),
8791 .ret => try emit.mirUnconditionalBranchRegister(inst),
8892
......@@ -160,15 +164,22 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {
160164 assert(offset & 0b11 == 0);
161165
162166 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 },
163174 .b, .bl => {
164 if (std.math.cast(i26, offset >> 2)) |_| {
175 if (std.math.cast(i26, @shrExact(offset, 2))) |_| {
165176 return BranchType.unconditional_branch_immediate;
166177 } else |_| {
167 return emit.fail("TODO support branches larger than +-128 MiB", .{});
178 return emit.fail("TODO support unconditional branches larger than +-128 MiB", .{});
168179 }
169180 },
170181 .b_cond => {
171 if (std.math.cast(i19, offset >> 2)) |_| {
182 if (std.math.cast(i19, @shrExact(offset, 2))) |_| {
172183 return BranchType.b_cond;
173184 } else |_| {
174185 return emit.fail("TODO support conditional branches larger than +-1 MiB", .{});
......@@ -183,8 +194,10 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
183194
184195 if (isBranch(tag)) {
185196 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,
188201 }
189202 }
190203
......@@ -222,7 +235,11 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
222235
223236fn isBranch(tag: Mir.Inst.Tag) bool {
224237 return switch (tag) {
225 .b, .bl, .b_cond => true,
238 .cbz,
239 .b,
240 .bl,
241 .b_cond,
242 => true,
226243 else => false,
227244 };
228245}
......@@ -231,6 +248,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {
231248 const tag = emit.mir.instructions.items(.tag)[inst];
232249
233250 switch (tag) {
251 .cbz => return emit.mir.instructions.items(.data)[inst].r_inst.inst,
234252 .b, .bl => return emit.mir.instructions.items(.data)[inst].inst,
235253 .b_cond => return emit.mir.instructions.items(.data)[inst].inst_cond.inst,
236254 else => unreachable,
......@@ -494,6 +512,23 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
494512 }
495513}
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
497532fn mirUnconditionalBranchRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
498533 const tag = emit.mir.instructions.items(.tag)[inst];
499534 const reg = emit.mir.instructions.items(.data)[inst].reg;
src/arch/aarch64/Mir.zig+9
......@@ -40,6 +40,8 @@ pub const Inst = struct {
4040 brk,
4141 /// Pseudo-instruction: Call extern
4242 call_extern,
43 /// Compare and Branch on Zero
44 cbz,
4345 /// Compare (immediate)
4446 cmp_immediate,
4547 /// Compare (shifted register)
......@@ -184,6 +186,13 @@ pub const Inst = struct {
184186 rd: Register,
185187 cond: bits.Instruction.Condition,
186188 },
189 /// A register and another instruction
190 ///
191 /// Used by e.g. cbz
192 r_inst: struct {
193 rt: Register,
194 inst: Index,
195 },
187196 /// Two registers
188197 ///
189198 /// Used by e.g. mov_register
test/stage2/aarch64.zig+25
......@@ -102,6 +102,31 @@ pub fn addCases(ctx: *TestContext) !void {
102102 ,
103103 "Hello, World!\n",
104104 );
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 );
105130 }
106131
107132 // macOS tests