authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-11-07 17:57:21+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-11-10 19:48:16+01:00
loga5a012e8599e57da3e80ff770f9de492037e4f4a
tree86fb5332cb15054858b25900829344678d901e69
parent8cb00519cddadae8728d2b2e51a36da71d5bfe67
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement genSetReg for condition flags


4 files changed, 159 insertions(+), 0 deletions(-)

src/arch/aarch64/CodeGen.zig+19
......@@ -2182,6 +2182,25 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
21822182 else => unreachable, // unexpected register size
21832183 }
21842184 },
2185 .compare_flags_unsigned,
2186 .compare_flags_signed,
2187 => |op| {
2188 const condition = switch (mcv) {
2189 .compare_flags_unsigned => Instruction.Condition.fromCompareOperatorUnsigned(op),
2190 .compare_flags_signed => Instruction.Condition.fromCompareOperatorSigned(op),
2191 else => unreachable,
2192 };
2193
2194 _ = try self.addInst(.{
2195 .tag = .cset,
2196 .data = .{ .rrr_cond = .{
2197 .rd = reg,
2198 .rn = .xzr,
2199 .rm = .xzr,
2200 .cond = condition,
2201 } },
2202 });
2203 },
21852204 .immediate => |x| {
21862205 _ = try self.addInst(.{
21872206 .tag = .movz,
src/arch/aarch64/Emit.zig+17
......@@ -81,6 +81,8 @@ pub fn emitMir(
8181
8282 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
8383
84 .cset => try emit.mirConditionalSelect(inst),
85
8486 .dbg_line => try emit.mirDbgLine(inst),
8587
8688 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
......@@ -478,6 +480,21 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
478480 }
479481}
480482
483fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
484 const tag = emit.mir.instructions.items(.tag)[inst];
485 const rrr_cond = emit.mir.instructions.items(.data)[inst].rrr_cond;
486
487 switch (tag) {
488 .cset => try emit.writeInstruction(Instruction.csinc(
489 rrr_cond.rd,
490 rrr_cond.rn,
491 rrr_cond.rm,
492 rrr_cond.cond,
493 )),
494 else => unreachable,
495 }
496}
497
481498fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
482499 assert(emit.mir.instructions.items(.tag)[inst] == .load_memory);
483500 const payload = emit.mir.instructions.items(.data)[inst].payload;
src/arch/aarch64/Mir.zig+11
......@@ -40,6 +40,8 @@ pub const Inst = struct {
4040 cmp_immediate,
4141 /// Compare (shifted register)
4242 cmp_shifted_register,
43 /// Conditional set
44 cset,
4345 /// Pseudo-instruction: End of prologue
4446 dbg_prologue_end,
4547 /// Pseudo-instruction: Beginning of epilogue
......@@ -155,6 +157,15 @@ pub const Inst = struct {
155157 imm6: u6,
156158 shift: bits.Instruction.AddSubtractShiftedRegisterShift,
157159 },
160 /// Three registers and a condition
161 ///
162 /// Used by e.g. cset
163 rrr_cond: struct {
164 rd: Register,
165 rn: Register,
166 rm: Register,
167 cond: bits.Instruction.Condition,
168 },
158169 /// Three registers and a LoadStoreOffset
159170 ///
160171 /// Used by e.g. str_register
src/arch/aarch64/bits.zig+112
......@@ -321,6 +321,17 @@ pub const Instruction = union(enum) {
321321 fixed: u6 = 0b011010,
322322 sf: u1,
323323 },
324 conditional_select: struct {
325 rd: u5,
326 rn: u5,
327 op2: u2,
328 cond: u4,
329 rm: u5,
330 fixed: u8 = 0b11010100,
331 s: u1,
332 op: u1,
333 sf: u1,
334 },
324335
325336 pub const Shift = struct {
326337 shift: Type = .lsl,
......@@ -388,6 +399,57 @@ pub const Instruction = union(enum) {
388399 /// Integer: Always
389400 /// Floating point: Always
390401 nv,
402
403 /// Converts a std.math.CompareOperator into a condition flag,
404 /// i.e. returns the condition that is true iff the result of the
405 /// comparison is true. Assumes signed comparison
406 pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition {
407 return switch (op) {
408 .gte => .ge,
409 .gt => .gt,
410 .neq => .ne,
411 .lt => .lt,
412 .lte => .le,
413 .eq => .eq,
414 };
415 }
416
417 /// Converts a std.math.CompareOperator into a condition flag,
418 /// i.e. returns the condition that is true iff the result of the
419 /// comparison is true. Assumes unsigned comparison
420 pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition {
421 return switch (op) {
422 .gte => .cs,
423 .gt => .hi,
424 .neq => .ne,
425 .lt => .cc,
426 .lte => .ls,
427 .eq => .eq,
428 };
429 }
430
431 /// Returns the condition which is true iff the given condition is
432 /// false (if such a condition exists)
433 pub fn negate(cond: Condition) Condition {
434 return switch (cond) {
435 .eq => .ne,
436 .ne => .eq,
437 .cs => .cc,
438 .cc => .cs,
439 .mi => .pl,
440 .pl => .mi,
441 .vs => .vc,
442 .vc => .vs,
443 .hi => .ls,
444 .ls => .hi,
445 .ge => .lt,
446 .lt => .ge,
447 .gt => .le,
448 .le => .gt,
449 .al => unreachable,
450 .nv => unreachable,
451 };
452 }
391453 };
392454
393455 pub fn toU32(self: Instruction) u32 {
......@@ -407,6 +469,7 @@ pub const Instruction = union(enum) {
407469 // TODO once packed structs work, this can be refactored
408470 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
409471 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
472 .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31,
410473 };
411474 }
412475
......@@ -883,6 +946,33 @@ pub const Instruction = union(enum) {
883946 };
884947 }
885948
949 fn conditionalSelect(
950 op2: u2,
951 op: u1,
952 s: u1,
953 rd: Register,
954 rn: Register,
955 rm: Register,
956 cond: Condition,
957 ) Instruction {
958 return Instruction{
959 .conditional_select = .{
960 .rd = rd.id(),
961 .rn = rn.id(),
962 .op2 = op2,
963 .cond = @enumToInt(cond),
964 .rm = rm.id(),
965 .s = s,
966 .op = op,
967 .sf = switch (rd.size()) {
968 32 => 0b0,
969 64 => 0b1,
970 else => unreachable, // unexpected register size
971 },
972 },
973 };
974 }
975
886976 // Helper functions for assembly syntax functions
887977
888978 // Move wide (immediate)
......@@ -1154,6 +1244,24 @@ pub const Instruction = union(enum) {
11541244 pub fn cbnz(rt: Register, offset: i21) Instruction {
11551245 return compareAndBranch(0b1, rt, offset);
11561246 }
1247
1248 // Conditional select
1249
1250 pub fn csel(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1251 return conditionalSelect(0b00, 0b0, 0b0, rd, rn, rm, cond);
1252 }
1253
1254 pub fn csinc(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1255 return conditionalSelect(0b01, 0b0, 0b0, rd, rn, rm, cond);
1256 }
1257
1258 pub fn csinv(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1259 return conditionalSelect(0b00, 0b1, 0b0, rd, rn, rm, cond);
1260 }
1261
1262 pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1263 return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond);
1264 }
11571265};
11581266
11591267test {
......@@ -1319,6 +1427,10 @@ test "serialize instructions" {
13191427 .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5),
13201428 .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000,
13211429 },
1430 .{ // csinc x1, x2, x4, eq
1431 .inst = Instruction.csinc(.x1, .x2, .x4, .eq),
1432 .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001,
1433 },
13221434 };
13231435
13241436 for (testcases) |case| {