stage2 ARM: implement genSetReg with compare_flags

This commit is contained in:
joachimschmidt557 2020-12-28 21:09:48 +01:00
parent 85e1b47c40
commit c52ca0b178
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5
2 changed files with 88 additions and 19 deletions

View File

@ -658,6 +658,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
const mcv = try self.genFuncInst(inst);
if (!inst.isUnused()) {
log.debug("{*} => {}", .{ inst, mcv });
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
try branch.inst_table.putNoClobber(self.gpa, inst, mcv);
}
@ -2039,27 +2040,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
const condition: Condition = switch (cond) {
.compare_flags_signed => |cmp_op| blk: {
// Here we map to the opposite condition because the jump is to the false branch.
const condition: Condition = switch (cmp_op) {
.gte => .lt,
.gt => .le,
.neq => .eq,
.lt => .ge,
.lte => .gt,
.eq => .ne,
};
break :blk condition;
const condition = Condition.fromCompareOperatorSigned(cmp_op);
break :blk condition.negate();
},
.compare_flags_unsigned => |cmp_op| blk: {
// Here we map to the opposite condition because the jump is to the false branch.
const condition: Condition = switch (cmp_op) {
.gte => .cc,
.gt => .ls,
.neq => .eq,
.lt => .cs,
.lte => .hi,
.eq => .ne,
};
break :blk condition;
const condition = Condition.fromCompareOperatorUnsigned(cmp_op);
break :blk condition.negate();
},
.register => |reg| blk: {
// cmp reg, 1
@ -2239,7 +2226,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
},
.arm, .armeb => {
if (math.cast(i26, @intCast(i32, index) - @intCast(i32, self.code.items.len))) |delta| {
if (math.cast(i26, @intCast(i32, index) - @intCast(i32, self.code.items.len + 8))) |delta| {
writeInt(u32, try self.code.addManyAsArray(4), Instruction.b(.al, delta).toU32());
} else |err| {
return self.fail(src, "TODO: enable larger branch offset", .{});
@ -2736,6 +2723,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
// Write the debug undefined value.
return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa });
},
.compare_flags_unsigned,
.compare_flags_signed,
=> |op| {
const condition = switch (mcv) {
.compare_flags_unsigned => Condition.fromCompareOperatorUnsigned(op),
.compare_flags_signed => Condition.fromCompareOperatorSigned(op),
else => unreachable,
};
// mov reg, 0
// moveq reg, 1
const zero = Instruction.Operand.imm(0, 0);
const one = Instruction.Operand.imm(1, 0);
writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, zero).toU32());
writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(condition, reg, one).toU32());
},
.immediate => |x| {
if (x > math.maxInt(u32)) return self.fail(src, "ARM registers are 32-bit wide", .{});

View File

@ -35,8 +35,74 @@ pub const Condition = enum(u4) {
le,
/// always
al,
/// Converts a std.math.CompareOperator into a condition flag,
/// i.e. returns the condition that is true iff the result of the
/// comparison is true. Assumes signed comparison
pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition {
return switch (op) {
.gte => .ge,
.gt => .gt,
.neq => .ne,
.lt => .lt,
.lte => .le,
.eq => .eq,
};
}
/// Converts a std.math.CompareOperator into a condition flag,
/// i.e. returns the condition that is true iff the result of the
/// comparison is true. Assumes unsigned comparison
pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition {
return switch (op) {
.gte => .cs,
.gt => .hi,
.neq => .ne,
.lt => .cc,
.lte => .ls,
.eq => .eq,
};
}
/// Returns the condition which is true iff the given condition is
/// false (if such a condition exists)
pub fn negate(cond: Condition) Condition {
return switch (cond) {
.eq => .ne,
.ne => .eq,
.cs => .cc,
.cc => .cs,
.mi => .pl,
.pl => .mi,
.vs => .vc,
.vc => .vs,
.hi => .ls,
.ls => .hi,
.ge => .lt,
.lt => .ge,
.gt => .le,
.le => .gt,
.al => unreachable,
};
}
};
test "condition from CompareOperator" {
testing.expectEqual(@as(Condition, .eq), Condition.fromCompareOperatorSigned(.eq));
testing.expectEqual(@as(Condition, .eq), Condition.fromCompareOperatorUnsigned(.eq));
testing.expectEqual(@as(Condition, .gt), Condition.fromCompareOperatorSigned(.gt));
testing.expectEqual(@as(Condition, .hi), Condition.fromCompareOperatorUnsigned(.gt));
testing.expectEqual(@as(Condition, .le), Condition.fromCompareOperatorSigned(.lte));
testing.expectEqual(@as(Condition, .ls), Condition.fromCompareOperatorUnsigned(.lte));
}
test "negate condition" {
testing.expectEqual(@as(Condition, .eq), Condition.ne.negate());
testing.expectEqual(@as(Condition, .ne), Condition.eq.negate());
}
/// Represents a register in the ARM instruction set architecture
pub const Register = enum(u5) {
r0,