stage2 AArch64: minor refactors in Mir + Emit

This commit is contained in:
joachimschmidt557 2022-02-08 19:57:01 +01:00
parent f598d2ae05
commit f47245865e
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5
3 changed files with 78 additions and 98 deletions

View File

@ -2121,8 +2121,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
.immediate => |imm| {
_ = try self.addInst(.{
.tag = .cmp_immediate,
.data = .{ .rr_imm12_sh = .{
.rd = .xzr,
.data = .{ .r_imm12_sh = .{
.rn = lhs_mcv.register,
.imm12 = @intCast(u12, imm),
} },
@ -2334,8 +2333,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
_ = try self.addInst(.{
.tag = .cmp_immediate,
.data = .{ .rr_imm12_sh = .{
.rd = .xzr,
.data = .{ .r_imm12_sh = .{
.rn = reg_mcv.register,
.imm12 = 0,
} },
@ -2559,7 +2557,16 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
const operand_mcv = try self.resolveInst(operand);
const block_mcv = block_data.mcv;
if (block_mcv == .none) {
block_data.mcv = operand_mcv;
block_data.mcv = switch (operand_mcv) {
.none, .dead, .unreach => unreachable,
.register, .stack_offset, .memory => operand_mcv,
.immediate => blk: {
const new_mcv = try self.allocRegOrMem(block, true);
try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
break :blk new_mcv;
},
else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}),
};
} else {
try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv);
}
@ -2845,10 +2852,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
_ = try self.addInst(.{
.tag = .cset,
.data = .{ .rrr_cond = .{
.data = .{ .r_cond = .{
.rd = reg,
.rn = .xzr,
.rm = .xzr,
.cond = condition,
} },
});
@ -2933,7 +2938,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
} },
});
},
3 => return self.fail("TODO implement genSetReg types size 3", .{}),
3, 5, 6, 7 => return self.fail("TODO implement genSetReg types size {}", .{abi_size}),
else => unreachable,
}
},
@ -3114,27 +3119,6 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
}
}
/// If the MCValue is an immediate, and it does not fit within this type,
/// we put it in a register.
/// A potential opportunity for future optimization here would be keeping track
/// of the fact that the instruction is available both as an immediate
/// and as a register.
fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCValue {
const mcv = try self.resolveInst(operand);
const ti = @typeInfo(T).Int;
switch (mcv) {
.immediate => |imm| {
// This immediate is unsigned.
const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));
if (imm >= math.maxInt(U)) {
return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) };
}
},
else => {},
}
return mcv;
}
fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
@ -3248,19 +3232,11 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
}
},
.ErrorSet => {
switch (typed_value.val.tag()) {
.@"error" => {
const err_name = typed_value.val.castTag(.@"error").?.data.name;
const module = self.bin_file.options.module.?;
const global_error_set = module.global_error_set;
const error_index = global_error_set.get(err_name).?;
return MCValue{ .immediate = error_index };
},
else => {
// In this case we are rendering an error union which has a 0 bits payload.
return MCValue{ .immediate = 0 };
},
}
const err_name = typed_value.val.castTag(.@"error").?.data.name;
const module = self.bin_file.options.module.?;
const global_error_set = module.global_error_set;
const error_index = global_error_set.get(err_name).?;
return MCValue{ .immediate = error_index };
},
.ErrorUnion => {
const error_type = typed_value.ty.errorUnionSet();
@ -3425,13 +3401,18 @@ fn parseRegName(name: []const u8) ?Register {
}
fn registerAlias(reg: Register, size_bytes: u32) Register {
_ = size_bytes;
return reg;
if (size_bytes == 0) {
unreachable; // should be comptime known
} else if (size_bytes <= 4) {
return reg.to32();
} else if (size_bytes <= 8) {
return reg.to64();
} else {
unreachable; // TODO handle floating-point registers
}
}
/// For most architectures this does nothing. For x86_64 it resolves any aliased registers
/// to the 64-bit wide ones.
/// Resolves any aliased registers to the 64-bit wide ones.
fn toCanonicalReg(reg: Register) Register {
return reg;
return reg.to64();
}

View File

@ -423,27 +423,30 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh;
switch (tag) {
.add_immediate => try emit.writeInstruction(Instruction.add(
rr_imm12_sh.rd,
rr_imm12_sh.rn,
rr_imm12_sh.imm12,
rr_imm12_sh.sh == 1,
)),
.cmp_immediate => try emit.writeInstruction(Instruction.subs(
rr_imm12_sh.rd,
rr_imm12_sh.rn,
rr_imm12_sh.imm12,
rr_imm12_sh.sh == 1,
)),
.sub_immediate => try emit.writeInstruction(Instruction.sub(
rr_imm12_sh.rd,
rr_imm12_sh.rn,
rr_imm12_sh.imm12,
rr_imm12_sh.sh == 1,
)),
.add_immediate,
.sub_immediate,
=> {
const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh;
const rd = rr_imm12_sh.rd;
const rn = rr_imm12_sh.rn;
const imm12 = rr_imm12_sh.imm12;
const sh = rr_imm12_sh.sh == 1;
switch (tag) {
.add_immediate => try emit.writeInstruction(Instruction.add(rd, rn, imm12, sh)),
.sub_immediate => try emit.writeInstruction(Instruction.sub(rd, rn, imm12, sh)),
else => unreachable,
}
},
.cmp_immediate => {
const r_imm12_sh = emit.mir.instructions.items(.data)[inst].r_imm12_sh;
const rn = r_imm12_sh.rn;
const imm12 = r_imm12_sh.imm12;
const sh = r_imm12_sh.sh == 1;
try emit.writeInstruction(Instruction.subs(.xzr, rn, imm12, sh));
},
else => unreachable,
}
}
@ -589,15 +592,11 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const rrr_cond = emit.mir.instructions.items(.data)[inst].rrr_cond;
switch (tag) {
.cset => try emit.writeInstruction(Instruction.csinc(
rrr_cond.rd,
rrr_cond.rn,
rrr_cond.rm,
rrr_cond.cond,
)),
.cset => {
const r_cond = emit.mir.instructions.items(.data)[inst].r_cond;
try emit.writeInstruction(Instruction.csinc(r_cond.rd, .xzr, .xzr, r_cond.cond));
},
else => unreachable,
}
}
@ -662,20 +661,14 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const load_store_register_pair = emit.mir.instructions.items(.data)[inst].load_store_register_pair;
const rt = load_store_register_pair.rt;
const rt2 = load_store_register_pair.rt2;
const rn = load_store_register_pair.rn;
const offset = load_store_register_pair.offset;
switch (tag) {
.stp => try emit.writeInstruction(Instruction.stp(
load_store_register_pair.rt,
load_store_register_pair.rt2,
load_store_register_pair.rn,
load_store_register_pair.offset,
)),
.ldp => try emit.writeInstruction(Instruction.ldp(
load_store_register_pair.rt,
load_store_register_pair.rt2,
load_store_register_pair.rn,
load_store_register_pair.offset,
)),
.stp => try emit.writeInstruction(Instruction.stp(rt, rt2, rn, offset)),
.ldp => try emit.writeInstruction(Instruction.ldp(rt, rt2, rn, offset)),
else => unreachable,
}
}

View File

@ -175,6 +175,13 @@ pub const Inst = struct {
imm16: u16,
hw: u2 = 0,
},
/// A register and a condition
///
/// Used by e.g. cset
r_cond: struct {
rd: Register,
cond: bits.Instruction.Condition,
},
/// Two registers
///
/// Used by e.g. mov_register
@ -182,6 +189,14 @@ pub const Inst = struct {
rd: Register,
rn: Register,
},
/// A register, an unsigned 12-bit immediate, and an optional shift
///
/// Used by e.g. cmp_immediate
r_imm12_sh: struct {
rn: Register,
imm12: u12,
sh: u1 = 0,
},
/// Two registers, an unsigned 12-bit immediate, and an optional shift
///
/// Used by e.g. sub_immediate
@ -209,15 +224,6 @@ pub const Inst = struct {
imm6: u6,
shift: bits.Instruction.AddSubtractShiftedRegisterShift,
},
/// Three registers and a condition
///
/// Used by e.g. cset
rrr_cond: struct {
rd: Register,
rn: Register,
rm: Register,
cond: bits.Instruction.Condition,
},
/// Two registers and a LoadStoreOffsetImmediate
///
/// Used by e.g. str_immediate