aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoachim Schmidt <joachim.schmidt557@outlook.com>2022-02-26 22:50:31 +0100
committerGitHub <noreply@github.com>2022-02-26 22:50:31 +0100
commit058e482247c73ecb6404c7c1e3d2194f4aa9e059 (patch)
tree3477f4e9793eda2c0e7c0be6cb431db445c473e6 /src
parent8349a644d0b9d4b2d58d736a14cdcc567a9e9b89 (diff)
parentf48f4baf676061742adb9674bc5e43e82c63f96a (diff)
downloadzig-058e482247c73ecb6404c7c1e3d2194f4aa9e059.tar.gz
zig-058e482247c73ecb6404c7c1e3d2194f4aa9e059.zip
Merge pull request #10996 from joachimschmidt557/stage2-arm
stage2 ARM: implement truncate to integers with <= 32 bits
Diffstat (limited to 'src')
-rw-r--r--src/arch/arm/CodeGen.zig284
-rw-r--r--src/arch/arm/Emit.zig61
-rw-r--r--src/arch/arm/Mir.zig22
-rw-r--r--src/arch/arm/bits.zig56
4 files changed, 297 insertions, 126 deletions
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig
index 8ad9e980cf..8f1d3e8be4 100644
--- a/src/arch/arm/CodeGen.zig
+++ b/src/arch/arm/CodeGen.zig
@@ -439,7 +439,7 @@ fn gen(self: *Self) !void {
// the code. Therefore, we can just delete
// the space initially reserved for the
// jump
- self.mir_instructions.len -= 1;
+ self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.items[0]);
} else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
self.mir_instructions.set(jmp_reloc, .{
.tag = .b,
@@ -749,6 +749,17 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
/// Use a pointer instruction as the basis for allocating stack memory.
fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
const elem_ty = self.air.typeOfIndex(inst).elemType();
+
+ if (!elem_ty.hasRuntimeBits()) {
+ // As this stack item will never be dereferenced at runtime,
+ // return the current stack offset
+ try self.stack.putNoClobber(self.gpa, self.next_stack_offset, .{
+ .inst = inst,
+ .size = 0,
+ });
+ return self.next_stack_offset;
+ }
+
const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
};
@@ -872,11 +883,61 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
if (self.liveness.isUnused(inst))
return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
+ const operand_ty = self.air.typeOf(ty_op.operand);
const operand = try self.resolveInst(ty_op.operand);
- _ = operand;
+ const info_a = operand_ty.intInfo(self.target.*);
+ const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
- return self.fail("TODO implement trunc for {}", .{self.target.cpu.arch});
- // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
+ 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;
+ }
+
+ break :dest_reg try self.register_manager.allocReg(null);
+ };
+
+ 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 };
+ },
+ }
+ } else {
+ return self.fail("TODO: truncate to ints > 32 bits", .{});
+ }
+ };
+
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
@@ -1514,7 +1575,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
.compare_flags_signed, .compare_flags_unsigned => unreachable,
.embedded_in_code => unreachable,
.register => |dst_reg| {
- try self.genLdrRegister(dst_reg, reg, elem_size);
+ try self.genLdrRegister(dst_reg, reg, elem_ty);
},
.stack_offset => |off| {
if (elem_size <= 4) {
@@ -1615,7 +1676,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
switch (value) {
.register => |value_reg| {
- try self.genStrRegister(value_reg, addr_reg, @intCast(u32, value_ty.abiSize(self.target.*)));
+ try self.genStrRegister(value_reg, addr_reg, value_ty);
},
else => {
if (value_ty.abiSize(self.target.*) <= 4) {
@@ -2180,68 +2241,71 @@ fn binOp(
}
}
-fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void {
- switch (abi_size) {
- 1, 3, 4 => {
- const tag: Mir.Inst.Tag = switch (abi_size) {
- 1 => .ldrb,
- 3, 4 => .ldr,
- else => unreachable,
- };
+fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {
+ const abi_size = ty.abiSize(self.target.*);
- _ = try self.addInst(.{
- .tag = tag,
- .data = .{ .rr_offset = .{
- .rt = dest_reg,
- .rn = addr_reg,
- .offset = .{ .offset = Instruction.Offset.none },
- } },
- });
- },
- 2 => {
- _ = try self.addInst(.{
- .tag = .ldrh,
- .data = .{ .rr_extra_offset = .{
- .rt = dest_reg,
- .rn = addr_reg,
- .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
- } },
- });
- },
- else => unreachable, // invalid abi_size for a register
- }
+ const tag: Mir.Inst.Tag = switch (abi_size) {
+ 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
+ 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
+ 3, 4 => .ldr,
+ else => unreachable,
+ };
+
+ const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
+ .rt = dest_reg,
+ .rn = addr_reg,
+ .offset = .{ .offset = Instruction.Offset.none },
+ } };
+ const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
+ .rt = dest_reg,
+ .rn = addr_reg,
+ .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
+ } };
+
+ const data: Mir.Inst.Data = switch (abi_size) {
+ 1 => if (ty.isSignedInt()) rr_extra_offset else rr_offset,
+ 2 => rr_extra_offset,
+ 3, 4 => rr_offset,
+ else => unreachable,
+ };
+
+ _ = try self.addInst(.{
+ .tag = tag,
+ .data = data,
+ });
}
-fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, abi_size: u32) !void {
- switch (abi_size) {
- 1, 3, 4 => {
- const tag: Mir.Inst.Tag = switch (abi_size) {
- 1 => .strb,
- 3, 4 => .str,
- else => unreachable,
- };
+fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Type) !void {
+ const abi_size = ty.abiSize(self.target.*);
- _ = try self.addInst(.{
- .tag = tag,
- .data = .{ .rr_offset = .{
- .rt = source_reg,
- .rn = addr_reg,
- .offset = .{ .offset = Instruction.Offset.none },
- } },
- });
- },
- 2 => {
- _ = try self.addInst(.{
- .tag = .strh,
- .data = .{ .rr_extra_offset = .{
- .rt = source_reg,
- .rn = addr_reg,
- .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
- } },
- });
- },
- else => unreachable, // invalid abi_size for a register
- }
+ const tag: Mir.Inst.Tag = switch (abi_size) {
+ 1 => .strb,
+ 2 => .strh,
+ 3, 4 => .str,
+ else => unreachable,
+ };
+
+ const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
+ .rt = source_reg,
+ .rn = addr_reg,
+ .offset = .{ .offset = Instruction.Offset.none },
+ } };
+ const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
+ .rt = source_reg,
+ .rn = addr_reg,
+ .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
+ } };
+
+ const data: Mir.Inst.Data = switch (abi_size) {
+ 1, 3, 4 => rr_offset,
+ 2 => rr_extra_offset,
+ else => unreachable,
+ };
+
+ _ = try self.addInst(.{
+ .tag = tag,
+ .data = data,
+ });
}
fn genInlineMemcpy(
@@ -2834,8 +2898,6 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
}
fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
- _ = operand;
-
const error_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
@@ -3569,55 +3631,59 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
// The value is in memory at a hard-coded address.
// If the type is a pointer, it means the pointer address is at this memory location.
try self.genSetReg(ty, reg, .{ .immediate = @intCast(u32, addr) });
- try self.genLdrRegister(reg, reg, @intCast(u32, ty.abiSize(self.target.*)));
+ try self.genLdrRegister(reg, reg, ty);
},
.stack_offset => |unadjusted_off| {
// TODO: maybe addressing from sp instead of fp
const abi_size = @intCast(u32, ty.abiSize(self.target.*));
const adj_off = unadjusted_off + abi_size;
- switch (abi_size) {
- 1, 4 => {
- const offset = if (adj_off <= math.maxInt(u12)) blk: {
- break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
- } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
+ const tag: Mir.Inst.Tag = switch (abi_size) {
+ 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
+ 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
+ 3, 4 => .ldr,
+ else => unreachable,
+ };
- const tag: Mir.Inst.Tag = switch (abi_size) {
- 1 => .ldrb,
- 4 => .ldr,
- else => unreachable,
- };
+ const extra_offset = switch (abi_size) {
+ 1 => ty.isSignedInt(),
+ 2 => true,
+ 3, 4 => false,
+ else => unreachable,
+ };
- _ = try self.addInst(.{
- .tag = tag,
- .data = .{ .rr_offset = .{
- .rt = reg,
- .rn = .fp,
- .offset = .{
- .offset = offset,
- .positive = false,
- },
- } },
- });
- },
- 2 => {
- const offset = if (adj_off <= math.maxInt(u8)) blk: {
- break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
- } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
+ if (extra_offset) {
+ const offset = if (adj_off <= math.maxInt(u8)) blk: {
+ break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
+ } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
- _ = try self.addInst(.{
- .tag = .ldrh,
- .data = .{ .rr_extra_offset = .{
- .rt = reg,
- .rn = .fp,
- .offset = .{
- .offset = offset,
- .positive = false,
- },
- } },
- });
- },
- else => return self.fail("TODO a type of size {} is not allowed in a register", .{abi_size}),
+ _ = try self.addInst(.{
+ .tag = tag,
+ .data = .{ .rr_extra_offset = .{
+ .rt = reg,
+ .rn = .fp,
+ .offset = .{
+ .offset = offset,
+ .positive = false,
+ },
+ } },
+ });
+ } else {
+ const offset = if (adj_off <= math.maxInt(u12)) blk: {
+ break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
+ } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
+
+ _ = try self.addInst(.{
+ .tag = tag,
+ .data = .{ .rr_offset = .{
+ .rt = reg,
+ .rn = .fp,
+ .offset = .{
+ .offset = offset,
+ .positive = false,
+ },
+ } },
+ });
}
},
.stack_argument_offset => |unadjusted_off| {
@@ -3625,9 +3691,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
const adj_off = unadjusted_off + abi_size;
const tag: Mir.Inst.Tag = switch (abi_size) {
- 1 => .ldrb_stack_argument,
- 2 => .ldrh_stack_argument,
- 4 => .ldr_stack_argument,
+ 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,
+ 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument,
+ 3, 4 => .ldr_stack_argument,
else => unreachable,
};
diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig
index 3ee70583d0..7ffd6de2dd 100644
--- a/src/arch/arm/Emit.zig
+++ b/src/arch/arm/Emit.zig
@@ -115,8 +115,12 @@ pub fn emitMir(
.ldr_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
+ .ldrsb_stack_argument => try emit.mirLoadStackArgument(inst),
+ .ldrsh_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrh => try emit.mirLoadStoreExtra(inst),
+ .ldrsb => try emit.mirLoadStore(inst),
+ .ldrsh => try emit.mirLoadStoreExtra(inst),
.strh => try emit.mirLoadStoreExtra(inst),
.movw => try emit.mirSpecialMove(inst),
@@ -130,6 +134,9 @@ pub fn emitMir(
.push => try emit.mirBlockDataTransfer(inst),
.svc => try emit.mirSupervisorCall(inst),
+
+ .sbfx => try emit.mirBitFieldExtract(inst),
+ .ubfx => try emit.mirBitFieldExtract(inst),
}
}
}
@@ -590,36 +597,42 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset;
switch (tag) {
- .ldr_stack_argument => {
+ .ldr_stack_argument,
+ .ldrb_stack_argument,
+ => {
const offset = if (raw_offset <= math.maxInt(u12)) blk: {
break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
} else return emit.fail("TODO mirLoadStack larger offsets", .{});
- try emit.writeInstruction(Instruction.ldr(
- cond,
- r_stack_offset.rt,
- .fp,
- .{ .offset = offset },
- ));
- },
- .ldrb_stack_argument => {
- const offset = if (raw_offset <= math.maxInt(u12)) blk: {
- break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
- } else return emit.fail("TODO mirLoadStack larger offsets", .{});
+ const ldr = switch (tag) {
+ .ldr_stack_argument => Instruction.ldr,
+ .ldrb_stack_argument => Instruction.ldrb,
+ else => unreachable,
+ };
- try emit.writeInstruction(Instruction.ldrb(
+ try emit.writeInstruction(ldr(
cond,
r_stack_offset.rt,
.fp,
.{ .offset = offset },
));
},
- .ldrh_stack_argument => {
+ .ldrh_stack_argument,
+ .ldrsb_stack_argument,
+ .ldrsh_stack_argument,
+ => {
const offset = if (raw_offset <= math.maxInt(u8)) blk: {
break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
} else return emit.fail("TODO mirLoadStack larger offsets", .{});
- try emit.writeInstruction(Instruction.ldrh(
+ const ldr = switch (tag) {
+ .ldrh_stack_argument => Instruction.ldrh,
+ .ldrsb_stack_argument => Instruction.ldrsb,
+ .ldrsh_stack_argument => Instruction.ldrsh,
+ else => unreachable,
+ };
+
+ try emit.writeInstruction(ldr(
cond,
r_stack_offset.rt,
.fp,
@@ -637,6 +650,8 @@ fn mirLoadStoreExtra(emit: *Emit, inst: Mir.Inst.Index) !void {
switch (tag) {
.ldrh => try emit.writeInstruction(Instruction.ldrh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
+ .ldrsb => try emit.writeInstruction(Instruction.ldrsb(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
+ .ldrsh => try emit.writeInstruction(Instruction.ldrsh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
.strh => try emit.writeInstruction(Instruction.strh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
else => unreachable,
}
@@ -691,3 +706,19 @@ fn mirSupervisorCall(emit: *Emit, inst: Mir.Inst.Index) !void {
else => unreachable,
}
}
+
+fn mirBitFieldExtract(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ const cond = emit.mir.instructions.items(.cond)[inst];
+ const rr_lsb_width = emit.mir.instructions.items(.data)[inst].rr_lsb_width;
+ const rd = rr_lsb_width.rd;
+ const rn = rr_lsb_width.rn;
+ const lsb = rr_lsb_width.lsb;
+ const width = rr_lsb_width.width;
+
+ switch (tag) {
+ .sbfx => try emit.writeInstruction(Instruction.sbfx(cond, rd, rn, lsb, width)),
+ .ubfx => try emit.writeInstruction(Instruction.ubfx(cond, rd, rn, lsb, width)),
+ else => unreachable,
+ }
+}
diff --git a/src/arch/arm/Mir.zig b/src/arch/arm/Mir.zig
index e6f1bcb0a2..7852a39885 100644
--- a/src/arch/arm/Mir.zig
+++ b/src/arch/arm/Mir.zig
@@ -64,6 +64,14 @@ pub const Inst = struct {
ldrh,
/// Load Register Halfword
ldrh_stack_argument,
+ /// Load Register Signed Byte
+ ldrsb,
+ /// Load Register Signed Byte
+ ldrsb_stack_argument,
+ /// Load Register Signed Halfword
+ ldrsh,
+ /// Load Register Signed Halfword
+ ldrsh_stack_argument,
/// Logical Shift Left
lsl,
/// Logical Shift Right
@@ -88,6 +96,8 @@ pub const Inst = struct {
push,
/// Reverse Subtract
rsb,
+ /// Signed Bit Field Extract
+ sbfx,
/// Store Register
str,
/// Store Register Byte
@@ -98,6 +108,8 @@ pub const Inst = struct {
sub,
/// Supervisor Call
svc,
+ /// Unsigned Bit Field Extract
+ ubfx,
};
/// The position of an MIR instruction within the `Mir` instructions array.
@@ -179,6 +191,16 @@ pub const Inst = struct {
rn: Register,
offset: bits.Instruction.ExtraLoadStoreOffsetArgs,
},
+ /// Two registers and a lsb (range 0-31) and a width (range
+ /// 1-32)
+ ///
+ /// Used by e.g. sbfx
+ rr_lsb_width: struct {
+ rd: Register,
+ rn: Register,
+ lsb: u5,
+ width: u6,
+ },
/// Three registers
///
/// Used by e.g. mul
diff --git a/src/arch/arm/bits.zig b/src/arch/arm/bits.zig
index 792bf0dc05..568b7580c8 100644
--- a/src/arch/arm/bits.zig
+++ b/src/arch/arm/bits.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const DW = std.dwarf;
+const assert = std.debug.assert;
const testing = std.testing;
/// The condition field specifies the flags necessary for an
@@ -237,6 +238,17 @@ pub const Instruction = union(enum) {
fixed_3: u5 = 0b00010,
cond: u4,
},
+ bit_field_extract: packed struct {
+ rn: u4,
+ fixed_1: u3 = 0b101,
+ lsb: u5,
+ rd: u4,
+ widthm1: u5,
+ fixed_2: u1 = 0b1,
+ unsigned: u1,
+ fixed_3: u5 = 0b01111,
+ cond: u4,
+ },
single_data_transfer: packed struct {
offset: u12,
rd: u4,
@@ -576,6 +588,7 @@ pub const Instruction = union(enum) {
.multiply => |v| @bitCast(u32, v),
.multiply_long => |v| @bitCast(u32, v),
.integer_saturating_arithmetic => |v| @bitCast(u32, v),
+ .bit_field_extract => |v| @bitCast(u32, v),
.single_data_transfer => |v| @bitCast(u32, v),
.extra_load_store => |v| @bitCast(u32, v),
.block_data_transfer => |v| @bitCast(u32, v),
@@ -691,6 +704,27 @@ pub const Instruction = union(enum) {
};
}
+ fn bitFieldExtract(
+ unsigned: u1,
+ cond: Condition,
+ rd: Register,
+ rn: Register,
+ lsb: u5,
+ width: u6,
+ ) Instruction {
+ assert(width > 0 and width <= 32);
+ return Instruction{
+ .bit_field_extract = .{
+ .rn = rn.id(),
+ .lsb = lsb,
+ .rd = rd.id(),
+ .widthm1 = @intCast(u5, width - 1),
+ .unsigned = unsigned,
+ .cond = @enumToInt(cond),
+ },
+ };
+ }
+
fn singleDataTransfer(
cond: Condition,
rd: Register,
@@ -1044,6 +1078,16 @@ pub const Instruction = union(enum) {
return multiplyLong(cond, 1, 1, 1, rdhi, rdlo, rm, rn);
}
+ // Bit field extract
+
+ pub fn ubfx(cond: Condition, rd: Register, rn: Register, lsb: u5, width: u6) Instruction {
+ return bitFieldExtract(0b1, cond, rd, rn, lsb, width);
+ }
+
+ pub fn sbfx(cond: Condition, rd: Register, rn: Register, lsb: u5, width: u6) Instruction {
+ return bitFieldExtract(0b0, cond, rd, rn, lsb, width);
+ }
+
// Single data transfer
pub const OffsetArgs = struct {
@@ -1079,11 +1123,19 @@ pub const Instruction = union(enum) {
};
pub fn strh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
- return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0, 0b01, rn, rt, args.offset);
+ return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b0, 0b01, rn, rt, args.offset);
}
pub fn ldrh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
- return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 1, 0b01, rn, rt, args.offset);
+ return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b01, rn, rt, args.offset);
+ }
+
+ pub fn ldrsh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
+ return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b11, rn, rt, args.offset);
+ }
+
+ pub fn ldrsb(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
+ return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b10, rn, rt, args.offset);
}
// Block data transfer