authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-03 20:31:01+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-04 21:07:10+01:00
log04f379dd414184a42412f4497b0573d7612d6730
treeb0cdc7bf12be59a5f28915485aaf7304c742dc15
parent71321b694195a87ab7394a25badf5295eb01875e

stage2 ARM: optimize airSliceElemVal for elem_size 1 or 4

In these cases, the AIR inst can be lowered to only one ldr instruction. Also fixes shifts in arm.bits.Offset

2 files changed, 139 insertions(+), 105 deletions(-)

src/arch/arm/CodeGen.zig+81-79
...@@ -1222,9 +1222,16 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1222,9 +1222,16 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
1222fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {1222fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1223 const is_volatile = false; // TODO1223 const is_volatile = false; // TODO
1224 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1224 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1225 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {1225
1226 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1227 const result: MCValue = result: {
1226 const slice_mcv = try self.resolveInst(bin_op.lhs);1228 const slice_mcv = try self.resolveInst(bin_op.lhs);
12271229
1230 // TODO optimize for the case where the index is a constant,
1231 // i.e. index_mcv == .immediate
1232 const index_mcv = try self.resolveInst(bin_op.rhs);
1233 const index_is_register = index_mcv == .register;
1234
1228 const slice_ty = self.air.typeOf(bin_op.lhs);1235 const slice_ty = self.air.typeOf(bin_op.lhs);
1229 const elem_ty = slice_ty.childType();1236 const elem_ty = slice_ty.childType();
1230 const elem_size = elem_ty.abiSize(self.target.*);1237 const elem_size = elem_ty.abiSize(self.target.*);
...@@ -1232,12 +1239,8 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1232,12 +1239,8 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1232 var buf: Type.SlicePtrFieldTypeBuffer = undefined;1239 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1233 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);1240 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
12341241
1235 // TODO optimize this for the case when elem_size is a power1242 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});
1236 // of two (includes elem_size == 1)1243 defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register});
1237 const offset_mcv = try self.genArmMulConstant(inst, bin_op.rhs, 1, @intCast(u32, elem_size));
1238 assert(offset_mcv == .register); // result of multiplication should always be register
1239 self.register_manager.freezeRegs(&.{offset_mcv.register});
1240 defer self.register_manager.unfreezeRegs(&.{offset_mcv.register});
12411244
1242 const base_mcv: MCValue = switch (slice_mcv) {1245 const base_mcv: MCValue = switch (slice_mcv) {
1243 .stack_offset => .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, slice_mcv) },1246 .stack_offset => .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, slice_mcv) },
...@@ -1246,61 +1249,67 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1246,61 +1249,67 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1246 self.register_manager.freezeRegs(&.{base_mcv.register});1249 self.register_manager.freezeRegs(&.{base_mcv.register});
1247 defer self.register_manager.unfreezeRegs(&.{base_mcv.register});1250 defer self.register_manager.unfreezeRegs(&.{base_mcv.register});
12481251
1249 if (elem_size <= 4) {1252 switch (elem_size) {
1250 const dst_reg = try self.register_manager.allocReg(inst);1253 1, 4 => {
1251 self.register_manager.freezeRegs(&.{dst_reg});1254 const dst_reg = try self.register_manager.allocReg(inst);
1252 defer self.register_manager.unfreezeRegs(&.{dst_reg});1255 const dst_mcv = MCValue{ .register = dst_reg };
1256 self.register_manager.freezeRegs(&.{dst_reg});
1257 defer self.register_manager.unfreezeRegs(&.{dst_reg});
12531258
1254 switch (elem_size) {1259 const index_reg: Register = switch (index_mcv) {
1255 1, 4 => {1260 .register => |reg| reg,
1256 const tag: Mir.Inst.Tag = switch (elem_size) {1261 else => try self.copyToTmpRegister(Type.usize, index_mcv),
1257 1 => .ldrb,1262 };
1258 4 => .ldr,1263 self.register_manager.freezeRegs(&.{index_reg});
1259 else => unreachable,1264 defer self.register_manager.unfreezeRegs(&.{index_reg});
1260 };
12611265
1262 _ = try self.addInst(.{1266 const tag: Mir.Inst.Tag = switch (elem_size) {
1263 .tag = tag,1267 1 => .ldrb,
1264 .data = .{ .rr_offset = .{1268 4 => .ldr,
1265 .rt = dst_reg,1269 else => unreachable,
1266 .rn = base_mcv.register,1270 };
1267 .offset = .{ .offset = Instruction.Offset.reg(offset_mcv.register, 0) },1271 const shift: u5 = switch (elem_size) {
1268 } },1272 1 => 0,
1269 });1273 4 => 2,
1270 },1274 else => unreachable,
1271 2 => {1275 };
1272 _ = try self.addInst(.{
1273 .tag = .ldrh,
1274 .data = .{ .rr_extra_offset = .{
1275 .rt = dst_reg,
1276 .rn = base_mcv.register,
1277 .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.reg(offset_mcv.register) },
1278 } },
1279 });
1280 },
1281 else => unreachable,
1282 }
12831276
1284 break :result MCValue{ .register = dst_reg };1277 _ = try self.addInst(.{
1285 } else {1278 .tag = tag,
1286 const dst_mcv = try self.allocRegOrMem(inst, false);1279 .data = .{ .rr_offset = .{
1280 .rt = dst_reg,
1281 .rn = base_mcv.register,
1282 .offset = .{ .offset = Instruction.Offset.reg(index_reg, .{ .lsl = shift }) },
1283 } },
1284 });
12871285
1288 const addr_reg = try self.register_manager.allocReg(null);1286 break :result dst_mcv;
1289 self.register_manager.freezeRegs(&.{addr_reg});1287 },
1290 defer self.register_manager.unfreezeRegs(&.{addr_reg});1288 else => {
1289 const dst_mcv = try self.allocRegOrMem(inst, true);
1290
1291 const offset_mcv = try self.genArmMulConstant(bin_op.rhs, @intCast(u32, elem_size));
1292 assert(offset_mcv == .register); // result of multiplication should always be register
1293 self.register_manager.freezeRegs(&.{offset_mcv.register});
1294 defer self.register_manager.unfreezeRegs(&.{offset_mcv.register});
12911295
1292 try self.genArmBinOpCode(addr_reg, base_mcv, offset_mcv, false, .add, .unsigned);1296 const addr_reg = try self.register_manager.allocReg(null);
1297 self.register_manager.freezeRegs(&.{addr_reg});
1298 defer self.register_manager.unfreezeRegs(&.{addr_reg});
12931299
1294 // I know we will unfreeze these registers at the end of1300 try self.genArmBinOpCode(addr_reg, base_mcv, offset_mcv, false, .add, .unsigned);
1295 // the scope of :result. However, at this point in time,
1296 // neither the base register nor the offset register
1297 // contains any valuable data anymore. In order to reduce
1298 // register pressure, unfreeze them prematurely
1299 self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
13001301
1301 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);1302 // I know we will unfreeze these registers at the end of
1303 // the scope of :result. However, at this point in time,
1304 // neither the base register nor the offset register
1305 // contains any valuable data anymore. In order to reduce
1306 // register pressure, unfreeze them prematurely
1307 self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
13021308
1303 break :result dst_mcv;1309 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1310
1311 break :result dst_mcv;
1312 },
1304 }1313 }
1305 };1314 };
1306 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1315 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -1931,8 +1940,8 @@ fn genArmBinOpCode(...@@ -1931,8 +1940,8 @@ fn genArmBinOpCode(
1931 .shl, .shr => {1940 .shl, .shr => {
1932 assert(!swap_lhs_and_rhs);1941 assert(!swap_lhs_and_rhs);
1933 const shift_amount = switch (operand) {1942 const shift_amount = switch (operand) {
1934 .Register => |reg_op| Instruction.ShiftAmount.reg(@intToEnum(Register, reg_op.rm)),1943 .register => |reg_op| Instruction.ShiftAmount.reg(@intToEnum(Register, reg_op.rm)),
1935 .Immediate => |imm_op| Instruction.ShiftAmount.imm(@intCast(u5, imm_op.imm)),1944 .immediate => |imm_op| Instruction.ShiftAmount.imm(@intCast(u5, imm_op.imm)),
1936 };1945 };
19371946
1938 const tag: Mir.Inst.Tag = switch (op) {1947 const tag: Mir.Inst.Tag = switch (op) {
...@@ -2036,12 +2045,11 @@ fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Ai...@@ -2036,12 +2045,11 @@ fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Ai
2036 return dst_mcv;2045 return dst_mcv;
2037}2046}
20382047
2039fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_index: Liveness.OperandInt, imm: u32) !MCValue {2048fn genArmMulConstant(self: *Self, op: Air.Inst.Ref, imm: u32) !MCValue {
2040 const lhs = try self.resolveInst(op);2049 const lhs = try self.resolveInst(op);
2041 const rhs = MCValue{ .immediate = imm };2050 const rhs = MCValue{ .immediate = imm };
20422051
2043 const lhs_is_register = lhs == .register;2052 const lhs_is_register = lhs == .register;
2044 const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op, op_index, lhs);
20452053
2046 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});2054 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
2047 defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register});2055 defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register});
...@@ -2054,23 +2062,17 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind...@@ -2054,23 +2062,17 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind
2054 var rhs_mcv: MCValue = rhs;2062 var rhs_mcv: MCValue = rhs;
20552063
2056 // Allocate registers for operands and/or destination2064 // Allocate registers for operands and/or destination
2057 if (reuse_lhs) {2065 // Allocate 1 or 2 registers
2058 // Allocate 1 register2066 if (lhs_is_register) {
2059 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };2067 // Move RHS to register
2060 dst_mcv = lhs;2068 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
2069 rhs_mcv = dst_mcv;
2061 } else {2070 } else {
2062 // Allocate 1 or 2 registers2071 // Move LHS and RHS to register
2063 if (lhs_is_register) {2072 const regs = try self.register_manager.allocRegs(2, .{ null, null });
2064 // Move RHS to register2073 lhs_mcv = MCValue{ .register = regs[0] };
2065 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };2074 rhs_mcv = MCValue{ .register = regs[1] };
2066 rhs_mcv = dst_mcv;2075 dst_mcv = lhs_mcv;
2067 } else {
2068 // Move LHS and RHS to register
2069 const regs = try self.register_manager.allocRegs(2, .{ null, null });
2070 lhs_mcv = MCValue{ .register = regs[0] };
2071 rhs_mcv = MCValue{ .register = regs[1] };
2072 dst_mcv = lhs_mcv;
2073 }
2074 }2076 }
20752077
2076 // Move the operands to the newly allocated registers2078 // Move the operands to the newly allocated registers
...@@ -2132,7 +2134,7 @@ fn genArmInlineMemcpy(...@@ -2132,7 +2134,7 @@ fn genArmInlineMemcpy(
2132 .data = .{ .rr_offset = .{2134 .data = .{ .rr_offset = .{
2133 .rt = tmp,2135 .rt = tmp,
2134 .rn = src,2136 .rn = src,
2135 .offset = .{ .offset = Instruction.Offset.reg(count, 0) },2137 .offset = .{ .offset = Instruction.Offset.reg(count, .none) },
2136 } },2138 } },
2137 });2139 });
21382140
...@@ -2142,7 +2144,7 @@ fn genArmInlineMemcpy(...@@ -2142,7 +2144,7 @@ fn genArmInlineMemcpy(
2142 .data = .{ .rr_offset = .{2144 .data = .{ .rr_offset = .{
2143 .rt = tmp,2145 .rt = tmp,
2144 .rn = dst,2146 .rn = dst,
2145 .offset = .{ .offset = Instruction.Offset.reg(count, 0) },2147 .offset = .{ .offset = Instruction.Offset.reg(count, .none) },
2146 } },2148 } },
2147 });2149 });
21482150
...@@ -3126,7 +3128,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3126,7 +3128,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3126 1, 4 => {3128 1, 4 => {
3127 const offset = if (math.cast(u12, adj_off)) |imm| blk: {3129 const offset = if (math.cast(u12, adj_off)) |imm| blk: {
3128 break :blk Instruction.Offset.imm(imm);3130 break :blk Instruction.Offset.imm(imm);
3129 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);3131 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
31303132
3131 const tag: Mir.Inst.Tag = switch (abi_size) {3133 const tag: Mir.Inst.Tag = switch (abi_size) {
3132 1 => .strb,3134 1 => .strb,
...@@ -3450,7 +3452,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3450,7 +3452,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3450 1, 4 => {3452 1, 4 => {
3451 const offset = if (adj_off <= math.maxInt(u12)) blk: {3453 const offset = if (adj_off <= math.maxInt(u12)) blk: {
3452 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));3454 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
3453 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);3455 } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
34543456
3455 const tag: Mir.Inst.Tag = switch (abi_size) {3457 const tag: Mir.Inst.Tag = switch (abi_size) {
3456 1 => .ldrb,3458 1 => .ldrb,
...@@ -3536,7 +3538,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -3536,7 +3538,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
3536 1, 4 => {3538 1, 4 => {
3537 const offset = if (math.cast(u12, adj_off)) |imm| blk: {3539 const offset = if (math.cast(u12, adj_off)) |imm| blk: {
3538 break :blk Instruction.Offset.imm(imm);3540 break :blk Instruction.Offset.imm(imm);
3539 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);3541 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
35403542
3541 const tag: Mir.Inst.Tag = switch (abi_size) {3543 const tag: Mir.Inst.Tag = switch (abi_size) {
3542 1 => .strb,3544 1 => .strb,
src/arch/arm/bits.zig+58-26
...@@ -343,11 +343,11 @@ pub const Instruction = union(enum) {...@@ -343,11 +343,11 @@ pub const Instruction = union(enum) {
343 /// which can either be content from a register or an immediate343 /// which can either be content from a register or an immediate
344 /// value344 /// value
345 pub const Operand = union(enum) {345 pub const Operand = union(enum) {
346 Register: packed struct {346 register: packed struct {
347 rm: u4,347 rm: u4,
348 shift: u8,348 shift: u8,
349 },349 },
350 Immediate: packed struct {350 immediate: packed struct {
351 imm: u8,351 imm: u8,
352 rotate: u4,352 rotate: u4,
353 },353 },
...@@ -356,12 +356,12 @@ pub const Instruction = union(enum) {...@@ -356,12 +356,12 @@ pub const Instruction = union(enum) {
356 /// register can be shifted by a specific immediate value or356 /// register can be shifted by a specific immediate value or
357 /// by the contents of another register357 /// by the contents of another register
358 pub const Shift = union(enum) {358 pub const Shift = union(enum) {
359 Immediate: packed struct {359 immediate: packed struct {
360 fixed: u1 = 0b0,360 fixed: u1 = 0b0,
361 typ: u2,361 typ: u2,
362 amount: u5,362 amount: u5,
363 },363 },
364 Register: packed struct {364 register: packed struct {
365 fixed_1: u1 = 0b1,365 fixed_1: u1 = 0b1,
366 typ: u2,366 typ: u2,
367 fixed_2: u1 = 0b0,367 fixed_2: u1 = 0b0,
...@@ -376,7 +376,7 @@ pub const Instruction = union(enum) {...@@ -376,7 +376,7 @@ pub const Instruction = union(enum) {
376 };376 };
377377
378 pub const none = Shift{378 pub const none = Shift{
379 .Immediate = .{379 .immediate = .{
380 .amount = 0,380 .amount = 0,
381 .typ = 0,381 .typ = 0,
382 },382 },
...@@ -384,14 +384,14 @@ pub const Instruction = union(enum) {...@@ -384,14 +384,14 @@ pub const Instruction = union(enum) {
384384
385 pub fn toU8(self: Shift) u8 {385 pub fn toU8(self: Shift) u8 {
386 return switch (self) {386 return switch (self) {
387 .Register => |v| @bitCast(u8, v),387 .register => |v| @bitCast(u8, v),
388 .Immediate => |v| @bitCast(u8, v),388 .immediate => |v| @bitCast(u8, v),
389 };389 };
390 }390 }
391391
392 pub fn reg(rs: Register, typ: Type) Shift {392 pub fn reg(rs: Register, typ: Type) Shift {
393 return Shift{393 return Shift{
394 .Register = .{394 .register = .{
395 .rs = rs.id(),395 .rs = rs.id(),
396 .typ = @enumToInt(typ),396 .typ = @enumToInt(typ),
397 },397 },
...@@ -400,7 +400,7 @@ pub const Instruction = union(enum) {...@@ -400,7 +400,7 @@ pub const Instruction = union(enum) {
400400
401 pub fn imm(amount: u5, typ: Type) Shift {401 pub fn imm(amount: u5, typ: Type) Shift {
402 return Shift{402 return Shift{
403 .Immediate = .{403 .immediate = .{
404 .amount = amount,404 .amount = amount,
405 .typ = @enumToInt(typ),405 .typ = @enumToInt(typ),
406 },406 },
...@@ -410,14 +410,14 @@ pub const Instruction = union(enum) {...@@ -410,14 +410,14 @@ pub const Instruction = union(enum) {
410410
411 pub fn toU12(self: Operand) u12 {411 pub fn toU12(self: Operand) u12 {
412 return switch (self) {412 return switch (self) {
413 .Register => |v| @bitCast(u12, v),413 .register => |v| @bitCast(u12, v),
414 .Immediate => |v| @bitCast(u12, v),414 .immediate => |v| @bitCast(u12, v),
415 };415 };
416 }416 }
417417
418 pub fn reg(rm: Register, shift: Shift) Operand {418 pub fn reg(rm: Register, shift: Shift) Operand {
419 return Operand{419 return Operand{
420 .Register = .{420 .register = .{
421 .rm = rm.id(),421 .rm = rm.id(),
422 .shift = shift.toU8(),422 .shift = shift.toU8(),
423 },423 },
...@@ -426,7 +426,7 @@ pub const Instruction = union(enum) {...@@ -426,7 +426,7 @@ pub const Instruction = union(enum) {
426426
427 pub fn imm(immediate: u8, rotate: u4) Operand {427 pub fn imm(immediate: u8, rotate: u4) Operand {
428 return Operand{428 return Operand{
429 .Immediate = .{429 .immediate = .{
430 .imm = immediate,430 .imm = immediate,
431 .rotate = rotate,431 .rotate = rotate,
432 },432 },
...@@ -447,7 +447,7 @@ pub const Instruction = union(enum) {...@@ -447,7 +447,7 @@ pub const Instruction = union(enum) {
447 return for (masks) |mask, i| {447 return for (masks) |mask, i| {
448 if (x & mask == x) {448 if (x & mask == x) {
449 break Operand{449 break Operand{
450 .Immediate = .{450 .immediate = .{
451 .imm = @intCast(u8, std.math.rotl(u32, x, 2 * i)),451 .imm = @intCast(u8, std.math.rotl(u32, x, 2 * i)),
452 .rotate = @intCast(u4, i),452 .rotate = @intCast(u4, i),
453 },453 },
...@@ -461,35 +461,67 @@ pub const Instruction = union(enum) {...@@ -461,35 +461,67 @@ pub const Instruction = union(enum) {
461 /// instruction. Data can be loaded from memory with either an461 /// instruction. Data can be loaded from memory with either an
462 /// immediate offset or an offset that is stored in some register.462 /// immediate offset or an offset that is stored in some register.
463 pub const Offset = union(enum) {463 pub const Offset = union(enum) {
464 Immediate: u12,464 immediate: u12,
465 Register: packed struct {465 register: packed struct {
466 rm: u4,466 rm: u4,
467 shift: u8,467 fixed: u1 = 0b0,
468 stype: u2,
469 imm5: u5,
468 },470 },
469471
472 pub const Shift = union(enum) {
473 /// No shift
474 none,
475 /// Logical shift left
476 lsl: u5,
477 /// Logical shift right
478 lsr: u5,
479 /// Arithmetic shift right
480 asr: u5,
481 /// Rotate right
482 ror: u5,
483 /// Rotate right one bit, with extend
484 rrx,
485 };
486
470 pub const none = Offset{487 pub const none = Offset{
471 .Immediate = 0,488 .immediate = 0,
472 };489 };
473490
474 pub fn toU12(self: Offset) u12 {491 pub fn toU12(self: Offset) u12 {
475 return switch (self) {492 return switch (self) {
476 .Register => |v| @bitCast(u12, v),493 .register => |v| @bitCast(u12, v),
477 .Immediate => |v| v,494 .immediate => |v| v,
478 };495 };
479 }496 }
480497
481 pub fn reg(rm: Register, shift: u8) Offset {498 pub fn reg(rm: Register, shift: Shift) Offset {
482 return Offset{499 return Offset{
483 .Register = .{500 .register = .{
484 .rm = rm.id(),501 .rm = rm.id(),
485 .shift = shift,502 .stype = switch (shift) {
503 .none => 0b00,
504 .lsl => 0b00,
505 .lsr => 0b01,
506 .asr => 0b10,
507 .ror => 0b11,
508 .rrx => 0b11,
509 },
510 .imm5 = switch (shift) {
511 .none => 0,
512 .lsl => |n| n,
513 .lsr => |n| n,
514 .asr => |n| n,
515 .ror => |n| n,
516 .rrx => 0,
517 },
486 },518 },
487 };519 };
488 }520 }
489521
490 pub fn imm(immediate: u12) Offset {522 pub fn imm(immediate: u12) Offset {
491 return Offset{523 return Offset{
492 .Immediate = immediate,524 .immediate = immediate,
493 };525 };
494 }526 }
495 };527 };
...@@ -567,7 +599,7 @@ pub const Instruction = union(enum) {...@@ -567,7 +599,7 @@ pub const Instruction = union(enum) {
567 return Instruction{599 return Instruction{
568 .data_processing = .{600 .data_processing = .{
569 .cond = @enumToInt(cond),601 .cond = @enumToInt(cond),
570 .i = @boolToInt(op2 == .Immediate),602 .i = @boolToInt(op2 == .immediate),
571 .opcode = @enumToInt(opcode),603 .opcode = @enumToInt(opcode),
572 .s = s,604 .s = s,
573 .rn = rn.id(),605 .rn = rn.id(),
...@@ -681,7 +713,7 @@ pub const Instruction = union(enum) {...@@ -681,7 +713,7 @@ pub const Instruction = union(enum) {
681 .byte_word = byte_word,713 .byte_word = byte_word,
682 .up_down = @boolToInt(positive),714 .up_down = @boolToInt(positive),
683 .pre_post = @boolToInt(pre_index),715 .pre_post = @boolToInt(pre_index),
684 .imm = @boolToInt(offset != .Immediate),716 .imm = @boolToInt(offset != .immediate),
685 },717 },
686 };718 };
687 }719 }