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...@@ -2182,6 +2182,25 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2182 else => unreachable, // unexpected register size2182 else => unreachable, // unexpected register size
2183 }2183 }
2184 },2184 },
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 },
2185 .immediate => |x| {2204 .immediate => |x| {
2186 _ = try self.addInst(.{2205 _ = try self.addInst(.{
2187 .tag = .movz,2206 .tag = .movz,
src/arch/aarch64/Emit.zig+17
...@@ -81,6 +81,8 @@ pub fn emitMir(...@@ -81,6 +81,8 @@ pub fn emitMir(
8181
82 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),82 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
8383
84 .cset => try emit.mirConditionalSelect(inst),
85
84 .dbg_line => try emit.mirDbgLine(inst),86 .dbg_line => try emit.mirDbgLine(inst),
8587
86 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),88 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
...@@ -478,6 +480,21 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -478,6 +480,21 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
478 }480 }
479}481}
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
481fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {498fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
482 assert(emit.mir.instructions.items(.tag)[inst] == .load_memory);499 assert(emit.mir.instructions.items(.tag)[inst] == .load_memory);
483 const payload = emit.mir.instructions.items(.data)[inst].payload;500 const payload = emit.mir.instructions.items(.data)[inst].payload;
src/arch/aarch64/Mir.zig+11
...@@ -40,6 +40,8 @@ pub const Inst = struct {...@@ -40,6 +40,8 @@ pub const Inst = struct {
40 cmp_immediate,40 cmp_immediate,
41 /// Compare (shifted register)41 /// Compare (shifted register)
42 cmp_shifted_register,42 cmp_shifted_register,
43 /// Conditional set
44 cset,
43 /// Pseudo-instruction: End of prologue45 /// Pseudo-instruction: End of prologue
44 dbg_prologue_end,46 dbg_prologue_end,
45 /// Pseudo-instruction: Beginning of epilogue47 /// Pseudo-instruction: Beginning of epilogue
...@@ -155,6 +157,15 @@ pub const Inst = struct {...@@ -155,6 +157,15 @@ pub const Inst = struct {
155 imm6: u6,157 imm6: u6,
156 shift: bits.Instruction.AddSubtractShiftedRegisterShift,158 shift: bits.Instruction.AddSubtractShiftedRegisterShift,
157 },159 },
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 },
158 /// Three registers and a LoadStoreOffset169 /// Three registers and a LoadStoreOffset
159 ///170 ///
160 /// Used by e.g. str_register171 /// Used by e.g. str_register
src/arch/aarch64/bits.zig+112
...@@ -321,6 +321,17 @@ pub const Instruction = union(enum) {...@@ -321,6 +321,17 @@ pub const Instruction = union(enum) {
321 fixed: u6 = 0b011010,321 fixed: u6 = 0b011010,
322 sf: u1,322 sf: u1,
323 },323 },
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
325 pub const Shift = struct {336 pub const Shift = struct {
326 shift: Type = .lsl,337 shift: Type = .lsl,
...@@ -388,6 +399,57 @@ pub const Instruction = union(enum) {...@@ -388,6 +399,57 @@ pub const Instruction = union(enum) {
388 /// Integer: Always399 /// Integer: Always
389 /// Floating point: Always400 /// Floating point: Always
390 nv,401 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 }
391 };453 };
392454
393 pub fn toU32(self: Instruction) u32 {455 pub fn toU32(self: Instruction) u32 {
...@@ -407,6 +469,7 @@ pub const Instruction = union(enum) {...@@ -407,6 +469,7 @@ pub const Instruction = union(enum) {
407 // TODO once packed structs work, this can be refactored469 // TODO once packed structs work, this can be refactored
408 .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),470 .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),
409 .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),471 .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,
410 };473 };
411 }474 }
412475
...@@ -883,6 +946,33 @@ pub const Instruction = union(enum) {...@@ -883,6 +946,33 @@ pub const Instruction = union(enum) {
883 };946 };
884 }947 }
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
886 // Helper functions for assembly syntax functions976 // Helper functions for assembly syntax functions
887977
888 // Move wide (immediate)978 // Move wide (immediate)
...@@ -1154,6 +1244,24 @@ pub const Instruction = union(enum) {...@@ -1154,6 +1244,24 @@ pub const Instruction = union(enum) {
1154 pub fn cbnz(rt: Register, offset: i21) Instruction {1244 pub fn cbnz(rt: Register, offset: i21) Instruction {
1155 return compareAndBranch(0b1, rt, offset);1245 return compareAndBranch(0b1, rt, offset);
1156 }1246 }
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 }
1157};1265};
11581266
1159test {1267test {
...@@ -1319,6 +1427,10 @@ test "serialize instructions" {...@@ -1319,6 +1427,10 @@ test "serialize instructions" {
1319 .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5),1427 .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5),
1320 .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000,1428 .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000,
1321 },1429 },
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 },
1322 };1434 };
13231435
1324 for (testcases) |case| {1436 for (testcases) |case| {