Merge pull request #24856 from jacobly0/aarch64-oom

aarch64: more assembler instructions
This commit is contained in:
Andrew Kelley 2025-08-15 10:44:00 -07:00 committed by GitHub
commit 6d7c6a0f4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 1453 additions and 169 deletions

View File

@ -6,11 +6,9 @@ pub const Operand = union(enum) {
};
pub fn nextInstruction(as: *Assemble) !?Instruction {
@setEvalBranchQuota(140_000);
comptime var ct_token_buf: [token_buf_len]u8 = undefined;
var token_buf: [token_buf_len]u8 = undefined;
const original_source = while (true) {
const original_source = as.source;
var token_buf: [token_buf_len]u8 = undefined;
const source_token = try as.nextToken(&token_buf, .{});
switch (source_token.len) {
0 => return null,
@ -27,73 +25,9 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
\\=========================
\\
, .{std.zig.fmtString(std.mem.span(original_source))});
inline for (instructions) |instruction| {
next_pattern: {
as.source = original_source;
const Symbols = @TypeOf(instruction.symbols);
var symbols: Symbols: {
const symbols = @typeInfo(Symbols).@"struct".fields;
var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined;
for (&symbol_fields, symbols) |*symbol_field, symbol| {
const Storage = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage();
symbol_field.* = .{
.name = symbol.name,
.type = Storage,
.default_value_ptr = null,
.is_comptime = false,
.alignment = @alignOf(Storage),
};
}
break :Symbols @Type(.{ .@"struct" = .{
.layout = .auto,
.fields = &symbol_fields,
.decls = &.{},
.is_tuple = false,
} });
} = undefined;
const Symbol = std.meta.FieldEnum(Symbols);
comptime var unused_symbols: std.enums.EnumSet(Symbol) = .initFull();
comptime var pattern_as: Assemble = .{ .source = instruction.pattern, .operands = undefined };
inline while (true) {
const pattern_token = comptime pattern_as.nextToken(&ct_token_buf, .{ .placeholders = true }) catch |err|
@compileError(@errorName(err) ++ " while parsing '" ++ instruction.pattern ++ "'");
const source_token = try as.nextToken(&token_buf, .{ .operands = true });
log.debug("\"{f}\" -> \"{f}\"", .{
std.zig.fmtString(pattern_token),
std.zig.fmtString(source_token),
});
if (pattern_token.len == 0) {
comptime var unused_symbol_it = unused_symbols.iterator();
inline while (comptime unused_symbol_it.next()) |unused_symbol|
@compileError(@tagName(unused_symbol) ++ " unused while parsing '" ++ instruction.pattern ++ "'");
switch (source_token.len) {
0 => {},
else => switch (source_token[0]) {
else => break :next_pattern,
'\n', ';' => {},
},
}
const encode = @field(Instruction, @tagName(instruction.encode[0]));
const Encode = @TypeOf(encode);
var args: std.meta.ArgsTuple(Encode) = undefined;
inline for (&args, @typeInfo(Encode).@"fn".params, 1..instruction.encode.len) |*arg, param, encode_index|
arg.* = zonCast(param.type.?, instruction.encode[encode_index], symbols);
return @call(.auto, encode, args);
} else if (pattern_token[0] == '<') {
const symbol_name = comptime pattern_token[1 .. std.mem.indexOfScalarPos(u8, pattern_token, 1, '|') orelse
pattern_token.len - 1];
const symbol = @field(Symbol, symbol_name);
const symbol_ptr = &@field(symbols, symbol_name);
const symbol_value = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern;
if (comptime unused_symbols.contains(symbol)) {
log.debug("{s} = {any}", .{ symbol_name, symbol_value });
symbol_ptr.* = symbol_value;
comptime unused_symbols.remove(symbol);
} else if (symbol_ptr.* != symbol_value) break :next_pattern;
} else if (!toUpperEqlAssertUpper(source_token, pattern_token)) break :next_pattern;
}
}
log.debug("'{s}' not matched...", .{instruction.pattern});
for (matchers) |matcher| {
as.source = original_source;
if (try matcher(as)) |result| return result;
}
as.source = original_source;
log.debug("Nothing matched!\n", .{});
@ -106,6 +40,12 @@ fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {
switch (@typeInfo(ZonValue)) {
.void, .bool, .int, .float, .pointer, .comptime_float, .comptime_int, .@"enum" => return zon_value,
.@"struct" => |zon_struct| switch (@typeInfo(Result)) {
.pointer => |result_pointer| {
comptime assert(result_pointer.size == .slice and result_pointer.is_const);
var elems: [zon_value.len]result_pointer.child = undefined;
inline for (&elems, zon_value) |*elem, zon_elem| elem.* = zonCast(result_pointer.child, zon_elem, symbols);
return &elems;
},
.@"struct" => |result_struct| {
comptime var used_zon_fields = 0;
var result: Result = undefined;
@ -158,6 +98,103 @@ fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {
}
}
const matchers = matchers: {
const instructions = @import("instructions.zon");
var mut_matchers: [instructions.len]*const fn (as: *Assemble) error{InvalidSyntax}!?Instruction = undefined;
for (instructions, &mut_matchers) |instruction, *matcher| matcher.* = struct {
fn match(as: *Assemble) !?Instruction {
comptime for (@typeInfo(@TypeOf(instruction)).@"struct".fields) |field| {
if (std.mem.eql(u8, field.name, "requires")) continue;
if (std.mem.eql(u8, field.name, "pattern")) continue;
if (std.mem.eql(u8, field.name, "symbols")) continue;
if (std.mem.eql(u8, field.name, "encode")) continue;
@compileError("unexpected field '" ++ field.name ++ "'");
};
if (@hasField(@TypeOf(instruction), "requires")) _ = zonCast(
[]const std.Target.aarch64.Feature,
instruction.requires,
.{},
);
var symbols: Symbols: {
const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields;
var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined;
for (&symbol_fields, symbols) |*symbol_field, symbol| {
const Storage = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage();
symbol_field.* = .{
.name = symbol.name,
.type = Storage,
.default_value_ptr = null,
.is_comptime = false,
.alignment = @alignOf(Storage),
};
}
break :Symbols @Type(.{ .@"struct" = .{
.layout = .auto,
.fields = &symbol_fields,
.decls = &.{},
.is_tuple = false,
} });
} = undefined;
const Symbol = std.meta.FieldEnum(@TypeOf(instruction.symbols));
comptime var unused_symbols: std.enums.EnumSet(Symbol) = .initFull();
comptime var pattern_as: Assemble = .{ .source = instruction.pattern, .operands = undefined };
inline while (true) {
comptime var ct_token_buf: [token_buf_len]u8 = undefined;
var token_buf: [token_buf_len]u8 = undefined;
const pattern_token = comptime pattern_as.nextToken(&ct_token_buf, .{ .placeholders = true }) catch |err|
@compileError(@errorName(err) ++ " while parsing '" ++ instruction.pattern ++ "'");
const source_token = try as.nextToken(&token_buf, .{ .operands = true });
log.debug("\"{f}\" -> \"{f}\"", .{
std.zig.fmtString(pattern_token),
std.zig.fmtString(source_token),
});
if (pattern_token.len == 0) {
comptime var unused_symbol_it = unused_symbols.iterator();
inline while (comptime unused_symbol_it.next()) |unused_symbol|
@compileError(@tagName(unused_symbol) ++ " unused while parsing '" ++ instruction.pattern ++ "'");
switch (source_token.len) {
0 => {},
else => switch (source_token[0]) {
else => {
log.debug("'{s}' not matched...", .{instruction.pattern});
return null;
},
'\n', ';' => {},
},
}
const encode = @field(Instruction, @tagName(instruction.encode[0]));
const Encode = @TypeOf(encode);
var args: std.meta.ArgsTuple(Encode) = undefined;
inline for (&args, @typeInfo(Encode).@"fn".params, 1..instruction.encode.len) |*arg, param, encode_index|
arg.* = zonCast(param.type.?, instruction.encode[encode_index], symbols);
return @call(.auto, encode, args);
} else if (pattern_token[0] == '<') {
const symbol_name = comptime pattern_token[1 .. std.mem.indexOfScalarPos(u8, pattern_token, 1, '|') orelse
pattern_token.len - 1];
const symbol = @field(Symbol, symbol_name);
const symbol_ptr = &@field(symbols, symbol_name);
const symbol_value = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse {
log.debug("'{s}' not matched...", .{instruction.pattern});
return null;
};
if (comptime unused_symbols.contains(symbol)) {
log.debug("{s} = {any}", .{ symbol_name, symbol_value });
symbol_ptr.* = symbol_value;
comptime unused_symbols.remove(symbol);
} else if (symbol_ptr.* != symbol_value) {
log.debug("'{s}' not matched...", .{instruction.pattern});
return null;
}
} else if (!toUpperEqlAssertUpper(source_token, pattern_token)) {
log.debug("'{s}' not matched...", .{instruction.pattern});
return null;
}
}
}
}.match;
break :matchers mut_matchers;
};
fn toUpperEqlAssertUpper(lhs: []const u8, rhs: []const u8) bool {
if (lhs.len != rhs.len) return false;
for (lhs, rhs) |l, r| {
@ -281,9 +318,10 @@ const SymbolSpec = union(enum) {
multiple_of: ?comptime_int = null,
min_valid: ?comptime_int = null,
max_valid: ?comptime_int = null,
adjust: enum { none, neg_wrap, dec } = .none,
},
fimm: struct { only_valid: ?f16 = null },
extend: struct { size: aarch64.encoding.Register.GeneralSize },
extend: struct { size: ?aarch64.encoding.Register.GeneralSize = null },
shift: struct { allow_ror: bool = true },
barrier: struct { only_sy: bool = false },
@ -293,7 +331,7 @@ const SymbolSpec = union(enum) {
.reg => aarch64.encoding.Register,
.arrangement => aarch64.encoding.Register.Arrangement,
.systemreg => aarch64.encoding.Register.System,
.imm => |imm| @Type(.{ .int = imm.type }),
.imm => |imm_spec| @Type(.{ .int = imm_spec.type }),
.fimm => f16,
.extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option,
.shift => Instruction.DataProcessingRegister.Shift.Op,
@ -372,7 +410,13 @@ const SymbolSpec = union(enum) {
return systemreg;
},
.imm => |imm_spec| {
const imm = std.fmt.parseInt(Result, token, 0) catch {
const imm = std.fmt.parseInt(@Type(.{ .int = .{
.signedness = imm_spec.type.signedness,
.bits = switch (imm_spec.adjust) {
.none, .neg_wrap => imm_spec.type.bits,
.dec => imm_spec.type.bits + 1,
},
} }), token, 0) catch {
log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)});
return null;
};
@ -388,7 +432,14 @@ const SymbolSpec = union(enum) {
log.debug("out of range immediate: \"{f}\"", .{std.zig.fmtString(token)});
return null;
};
return imm;
return switch (imm_spec.adjust) {
.none => imm,
.neg_wrap => -%imm,
.dec => std.math.cast(Result, imm - 1) orelse {
log.debug("out of range immediate: \"{f}\"", .{std.zig.fmtString(token)});
return null;
},
};
},
.fimm => |fimm_spec| {
const full_fimm = std.fmt.parseFloat(f128, token) catch {
@ -433,10 +484,10 @@ const SymbolSpec = union(enum) {
log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)});
return null;
};
if (extend.sf() != extend_spec.size) {
if (extend_spec.size) |size| if (extend.sf() != size) {
log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)});
return null;
}
};
return extend;
},
.shift => |shift_spec| {
@ -488,6 +539,16 @@ const SymbolSpec = union(enum) {
test "add sub" {
var as: Assemble = .{
.source =
\\ adc w0, w0, w1
\\ adc w2, w3, w4
\\ adc w5, w5, wzr
\\ adc w6, w7, wzr
\\
\\ adcs w0, w0, w1
\\ adcs w2, w3, w4
\\ adcs w5, w5, wzr
\\ adcs w6, w7, wzr
\\
\\ add w0, w0, w1
\\ add w2, w3, w4
\\ add wsp, w5, w6
@ -513,13 +574,13 @@ test "add sub" {
\\ add w0, w0, w1
\\ add w2, w3, w4, uxtb #0
\\ add wsp, w5, w6, uxth #1
\\ add w7, wsp, w8, uxtw #0
\\ add wsp, wsp, w9, uxtw #2
\\ add w10, w10, wzr, uxtw #3
\\ add w7, wsp, w8, uxtw #2
\\ add wsp, wsp, w9, uxtx #0
\\ add w10, w10, wzr, uxtx #3
\\ add w11, w12, wzr, sxtb #4
\\ add wsp, w13, wzr, sxth #0
\\ add w14, wsp, wzr, sxtw #1
\\ add wsp, wsp, wzr, sxtw #2
\\ add wsp, wsp, wzr, sxtx #2
\\
\\ add x0, x0, x1
\\ add x2, x3, w4, uxtb #0
@ -582,6 +643,125 @@ test "add sub" {
\\ add xzr, xzr, x13, asr #0x1F
\\ add xzr, xzr, xzr, asr #0x3f
\\
\\ addg x0, sp, #0, #0xf
\\ addg sp, x1, #0x3f0, #0
\\
\\ adds w0, w0, w1
\\ adds w2, w3, w4
\\ adds w5, w5, w6
\\ adds w7, wsp, w8
\\ adds w9, wsp, w9
\\ adds w10, w10, wzr
\\ adds w11, w12, wzr
\\ adds wzr, w13, wzr
\\ adds w14, wsp, wzr
\\ adds wzr, wsp, wzr
\\
\\ adds x0, x0, x1
\\ adds x2, x3, x4
\\ adds x5, x5, x6
\\ adds x7, sp, x8
\\ adds x9, sp, x9
\\ adds x10, x10, xzr
\\ adds x11, x12, xzr
\\ adds xzr, x13, xzr
\\ adds x14, sp, xzr
\\ adds xzr, sp, xzr
\\
\\ adds w0, w0, w1
\\ adds w2, w3, w4, uxtb #0
\\ adds wzr, w5, w6, uxth #1
\\ adds w7, wsp, w8, uxtw #2
\\ adds w9, wsp, w9, uxtx #0
\\ adds w10, w10, wzr, uxtx #3
\\ adds w11, w12, wzr, sxtb #4
\\ adds wzr, w13, wzr, sxth #0
\\ adds w14, wsp, wzr, sxtw #1
\\ adds wzr, wsp, wzr, sxtx #2
\\
\\ adds x0, x0, x1
\\ adds x2, x3, w4, uxtb #0
\\ adds xzr, x5, w6, uxth #1
\\ adds x7, sp, w8, uxtw #2
\\ adds xzr, sp, x9, uxtx #0
\\ adds x10, x10, xzr, uxtx #3
\\ adds x11, x12, wzr, sxtb #4
\\ adds xzr, x13, wzr, sxth #0
\\ adds x14, sp, wzr, sxtw #1
\\ adds xzr, sp, xzr, sxtx #2
\\
\\ adds w0, w0, #0
\\ adds w0, w1, #1, lsl #0
\\ adds wzr, w2, #2, lsl #12
\\ adds w3, wsp, #3, lsl #0
\\ adds wzr, wsp, #4095, lsl #12
\\ adds w0, w1, #0
\\ adds w2, w3, #0, lsl #0
\\ adds w4, wsp, #0
\\ adds w5, wsp, #0, lsl #0
\\ adds wzr, w6, #0
\\ adds wzr, w7, #0, lsl #0
\\ adds wzr, wsp, #0
\\ adds wzr, wsp, #0, lsl #0
\\
\\ adds x0, x0, #0
\\ adds x0, x1, #1, lsl #0
\\ adds xzr, x2, #2, lsl #12
\\ adds x3, sp, #3, lsl #0
\\ adds xzr, sp, #4095, lsl #12
\\ adds x0, x1, #0
\\ adds x2, x3, #0, lsl #0
\\ adds x4, sp, #0
\\ adds x5, sp, #0, lsl #0
\\ adds xzr, x6, #0
\\ adds xzr, x7, #0, lsl #0
\\ adds xzr, sp, #0
\\ adds xzr, sp, #0, lsl #0
\\
\\ adds w0, w0, w0
\\ adds w1, w1, w2, lsl #0
\\ adds w3, w4, w5, lsl #1
\\ adds w6, w6, wzr, lsl #31
\\ adds w7, wzr, w8, lsr #0
\\ adds w9, wzr, wzr, lsr #30
\\ adds wzr, w10, w11, lsr #31
\\ adds wzr, w12, wzr, asr #0x0
\\ adds wzr, wzr, w13, asr #0x10
\\ adds wzr, wzr, wzr, asr #0x1f
\\
\\ adds x0, x0, x0
\\ adds x1, x1, x2, lsl #0
\\ adds x3, x4, x5, lsl #1
\\ adds x6, x6, xzr, lsl #63
\\ adds x7, xzr, x8, lsr #0
\\ adds x9, xzr, xzr, lsr #62
\\ adds xzr, x10, x11, lsr #63
\\ adds xzr, x12, xzr, asr #0x0
\\ adds xzr, xzr, x13, asr #0x1F
\\ adds xzr, xzr, xzr, asr #0x3f
\\
\\ neg w0, w0
\\ neg w1, w2, lsl #0
\\ neg w3, wzr, lsl #7
\\ neg wzr, w4, lsr #14
\\ neg wzr, wzr, asr #21
\\
\\ neg x0, x0
\\ neg x1, x2, lsl #0
\\ neg x3, xzr, lsl #11
\\ neg xzr, x4, lsr #22
\\ neg xzr, xzr, asr #33
\\
\\ sbc w0, w0, w1
\\ sbc w2, w3, w4
\\ sbc w5, w5, wzr
\\ sbc w6, w7, wzr
\\
\\ sbcs w0, w0, w1
\\ sbcs w2, w3, w4
\\ sbcs w5, w5, wzr
\\ sbcs w6, w7, wzr
\\
\\ sub w0, w0, w1
\\ sub w2, w3, w4
\\ sub wsp, w5, w6
@ -607,13 +787,13 @@ test "add sub" {
\\ sub w0, w0, w1
\\ sub w2, w3, w4, uxtb #0
\\ sub wsp, w5, w6, uxth #1
\\ sub w7, wsp, w8, uxtw #0
\\ sub wsp, wsp, w9, uxtw #2
\\ sub w10, w10, wzr, uxtw #3
\\ sub w7, wsp, w8, uxtw #2
\\ sub wsp, wsp, w9, uxtx #0
\\ sub w10, w10, wzr, uxtx #3
\\ sub w11, w12, wzr, sxtb #4
\\ sub wsp, w13, wzr, sxth #0
\\ sub w14, wsp, wzr, sxtw #1
\\ sub wsp, wsp, wzr, sxtw #2
\\ sub wsp, wsp, wzr, sxtx #2
\\
\\ sub x0, x0, x1
\\ sub x2, x3, w4, uxtb #0
@ -676,21 +856,116 @@ test "add sub" {
\\ sub xzr, xzr, x13, asr #0x1F
\\ sub xzr, xzr, xzr, asr #0x3f
\\
\\ neg w0, w0
\\ neg w1, w2, lsl #0
\\ neg w3, wzr, lsl #7
\\ neg wzr, w4, lsr #14
\\ neg wzr, wzr, asr #21
\\ subg x0, sp, #0, #0xf
\\ subg sp, x1, #0x3f0, #0
\\
\\ neg x0, x0
\\ neg x1, x2, lsl #0
\\ neg x3, xzr, lsl #11
\\ neg xzr, x4, lsr #22
\\ neg xzr, xzr, asr #33
\\ subs w0, w0, w1
\\ subs w2, w3, w4
\\ subs w5, w5, w6
\\ subs w7, wsp, w8
\\ subs w9, wsp, w9
\\ subs w10, w10, wzr
\\ subs w11, w12, wzr
\\ subs wzr, w13, wzr
\\ subs w14, wsp, wzr
\\ subs wzr, wsp, wzr
\\
\\ subs x0, x0, x1
\\ subs x2, x3, x4
\\ subs x5, x5, x6
\\ subs x7, sp, x8
\\ subs x9, sp, x9
\\ subs x10, x10, xzr
\\ subs x11, x12, xzr
\\ subs xzr, x13, xzr
\\ subs x14, sp, xzr
\\ subs xzr, sp, xzr
\\
\\ subs w0, w0, w1
\\ subs w2, w3, w4, uxtb #0
\\ subs wzr, w5, w6, uxth #1
\\ subs w7, wsp, w8, uxtw #2
\\ subs w9, wsp, w9, uxtx #0
\\ subs w10, w10, wzr, uxtx #3
\\ subs w11, w12, wzr, sxtb #4
\\ subs wzr, w13, wzr, sxth #0
\\ subs w14, wsp, wzr, sxtw #1
\\ subs wzr, wsp, wzr, sxtx #2
\\
\\ subs x0, x0, x1
\\ subs x2, x3, w4, uxtb #0
\\ subs xzr, x5, w6, uxth #1
\\ subs x7, sp, w8, uxtw #2
\\ subs xzr, sp, x9, uxtx #0
\\ subs x10, x10, xzr, uxtx #3
\\ subs x11, x12, wzr, sxtb #4
\\ subs xzr, x13, wzr, sxth #0
\\ subs x14, sp, wzr, sxtw #1
\\ subs xzr, sp, xzr, sxtx #2
\\
\\ subs w0, w0, #0
\\ subs w0, w1, #1, lsl #0
\\ subs wzr, w2, #2, lsl #12
\\ subs w3, wsp, #3, lsl #0
\\ subs wzr, wsp, #4095, lsl #12
\\ subs w0, w1, #0
\\ subs w2, w3, #0, lsl #0
\\ subs w4, wsp, #0
\\ subs w5, wsp, #0, lsl #0
\\ subs wzr, w6, #0
\\ subs wzr, w7, #0, lsl #0
\\ subs wzr, wsp, #0
\\ subs wzr, wsp, #0, lsl #0
\\
\\ subs x0, x0, #0
\\ subs x0, x1, #1, lsl #0
\\ subs xzr, x2, #2, lsl #12
\\ subs x3, sp, #3, lsl #0
\\ subs xzr, sp, #4095, lsl #12
\\ subs x0, x1, #0
\\ subs x2, x3, #0, lsl #0
\\ subs x4, sp, #0
\\ subs x5, sp, #0, lsl #0
\\ subs xzr, x6, #0
\\ subs xzr, x7, #0, lsl #0
\\ subs xzr, sp, #0
\\ subs xzr, sp, #0, lsl #0
\\
\\ subs w0, w0, w0
\\ subs w1, w1, w2, lsl #0
\\ subs w3, w4, w5, lsl #1
\\ subs w6, w6, wzr, lsl #31
\\ subs w7, wzr, w8, lsr #0
\\ subs w9, wzr, wzr, lsr #30
\\ subs wzr, w10, w11, lsr #31
\\ subs wzr, w12, wzr, asr #0x0
\\ subs wzr, wzr, w13, asr #0x10
\\ subs wzr, wzr, wzr, asr #0x1f
\\
\\ subs x0, x0, x0
\\ subs x1, x1, x2, lsl #0
\\ subs x3, x4, x5, lsl #1
\\ subs x6, x6, xzr, lsl #63
\\ subs x7, xzr, x8, lsr #0
\\ subs x9, xzr, xzr, lsr #62
\\ subs xzr, x10, x11, lsr #63
\\ subs xzr, x12, xzr, asr #0x0
\\ subs xzr, xzr, x13, asr #0x1F
\\ subs xzr, xzr, xzr, asr #0x3f
,
.operands = .empty,
};
try std.testing.expectFmt("adc w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adc w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adc w5, w5, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adc w6, w7, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adcs w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adcs w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adcs w5, w5, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adcs w6, w7, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?});
@ -714,24 +989,24 @@ test "add sub" {
try std.testing.expectFmt("add sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w2, w3, w4, uxtb", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w7, wsp, w8, lsl #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add wsp, wsp, w9, uxtx", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w10, w10, wzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add wsp, w13, wzr, sxth", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add wsp, wsp, wzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add x2, x3, w4, uxtb", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add sp, x13, wzr, sxth", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
@ -785,6 +1060,125 @@ test "add sub" {
try std.testing.expectFmt("add xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("add xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("addg x0, sp, #0x0, #0xf", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("addg sp, x1, #0x3f0, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w5, w5, w6", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w9, wsp, w9", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn w13, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x2, x3, x4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x5, x5, x6", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x7, sp, x8", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x9, sp, x9", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn x13, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn sp, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w2, w3, w4, uxtb", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w7, wsp, w8, lsl #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w9, wsp, w9, uxtx", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w10, w10, wzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn w13, wzr, sxth", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn wsp, wzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x2, x3, w4, uxtb", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn sp, x9", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn x13, wzr, sxth", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds wzr, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds wzr, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w4, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w5, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds wzr, w6, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds wzr, w7, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds wzr, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds wzr, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds xzr, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds xzr, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x4, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x5, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds xzr, x6, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds xzr, x7, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds xzr, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds xzr, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("adds x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmn xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg w0, w0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg w1, w2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg w3, wzr, lsl #7", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg wzr, w4, lsr #14", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg wzr, wzr, asr #21", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg x0, x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg x1, x2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg x3, xzr, lsl #11", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg xzr, x4, lsr #22", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg xzr, xzr, asr #33", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbc w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbc w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbc w5, w5, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbc w6, w7, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbcs w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbcs w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbcs w5, w5, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbcs w6, w7, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?});
@ -808,24 +1202,24 @@ test "add sub" {
try std.testing.expectFmt("sub sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w2, w3, w4, uxtb", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w7, wsp, w8, lsl #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub wsp, wsp, w9, uxtx", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w10, w10, wzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub wsp, w13, wzr, sxth", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub wsp, wsp, wzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub x2, x3, w4, uxtb", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub sp, x13, wzr, sxth", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sub sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
@ -879,17 +1273,102 @@ test "add sub" {
try std.testing.expectFmt("neg xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg w0, w0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg w1, w2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg w3, wzr, lsl #7", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg wzr, w4, lsr #14", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg wzr, wzr, asr #21", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subg x0, sp, #0x0, #0xf", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subg sp, x1, #0x3f0, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg x0, x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg x1, x2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg x3, xzr, lsl #11", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg xzr, x4, lsr #22", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("neg xzr, xzr, asr #33", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w5, w5, w6", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w9, wsp, w9", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp w13, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x2, x3, x4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x5, x5, x6", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x7, sp, x8", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x9, sp, x9", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp x13, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp sp, xzr", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w2, w3, w4, uxtb", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w7, wsp, w8, lsl #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w9, wsp, w9, uxtx", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w10, w10, wzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp w13, wzr, sxth", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp wsp, wzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x2, x3, w4, uxtb", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp sp, x9", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp x13, wzr, sxth", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs wzr, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs wzr, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w4, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w5, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs wzr, w6, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs wzr, w7, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs wzr, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs wzr, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs xzr, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs xzr, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x4, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x5, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs xzr, x6, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs xzr, x7, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs xzr, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs xzr, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("negs w7, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("negs w9, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("subs x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("negs x7, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("negs x9, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cmp xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expect(null == try as.nextInstruction());
}
@ -966,44 +1445,62 @@ test "bit manipulation" {
test "bitfield" {
var as: Assemble = .{
.source =
\\sbfm w0, w0, #0, #31
\\sbfm w0, w0, #31, #0
\\bfc w0, #1, #31
\\bfc w1, #31, #1
\\bfc x2, #1, #63
\\bfc x3, #63, #1
\\
\\sbfm x0, x0, #0, #63
\\sbfm x0, x0, #63, #0
\\bfi w0, w1, #1, #31
\\bfi w2, wzr, #31, #1
\\bfi x3, xzr, #1, #63
\\bfi x4, x5, #63, #1
\\
\\bfm w0, w0, #0, #31
\\bfm w0, w0, #31, #0
\\bfm w0, wzr, #25, #5
\\bfm w1, w2, #31, #1
\\bfm w3, w4, #1, #31
\\bfm x5, xzr, #57, #7
\\bfm x6, x7, #63, #1
\\bfm x8, x9, #1, #63
\\
\\bfm x0, x0, #0, #63
\\bfm x0, x0, #63, #0
\\sbfm w0, w1, #31, #1
\\sbfm w2, w3, #1, #31
\\sbfm x4, x5, #63, #1
\\sbfm x6, x7, #1, #63
\\
\\ubfm w0, w0, #0, #31
\\ubfm w0, w0, #31, #0
\\
\\ubfm x0, x0, #0, #63
\\ubfm x0, x0, #63, #0
\\ubfm w0, w1, #31, #1
\\ubfm w2, w3, #1, #31
\\ubfm x4, x5, #63, #1
\\ubfm x6, x7, #1, #63
,
.operands = .empty,
};
try std.testing.expectFmt("sbfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfc w0, #1, #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfc w1, #31, #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfc x2, #1, #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfc x3, #63, #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfi w0, w1, #1, #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfc w2, #31, #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfc x3, #1, #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfi x4, x5, #63, #1", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfc w0, #7, #6", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfi w1, w2, #1, #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfxil w3, w4, #1, #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfc x5, #7, #8", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfi x6, x7, #1, #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfxil x8, x9, #1, #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("bfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbfiz w0, w1, #1, #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbfx w2, w3, #1, #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbfiz x4, x5, #1, #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("sbfx x6, x7, #1, #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("ubfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("ubfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("ubfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("ubfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("ubfiz w0, w1, #1, #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("ubfx w2, w3, #1, #31", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("ubfiz x4, x5, #1, #2", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("ubfx x6, x7, #1, #63", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expect(null == try as.nextInstruction());
}
@ -1113,6 +1610,22 @@ test "extract" {
try std.testing.expect(null == try as.nextInstruction());
}
test "flags" {
var as: Assemble = .{
.source =
\\AXFLAG
\\CFINV
\\XAFLAG
,
.operands = .empty,
};
try std.testing.expectFmt("axflag", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("cfinv", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expectFmt("xaflag", "{f}", .{(try as.nextInstruction()).?});
try std.testing.expect(null == try as.nextInstruction());
}
test "hints" {
var as: Assemble = .{
.source =
@ -2935,6 +3448,5 @@ const aarch64 = @import("../aarch64.zig");
const Assemble = @This();
const assert = std.debug.assert;
const Instruction = aarch64.encoding.Instruction;
const instructions = @import("instructions.zon");
const std = @import("std");
const log = std.log.scoped(.@"asm");

View File

@ -80,7 +80,22 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr
@tagName(sh),
});
},
.add_subtract_immediate_with_tags => {},
.add_subtract_immediate_with_tags => |add_subtract_immediate_with_tags| {
const decoded = add_subtract_immediate_with_tags.decode();
if (decoded == .unallocated) break :unallocated;
const group = add_subtract_immediate_with_tags.group;
return writer.print("{f}{s}{f}{s}{f}{s}#0x{x}{s}#0x{x}", .{
fmtCase(decoded, dis.case),
dis.mnemonic_operands_separator,
group.Rd.decode(.{ .sp = true }).x().fmtCase(dis.case),
dis.operands_separator,
group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
dis.operands_separator,
@as(u10, group.uimm6) << 4,
dis.operands_separator,
group.uimm4,
});
},
.logical_immediate => |logical_immediate| {
const decoded = logical_immediate.decode();
if (decoded == .unallocated) break :unallocated;
@ -172,17 +187,69 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr
if (decoded == .unallocated) break :unallocated;
const group = bitfield.group;
const sf = group.sf;
return writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{
const Rd = group.Rd.decode(.{}).general(sf);
const Rn = group.Rn.decode(.{}).general(sf);
return if (!dis.enable_aliases) writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{
fmtCase(decoded, dis.case),
dis.mnemonic_operands_separator,
group.Rd.decode(.{}).general(sf).fmtCase(dis.case),
Rd.fmtCase(dis.case),
dis.operands_separator,
group.Rn.decode(.{}).general(sf).fmtCase(dis.case),
Rn.fmtCase(dis.case),
dis.operands_separator,
group.imm.immr,
dis.operands_separator,
group.imm.imms,
});
}) else if (group.imm.imms >= group.imm.immr) writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{
fmtCase(@as(enum { sbfx, bfxil, ubfx }, switch (decoded) {
.unallocated => unreachable,
.sbfm => .sbfx,
.bfm => .bfxil,
.ubfm => .ubfx,
}), dis.case),
dis.mnemonic_operands_separator,
Rd.fmtCase(dis.case),
dis.operands_separator,
Rn.fmtCase(dis.case),
dis.operands_separator,
group.imm.immr,
dis.operands_separator,
switch (sf) {
.word => @as(u6, group.imm.imms - group.imm.immr) + 1,
.doubleword => @as(u7, group.imm.imms - group.imm.immr) + 1,
},
}) else {
const prefer_bfc = switch (decoded) {
.unallocated => unreachable,
.sbfm, .ubfm => false,
.bfm => Rn.alias == .zr,
};
try writer.print("{f}{s}{f}", .{
fmtCase(@as(enum { sbfiz, bfc, bfi, ubfiz }, switch (decoded) {
.unallocated => unreachable,
.sbfm => .sbfiz,
.bfm => if (prefer_bfc) .bfc else .bfi,
.ubfm => .ubfiz,
}), dis.case),
dis.mnemonic_operands_separator,
Rd.fmtCase(dis.case),
});
if (!prefer_bfc) try writer.print("{s}{f}", .{
dis.operands_separator,
Rn.fmtCase(dis.case),
});
try writer.print("{s}#{d}{s}#{d}", .{
dis.operands_separator,
switch (sf) {
.word => -%@as(u5, @intCast(group.imm.immr)),
.doubleword => -%@as(u6, @intCast(group.imm.immr)),
},
dis.operands_separator,
switch (sf) {
.word => @as(u6, group.imm.imms) + 1,
.doubleword => @as(u7, group.imm.imms) + 1,
},
});
};
},
.extract => |extract| {
const decoded = extract.decode();
@ -249,7 +316,11 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr
else => |decoded| return writer.print("{f}", .{fmtCase(decoded, dis.case)}),
},
.barriers => {},
.pstate => {},
.pstate => |pstate| {
const decoded = pstate.decode();
if (decoded == .unallocated) break :unallocated;
return writer.print("{f}", .{fmtCase(decoded, dis.case)});
},
.system_result => {},
.system => {},
.system_register_move => {},
@ -695,9 +766,19 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr
if (decoded == .unallocated) break :unallocated;
const group = add_subtract_extended_register.group;
const sf = group.sf;
const Rm = group.Rm.decode(.{}).general(group.option.sf());
const Rm = group.Rm.decode(.{}).general(switch (sf) {
.word => .word,
.doubleword => group.option.sf(),
});
const Rn = group.Rn.decode(.{ .sp = true }).general(sf);
const Rd = group.Rd.decode(.{ .sp = true }).general(sf);
const Rd = group.Rd.decode(.{ .sp = !group.S }).general(sf);
const prefer_lsl = (Rd.alias == .sp or Rn.alias == .sp) and group.option == @as(
aarch64.encoding.Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option,
switch (sf) {
.word => .uxtw,
.doubleword => .uxtx,
},
);
if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
fmtCase(@as(enum { cmn, cmp }, switch (group.op) {
.add => .cmn,
@ -716,14 +797,13 @@ pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, wr
dis.operands_separator,
Rm.fmtCase(dis.case),
});
return if (group.option != @as(aarch64.encoding.Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option, switch (sf) {
.word => .uxtw,
.doubleword => .uxtx,
}) or group.imm3 != 0) writer.print("{s}{f} #{d}", .{
dis.operands_separator,
fmtCase(group.option, dis.case),
group.imm3,
});
return if (!prefer_lsl or group.imm3 != 0) {
try writer.print("{s}{f}", .{
dis.operands_separator,
if (prefer_lsl) fmtCase(.lsl, dis.case) else fmtCase(group.option, dis.case),
});
if (group.imm3 != 0) try writer.print(" #{d}", .{group.imm3});
};
},
.add_subtract_with_carry => |add_subtract_with_carry| {
const decoded = add_subtract_with_carry.decode();

View File

@ -2563,6 +2563,10 @@ pub const Instruction = packed union {
/// PSTATE
pub const Pstate = packed union {
group: @This().Group,
msr: Msr,
cfinv: Cfinv,
xaflag: Xaflag,
axflag: Axflag,
pub const Group = packed struct {
Rt: Register.Encoded,
@ -2615,6 +2619,7 @@ pub const Instruction = packed union {
pub const Decoded = union(enum) {
unallocated,
msr: Msr,
cfinv: Cfinv,
xaflag: Xaflag,
axflag: Axflag,
@ -11414,7 +11419,10 @@ pub const Instruction = packed union {
assert(n.format.general == sf);
form: switch (form) {
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.register.format.general == extended_register_explicit.option.sf());
assert(extended_register_explicit.register.format.general == switch (sf) {
.word => .word,
.doubleword => extended_register_explicit.option.sf(),
});
return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
.add = .{
.Rd = d.alias.encode(.{ .sp = true }),
@ -11484,6 +11492,18 @@ pub const Instruction = packed union {
} },
}
}
/// C7.2.6 ADDG
pub fn addg(d: Register, n: Register, uimm6: u10, uimm4: u4) Instruction {
assert(d.format.general == .doubleword and n.format.general == .doubleword);
return .{ .data_processing_immediate = .{ .add_subtract_immediate_with_tags = .{
.addg = .{
.Xd = d.alias.encode(.{ .sp = true }),
.Xn = n.alias.encode(.{ .sp = true }),
.uimm4 = uimm4,
.uimm6 = @intCast(@shrExact(uimm6, 4)),
},
} } };
}
/// C7.2.4 ADDP (scalar)
/// C7.2.5 ADDP (vector)
pub fn addp(d: Register, n: Register, form: union(enum) {
@ -11536,7 +11556,10 @@ pub const Instruction = packed union {
assert(n.format.general == sf);
form: switch (form) {
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.register.format.general == extended_register_explicit.option.sf());
assert(extended_register_explicit.register.format.general == switch (sf) {
.word => .word,
.doubleword => extended_register_explicit.option.sf(),
});
return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
.adds = .{
.Rd = d.alias.encode(.{}),
@ -11768,6 +11791,12 @@ pub const Instruction = packed union {
},
} } };
}
/// C6.2.24 AXFLAG
pub fn axflag() Instruction {
return .{ .branch_exception_generating_system = .{ .pstate = .{
.axflag = .{},
} } };
}
/// C6.2.25 B
pub fn b(label: i28) Instruction {
return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
@ -12066,6 +12095,12 @@ pub const Instruction = packed union {
} } },
}
}
/// C6.2.52 CFINV
pub fn cfinv() Instruction {
return .{ .branch_exception_generating_system = .{ .pstate = .{
.cfinv = .{},
} } };
}
/// C6.2.56 CLREX
pub fn clrex(imm: u4) Instruction {
return .{ .branch_exception_generating_system = .{ .barriers = .{
@ -16057,7 +16092,10 @@ pub const Instruction = packed union {
assert(n.format.general == sf);
form: switch (form) {
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.register.format.general == extended_register_explicit.option.sf());
assert(extended_register_explicit.register.format.general == switch (sf) {
.word => .word,
.doubleword => extended_register_explicit.option.sf(),
});
return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
.sub = .{
.Rd = d.alias.encode(.{ .sp = true }),
@ -16127,6 +16165,18 @@ pub const Instruction = packed union {
} },
}
}
/// C7.2.359 SUBG
pub fn subg(d: Register, n: Register, uimm6: u10, uimm4: u4) Instruction {
assert(d.format.general == .doubleword and n.format.general == .doubleword);
return .{ .data_processing_immediate = .{ .add_subtract_immediate_with_tags = .{
.subg = .{
.Xd = d.alias.encode(.{ .sp = true }),
.Xn = n.alias.encode(.{ .sp = true }),
.uimm4 = uimm4,
.uimm6 = @intCast(@shrExact(uimm6, 4)),
},
} } };
}
/// C6.2.362 SUBS (extended register)
/// C6.2.363 SUBS (immediate)
/// C6.2.364 SUBS (shifted register)
@ -16147,7 +16197,10 @@ pub const Instruction = packed union {
assert(n.format.general == sf);
form: switch (form) {
.extended_register_explicit => |extended_register_explicit| {
assert(extended_register_explicit.register.format.general == extended_register_explicit.option.sf());
assert(extended_register_explicit.register.format.general == switch (sf) {
.word => .word,
.doubleword => extended_register_explicit.option.sf(),
});
return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
.subs = .{
.Rd = d.alias.encode(.{}),
@ -16471,6 +16524,12 @@ pub const Instruction = packed union {
.wfi = .{},
} } };
}
/// C6.2.400 XAFLAG
pub fn xaflag() Instruction {
return .{ .branch_exception_generating_system = .{ .pstate = .{
.xaflag = .{},
} } };
}
/// C6.2.402 YIELD
pub fn yield() Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{

View File

@ -1,4 +1,42 @@
.{
// C6.2.1 ADC
.{
.pattern = "ADC <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
},
.encode = .{ .adc, .Wd, .Wn, .Wm },
},
.{
.pattern = "ADC <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
},
.encode = .{ .adc, .Xd, .Xn, .Xm },
},
// C6.2.2 ADCS
.{
.pattern = "ADCS <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
},
.encode = .{ .adcs, .Wd, .Wn, .Wm },
},
.{
.pattern = "ADCS <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
},
.encode = .{ .adcs, .Xd, .Xn, .Xm },
},
// C6.2.3 ADD (extended register)
.{
.pattern = "ADD <Wd|WSP>, <Wn|WSP>, <Wm>",
@ -9,13 +47,27 @@
},
.encode = .{ .add, .Wd, .Wn, .{ .register = .Wm } },
},
.{
.pattern = "ADD <Wd|WSP>, <Wn|WSP>, <Wm>, <extend>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{} },
},
.encode = .{ .add, .Wd, .Wn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "ADD <Wd|WSP>, <Wn|WSP>, <Wm>, <extend> #<amount>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{ .size = .word } },
.extend = .{ .extend = .{} },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
},
.encode = .{ .add, .Wd, .Wn, .{ .extended_register_explicit = .{
@ -33,6 +85,20 @@
},
.encode = .{ .add, .Xd, .Xn, .{ .register = .Xm } },
},
.{
.pattern = "ADD <Xd|SP>, <Xn|SP>, <Wm>, <extend>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{ .size = .word } },
},
.encode = .{ .add, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "ADD <Xd|SP>, <Xn|SP>, <Wm>, <extend> #<amount>",
.symbols = .{
@ -48,6 +114,20 @@
.amount = .amount,
} } },
},
.{
.pattern = "ADD <Xd|SP>, <Xn|SP>, <Xm>, <extend>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.extend = .{ .extend = .{ .size = .doubleword } },
},
.encode = .{ .add, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Xm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "ADD <Xd|SP>, <Xn|SP>, <Xm>, <extend> #<amount>",
.symbols = .{
@ -151,6 +231,212 @@
.amount = .amount,
} } },
},
// C6.2.6 ADDG
.{
.requires = .{.mte},
.pattern = "ADDG <Xd|SP>, <Xn|SP>, #<uimm6>, #<uimm4>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.uimm6 = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 10 }, .multiple_of = 16 } },
.uimm4 = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } },
},
.encode = .{ .addg, .Xd, .Xn, .uimm6, .uimm4 },
},
// C6.2.7 ADDS (extended register)
.{
.pattern = "ADDS <Wd>, <Wn|WSP>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
},
.encode = .{ .adds, .Wd, .Wn, .{ .register = .Wm } },
},
.{
.pattern = "ADDS <Wd>, <Wn|WSP>, <Wm>, <extend>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{} },
},
.encode = .{ .adds, .Wd, .Wn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "ADDS <Wd>, <Wn|WSP>, <Wm>, <extend> #<amount>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{} },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
},
.encode = .{ .adds, .Wd, .Wn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = .amount,
} } },
},
.{
.pattern = "ADDS <Xd>, <Xn|SP>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .register = .Xm } },
},
.{
.pattern = "ADDS <Xd>, <Xn|SP>, <Wm>, <extend>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{ .size = .word } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "ADDS <Xd>, <Xn|SP>, <Wm>, <extend> #<amount>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{ .size = .word } },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = .amount,
} } },
},
.{
.pattern = "ADDS <Xd>, <Xn|SP>, <Xm>, <extend>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.extend = .{ .extend = .{ .size = .doubleword } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Xm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "ADDS <Xd>, <Xn|SP>, <Xm>, <extend> #<amount>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.extend = .{ .extend = .{ .size = .doubleword } },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Xm,
.option = .extend,
.amount = .amount,
} } },
},
// C6.2.8 ADDS (immediate)
.{
.pattern = "ADDS <Wd>, <Wn|WSP>, #<imm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
},
.encode = .{ .adds, .Wd, .Wn, .{ .immediate = .imm } },
},
.{
.pattern = "ADDS <Wd>, <Wn|WSP>, #<imm>, LSL #<shift>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
.shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
},
.encode = .{ .adds, .Wd, .Wn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
},
.{
.pattern = "ADDS <Xd>, <Xn|SP>, #<imm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .immediate = .imm } },
},
.{
.pattern = "ADDS <Xd>, <Xn|SP>, #<imm>, LSL #<shift>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
.shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
},
// C6.2.9 ADDS (shifted register)
.{
.pattern = "ADDS <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
},
.encode = .{ .adds, .Wd, .Wn, .{ .register = .Wm } },
},
.{
.pattern = "ADDS <Wd>, <Wn>, <Wm>, <shift> #<amount>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.shift = .{ .shift = .{ .allow_ror = false } },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
},
.encode = .{ .adds, .Wd, .Wn, .{ .shifted_register_explicit = .{
.register = .Wm,
.shift = .shift,
.amount = .amount,
} } },
},
.{
.pattern = "ADDS <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .register = .Xm } },
},
.{
.pattern = "ADDS <Xd>, <Xn>, <Xm>, <shift> #<amount>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.shift = .{ .shift = .{ .allow_ror = false } },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
},
.encode = .{ .adds, .Xd, .Xn, .{ .shifted_register_explicit = .{
.register = .Xm,
.shift = .shift,
.amount = .amount,
} } },
},
// C6.2.13 AND (shifted register)
.{
.pattern = "AND <Wd>, <Wn>, <Wm>",
@ -306,6 +592,53 @@
},
.encode = .{ .asrv, .Xd, .Xn, .Xm },
},
// C6.2.24 AXFLAG
.{
.requires = .{.altnzcv},
.pattern = "AXFLAG",
.symbols = .{},
.encode = .{.axflag},
},
// C6.2.28 BFC
.{
.pattern = "BFC <Wd>, #<lsb>, #<width>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .adjust = .neg_wrap } },
.width = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .adjust = .dec } },
},
.encode = .{ .bfm, .Wd, .wzr, .{ .N = .word, .immr = .lsb, .imms = .width } },
},
.{
.pattern = "BFC <Xd>, #<lsb>, #<width>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .adjust = .neg_wrap } },
.width = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .adjust = .dec } },
},
.encode = .{ .bfm, .Xd, .xzr, .{ .N = .doubleword, .immr = .lsb, .imms = .width } },
},
// C6.2.29 BFI
.{
.pattern = "BFI <Wd>, <Wn>, #<lsb>, #<width>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .adjust = .neg_wrap } },
.width = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .adjust = .dec } },
},
.encode = .{ .bfm, .Wd, .Wn, .{ .N = .word, .immr = .lsb, .imms = .width } },
},
.{
.pattern = "BFI <Xd>, <Xn>, #<lsb>, #<width>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .adjust = .neg_wrap } },
.width = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .adjust = .dec } },
},
.encode = .{ .bfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .lsb, .imms = .width } },
},
// C6.2.30 BFM
.{
.pattern = "BFM <Wd>, <Wn>, #<immr>, #<imms>",
@ -351,6 +684,13 @@
},
.encode = .{ .brk, .imm },
},
// C6.2.52 CFINV
.{
.requires = .{.flagm},
.pattern = "CFINV",
.symbols = .{},
.encode = .{.cfinv},
},
// C6.2.56 CLREX
.{
.pattern = "CLREX",
@ -1391,6 +1731,44 @@
},
.encode = .{ .rorv, .Xd, .Xn, .Xm },
},
// C6.2.265 SBC
.{
.pattern = "SBC <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
},
.encode = .{ .sbc, .Wd, .Wn, .Wm },
},
.{
.pattern = "SBC <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
},
.encode = .{ .sbc, .Xd, .Xn, .Xm },
},
// C6.2.266 SBCS
.{
.pattern = "SBCS <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
},
.encode = .{ .sbcs, .Wd, .Wn, .Wm },
},
.{
.pattern = "SBCS <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
},
.encode = .{ .sbcs, .Xd, .Xn, .Xm },
},
// C6.2.268 SBFM
.{
.pattern = "SBFM <Wd>, <Wn>, #<immr>, #<imms>",
@ -1663,13 +2041,27 @@
},
.encode = .{ .sub, .Wd, .Wn, .{ .register = .Wm } },
},
.{
.pattern = "SUB <Wd|WSP>, <Wn|WSP>, <Wm>, <extend>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{} },
},
.encode = .{ .sub, .Wd, .Wn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "SUB <Wd|WSP>, <Wn|WSP>, <Wm>, <extend> #<amount>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{ .size = .word } },
.extend = .{ .extend = .{} },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
},
.encode = .{ .sub, .Wd, .Wn, .{ .extended_register_explicit = .{
@ -1687,6 +2079,20 @@
},
.encode = .{ .sub, .Xd, .Xn, .{ .register = .Xm } },
},
.{
.pattern = "SUB <Xd|SP>, <Xn|SP>, <Wm>, <extend>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{ .size = .word } },
},
.encode = .{ .sub, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "SUB <Xd|SP>, <Xn|SP>, <Wm>, <extend> #<amount>",
.symbols = .{
@ -1702,6 +2108,20 @@
.amount = .amount,
} } },
},
.{
.pattern = "SUB <Xd|SP>, <Xn|SP>, <Xm>, <extend>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.extend = .{ .extend = .{ .size = .doubleword } },
},
.encode = .{ .sub, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Xm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "SUB <Xd|SP>, <Xn|SP>, <Xm>, <extend> #<amount>",
.symbols = .{
@ -1805,6 +2225,212 @@
.amount = .amount,
} } },
},
// C6.2.359 SUBG
.{
.requires = .{.mte},
.pattern = "SUBG <Xd|SP>, <Xn|SP>, #<uimm6>, #<uimm4>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.uimm6 = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 10 }, .multiple_of = 16 } },
.uimm4 = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } },
},
.encode = .{ .subg, .Xd, .Xn, .uimm6, .uimm4 },
},
// C6.2.362 SUBS (extended register)
.{
.pattern = "SUBS <Wd>, <Wn|WSP>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
},
.encode = .{ .subs, .Wd, .Wn, .{ .register = .Wm } },
},
.{
.pattern = "SUBS <Wd>, <Wn|WSP>, <Wm>, <extend>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{} },
},
.encode = .{ .subs, .Wd, .Wn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "SUBS <Wd>, <Wn|WSP>, <Wm>, <extend> #<amount>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{} },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
},
.encode = .{ .subs, .Wd, .Wn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = .amount,
} } },
},
.{
.pattern = "SUBS <Xd>, <Xn|SP>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .register = .Xm } },
},
.{
.pattern = "SUBS <Xd>, <Xn|SP>, <Wm>, <extend>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{ .size = .word } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "SUBS <Xd>, <Xn|SP>, <Wm>, <extend> #<amount>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.extend = .{ .extend = .{ .size = .word } },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Wm,
.option = .extend,
.amount = .amount,
} } },
},
.{
.pattern = "SUBS <Xd>, <Xn|SP>, <Xm>, <extend>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.extend = .{ .extend = .{ .size = .doubleword } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Xm,
.option = .extend,
.amount = 0,
} } },
},
.{
.pattern = "SUBS <Xd>, <Xn|SP>, <Xm>, <extend> #<amount>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.extend = .{ .extend = .{ .size = .doubleword } },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .extended_register_explicit = .{
.register = .Xm,
.option = .extend,
.amount = .amount,
} } },
},
// C6.2.363 SUBS (immediate)
.{
.pattern = "SUBS <Wd>, <Wn|WSP>, #<imm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
},
.encode = .{ .subs, .Wd, .Wn, .{ .immediate = .imm } },
},
.{
.pattern = "SUBS <Wd>, <Wn|WSP>, #<imm>, LSL #<shift>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word }, .allow_sp = true } },
.imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
.shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
},
.encode = .{ .subs, .Wd, .Wn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
},
.{
.pattern = "SUBS <Xd>, <Xn|SP>, #<imm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .immediate = .imm } },
},
.{
.pattern = "SUBS <Xd>, <Xn|SP>, #<imm>, LSL #<shift>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } },
.imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
.shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
},
// C6.2.364 SUBS (shifted register)
.{
.pattern = "SUBS <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
},
.encode = .{ .subs, .Wd, .Wn, .{ .register = .Wm } },
},
.{
.pattern = "SUBS <Wd>, <Wn>, <Wm>, <shift> #<amount>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .general = .word } } },
.Wn = .{ .reg = .{ .format = .{ .general = .word } } },
.Wm = .{ .reg = .{ .format = .{ .general = .word } } },
.shift = .{ .shift = .{ .allow_ror = false } },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
},
.encode = .{ .subs, .Wd, .Wn, .{ .shifted_register_explicit = .{
.register = .Wm,
.shift = .shift,
.amount = .amount,
} } },
},
.{
.pattern = "SUBS <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .register = .Xm } },
},
.{
.pattern = "SUBS <Xd>, <Xn>, <Xm>, <shift> #<amount>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .general = .doubleword } } },
.shift = .{ .shift = .{ .allow_ror = false } },
.amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
},
.encode = .{ .subs, .Xd, .Xn, .{ .shifted_register_explicit = .{
.register = .Xm,
.shift = .shift,
.amount = .amount,
} } },
},
// C6.2.365 SVC
.{
.pattern = "SVC #<imm>",
@ -1933,6 +2559,13 @@
.symbols = .{},
.encode = .{.wfi},
},
// C6.2.400 XAFLAG
.{
.requires = .{.altnzcv},
.pattern = "XAFLAG",
.symbols = .{},
.encode = .{.xaflag},
},
// C6.2.402 YIELD
.{
.pattern = "YIELD",