aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoachim Schmidt <joachim.schmidt557@outlook.com>2022-03-17 09:40:41 +0100
committerGitHub <noreply@github.com>2022-03-17 09:40:41 +0100
commit3c3826bf93f7cbd88ecc30b43afac12cde313ffa (patch)
tree617ffc8f30d7750aad90ddbafcf2e33580a2a02d /src
parent87779cfd93fdcb525f386d693a099e4188a3fc44 (diff)
parentdcc1de12b097db4971b85cfc0b4e18fec2c8b2c4 (diff)
downloadzig-3c3826bf93f7cbd88ecc30b43afac12cde313ffa.tar.gz
zig-3c3826bf93f7cbd88ecc30b43afac12cde313ffa.zip
Merge pull request #11192 from joachimschmidt557/stage2-arm
stage2 ARM: misc improvements
Diffstat (limited to 'src')
-rw-r--r--src/arch/arm/CodeGen.zig282
-rw-r--r--src/arch/arm/Emit.zig7
-rw-r--r--src/arch/arm/Mir.zig2
3 files changed, 189 insertions, 102 deletions
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig
index 0ccec1be88..0a3413569a 100644
--- a/src/arch/arm/CodeGen.zig
+++ b/src/arch/arm/CodeGen.zig
@@ -530,13 +530,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
switch (air_tags[inst]) {
// zig fmt: off
.add, .ptr_add => try self.airBinOp(inst),
- .addwrap => try self.airAddWrap(inst),
+ .addwrap => try self.airBinOp(inst),
.add_sat => try self.airAddSat(inst),
.sub, .ptr_sub => try self.airBinOp(inst),
- .subwrap => try self.airSubWrap(inst),
+ .subwrap => try self.airBinOp(inst),
.sub_sat => try self.airSubSat(inst),
.mul => try self.airBinOp(inst),
- .mulwrap => try self.airMulWrap(inst),
+ .mulwrap => try self.airBinOp(inst),
.mul_sat => try self.airMulSat(inst),
.rem => try self.airRem(inst),
.mod => try self.airMod(inst),
@@ -939,63 +939,85 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
// return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
-fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
- const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- if (self.liveness.isUnused(inst))
- return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
+fn truncRegister(
+ self: *Self,
+ operand_reg: Register,
+ dest_reg: Register,
+ int_signedness: std.builtin.Signedness,
+ int_bits: u16,
+) !void {
+ // TODO check if sxtb/uxtb/sxth/uxth are more efficient
+ _ = try self.addInst(.{
+ .tag = switch (int_signedness) {
+ .signed => .sbfx,
+ .unsigned => .ubfx,
+ },
+ .data = .{ .rr_lsb_width = .{
+ .rd = dest_reg,
+ .rn = operand_reg,
+ .lsb = 0,
+ .width = @intCast(u6, int_bits),
+ } },
+ });
+}
- const operand_ty = self.air.typeOf(ty_op.operand);
- const operand = try self.resolveInst(ty_op.operand);
+fn trunc(
+ self: *Self,
+ maybe_inst: ?Air.Inst.Index,
+ operand: MCValue,
+ operand_ty: Type,
+ dest_ty: Type,
+) !MCValue {
const info_a = operand_ty.intInfo(self.target.*);
- const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
-
- const result: MCValue = blk: {
- if (info_b.bits <= 32) {
- const operand_reg = switch (operand) {
- .register => |r| r,
- else => operand_reg: {
- if (info_a.bits <= 32) {
- break :operand_reg try self.copyToTmpRegister(operand_ty, operand);
- } else {
- return self.fail("TODO load least significant word into register", .{});
- }
- },
- };
- self.register_manager.freezeRegs(&.{operand_reg});
- defer self.register_manager.unfreezeRegs(&.{operand_reg});
-
- const dest_reg = dest_reg: {
- if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
- break :dest_reg operand_reg;
+ const info_b = dest_ty.intInfo(self.target.*);
+
+ if (info_b.bits <= 32) {
+ const operand_reg = switch (operand) {
+ .register => |r| r,
+ else => operand_reg: {
+ if (info_a.bits <= 32) {
+ break :operand_reg try self.copyToTmpRegister(operand_ty, operand);
+ } else {
+ return self.fail("TODO load least significant word into register", .{});
}
+ },
+ };
+ self.register_manager.freezeRegs(&.{operand_reg});
+ defer self.register_manager.unfreezeRegs(&.{operand_reg});
- break :dest_reg try self.register_manager.allocReg(null);
- };
+ const dest_reg = if (maybe_inst) |inst| blk: {
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- switch (info_b.bits) {
- 32 => {
- try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });
- break :blk MCValue{ .register = dest_reg };
- },
- else => {
- _ = try self.addInst(.{
- .tag = switch (info_b.signedness) {
- .signed => .sbfx,
- .unsigned => .ubfx,
- },
- .data = .{ .rr_lsb_width = .{
- .rd = dest_reg,
- .rn = operand_reg,
- .lsb = 0,
- .width = @intCast(u6, info_b.bits),
- } },
- });
- break :blk MCValue{ .register = dest_reg };
- },
+ if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
+ break :blk operand_reg;
+ } else {
+ break :blk try self.register_manager.allocReg(inst);
}
- } else {
- return self.fail("TODO: truncate to ints > 32 bits", .{});
+ } else try self.register_manager.allocReg(null);
+
+ switch (info_b.bits) {
+ 32 => {
+ try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });
+ return MCValue{ .register = dest_reg };
+ },
+ else => {
+ try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);
+ return MCValue{ .register = dest_reg };
+ },
}
+ } else {
+ return self.fail("TODO: truncate to ints > 32 bits", .{});
+ }
+}
+
+fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand = try self.resolveInst(ty_op.operand);
+ const operand_ty = self.air.typeOf(ty_op.operand);
+ const dest_ty = self.air.typeOfIndex(inst);
+
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
+ break :blk try self.trunc(inst, operand, operand_ty, dest_ty);
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
@@ -1099,6 +1121,10 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
} },
});
+ if (int_info.bits < 32) {
+ try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits);
+ }
+
break :result MCValue{ .register = dest_reg };
} else {
return self.fail("TODO ARM not on integers > u32/i32", .{});
@@ -1957,8 +1983,8 @@ fn binOpRegister(
if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
const mir_tag: Mir.Inst.Tag = switch (tag) {
- .add, .ptr_add => .add,
- .sub, .ptr_sub => .sub,
+ .add => .add,
+ .sub => .sub,
.cmp_eq => .cmp,
.mul => .mul,
.bit_and,
@@ -1967,12 +1993,8 @@ fn binOpRegister(
.bit_or,
.bool_or,
=> .orr,
- .shl,
- .shl_exact,
- => .lsl,
- .shr,
- .shr_exact,
- => switch (lhs_ty.intInfo(self.target.*).signedness) {
+ .shl_exact => .lsl,
+ .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
.signed => Mir.Inst.Tag.asr,
.unsigned => Mir.Inst.Tag.lsr,
},
@@ -1988,16 +2010,12 @@ fn binOpRegister(
.bit_or,
.bool_or,
.xor,
- .ptr_add,
- .ptr_sub,
=> .{ .rr_op = .{
.rd = dest_reg,
.rn = lhs_reg,
.op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
} },
- .shl,
.shl_exact,
- .shr,
.shr_exact,
=> .{ .rr_shift = .{
.rd = dest_reg,
@@ -2094,12 +2112,8 @@ fn binOpImmediate(
.bit_or,
.bool_or,
=> .orr,
- .shl,
- .shl_exact,
- => .lsl,
- .shr,
- .shr_exact,
- => switch (lhs_ty.intInfo(self.target.*).signedness) {
+ .shl_exact => .lsl,
+ .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
.signed => Mir.Inst.Tag.asr,
.unsigned => Mir.Inst.Tag.lsr,
},
@@ -2120,9 +2134,7 @@ fn binOpImmediate(
.rn = lhs_reg,
.op = Instruction.Operand.fromU32(rhs.immediate).?,
} },
- .shl,
.shl_exact,
- .shr,
.shr_exact,
=> .{ .rr_shift = .{
.rd = dest_reg,
@@ -2225,6 +2237,39 @@ fn binOp(
else => unreachable,
}
},
+ .addwrap,
+ .subwrap,
+ .mulwrap,
+ => {
+ const base_tag: Air.Inst.Tag = switch (tag) {
+ .addwrap => .add,
+ .subwrap => .sub,
+ .mulwrap => .mul,
+ else => unreachable,
+ };
+
+ // Generate an add/sub/mul
+ const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+
+ // Truncate if necessary
+ switch (lhs_ty.zigTypeTag()) {
+ .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
+ .Int => {
+ const int_info = lhs_ty.intInfo(self.target.*);
+ if (int_info.bits <= 32) {
+ const result_reg = result.register;
+
+ if (int_info.bits < 32) {
+ try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
+ return result;
+ } else return result;
+ } else {
+ return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
+ }
+ },
+ else => unreachable,
+ }
+ },
.bit_and,
.bit_or,
.xor,
@@ -2253,8 +2298,8 @@ fn binOp(
else => unreachable,
}
},
- .shl,
- .shr,
+ .shl_exact,
+ .shr_exact,
=> {
switch (lhs_ty.zigTypeTag()) {
.Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
@@ -2275,6 +2320,41 @@ fn binOp(
else => unreachable,
}
},
+ .shl,
+ .shr,
+ => {
+ const base_tag: Air.Inst.Tag = switch (tag) {
+ .shl => .shl_exact,
+ .shr => .shr_exact,
+ else => unreachable,
+ };
+
+ // Generate a shl_exact/shr_exact
+ const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+
+ // Truncate if necessary
+ switch (tag) {
+ .shr => return result,
+ .shl => switch (lhs_ty.zigTypeTag()) {
+ .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
+ .Int => {
+ const int_info = lhs_ty.intInfo(self.target.*);
+ if (int_info.bits <= 32) {
+ const result_reg = result.register;
+
+ if (int_info.bits < 32) {
+ try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
+ return result;
+ } else return result;
+ } else {
+ return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
+ }
+ },
+ else => unreachable,
+ },
+ else => unreachable,
+ }
+ },
.bool_and,
.bool_or,
=> {
@@ -2308,7 +2388,13 @@ fn binOp(
const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
if (elem_size == 1) {
- return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+ const base_tag: Air.Inst.Tag = switch (tag) {
+ .ptr_add => .add,
+ .ptr_sub => .sub,
+ else => unreachable,
+ };
+
+ return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
} else {
// convert the offset into a byte offset by
// multiplying it with elem_size
@@ -2876,35 +2962,19 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
const condition = Condition.fromCompareOperatorUnsigned(cmp_op);
break :blk condition.negate();
},
- .register => |reg| blk: {
- try self.spillCompareFlagsIfOccupied();
-
- // cmp reg, 1
- // bne ...
- _ = try self.addInst(.{
- .tag = .cmp,
- .cond = .al,
- .data = .{ .rr_op = .{
- .rd = .r0,
- .rn = reg,
- .op = Instruction.Operand.imm(1, 0),
- } },
- });
+ else => blk: {
+ const reg = switch (cond) {
+ .register => |r| r,
+ else => try self.copyToTmpRegister(Type.bool, cond),
+ };
- break :blk .ne;
- },
- .stack_offset,
- .memory,
- .stack_argument_offset,
- => blk: {
try self.spillCompareFlagsIfOccupied();
- const reg = try self.copyToTmpRegister(Type.initTag(.bool), cond);
-
// cmp reg, 1
// bne ...
_ = try self.addInst(.{
.tag = .cmp,
+ .cond = .al,
.data = .{ .rr_op = .{
.rd = .r0,
.rn = reg,
@@ -2914,7 +2984,6 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
break :blk .ne;
},
- else => return self.fail("TODO implement condbr {} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),
};
break :reloc try self.addInst(.{
@@ -3603,9 +3672,18 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
},
.memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
- .embedded_in_code,
- .stack_argument_offset,
- => return self.fail("TODO genSetStack with src={}", .{mcv}),
+ .stack_argument_offset => |unadjusted_off| {
+ const adj_off = unadjusted_off + abi_size;
+
+ _ = try self.addInst(.{
+ .tag = .ldr_ptr_stack_argument,
+ .data = .{ .r_stack_offset = .{
+ .rt = src_reg,
+ .stack_offset = adj_off,
+ } },
+ });
+ },
+ .embedded_in_code => return self.fail("TODO genSetStack with src={}", .{mcv}),
else => unreachable,
}
diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig
index 963879519f..c5aaeb4612 100644
--- a/src/arch/arm/Emit.zig
+++ b/src/arch/arm/Emit.zig
@@ -112,6 +112,7 @@ pub fn emitMir(
.str => try emit.mirLoadStore(inst),
.strb => try emit.mirLoadStore(inst),
+ .ldr_ptr_stack_argument => try emit.mirLoadStackArgument(inst),
.ldr_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
@@ -597,6 +598,12 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset;
switch (tag) {
+ .ldr_ptr_stack_argument => {
+ const operand = Instruction.Operand.fromU32(raw_offset) orelse
+ return emit.fail("TODO mirLoadStack larger offsets", .{});
+
+ try emit.writeInstruction(Instruction.add(cond, r_stack_offset.rt, .fp, operand));
+ },
.ldr_stack_argument,
.ldrb_stack_argument,
=> {
diff --git a/src/arch/arm/Mir.zig b/src/arch/arm/Mir.zig
index 5dcc3f7095..c6fdfd3051 100644
--- a/src/arch/arm/Mir.zig
+++ b/src/arch/arm/Mir.zig
@@ -54,6 +54,8 @@ pub const Inst = struct {
eor,
/// Load Register
ldr,
+ /// Pseudo-instruction: Load pointer to stack argument offset
+ ldr_ptr_stack_argument,
/// Load Register
ldr_stack_argument,
/// Load Register Byte