diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-08-15 10:44:00 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-15 10:44:00 -0700 |
| commit | 6d7c6a0f4e4f77e10462c3d8becf4e51fe172ccf (patch) | |
| tree | 195f754a6aa24d8dbddbe91139edb59a971bd067 /src/codegen/aarch64 | |
| parent | c1eff72c4a0a9d036299b322184f271f6a61ea28 (diff) | |
| parent | 56d62395d146a6622d8b751bfed353bdd86e1421 (diff) | |
| download | zig-6d7c6a0f4e4f77e10462c3d8becf4e51fe172ccf.tar.gz zig-6d7c6a0f4e4f77e10462c3d8becf4e51fe172ccf.zip | |
Merge pull request #24856 from jacobly0/aarch64-oom
aarch64: more assembler instructions
Diffstat (limited to 'src/codegen/aarch64')
| -rw-r--r-- | src/codegen/aarch64/Assemble.zig | 826 | ||||
| -rw-r--r-- | src/codegen/aarch64/Disassemble.zig | 112 | ||||
| -rw-r--r-- | src/codegen/aarch64/encoding.zig | 67 | ||||
| -rw-r--r-- | src/codegen/aarch64/instructions.zon | 637 |
4 files changed, 1463 insertions, 179 deletions
diff --git a/src/codegen/aarch64/Assemble.zig b/src/codegen/aarch64/Assemble.zig index dbcfa695df..4b5aa8e04f 100644 --- a/src/codegen/aarch64/Assemble.zig +++ b/src/codegen/aarch64/Assemble.zig @@ -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 - \\ - \\ neg x0, x0 - \\ neg x1, x2, lsl #0 - \\ neg x3, xzr, lsl #11 - \\ neg xzr, x4, lsr #22 - \\ neg xzr, xzr, asr #33 + \\ subg x0, sp, #0, #0xf + \\ subg sp, x1, #0x3f0, #0 + \\ + \\ 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("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("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("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 - \\ - \\sbfm x0, x0, #0, #63 - \\sbfm x0, x0, #63, #0 - \\ - \\bfm w0, w0, #0, #31 - \\bfm w0, w0, #31, #0 - \\ - \\bfm x0, x0, #0, #63 - \\bfm x0, x0, #63, #0 - \\ - \\ubfm w0, w0, #0, #31 - \\ubfm w0, w0, #31, #0 - \\ - \\ubfm x0, x0, #0, #63 - \\ubfm x0, x0, #63, #0 + \\bfc w0, #1, #31 + \\bfc w1, #31, #1 + \\bfc x2, #1, #63 + \\bfc x3, #63, #1 + \\ + \\bfi w0, w1, #1, #31 + \\bfi w2, wzr, #31, #1 + \\bfi x3, xzr, #1, #63 + \\bfi x4, x5, #63, #1 + \\ + \\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 + \\ + \\sbfm w0, w1, #31, #1 + \\sbfm w2, w3, #1, #31 + \\sbfm x4, x5, #63, #1 + \\sbfm x6, x7, #1, #63 + \\ + \\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("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("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("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("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("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("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("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("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("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"); diff --git a/src/codegen/aarch64/Disassemble.zig b/src/codegen/aarch64/Disassemble.zig index 6e33a04492..8aecb8128e 100644 --- a/src/codegen/aarch64/Disassemble.zig +++ b/src/codegen/aarch64/Disassemble.zig @@ -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(); diff --git a/src/codegen/aarch64/encoding.zig b/src/codegen/aarch64/encoding.zig index ad8f42d32a..9dbd4ddc7c 100644 --- a/src/codegen/aarch64/encoding.zig +++ b/src/codegen/aarch64/encoding.zig @@ -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 = .{ diff --git a/src/codegen/aarch64/instructions.zon b/src/codegen/aarch64/instructions.zon index dced3a118b..1159e57cbe 100644 --- a/src/codegen/aarch64/instructions.zon +++ b/src/codegen/aarch64/instructions.zon @@ -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>", @@ -10,12 +48,26 @@ .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 = .{ @@ -34,6 +86,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 = .{ .Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } }, @@ -49,6 +115,20 @@ } } }, }, .{ + .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 = .{ .Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } }, @@ -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>", @@ -1664,12 +2042,26 @@ .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 = .{ @@ -1688,6 +2080,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 = .{ .Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } }, @@ -1703,6 +2109,20 @@ } } }, }, .{ + .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 = .{ .Xd = .{ .reg = .{ .format = .{ .general = .doubleword }, .allow_sp = true } }, @@ -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", |
