| author | |
| committer | |
| log | 9d9b5a11e873cc15e3f1b6e506ecf22c8380c87d |
| tree | f9fbf35c57d927db32236129c8dbd24550edee7b |
| parent | ddc399440dd8bcb814c288e43a30f873bfbaca39 |
| parent | 5a4fe39fbbf9668b7fa14da774cb3de1c49604e7 |
| signature |
more RISC-V backend progress34 files changed, 1627 insertions(+), 496 deletions(-)
lib/std/simd.zig+32-4| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | //! SIMD (Single Instruction; Multiple Data) convenience functions. | 1 | //! SIMD (Single Instruction; Multiple Data) convenience functions. |
| 2 | //! | 2 | //! |
| 3 | //! May offer a potential boost in performance on some targets by performing | 3 | //! May offer a potential boost in performance on some targets by performing |
| 4 | //! the same operations on multiple elements at once. | 4 | //! the same operation on multiple elements at once. |
| 5 | //! | 5 | //! |
| 6 | //! Some functions are known to not work on MIPS. | 6 | //! Some functions are known to not work on MIPS. |
| 7 | 7 | ||
| ... | @@ -10,7 +10,6 @@ const builtin = @import("builtin"); | ... | @@ -10,7 +10,6 @@ const builtin = @import("builtin"); |
| 10 | 10 | ||
| 11 | pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu) ?comptime_int { | 11 | pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu) ?comptime_int { |
| 12 | // This is guesswork, if you have better suggestions can add it or edit the current here | 12 | // This is guesswork, if you have better suggestions can add it or edit the current here |
| 13 | // This can run in comptime only, but stage 1 fails at it, stage 2 can understand it | ||
| 14 | const element_bit_size = @max(8, std.math.ceilPowerOfTwo(u16, @bitSizeOf(T)) catch unreachable); | 13 | const element_bit_size = @max(8, std.math.ceilPowerOfTwo(u16, @bitSizeOf(T)) catch unreachable); |
| 15 | const vector_bit_size: u16 = blk: { | 14 | const vector_bit_size: u16 = blk: { |
| 16 | if (cpu.arch.isX86()) { | 15 | if (cpu.arch.isX86()) { |
| ... | @@ -37,8 +36,37 @@ pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu) | ... | @@ -37,8 +36,37 @@ pub fn suggestVectorLengthForCpu(comptime T: type, comptime cpu: std.Target.Cpu) |
| 37 | // the 2048 bits or using just 64 per vector or something in between | 36 | // the 2048 bits or using just 64 per vector or something in between |
| 38 | if (std.Target.mips.featureSetHas(cpu.features, std.Target.mips.Feature.mips3d)) break :blk 64; | 37 | if (std.Target.mips.featureSetHas(cpu.features, std.Target.mips.Feature.mips3d)) break :blk 64; |
| 39 | } else if (cpu.arch.isRISCV()) { | 38 | } else if (cpu.arch.isRISCV()) { |
| 40 | // in risc-v the Vector Extension allows configurable vector sizes, but a standard size of 128 is a safe estimate | 39 | // In RISC-V Vector Registers are length agnostic so there's no good way to determine the best size. |
| 41 | if (std.Target.riscv.featureSetHas(cpu.features, .v)) break :blk 128; | 40 | // The usual vector length in most RISC-V cpus is 256 bits, however it can get to multiple kB. |
| 41 | if (std.Target.riscv.featureSetHas(cpu.features, .v)) { | ||
| 42 | var vec_bit_length: u32 = 256; | ||
| 43 | if (std.Target.riscv.featureSetHas(cpu.features, .zvl32b)) { | ||
| 44 | vec_bit_length = 32; | ||
| 45 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl64b)) { | ||
| 46 | vec_bit_length = 64; | ||
| 47 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl128b)) { | ||
| 48 | vec_bit_length = 128; | ||
| 49 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl256b)) { | ||
| 50 | vec_bit_length = 256; | ||
| 51 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl512b)) { | ||
| 52 | vec_bit_length = 512; | ||
| 53 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl1024b)) { | ||
| 54 | vec_bit_length = 1024; | ||
| 55 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl2048b)) { | ||
| 56 | vec_bit_length = 2048; | ||
| 57 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl4096b)) { | ||
| 58 | vec_bit_length = 4096; | ||
| 59 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl8192b)) { | ||
| 60 | vec_bit_length = 8192; | ||
| 61 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl16384b)) { | ||
| 62 | vec_bit_length = 16384; | ||
| 63 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl32768b)) { | ||
| 64 | vec_bit_length = 32768; | ||
| 65 | } else if (std.Target.riscv.featureSetHas(cpu.features, .zvl65536b)) { | ||
| 66 | vec_bit_length = 65536; | ||
| 67 | } | ||
| 68 | break :blk vec_bit_length; | ||
| 69 | } | ||
| 42 | } else if (cpu.arch.isSPARC()) { | 70 | } else if (cpu.arch.isSPARC()) { |
| 43 | // TODO: Test Sparc capability to handle bigger vectors | 71 | // TODO: Test Sparc capability to handle bigger vectors |
| 44 | // In theory Sparc have 32 registers of 64 bits which can use in parallel | 72 | // In theory Sparc have 32 registers of 64 bits which can use in parallel |
lib/std/start.zig+20-1| ... | @@ -221,7 +221,26 @@ fn riscv_start() callconv(.C) noreturn { | ... | @@ -221,7 +221,26 @@ fn riscv_start() callconv(.C) noreturn { |
| 221 | } | 221 | } |
| 222 | break :ret root.main(); | 222 | break :ret root.main(); |
| 223 | }, | 223 | }, |
| 224 | else => @compileError("expected return type of main to be 'void', 'noreturn', 'u8'"), | 224 | .ErrorUnion => ret: { |
| 225 | const result = root.main() catch { | ||
| 226 | const stderr = std.io.getStdErr().writer(); | ||
| 227 | stderr.writeAll("failed with error\n") catch { | ||
| 228 | @panic("failed to print when main returned error"); | ||
| 229 | }; | ||
| 230 | break :ret 1; | ||
| 231 | }; | ||
| 232 | switch (@typeInfo(@TypeOf(result))) { | ||
| 233 | .Void => break :ret 0, | ||
| 234 | .Int => |info| { | ||
| 235 | if (info.bits != 8 or info.signedness == .signed) { | ||
| 236 | @compileError(bad_main_ret); | ||
| 237 | } | ||
| 238 | return result; | ||
| 239 | }, | ||
| 240 | else => @compileError(bad_main_ret), | ||
| 241 | } | ||
| 242 | }, | ||
| 243 | else => @compileError(bad_main_ret), | ||
| 225 | }); | 244 | }); |
| 226 | } | 245 | } |
| 227 | 246 |
src/arch/riscv64/CodeGen.zig+830-239| ... | @@ -1,8 +1,12 @@ | ... | @@ -1,8 +1,12 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const build_options = @import("build_options"); | ||
| 4 | |||
| 3 | const mem = std.mem; | 5 | const mem = std.mem; |
| 4 | const math = std.math; | 6 | const math = std.math; |
| 5 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 8 | const Allocator = mem.Allocator; | ||
| 9 | |||
| 6 | const Air = @import("../../Air.zig"); | 10 | const Air = @import("../../Air.zig"); |
| 7 | const Mir = @import("Mir.zig"); | 11 | const Mir = @import("Mir.zig"); |
| 8 | const Emit = @import("Emit.zig"); | 12 | const Emit = @import("Emit.zig"); |
| ... | @@ -14,18 +18,16 @@ const Zcu = @import("../../Zcu.zig"); | ... | @@ -14,18 +18,16 @@ const Zcu = @import("../../Zcu.zig"); |
| 14 | const Package = @import("../../Package.zig"); | 18 | const Package = @import("../../Package.zig"); |
| 15 | const InternPool = @import("../../InternPool.zig"); | 19 | const InternPool = @import("../../InternPool.zig"); |
| 16 | const Compilation = @import("../../Compilation.zig"); | 20 | const Compilation = @import("../../Compilation.zig"); |
| 21 | const trace = @import("../../tracy.zig").trace; | ||
| 22 | const codegen = @import("../../codegen.zig"); | ||
| 23 | |||
| 17 | const ErrorMsg = Zcu.ErrorMsg; | 24 | const ErrorMsg = Zcu.ErrorMsg; |
| 18 | const Target = std.Target; | 25 | const Target = std.Target; |
| 19 | const Allocator = mem.Allocator; | 26 | |
| 20 | const trace = @import("../../tracy.zig").trace; | ||
| 21 | const DW = std.dwarf; | ||
| 22 | const leb128 = std.leb; | ||
| 23 | const log = std.log.scoped(.riscv_codegen); | 27 | const log = std.log.scoped(.riscv_codegen); |
| 24 | const tracking_log = std.log.scoped(.tracking); | 28 | const tracking_log = std.log.scoped(.tracking); |
| 25 | const verbose_tracking_log = std.log.scoped(.verbose_tracking); | 29 | const verbose_tracking_log = std.log.scoped(.verbose_tracking); |
| 26 | const wip_mir_log = std.log.scoped(.wip_mir); | 30 | const wip_mir_log = std.log.scoped(.wip_mir); |
| 27 | const build_options = @import("build_options"); | ||
| 28 | const codegen = @import("../../codegen.zig"); | ||
| 29 | const Alignment = InternPool.Alignment; | 31 | const Alignment = InternPool.Alignment; |
| 30 | 32 | ||
| 31 | const CodeGenError = codegen.CodeGenError; | 33 | const CodeGenError = codegen.CodeGenError; |
| ... | @@ -37,6 +39,7 @@ const abi = @import("abi.zig"); | ... | @@ -37,6 +39,7 @@ const abi = @import("abi.zig"); |
| 37 | const Lower = @import("Lower.zig"); | 39 | const Lower = @import("Lower.zig"); |
| 38 | 40 | ||
| 39 | const Register = bits.Register; | 41 | const Register = bits.Register; |
| 42 | const CSR = bits.CSR; | ||
| 40 | const Immediate = bits.Immediate; | 43 | const Immediate = bits.Immediate; |
| 41 | const Memory = bits.Memory; | 44 | const Memory = bits.Memory; |
| 42 | const FrameIndex = bits.FrameIndex; | 45 | const FrameIndex = bits.FrameIndex; |
| ... | @@ -45,15 +48,16 @@ const RegisterLock = RegisterManager.RegisterLock; | ... | @@ -45,15 +48,16 @@ const RegisterLock = RegisterManager.RegisterLock; |
| 45 | 48 | ||
| 46 | const InnerError = CodeGenError || error{OutOfRegisters}; | 49 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 47 | 50 | ||
| 48 | gpa: Allocator, | ||
| 49 | pt: Zcu.PerThread, | 51 | pt: Zcu.PerThread, |
| 50 | air: Air, | 52 | air: Air, |
| 51 | mod: *Package.Module, | ||
| 52 | liveness: Liveness, | 53 | liveness: Liveness, |
| 54 | zcu: *Zcu, | ||
| 53 | bin_file: *link.File, | 55 | bin_file: *link.File, |
| 56 | gpa: Allocator, | ||
| 57 | |||
| 58 | mod: *Package.Module, | ||
| 54 | target: *const std.Target, | 59 | target: *const std.Target, |
| 55 | func_index: InternPool.Index, | 60 | func_index: InternPool.Index, |
| 56 | code: *std.ArrayList(u8), | ||
| 57 | debug_output: DebugInfoOutput, | 61 | debug_output: DebugInfoOutput, |
| 58 | err_msg: ?*ErrorMsg, | 62 | err_msg: ?*ErrorMsg, |
| 59 | args: []MCValue, | 63 | args: []MCValue, |
| ... | @@ -62,9 +66,7 @@ fn_type: Type, | ... | @@ -62,9 +66,7 @@ fn_type: Type, |
| 62 | arg_index: usize, | 66 | arg_index: usize, |
| 63 | src_loc: Zcu.LazySrcLoc, | 67 | src_loc: Zcu.LazySrcLoc, |
| 64 | 68 | ||
| 65 | /// MIR Instructions | ||
| 66 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, | 69 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| 67 | /// MIR extra data | ||
| 68 | mir_extra: std.ArrayListUnmanaged(u32) = .{}, | 70 | mir_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 69 | 71 | ||
| 70 | /// Byte offset within the source file of the ending curly. | 72 | /// Byte offset within the source file of the ending curly. |
| ... | @@ -87,6 +89,10 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{}, | ... | @@ -87,6 +89,10 @@ exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{}, |
| 87 | /// across each runtime branch upon joining. | 89 | /// across each runtime branch upon joining. |
| 88 | branch_stack: *std.ArrayList(Branch), | 90 | branch_stack: *std.ArrayList(Branch), |
| 89 | 91 | ||
| 92 | // Currently set vector properties, null means they haven't been set yet in the function. | ||
| 93 | avl: ?u64, | ||
| 94 | vtype: ?bits.VType, | ||
| 95 | |||
| 90 | // Key is the block instruction | 96 | // Key is the block instruction |
| 91 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, | 97 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, |
| 92 | register_manager: RegisterManager = .{}, | 98 | register_manager: RegisterManager = .{}, |
| ... | @@ -117,8 +123,9 @@ const MCValue = union(enum) { | ... | @@ -117,8 +123,9 @@ const MCValue = union(enum) { |
| 117 | /// No more references to this value remain. | 123 | /// No more references to this value remain. |
| 118 | /// The payload is the value of scope_generation at the point where the death occurred | 124 | /// The payload is the value of scope_generation at the point where the death occurred |
| 119 | dead: u32, | 125 | dead: u32, |
| 120 | /// The value is undefined. | 126 | /// The value is undefined. Contains a symbol index to an undefined constant. Null means |
| 121 | undef, | 127 | /// set the undefined value via immediate instead of a load. |
| 128 | undef: ?u32, | ||
| 122 | /// A pointer-sized integer that fits in a register. | 129 | /// A pointer-sized integer that fits in a register. |
| 123 | /// If the type is a pointer, this is the pointer address in virtual address space. | 130 | /// If the type is a pointer, this is the pointer address in virtual address space. |
| 124 | immediate: u64, | 131 | immediate: u64, |
| ... | @@ -725,16 +732,16 @@ pub fn generate( | ... | @@ -725,16 +732,16 @@ pub fn generate( |
| 725 | } | 732 | } |
| 726 | try branch_stack.append(.{}); | 733 | try branch_stack.append(.{}); |
| 727 | 734 | ||
| 728 | var function = Func{ | 735 | var function: Func = .{ |
| 729 | .gpa = gpa, | 736 | .gpa = gpa, |
| 730 | .air = air, | 737 | .air = air, |
| 731 | .pt = pt, | 738 | .pt = pt, |
| 732 | .mod = mod, | 739 | .mod = mod, |
| 740 | .zcu = zcu, | ||
| 741 | .bin_file = bin_file, | ||
| 733 | .liveness = liveness, | 742 | .liveness = liveness, |
| 734 | .target = target, | 743 | .target = target, |
| 735 | .bin_file = bin_file, | ||
| 736 | .func_index = func_index, | 744 | .func_index = func_index, |
| 737 | .code = code, | ||
| 738 | .debug_output = debug_output, | 745 | .debug_output = debug_output, |
| 739 | .err_msg = null, | 746 | .err_msg = null, |
| 740 | .args = undefined, // populated after `resolveCallingConventionValues` | 747 | .args = undefined, // populated after `resolveCallingConventionValues` |
| ... | @@ -746,6 +753,8 @@ pub fn generate( | ... | @@ -746,6 +753,8 @@ pub fn generate( |
| 746 | .end_di_line = func.rbrace_line, | 753 | .end_di_line = func.rbrace_line, |
| 747 | .end_di_column = func.rbrace_column, | 754 | .end_di_column = func.rbrace_column, |
| 748 | .scope_generation = 0, | 755 | .scope_generation = 0, |
| 756 | .avl = null, | ||
| 757 | .vtype = null, | ||
| 749 | }; | 758 | }; |
| 750 | defer { | 759 | defer { |
| 751 | function.frame_allocs.deinit(gpa); | 760 | function.frame_allocs.deinit(gpa); |
| ... | @@ -817,7 +826,7 @@ pub fn generate( | ... | @@ -817,7 +826,7 @@ pub fn generate( |
| 817 | else => |e| return e, | 826 | else => |e| return e, |
| 818 | }; | 827 | }; |
| 819 | 828 | ||
| 820 | var mir = Mir{ | 829 | var mir: Mir = .{ |
| 821 | .instructions = function.mir_instructions.toOwnedSlice(), | 830 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 822 | .extra = try function.mir_extra.toOwnedSlice(gpa), | 831 | .extra = try function.mir_extra.toOwnedSlice(gpa), |
| 823 | .frame_locs = function.frame_locs.toOwnedSlice(), | 832 | .frame_locs = function.frame_locs.toOwnedSlice(), |
| ... | @@ -825,7 +834,6 @@ pub fn generate( | ... | @@ -825,7 +834,6 @@ pub fn generate( |
| 825 | defer mir.deinit(gpa); | 834 | defer mir.deinit(gpa); |
| 826 | 835 | ||
| 827 | var emit: Emit = .{ | 836 | var emit: Emit = .{ |
| 828 | .bin_file = bin_file, | ||
| 829 | .lower = .{ | 837 | .lower = .{ |
| 830 | .pt = pt, | 838 | .pt = pt, |
| 831 | .allocator = gpa, | 839 | .allocator = gpa, |
| ... | @@ -836,6 +844,7 @@ pub fn generate( | ... | @@ -836,6 +844,7 @@ pub fn generate( |
| 836 | .link_mode = comp.config.link_mode, | 844 | .link_mode = comp.config.link_mode, |
| 837 | .pic = mod.pic, | 845 | .pic = mod.pic, |
| 838 | }, | 846 | }, |
| 847 | .bin_file = bin_file, | ||
| 839 | .debug_output = debug_output, | 848 | .debug_output = debug_output, |
| 840 | .code = code, | 849 | .code = code, |
| 841 | .prev_di_pc = 0, | 850 | .prev_di_pc = 0, |
| ... | @@ -896,7 +905,7 @@ fn formatWipMir( | ... | @@ -896,7 +905,7 @@ fn formatWipMir( |
| 896 | .pic = comp.root_mod.pic, | 905 | .pic = comp.root_mod.pic, |
| 897 | }; | 906 | }; |
| 898 | var first = true; | 907 | var first = true; |
| 899 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { | 908 | for ((lower.lowerMir(data.inst, .{ .allow_frame_locs = false }) catch |err| switch (err) { |
| 900 | error.LowerFail => { | 909 | error.LowerFail => { |
| 901 | defer { | 910 | defer { |
| 902 | lower.err_msg.?.deinit(data.func.gpa); | 911 | lower.err_msg.?.deinit(data.func.gpa); |
| ... | @@ -924,7 +933,7 @@ fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) | ... | @@ -924,7 +933,7 @@ fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) |
| 924 | } | 933 | } |
| 925 | 934 | ||
| 926 | const FormatDeclData = struct { | 935 | const FormatDeclData = struct { |
| 927 | mod: *Zcu, | 936 | zcu: *Zcu, |
| 928 | decl_index: InternPool.DeclIndex, | 937 | decl_index: InternPool.DeclIndex, |
| 929 | }; | 938 | }; |
| 930 | fn formatDecl( | 939 | fn formatDecl( |
| ... | @@ -933,11 +942,11 @@ fn formatDecl( | ... | @@ -933,11 +942,11 @@ fn formatDecl( |
| 933 | _: std.fmt.FormatOptions, | 942 | _: std.fmt.FormatOptions, |
| 934 | writer: anytype, | 943 | writer: anytype, |
| 935 | ) @TypeOf(writer).Error!void { | 944 | ) @TypeOf(writer).Error!void { |
| 936 | try writer.print("{}", .{data.mod.declPtr(data.decl_index).fqn.fmt(&data.mod.intern_pool)}); | 945 | try writer.print("{}", .{data.zcu.declPtr(data.decl_index).fqn.fmt(&data.zcu.intern_pool)}); |
| 937 | } | 946 | } |
| 938 | fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) { | 947 | fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) { |
| 939 | return .{ .data = .{ | 948 | return .{ .data = .{ |
| 940 | .mod = func.pt.zcu, | 949 | .zcu = func.zcu, |
| 941 | .decl_index = decl_index, | 950 | .decl_index = decl_index, |
| 942 | } }; | 951 | } }; |
| 943 | } | 952 | } |
| ... | @@ -989,13 +998,9 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | ... | @@ -989,13 +998,9 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 989 | .pseudo_dbg_prologue_end, | 998 | .pseudo_dbg_prologue_end, |
| 990 | .pseudo_dbg_line_column, | 999 | .pseudo_dbg_line_column, |
| 991 | .pseudo_dbg_epilogue_begin, | 1000 | .pseudo_dbg_epilogue_begin, |
| 992 | .pseudo_store_rm, | ||
| 993 | .pseudo_load_rm, | ||
| 994 | .pseudo_lea_rm, | ||
| 995 | .pseudo_mv, | ||
| 996 | .pseudo_dead, | 1001 | .pseudo_dead, |
| 997 | => false, | 1002 | => false, |
| 998 | }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)}) else wip_mir_log.debug(" | uses-mem", .{}); | 1003 | }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)}); |
| 999 | return result_index; | 1004 | return result_index; |
| 1000 | } | 1005 | } |
| 1001 | 1006 | ||
| ... | @@ -1042,9 +1047,84 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 { | ... | @@ -1042,9 +1047,84 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 { |
| 1042 | return result; | 1047 | return result; |
| 1043 | } | 1048 | } |
| 1044 | 1049 | ||
| 1050 | /// Returns a temporary register that contains the value of the `reg` csr. | ||
| 1051 | /// | ||
| 1052 | /// Caller's duty to lock the return register is needed. | ||
| 1053 | fn getCsr(func: *Func, csr: CSR) !Register { | ||
| 1054 | assert(func.hasFeature(.zicsr)); | ||
| 1055 | const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.usize)); | ||
| 1056 | _ = try func.addInst(.{ | ||
| 1057 | .tag = .csrrs, | ||
| 1058 | .ops = .csr, | ||
| 1059 | .data = .{ | ||
| 1060 | .csr = .{ | ||
| 1061 | .csr = csr, | ||
| 1062 | .rd = dst_reg, | ||
| 1063 | .rs1 = .x0, | ||
| 1064 | }, | ||
| 1065 | }, | ||
| 1066 | }); | ||
| 1067 | return dst_reg; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void { | ||
| 1071 | if (func.avl == avl) if (func.vtype) |vtype| { | ||
| 1072 | // it's already set, we don't need to do anything | ||
| 1073 | if (@as(u8, @bitCast(vtype)) == @as(u8, @bitCast(options))) return; | ||
| 1074 | }; | ||
| 1075 | |||
| 1076 | func.avl = avl; | ||
| 1077 | func.vtype = options; | ||
| 1078 | |||
| 1079 | if (avl == 0) { | ||
| 1080 | // the caller means to do "vsetvli zero, zero ..." which keeps the avl to whatever it was before | ||
| 1081 | const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options)); | ||
| 1082 | _ = try func.addInst(.{ | ||
| 1083 | .tag = .vsetvli, | ||
| 1084 | .ops = .rri, | ||
| 1085 | .data = .{ .i_type = .{ | ||
| 1086 | .rd = dst_reg, | ||
| 1087 | .rs1 = .zero, | ||
| 1088 | .imm12 = Immediate.u(options_int), | ||
| 1089 | } }, | ||
| 1090 | }); | ||
| 1091 | } else { | ||
| 1092 | // if the avl can fit into u5 we can use vsetivli otherwise use vsetvli | ||
| 1093 | if (avl <= std.math.maxInt(u5)) { | ||
| 1094 | const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options)); | ||
| 1095 | _ = try func.addInst(.{ | ||
| 1096 | .tag = .vsetivli, | ||
| 1097 | .ops = .rri, | ||
| 1098 | .data = .{ | ||
| 1099 | .i_type = .{ | ||
| 1100 | .rd = dst_reg, | ||
| 1101 | .rs1 = @enumFromInt(avl), | ||
| 1102 | .imm12 = Immediate.u(options_int), | ||
| 1103 | }, | ||
| 1104 | }, | ||
| 1105 | }); | ||
| 1106 | } else { | ||
| 1107 | const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options)); | ||
| 1108 | const temp_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = avl }); | ||
| 1109 | _ = try func.addInst(.{ | ||
| 1110 | .tag = .vsetvli, | ||
| 1111 | .ops = .rri, | ||
| 1112 | .data = .{ .i_type = .{ | ||
| 1113 | .rd = dst_reg, | ||
| 1114 | .rs1 = temp_reg, | ||
| 1115 | .imm12 = Immediate.u(options_int), | ||
| 1116 | } }, | ||
| 1117 | }); | ||
| 1118 | } | ||
| 1119 | } | ||
| 1120 | } | ||
| 1121 | |||
| 1045 | const required_features = [_]Target.riscv.Feature{ | 1122 | const required_features = [_]Target.riscv.Feature{ |
| 1046 | .d, | 1123 | .d, |
| 1047 | .m, | 1124 | .m, |
| 1125 | .a, | ||
| 1126 | .zicsr, | ||
| 1127 | .v, | ||
| 1048 | }; | 1128 | }; |
| 1049 | 1129 | ||
| 1050 | fn gen(func: *Func) !void { | 1130 | fn gen(func: *Func) !void { |
| ... | @@ -1102,7 +1182,19 @@ fn gen(func: *Func) !void { | ... | @@ -1102,7 +1182,19 @@ fn gen(func: *Func) !void { |
| 1102 | const backpatch_ra_restore = try func.addPseudo(.pseudo_dead); | 1182 | const backpatch_ra_restore = try func.addPseudo(.pseudo_dead); |
| 1103 | const backpatch_fp_restore = try func.addPseudo(.pseudo_dead); | 1183 | const backpatch_fp_restore = try func.addPseudo(.pseudo_dead); |
| 1104 | const backpatch_stack_alloc_restore = try func.addPseudo(.pseudo_dead); | 1184 | const backpatch_stack_alloc_restore = try func.addPseudo(.pseudo_dead); |
| 1105 | try func.addPseudoNone(.pseudo_ret); | 1185 | |
| 1186 | // ret | ||
| 1187 | _ = try func.addInst(.{ | ||
| 1188 | .tag = .jalr, | ||
| 1189 | .ops = .rri, | ||
| 1190 | .data = .{ | ||
| 1191 | .i_type = .{ | ||
| 1192 | .rd = .zero, | ||
| 1193 | .rs1 = .ra, | ||
| 1194 | .imm12 = Immediate.s(0), | ||
| 1195 | }, | ||
| 1196 | }, | ||
| 1197 | }); | ||
| 1106 | 1198 | ||
| 1107 | const frame_layout = try func.computeFrameLayout(); | 1199 | const frame_layout = try func.computeFrameLayout(); |
| 1108 | const need_save_reg = frame_layout.save_reg_list.count() > 0; | 1200 | const need_save_reg = frame_layout.save_reg_list.count() > 0; |
| ... | @@ -1273,7 +1365,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1273,7 +1365,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1273 | .round, | 1365 | .round, |
| 1274 | .trunc_float, | 1366 | .trunc_float, |
| 1275 | .neg, | 1367 | .neg, |
| 1276 | => try func.airUnaryMath(inst), | 1368 | => try func.airUnaryMath(inst, tag), |
| 1277 | 1369 | ||
| 1278 | .add_with_overflow => try func.airAddWithOverflow(inst), | 1370 | .add_with_overflow => try func.airAddWithOverflow(inst), |
| 1279 | .sub_with_overflow => try func.airSubWithOverflow(inst), | 1371 | .sub_with_overflow => try func.airSubWithOverflow(inst), |
| ... | @@ -1319,7 +1411,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1319,7 +1411,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1319 | .breakpoint => try func.airBreakpoint(), | 1411 | .breakpoint => try func.airBreakpoint(), |
| 1320 | .ret_addr => try func.airRetAddr(inst), | 1412 | .ret_addr => try func.airRetAddr(inst), |
| 1321 | .frame_addr => try func.airFrameAddress(inst), | 1413 | .frame_addr => try func.airFrameAddress(inst), |
| 1322 | .fence => try func.airFence(), | 1414 | .fence => try func.airFence(inst), |
| 1323 | .cond_br => try func.airCondBr(inst), | 1415 | .cond_br => try func.airCondBr(inst), |
| 1324 | .dbg_stmt => try func.airDbgStmt(inst), | 1416 | .dbg_stmt => try func.airDbgStmt(inst), |
| 1325 | .fptrunc => try func.airFptrunc(inst), | 1417 | .fptrunc => try func.airFptrunc(inst), |
| ... | @@ -1631,7 +1723,7 @@ fn computeFrameLayout(func: *Func) !FrameLayout { | ... | @@ -1631,7 +1723,7 @@ fn computeFrameLayout(func: *Func) !FrameLayout { |
| 1631 | 1723 | ||
| 1632 | // The total frame size is calculated by the amount of s registers you need to save * 8, as each | 1724 | // The total frame size is calculated by the amount of s registers you need to save * 8, as each |
| 1633 | // register is 8 bytes, the total allocation sizes, and 16 more register for the spilled ra and s0 | 1725 | // register is 8 bytes, the total allocation sizes, and 16 more register for the spilled ra and s0 |
| 1634 | // register. Finally we align the frame size to the align of the base pointer. | 1726 | // register. Finally we align the frame size to the alignment of the base pointer. |
| 1635 | const args_frame_size = frame_size[@intFromEnum(FrameIndex.args_frame)]; | 1727 | const args_frame_size = frame_size[@intFromEnum(FrameIndex.args_frame)]; |
| 1636 | const spill_frame_size = frame_size[@intFromEnum(FrameIndex.spill_frame)]; | 1728 | const spill_frame_size = frame_size[@intFromEnum(FrameIndex.spill_frame)]; |
| 1637 | const call_frame_size = frame_size[@intFromEnum(FrameIndex.call_frame)]; | 1729 | const call_frame_size = frame_size[@intFromEnum(FrameIndex.call_frame)]; |
| ... | @@ -1791,14 +1883,9 @@ fn symbolIndex(func: *Func) !u32 { | ... | @@ -1791,14 +1883,9 @@ fn symbolIndex(func: *Func) !u32 { |
| 1791 | const pt = func.pt; | 1883 | const pt = func.pt; |
| 1792 | const zcu = pt.zcu; | 1884 | const zcu = pt.zcu; |
| 1793 | const decl_index = zcu.funcOwnerDeclIndex(func.func_index); | 1885 | const decl_index = zcu.funcOwnerDeclIndex(func.func_index); |
| 1794 | return switch (func.bin_file.tag) { | 1886 | const elf_file = func.bin_file.cast(link.File.Elf).?; |
| 1795 | .elf => blk: { | 1887 | const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); |
| 1796 | const elf_file = func.bin_file.cast(link.File.Elf).?; | 1888 | return atom_index; |
| 1797 | const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); | ||
| 1798 | break :blk atom_index; | ||
| 1799 | }, | ||
| 1800 | else => return func.fail("TODO symbolIndex {s}", .{@tagName(func.bin_file.tag)}), | ||
| 1801 | }; | ||
| 1802 | } | 1889 | } |
| 1803 | 1890 | ||
| 1804 | fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex { | 1891 | fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex { |
| ... | @@ -1843,48 +1930,44 @@ fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass { | ... | @@ -1843,48 +1930,44 @@ fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass { |
| 1843 | const zcu = pt.zcu; | 1930 | const zcu = pt.zcu; |
| 1844 | return switch (ty.zigTypeTag(zcu)) { | 1931 | return switch (ty.zigTypeTag(zcu)) { |
| 1845 | .Float => .float, | 1932 | .Float => .float, |
| 1846 | .Vector => @panic("TODO: typeRegClass for Vectors"), | 1933 | .Vector => .vector, |
| 1847 | inline else => .int, | 1934 | else => .int, |
| 1848 | }; | 1935 | }; |
| 1849 | } | 1936 | } |
| 1850 | 1937 | ||
| 1851 | fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { | 1938 | fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { |
| 1852 | const pt = func.pt; | 1939 | return switch (ty.zigTypeTag(func.pt.zcu)) { |
| 1853 | const zcu = pt.zcu; | ||
| 1854 | return switch (ty.zigTypeTag(zcu)) { | ||
| 1855 | .Float => abi.Registers.Float.general_purpose, | 1940 | .Float => abi.Registers.Float.general_purpose, |
| 1856 | .Vector => @panic("TODO: regGeneralClassForType for Vectors"), | 1941 | .Vector => abi.Registers.Vector.general_purpose, |
| 1857 | else => abi.Registers.Integer.general_purpose, | 1942 | else => abi.Registers.Integer.general_purpose, |
| 1858 | }; | 1943 | }; |
| 1859 | } | 1944 | } |
| 1860 | 1945 | ||
| 1861 | fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { | 1946 | fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet { |
| 1862 | const pt = func.pt; | 1947 | return switch (ty.zigTypeTag(func.pt.zcu)) { |
| 1863 | const zcu = pt.zcu; | ||
| 1864 | return switch (ty.zigTypeTag(zcu)) { | ||
| 1865 | .Float => abi.Registers.Float.temporary, | 1948 | .Float => abi.Registers.Float.temporary, |
| 1866 | .Vector => @panic("TODO: regTempClassForType for Vectors"), | 1949 | .Vector => abi.Registers.Vector.general_purpose, // there are no temporary vector registers |
| 1867 | else => abi.Registers.Integer.temporary, | 1950 | else => abi.Registers.Integer.temporary, |
| 1868 | }; | 1951 | }; |
| 1869 | } | 1952 | } |
| 1870 | 1953 | ||
| 1871 | fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { | 1954 | fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1872 | const pt = func.pt; | 1955 | const pt = func.pt; |
| 1956 | const zcu = pt.zcu; | ||
| 1873 | 1957 | ||
| 1874 | const abi_size = math.cast(u32, elem_ty.abiSize(pt)) orelse { | 1958 | const bit_size = elem_ty.bitSize(pt); |
| 1875 | return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); | 1959 | const min_size: u64 = switch (elem_ty.zigTypeTag(zcu)) { |
| 1876 | }; | 1960 | .Float => if (func.hasFeature(.d)) 64 else 32, |
| 1877 | 1961 | .Vector => 256, // TODO: calculate it from avl * vsew | |
| 1878 | const min_size: u32 = switch (elem_ty.zigTypeTag(pt.zcu)) { | 1962 | else => 64, |
| 1879 | .Float => 4, | ||
| 1880 | .Vector => @panic("allocRegOrMem Vector"), | ||
| 1881 | else => 8, | ||
| 1882 | }; | 1963 | }; |
| 1883 | 1964 | ||
| 1884 | if (reg_ok and abi_size <= min_size) { | 1965 | if (reg_ok and bit_size <= min_size) { |
| 1885 | if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| { | 1966 | if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| { |
| 1886 | return .{ .register = reg }; | 1967 | return .{ .register = reg }; |
| 1887 | } | 1968 | } |
| 1969 | } else if (reg_ok and elem_ty.zigTypeTag(zcu) == .Vector) { | ||
| 1970 | return func.fail("did you forget to extend vector registers before allocating", .{}); | ||
| 1888 | } | 1971 | } |
| 1889 | 1972 | ||
| 1890 | const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(elem_ty, pt)); | 1973 | const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(elem_ty, pt)); |
| ... | @@ -1897,10 +1980,13 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool | ... | @@ -1897,10 +1980,13 @@ fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool |
| 1897 | fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } { | 1980 | fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } { |
| 1898 | if (reg_class == .float and !func.hasFeature(.f)) | 1981 | if (reg_class == .float and !func.hasFeature(.f)) |
| 1899 | std.debug.panic("allocReg class == float where F isn't enabled", .{}); | 1982 | std.debug.panic("allocReg class == float where F isn't enabled", .{}); |
| 1983 | if (reg_class == .vector and !func.hasFeature(.v)) | ||
| 1984 | std.debug.panic("allocReg class == vector where V isn't enabled", .{}); | ||
| 1900 | 1985 | ||
| 1901 | const class = switch (reg_class) { | 1986 | const class = switch (reg_class) { |
| 1902 | .int => abi.Registers.Integer.general_purpose, | 1987 | .int => abi.Registers.Integer.general_purpose, |
| 1903 | .float => abi.Registers.Float.general_purpose, | 1988 | .float => abi.Registers.Float.general_purpose, |
| 1989 | .vector => abi.Registers.Vector.general_purpose, | ||
| 1904 | }; | 1990 | }; |
| 1905 | 1991 | ||
| 1906 | const reg = try func.register_manager.allocReg(null, class); | 1992 | const reg = try func.register_manager.allocReg(null, class); |
| ... | @@ -1916,7 +2002,8 @@ fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?Regi | ... | @@ -1916,7 +2002,8 @@ fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?Regi |
| 1916 | return .{ op_reg, func.register_manager.lockReg(operand.register) }; | 2002 | return .{ op_reg, func.register_manager.lockReg(operand.register) }; |
| 1917 | } | 2003 | } |
| 1918 | 2004 | ||
| 1919 | const reg, const lock = try func.allocReg(func.typeRegClass(ty)); | 2005 | const class = func.typeRegClass(ty); |
| 2006 | const reg, const lock = try func.allocReg(class); | ||
| 1920 | try func.genSetReg(ty, reg, operand); | 2007 | try func.genSetReg(ty, reg, operand); |
| 1921 | return .{ reg, lock }; | 2008 | return .{ reg, lock }; |
| 1922 | } | 2009 | } |
| ... | @@ -2087,19 +2174,17 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2087,19 +2174,17 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { |
| 2087 | const operand = try func.resolveInst(ty_op.operand); | 2174 | const operand = try func.resolveInst(ty_op.operand); |
| 2088 | const ty = func.typeOf(ty_op.operand); | 2175 | const ty = func.typeOf(ty_op.operand); |
| 2089 | 2176 | ||
| 2090 | switch (ty.zigTypeTag(zcu)) { | 2177 | const operand_reg, const operand_lock = try func.promoteReg(ty, operand); |
| 2091 | .Bool => { | 2178 | defer if (operand_lock) |lock| func.register_manager.unlockReg(lock); |
| 2092 | const operand_reg = blk: { | ||
| 2093 | if (operand == .register) break :blk operand.register; | ||
| 2094 | break :blk try func.copyToTmpRegister(ty, operand); | ||
| 2095 | }; | ||
| 2096 | 2179 | ||
| 2097 | const dst_reg: Register = | 2180 | const dst_reg: Register = |
| 2098 | if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register) | 2181 | if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register) |
| 2099 | operand.register | 2182 | operand.register |
| 2100 | else | 2183 | else |
| 2101 | (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register; | 2184 | (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register; |
| 2102 | 2185 | ||
| 2186 | switch (ty.zigTypeTag(zcu)) { | ||
| 2187 | .Bool => { | ||
| 2103 | _ = try func.addInst(.{ | 2188 | _ = try func.addInst(.{ |
| 2104 | .tag = .pseudo, | 2189 | .tag = .pseudo, |
| 2105 | .ops = .pseudo_not, | 2190 | .ops = .pseudo_not, |
| ... | @@ -2110,12 +2195,34 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2110,12 +2195,34 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { |
| 2110 | }, | 2195 | }, |
| 2111 | }, | 2196 | }, |
| 2112 | }); | 2197 | }); |
| 2198 | }, | ||
| 2199 | .Int => { | ||
| 2200 | const size = ty.bitSize(pt); | ||
| 2201 | if (!math.isPowerOfTwo(size)) | ||
| 2202 | return func.fail("TODO: airNot non-pow 2 int size", .{}); | ||
| 2113 | 2203 | ||
| 2114 | break :result .{ .register = dst_reg }; | 2204 | switch (size) { |
| 2205 | 32, 64 => { | ||
| 2206 | _ = try func.addInst(.{ | ||
| 2207 | .tag = .xori, | ||
| 2208 | .ops = .rri, | ||
| 2209 | .data = .{ | ||
| 2210 | .i_type = .{ | ||
| 2211 | .rd = dst_reg, | ||
| 2212 | .rs1 = operand_reg, | ||
| 2213 | .imm12 = Immediate.s(-1), | ||
| 2214 | }, | ||
| 2215 | }, | ||
| 2216 | }); | ||
| 2217 | }, | ||
| 2218 | 8, 16 => return func.fail("TODO: airNot 8 or 16, {}", .{size}), | ||
| 2219 | else => unreachable, | ||
| 2220 | } | ||
| 2115 | }, | 2221 | }, |
| 2116 | .Int => return func.fail("TODO: airNot ints", .{}), | ||
| 2117 | else => unreachable, | 2222 | else => unreachable, |
| 2118 | } | 2223 | } |
| 2224 | |||
| 2225 | break :result .{ .register = dst_reg }; | ||
| 2119 | }; | 2226 | }; |
| 2120 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2227 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2121 | } | 2228 | } |
| ... | @@ -2205,7 +2312,11 @@ fn binOp( | ... | @@ -2205,7 +2312,11 @@ fn binOp( |
| 2205 | return func.fail("binOp libcall runtime-float ops", .{}); | 2312 | return func.fail("binOp libcall runtime-float ops", .{}); |
| 2206 | } | 2313 | } |
| 2207 | 2314 | ||
| 2208 | if (lhs_ty.bitSize(pt) > 64) return func.fail("TODO: binOp >= 64 bits", .{}); | 2315 | // don't have support for certain sizes of addition |
| 2316 | switch (lhs_ty.zigTypeTag(pt.zcu)) { | ||
| 2317 | .Vector => {}, // works differently and fails in a different place | ||
| 2318 | else => if (lhs_ty.bitSize(pt) > 64) return func.fail("TODO: binOp >= 64 bits", .{}), | ||
| 2319 | } | ||
| 2209 | 2320 | ||
| 2210 | const lhs_mcv = try func.resolveInst(lhs_air); | 2321 | const lhs_mcv = try func.resolveInst(lhs_air); |
| 2211 | const rhs_mcv = try func.resolveInst(rhs_air); | 2322 | const rhs_mcv = try func.resolveInst(rhs_air); |
| ... | @@ -2353,6 +2464,51 @@ fn genBinOp( | ... | @@ -2353,6 +2464,51 @@ fn genBinOp( |
| 2353 | }, | 2464 | }, |
| 2354 | }); | 2465 | }); |
| 2355 | }, | 2466 | }, |
| 2467 | .Vector => { | ||
| 2468 | const num_elem = lhs_ty.vectorLen(zcu); | ||
| 2469 | const elem_size = lhs_ty.childType(zcu).bitSize(pt); | ||
| 2470 | |||
| 2471 | const child_ty = lhs_ty.childType(zcu); | ||
| 2472 | |||
| 2473 | const mir_tag: Mir.Inst.Tag = switch (tag) { | ||
| 2474 | .add => switch (child_ty.zigTypeTag(zcu)) { | ||
| 2475 | .Int => .vaddvv, | ||
| 2476 | .Float => .vfaddvv, | ||
| 2477 | else => unreachable, | ||
| 2478 | }, | ||
| 2479 | .sub => switch (child_ty.zigTypeTag(zcu)) { | ||
| 2480 | .Int => .vsubvv, | ||
| 2481 | .Float => .vfsubvv, | ||
| 2482 | else => unreachable, | ||
| 2483 | }, | ||
| 2484 | else => return func.fail("TODO: genBinOp {s} Vector", .{@tagName(tag)}), | ||
| 2485 | }; | ||
| 2486 | |||
| 2487 | try func.setVl(.zero, num_elem, .{ | ||
| 2488 | .vsew = switch (elem_size) { | ||
| 2489 | 8 => .@"8", | ||
| 2490 | 16 => .@"16", | ||
| 2491 | 32 => .@"32", | ||
| 2492 | 64 => .@"64", | ||
| 2493 | else => unreachable, | ||
| 2494 | }, | ||
| 2495 | .vlmul = .m1, | ||
| 2496 | .vma = true, | ||
| 2497 | .vta = true, | ||
| 2498 | }); | ||
| 2499 | |||
| 2500 | _ = try func.addInst(.{ | ||
| 2501 | .tag = mir_tag, | ||
| 2502 | .ops = .rrr, | ||
| 2503 | .data = .{ | ||
| 2504 | .r_type = .{ | ||
| 2505 | .rd = dst_reg, | ||
| 2506 | .rs1 = rhs_reg, | ||
| 2507 | .rs2 = lhs_reg, | ||
| 2508 | }, | ||
| 2509 | }, | ||
| 2510 | }); | ||
| 2511 | }, | ||
| 2356 | else => unreachable, | 2512 | else => unreachable, |
| 2357 | } | 2513 | } |
| 2358 | }, | 2514 | }, |
| ... | @@ -2636,78 +2792,55 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2636,78 +2792,55 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 2636 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; | 2792 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2637 | 2793 | ||
| 2638 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | 2794 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 2639 | const lhs_ty = func.typeOf(extra.lhs); | 2795 | const ty = func.typeOf(extra.lhs); |
| 2640 | 2796 | switch (ty.zigTypeTag(zcu)) { | |
| 2641 | const int_info = lhs_ty.intInfo(zcu); | 2797 | .Vector => return func.fail("TODO implement add with overflow for Vector type", .{}), |
| 2642 | 2798 | .Int => { | |
| 2643 | const tuple_ty = func.typeOfIndex(inst); | 2799 | const int_info = ty.intInfo(zcu); |
| 2644 | const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false); | ||
| 2645 | const offset = result_mcv.load_frame; | ||
| 2646 | |||
| 2647 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { | ||
| 2648 | const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs); | ||
| 2649 | const add_result_reg = try func.copyToTmpRegister(lhs_ty, add_result); | ||
| 2650 | const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg); | ||
| 2651 | defer func.register_manager.unlockReg(add_result_reg_lock); | ||
| 2652 | 2800 | ||
| 2653 | const shift_amount: u6 = @intCast(Type.usize.bitSize(pt) - int_info.bits); | 2801 | const tuple_ty = func.typeOfIndex(inst); |
| 2802 | const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false); | ||
| 2803 | const offset = result_mcv.load_frame; | ||
| 2654 | 2804 | ||
| 2655 | const shift_reg, const shift_lock = try func.allocReg(.int); | 2805 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 2656 | defer func.register_manager.unlockReg(shift_lock); | 2806 | const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs); |
| 2657 | 2807 | ||
| 2658 | _ = try func.addInst(.{ | 2808 | const add_result_reg = try func.copyToTmpRegister(ty, add_result); |
| 2659 | .tag = .slli, | 2809 | const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg); |
| 2660 | .ops = .rri, | 2810 | defer func.register_manager.unlockReg(add_result_reg_lock); |
| 2661 | .data = .{ | ||
| 2662 | .i_type = .{ | ||
| 2663 | .rd = shift_reg, | ||
| 2664 | .rs1 = add_result_reg, | ||
| 2665 | .imm12 = Immediate.u(shift_amount), | ||
| 2666 | }, | ||
| 2667 | }, | ||
| 2668 | }); | ||
| 2669 | 2811 | ||
| 2670 | _ = try func.addInst(.{ | 2812 | try func.genSetMem( |
| 2671 | .tag = if (int_info.signedness == .unsigned) .srli else .srai, | 2813 | .{ .frame = offset.index }, |
| 2672 | .ops = .rri, | 2814 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))), |
| 2673 | .data = .{ | 2815 | ty, |
| 2674 | .i_type = .{ | 2816 | add_result, |
| 2675 | .rd = shift_reg, | 2817 | ); |
| 2676 | .rs1 = shift_reg, | ||
| 2677 | .imm12 = Immediate.u(shift_amount), | ||
| 2678 | }, | ||
| 2679 | }, | ||
| 2680 | }); | ||
| 2681 | |||
| 2682 | try func.genSetMem( | ||
| 2683 | .{ .frame = offset.index }, | ||
| 2684 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, pt))), | ||
| 2685 | lhs_ty, | ||
| 2686 | add_result, | ||
| 2687 | ); | ||
| 2688 | 2818 | ||
| 2689 | const overflow_reg, const overflow_lock = try func.allocReg(.int); | 2819 | const overflow_reg, const overflow_lock = try func.allocReg(.int); |
| 2690 | defer func.register_manager.unlockReg(overflow_lock); | 2820 | defer func.register_manager.unlockReg(overflow_lock); |
| 2691 | 2821 | ||
| 2692 | try func.genBinOp( | 2822 | try func.genBinOp( |
| 2693 | .cmp_neq, | 2823 | .cmp_neq, |
| 2694 | .{ .register = shift_reg }, | 2824 | .{ .register = add_result_reg }, |
| 2695 | lhs_ty, | 2825 | ty, |
| 2696 | .{ .register = add_result_reg }, | 2826 | .{ .register = add_result_reg }, |
| 2697 | lhs_ty, | 2827 | ty, |
| 2698 | overflow_reg, | 2828 | overflow_reg, |
| 2699 | ); | 2829 | ); |
| 2700 | 2830 | ||
| 2701 | try func.genSetMem( | 2831 | try func.genSetMem( |
| 2702 | .{ .frame = offset.index }, | 2832 | .{ .frame = offset.index }, |
| 2703 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))), | 2833 | offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, pt))), |
| 2704 | Type.u1, | 2834 | Type.u1, |
| 2705 | .{ .register = overflow_reg }, | 2835 | .{ .register = overflow_reg }, |
| 2706 | ); | 2836 | ); |
| 2707 | 2837 | ||
| 2708 | break :result result_mcv; | 2838 | break :result result_mcv; |
| 2709 | } else { | 2839 | } else { |
| 2710 | return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{}); | 2840 | return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{}); |
| 2841 | } | ||
| 2842 | }, | ||
| 2843 | else => unreachable, | ||
| 2711 | } | 2844 | } |
| 2712 | }; | 2845 | }; |
| 2713 | 2846 | ||
| ... | @@ -3229,7 +3362,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3229,7 +3362,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void { |
| 3229 | const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, pt)); | 3362 | const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, pt)); |
| 3230 | const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, pt)); | 3363 | const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, pt)); |
| 3231 | const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, pt)); | 3364 | const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, pt)); |
| 3232 | try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef); | 3365 | try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .{ .undef = null }); |
| 3233 | const operand = try func.resolveInst(ty_op.operand); | 3366 | const operand = try func.resolveInst(ty_op.operand); |
| 3234 | try func.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand); | 3367 | try func.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand); |
| 3235 | break :result .{ .load_frame = .{ .index = frame_index } }; | 3368 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| ... | @@ -3451,20 +3584,54 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3451,20 +3584,54 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3451 | else => try func.genSetReg(Type.usize, addr_reg, array_mcv.address()), | 3584 | else => try func.genSetReg(Type.usize, addr_reg, array_mcv.address()), |
| 3452 | } | 3585 | } |
| 3453 | 3586 | ||
| 3587 | const dst_mcv = try func.allocRegOrMem(result_ty, inst, false); | ||
| 3588 | |||
| 3589 | if (array_ty.isVector(zcu)) { | ||
| 3590 | // we need to load the vector, vslidedown to get the element we want | ||
| 3591 | // and store that element at in a load frame. | ||
| 3592 | |||
| 3593 | const src_reg, const src_lock = try func.allocReg(.vector); | ||
| 3594 | defer func.register_manager.unlockReg(src_lock); | ||
| 3595 | |||
| 3596 | // load the vector into a temporary register | ||
| 3597 | try func.genCopy(array_ty, .{ .register = src_reg }, .{ .indirect = .{ .reg = addr_reg } }); | ||
| 3598 | |||
| 3599 | // we need to construct a 1xbitSize vector because of how lane splitting works in RISC-V | ||
| 3600 | const single_ty = try pt.vectorType(.{ .child = elem_ty.toIntern(), .len = 1 }); | ||
| 3601 | |||
| 3602 | // we can do a shortcut here where we don't need a vslicedown | ||
| 3603 | // and can just copy to the frame index. | ||
| 3604 | if (!(index_mcv == .immediate and index_mcv.immediate == 0)) { | ||
| 3605 | const index_reg = try func.copyToTmpRegister(Type.usize, index_mcv); | ||
| 3606 | |||
| 3607 | _ = try func.addInst(.{ | ||
| 3608 | .tag = .vslidedownvx, | ||
| 3609 | .ops = .rrr, | ||
| 3610 | .data = .{ .r_type = .{ | ||
| 3611 | .rd = src_reg, | ||
| 3612 | .rs1 = index_reg, | ||
| 3613 | .rs2 = src_reg, | ||
| 3614 | } }, | ||
| 3615 | }); | ||
| 3616 | } | ||
| 3617 | |||
| 3618 | try func.genCopy(single_ty, dst_mcv, .{ .register = src_reg }); | ||
| 3619 | break :result dst_mcv; | ||
| 3620 | } | ||
| 3621 | |||
| 3454 | const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_abi_size); | 3622 | const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_abi_size); |
| 3455 | const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg); | 3623 | const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg); |
| 3456 | defer func.register_manager.unlockReg(offset_lock); | 3624 | defer func.register_manager.unlockReg(offset_lock); |
| 3457 | |||
| 3458 | const dst_mcv = try func.allocRegOrMem(result_ty, inst, false); | ||
| 3459 | _ = try func.addInst(.{ | 3625 | _ = try func.addInst(.{ |
| 3460 | .tag = .add, | 3626 | .tag = .add, |
| 3461 | .ops = .rrr, | 3627 | .ops = .rrr, |
| 3462 | .data = .{ .r_type = .{ | 3628 | .data = .{ .r_type = .{ |
| 3463 | .rd = addr_reg, | 3629 | .rd = addr_reg, |
| 3464 | .rs1 = offset_reg, | 3630 | .rs1 = addr_reg, |
| 3465 | .rs2 = addr_reg, | 3631 | .rs2 = offset_reg, |
| 3466 | } }, | 3632 | } }, |
| 3467 | }); | 3633 | }); |
| 3634 | |||
| 3468 | try func.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }); | 3635 | try func.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }); |
| 3469 | break :result dst_mcv; | 3636 | break :result dst_mcv; |
| 3470 | }; | 3637 | }; |
| ... | @@ -3541,9 +3708,50 @@ fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3541,9 +3708,50 @@ fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 3541 | } | 3708 | } |
| 3542 | 3709 | ||
| 3543 | fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { | 3710 | fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { |
| 3711 | const pt = func.pt; | ||
| 3544 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3712 | const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3545 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airGetUnionTag for {}", .{func.target.cpu.arch}); | 3713 | |
| 3546 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3714 | const tag_ty = func.typeOfIndex(inst); |
| 3715 | const union_ty = func.typeOf(ty_op.operand); | ||
| 3716 | const layout = union_ty.unionGetLayout(pt); | ||
| 3717 | |||
| 3718 | if (layout.tag_size == 0) { | ||
| 3719 | return func.finishAir(inst, .none, .{ ty_op.operand, .none, .none }); | ||
| 3720 | } | ||
| 3721 | |||
| 3722 | const operand = try func.resolveInst(ty_op.operand); | ||
| 3723 | |||
| 3724 | const frame_mcv = try func.allocRegOrMem(union_ty, null, false); | ||
| 3725 | try func.genCopy(union_ty, frame_mcv, operand); | ||
| 3726 | |||
| 3727 | const tag_abi_size = tag_ty.abiSize(pt); | ||
| 3728 | const result_reg, const result_lock = try func.allocReg(.int); | ||
| 3729 | defer func.register_manager.unlockReg(result_lock); | ||
| 3730 | |||
| 3731 | switch (frame_mcv) { | ||
| 3732 | .load_frame => |frame_addr| { | ||
| 3733 | if (tag_abi_size <= 8) { | ||
| 3734 | const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align)) | ||
| 3735 | @intCast(layout.payload_size) | ||
| 3736 | else | ||
| 3737 | 0; | ||
| 3738 | |||
| 3739 | try func.genCopy( | ||
| 3740 | tag_ty, | ||
| 3741 | .{ .register = result_reg }, | ||
| 3742 | .{ .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off } }, | ||
| 3743 | ); | ||
| 3744 | } else { | ||
| 3745 | return func.fail( | ||
| 3746 | "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {}", | ||
| 3747 | .{ frame_mcv, tag_ty.fmt(pt) }, | ||
| 3748 | ); | ||
| 3749 | } | ||
| 3750 | }, | ||
| 3751 | else => return func.fail("TODO: airGetUnionTag {s}", .{@tagName(operand)}), | ||
| 3752 | } | ||
| 3753 | |||
| 3754 | return func.finishAir(inst, .{ .register = result_reg }, .{ ty_op.operand, .none, .none }); | ||
| 3547 | } | 3755 | } |
| 3548 | 3756 | ||
| 3549 | fn airClz(func: *Func, inst: Air.Inst.Index) !void { | 3757 | fn airClz(func: *Func, inst: Air.Inst.Index) !void { |
| ... | @@ -3719,13 +3927,65 @@ fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3719,13 +3927,65 @@ fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void { |
| 3719 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3927 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3720 | } | 3928 | } |
| 3721 | 3929 | ||
| 3722 | fn airUnaryMath(func: *Func, inst: Air.Inst.Index) !void { | 3930 | fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 3723 | const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)]; | 3931 | const pt = func.pt; |
| 3724 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | 3932 | const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 3725 | const result: MCValue = if (func.liveness.isUnused(inst)) | 3933 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { |
| 3726 | .unreach | 3934 | const ty = func.typeOf(un_op); |
| 3727 | else | 3935 | |
| 3728 | return func.fail("TODO implementairUnaryMath {s} for {}", .{ @tagName(tag), func.target.cpu.arch }); | 3936 | const operand = try func.resolveInst(un_op); |
| 3937 | const operand_bit_size = ty.bitSize(pt); | ||
| 3938 | |||
| 3939 | if (!math.isPowerOfTwo(operand_bit_size)) | ||
| 3940 | return func.fail("TODO: airUnaryMath non-pow 2", .{}); | ||
| 3941 | |||
| 3942 | const operand_reg, const operand_lock = try func.promoteReg(ty, operand); | ||
| 3943 | defer if (operand_lock) |lock| func.register_manager.unlockReg(lock); | ||
| 3944 | |||
| 3945 | const dst_class = func.typeRegClass(ty); | ||
| 3946 | const dst_reg, const dst_lock = try func.allocReg(dst_class); | ||
| 3947 | defer func.register_manager.unlockReg(dst_lock); | ||
| 3948 | |||
| 3949 | switch (ty.zigTypeTag(pt.zcu)) { | ||
| 3950 | .Float => { | ||
| 3951 | assert(dst_class == .float); | ||
| 3952 | |||
| 3953 | switch (operand_bit_size) { | ||
| 3954 | 16, 80, 128 => return func.fail("TODO: airUnaryMath Float bit-size {}", .{operand_bit_size}), | ||
| 3955 | 32, 64 => {}, | ||
| 3956 | else => unreachable, | ||
| 3957 | } | ||
| 3958 | |||
| 3959 | switch (tag) { | ||
| 3960 | .sqrt => { | ||
| 3961 | _ = try func.addInst(.{ | ||
| 3962 | .tag = if (operand_bit_size == 64) .fsqrtd else .fsqrts, | ||
| 3963 | .ops = .rrr, | ||
| 3964 | .data = .{ | ||
| 3965 | .r_type = .{ | ||
| 3966 | .rd = dst_reg, | ||
| 3967 | .rs1 = operand_reg, | ||
| 3968 | .rs2 = .f0, // unused, spec says it's 0 | ||
| 3969 | }, | ||
| 3970 | }, | ||
| 3971 | }); | ||
| 3972 | }, | ||
| 3973 | else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}), | ||
| 3974 | } | ||
| 3975 | }, | ||
| 3976 | .Int => { | ||
| 3977 | assert(dst_class == .int); | ||
| 3978 | |||
| 3979 | switch (tag) { | ||
| 3980 | else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}), | ||
| 3981 | } | ||
| 3982 | }, | ||
| 3983 | else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(pt)}), | ||
| 3984 | } | ||
| 3985 | |||
| 3986 | break :result MCValue{ .register = dst_reg }; | ||
| 3987 | }; | ||
| 3988 | |||
| 3729 | return func.finishAir(inst, result, .{ un_op, .none, .none }); | 3989 | return func.finishAir(inst, result, .{ un_op, .none, .none }); |
| 3730 | } | 3990 | } |
| 3731 | 3991 | ||
| ... | @@ -3987,6 +4247,10 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3987,6 +4247,10 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3987 | }); | 4247 | }); |
| 3988 | } | 4248 | } |
| 3989 | 4249 | ||
| 4250 | if (field_off == 0) { | ||
| 4251 | try func.truncateRegister(field_ty, dst_reg); | ||
| 4252 | } | ||
| 4253 | |||
| 3990 | break :result if (field_off == 0) dst_mcv else try func.copyToNewRegister(inst, dst_mcv); | 4254 | break :result if (field_off == 0) dst_mcv else try func.copyToNewRegister(inst, dst_mcv); |
| 3991 | }, | 4255 | }, |
| 3992 | .load_frame => { | 4256 | .load_frame => { |
| ... | @@ -4121,9 +4385,28 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -4121,9 +4385,28 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void { |
| 4121 | return func.finishAir(inst, dst_mcv, .{ .none, .none, .none }); | 4385 | return func.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 4122 | } | 4386 | } |
| 4123 | 4387 | ||
| 4124 | fn airFence(func: *Func) !void { | 4388 | fn airFence(func: *Func, inst: Air.Inst.Index) !void { |
| 4125 | return func.fail("TODO implement fence() for {}", .{func.target.cpu.arch}); | 4389 | const order = func.air.instructions.items(.data)[@intFromEnum(inst)].fence; |
| 4126 | //return func.finishAirBookkeeping(); | 4390 | const pred: Mir.Barrier, const succ: Mir.Barrier = switch (order) { |
| 4391 | .unordered, .monotonic => unreachable, | ||
| 4392 | .acquire => .{ .r, .rw }, | ||
| 4393 | .release => .{ .rw, .r }, | ||
| 4394 | .acq_rel => .{ .rw, .rw }, | ||
| 4395 | .seq_cst => .{ .rw, .rw }, | ||
| 4396 | }; | ||
| 4397 | |||
| 4398 | _ = try func.addInst(.{ | ||
| 4399 | .tag = .pseudo, | ||
| 4400 | .ops = .pseudo_fence, | ||
| 4401 | .data = .{ | ||
| 4402 | .fence = .{ | ||
| 4403 | .pred = pred, | ||
| 4404 | .succ = succ, | ||
| 4405 | .fm = if (order == .acq_rel) .tso else .none, | ||
| 4406 | }, | ||
| 4407 | }, | ||
| 4408 | }); | ||
| 4409 | return func.finishAirBookkeeping(); | ||
| 4127 | } | 4410 | } |
| 4128 | 4411 | ||
| 4129 | fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 4412 | fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| ... | @@ -4374,7 +4657,27 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -4374,7 +4657,27 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void { |
| 4374 | .none => {}, | 4657 | .none => {}, |
| 4375 | .register, | 4658 | .register, |
| 4376 | .register_pair, | 4659 | .register_pair, |
| 4377 | => try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op }), | 4660 | => { |
| 4661 | if (ret_ty.isVector(zcu)) { | ||
| 4662 | const bit_size = ret_ty.totalVectorBits(pt); | ||
| 4663 | |||
| 4664 | // set the vtype to hold the entire vector's contents in a single element | ||
| 4665 | try func.setVl(.zero, 0, .{ | ||
| 4666 | .vsew = switch (bit_size) { | ||
| 4667 | 8 => .@"8", | ||
| 4668 | 16 => .@"16", | ||
| 4669 | 32 => .@"32", | ||
| 4670 | 64 => .@"64", | ||
| 4671 | else => unreachable, | ||
| 4672 | }, | ||
| 4673 | .vlmul = .m1, | ||
| 4674 | .vma = true, | ||
| 4675 | .vta = true, | ||
| 4676 | }); | ||
| 4677 | } | ||
| 4678 | |||
| 4679 | try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op }); | ||
| 4680 | }, | ||
| 4378 | .indirect => |reg_off| { | 4681 | .indirect => |reg_off| { |
| 4379 | try func.register_manager.getReg(reg_off.reg, null); | 4682 | try func.register_manager.getReg(reg_off.reg, null); |
| 4380 | const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg); | 4683 | const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg); |
| ... | @@ -5224,8 +5527,6 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5224,8 +5527,6 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { |
| 5224 | const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]); | 5527 | const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]); |
| 5225 | extra_i += inputs.len; | 5528 | extra_i += inputs.len; |
| 5226 | 5529 | ||
| 5227 | log.debug("airAsm input: {any}", .{inputs}); | ||
| 5228 | |||
| 5229 | const dead = !is_volatile and func.liveness.isUnused(inst); | 5530 | const dead = !is_volatile and func.liveness.isUnused(inst); |
| 5230 | const result: MCValue = if (dead) .unreach else result: { | 5531 | const result: MCValue = if (dead) .unreach else result: { |
| 5231 | if (outputs.len > 1) { | 5532 | if (outputs.len > 1) { |
| ... | @@ -5599,18 +5900,34 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5599,18 +5900,34 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5599 | const zcu = pt.zcu; | 5900 | const zcu = pt.zcu; |
| 5600 | const abi_size: u32 = @intCast(ty.abiSize(pt)); | 5901 | const abi_size: u32 = @intCast(ty.abiSize(pt)); |
| 5601 | 5902 | ||
| 5602 | if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size}); | 5903 | const max_size: u32 = switch (reg.class()) { |
| 5603 | 5904 | .int => 64, | |
| 5905 | .float => if (func.hasFeature(.d)) 64 else 32, | ||
| 5906 | .vector => 64, // TODO: calculate it from avl * vsew | ||
| 5907 | }; | ||
| 5908 | if (abi_size > max_size) return std.debug.panic("tried to set reg with size {}", .{abi_size}); | ||
| 5604 | const dst_reg_class = reg.class(); | 5909 | const dst_reg_class = reg.class(); |
| 5605 | 5910 | ||
| 5606 | switch (src_mcv) { | 5911 | switch (src_mcv) { |
| 5607 | .dead => unreachable, | 5912 | .unreach, |
| 5608 | .unreach, .none => return, // Nothing to do. | 5913 | .none, |
| 5609 | .undef => { | 5914 | .dead, |
| 5915 | => unreachable, | ||
| 5916 | .undef => |sym_index| { | ||
| 5610 | if (!func.wantSafety()) | 5917 | if (!func.wantSafety()) |
| 5611 | return; // The already existing value will do just fine. | 5918 | return; |
| 5612 | // Write the debug undefined value. | 5919 | |
| 5613 | return func.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); | 5920 | if (sym_index) |index| { |
| 5921 | return func.genSetReg(ty, reg, .{ .load_symbol = .{ .sym = index } }); | ||
| 5922 | } | ||
| 5923 | |||
| 5924 | switch (abi_size) { | ||
| 5925 | 1 => return func.genSetReg(ty, reg, .{ .immediate = 0xAA }), | ||
| 5926 | 2 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAA }), | ||
| 5927 | 3...4 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAAAAAA }), | ||
| 5928 | 5...8 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAAAAAAAAAAAAAA }), | ||
| 5929 | else => unreachable, | ||
| 5930 | } | ||
| 5614 | }, | 5931 | }, |
| 5615 | .immediate => |unsigned_x| { | 5932 | .immediate => |unsigned_x| { |
| 5616 | assert(dst_reg_class == .int); | 5933 | assert(dst_reg_class == .int); |
| ... | @@ -5688,11 +6005,25 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5688,11 +6005,25 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5688 | if (src_reg.id() == reg.id()) | 6005 | if (src_reg.id() == reg.id()) |
| 5689 | return; | 6006 | return; |
| 5690 | 6007 | ||
| 5691 | const src_reg_class = src_reg.class(); | 6008 | // there is no instruction for loading the contents of a vector register |
| 5692 | 6009 | // into an integer register, however we can cheat a bit by setting the element | |
| 5693 | if (src_reg_class == .float and dst_reg_class == .int) { | 6010 | // size to the total size of the vector, and vmv.x.s will work then |
| 5694 | // to move from float -> int, we use FMV.X.W | 6011 | if (src_reg.class() == .vector) { |
| 5695 | return func.fail("TODO: genSetReg float -> int", .{}); | 6012 | try func.setVl(.zero, 0, .{ |
| 6013 | .vsew = switch (ty.totalVectorBits(pt)) { | ||
| 6014 | 8 => .@"8", | ||
| 6015 | 16 => .@"16", | ||
| 6016 | 32 => .@"32", | ||
| 6017 | 64 => .@"64", | ||
| 6018 | else => |vec_bits| return func.fail("TODO: genSetReg vec -> {s} bits {d}", .{ | ||
| 6019 | @tagName(reg.class()), | ||
| 6020 | vec_bits, | ||
| 6021 | }), | ||
| 6022 | }, | ||
| 6023 | .vlmul = .m1, | ||
| 6024 | .vta = true, | ||
| 6025 | .vma = true, | ||
| 6026 | }); | ||
| 5696 | } | 6027 | } |
| 5697 | 6028 | ||
| 5698 | // mv reg, src_reg | 6029 | // mv reg, src_reg |
| ... | @@ -5707,21 +6038,31 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5707,21 +6038,31 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5707 | }, | 6038 | }, |
| 5708 | .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}), | 6039 | .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}), |
| 5709 | .load_frame => |frame| { | 6040 | .load_frame => |frame| { |
| 5710 | _ = try func.addInst(.{ | 6041 | if (reg.class() == .vector) { |
| 5711 | .tag = .pseudo, | 6042 | // vectors don't support an offset memory load so we need to put the true |
| 5712 | .ops = .pseudo_load_rm, | 6043 | // address into a register before loading from it. |
| 5713 | .data = .{ .rm = .{ | 6044 | const addr_reg, const addr_lock = try func.allocReg(.int); |
| 5714 | .r = reg, | 6045 | defer func.register_manager.unlockReg(addr_lock); |
| 5715 | .m = .{ | 6046 | |
| 5716 | .base = .{ .frame = frame.index }, | 6047 | try func.genCopy(ty, .{ .register = addr_reg }, src_mcv.address()); |
| 5717 | .mod = .{ | 6048 | try func.genCopy(ty, .{ .register = reg }, .{ .indirect = .{ .reg = addr_reg } }); |
| 5718 | .size = func.memSize(ty), | 6049 | } else { |
| 5719 | .unsigned = ty.isUnsignedInt(zcu), | 6050 | _ = try func.addInst(.{ |
| 5720 | .disp = frame.off, | 6051 | .tag = .pseudo, |
| 6052 | .ops = .pseudo_load_rm, | ||
| 6053 | .data = .{ .rm = .{ | ||
| 6054 | .r = reg, | ||
| 6055 | .m = .{ | ||
| 6056 | .base = .{ .frame = frame.index }, | ||
| 6057 | .mod = .{ | ||
| 6058 | .size = func.memSize(ty), | ||
| 6059 | .unsigned = ty.isUnsignedInt(zcu), | ||
| 6060 | .disp = frame.off, | ||
| 6061 | }, | ||
| 5721 | }, | 6062 | }, |
| 5722 | }, | 6063 | } }, |
| 5723 | } }, | 6064 | }); |
| 5724 | }); | 6065 | } |
| 5725 | }, | 6066 | }, |
| 5726 | .memory => |addr| { | 6067 | .memory => |addr| { |
| 5727 | try func.genSetReg(ty, reg, .{ .immediate = addr }); | 6068 | try func.genSetReg(ty, reg, .{ .immediate = addr }); |
| ... | @@ -5740,45 +6081,89 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5740,45 +6081,89 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5740 | _ = try func.addInst(.{ | 6081 | _ = try func.addInst(.{ |
| 5741 | .tag = .pseudo, | 6082 | .tag = .pseudo, |
| 5742 | .ops = .pseudo_lea_rm, | 6083 | .ops = .pseudo_lea_rm, |
| 5743 | .data = .{ .rm = .{ | 6084 | .data = .{ |
| 5744 | .r = reg, | 6085 | .rm = .{ |
| 5745 | .m = switch (src_mcv) { | 6086 | .r = reg, |
| 5746 | .register_offset => |reg_off| .{ | 6087 | .m = switch (src_mcv) { |
| 5747 | .base = .{ .reg = reg_off.reg }, | 6088 | .register_offset => |reg_off| .{ |
| 5748 | .mod = .{ | 6089 | .base = .{ .reg = reg_off.reg }, |
| 5749 | .size = func.memSize(ty), | 6090 | .mod = .{ |
| 5750 | .disp = reg_off.off, | 6091 | .size = .byte, // the size doesn't matter |
| 5751 | .unsigned = false, | 6092 | .disp = reg_off.off, |
| 6093 | .unsigned = false, | ||
| 6094 | }, | ||
| 5752 | }, | 6095 | }, |
| 5753 | }, | 6096 | .lea_frame => |frame| .{ |
| 5754 | .lea_frame => |frame| .{ | 6097 | .base = .{ .frame = frame.index }, |
| 5755 | .base = .{ .frame = frame.index }, | 6098 | .mod = .{ |
| 5756 | .mod = .{ | 6099 | .size = .byte, // the size doesn't matter |
| 5757 | .size = func.memSize(ty), | 6100 | .disp = frame.off, |
| 5758 | .disp = frame.off, | 6101 | .unsigned = false, |
| 5759 | .unsigned = false, | 6102 | }, |
| 5760 | }, | 6103 | }, |
| 6104 | else => unreachable, | ||
| 5761 | }, | 6105 | }, |
| 5762 | else => unreachable, | ||
| 5763 | }, | 6106 | }, |
| 5764 | } }, | 6107 | }, |
| 5765 | }); | 6108 | }); |
| 5766 | }, | 6109 | }, |
| 5767 | .indirect => |reg_off| { | 6110 | .indirect => |reg_off| { |
| 5768 | const float_class = dst_reg_class == .float; | 6111 | const load_tag: Mir.Inst.Tag = switch (reg.class()) { |
| 6112 | .float => switch (abi_size) { | ||
| 6113 | 1 => unreachable, // Zig does not support 8-bit floats | ||
| 6114 | 2 => return func.fail("TODO: genSetReg indirect 16-bit float", .{}), | ||
| 6115 | 4 => .flw, | ||
| 6116 | 8 => .fld, | ||
| 6117 | else => return std.debug.panic("TODO: genSetReg for float size {d}", .{abi_size}), | ||
| 6118 | }, | ||
| 6119 | .int => switch (abi_size) { | ||
| 6120 | 1 => .lb, | ||
| 6121 | 2 => .lh, | ||
| 6122 | 4 => .lw, | ||
| 6123 | 8 => .ld, | ||
| 6124 | else => return std.debug.panic("TODO: genSetReg for int size {d}", .{abi_size}), | ||
| 6125 | }, | ||
| 6126 | .vector => { | ||
| 6127 | assert(reg_off.off == 0); | ||
| 6128 | |||
| 6129 | // There is no vector instruction for loading with an offset to a base register, | ||
| 6130 | // so we need to get an offset register containing the address of the vector first | ||
| 6131 | // and load from it. | ||
| 6132 | const len = ty.vectorLen(zcu); | ||
| 6133 | const elem_ty = ty.childType(zcu); | ||
| 6134 | const elem_size = elem_ty.abiSize(pt); | ||
| 6135 | |||
| 6136 | try func.setVl(.zero, len, .{ | ||
| 6137 | .vsew = switch (elem_size) { | ||
| 6138 | 1 => .@"8", | ||
| 6139 | 2 => .@"16", | ||
| 6140 | 4 => .@"32", | ||
| 6141 | 8 => .@"64", | ||
| 6142 | else => unreachable, | ||
| 6143 | }, | ||
| 6144 | .vlmul = .m1, | ||
| 6145 | .vma = true, | ||
| 6146 | .vta = true, | ||
| 6147 | }); | ||
| 5769 | 6148 | ||
| 5770 | const load_tag: Mir.Inst.Tag = switch (abi_size) { | 6149 | _ = try func.addInst(.{ |
| 5771 | 1 => if (float_class) | 6150 | .tag = .pseudo, |
| 5772 | unreachable // Zig does not support 8-bit floats | 6151 | .ops = .pseudo_load_rm, |
| 5773 | else | 6152 | .data = .{ .rm = .{ |
| 5774 | .lb, | 6153 | .r = reg, |
| 5775 | 2 => if (float_class) | 6154 | .m = .{ |
| 5776 | return func.fail("TODO: genSetReg indirect 16-bit float", .{}) | 6155 | .base = .{ .reg = reg_off.reg }, |
| 5777 | else | 6156 | .mod = .{ |
| 5778 | .lh, | 6157 | .size = func.memSize(elem_ty), |
| 5779 | 4 => if (float_class) .flw else .lw, | 6158 | .unsigned = false, |
| 5780 | 8 => if (float_class) .fld else .ld, | 6159 | .disp = 0, |
| 5781 | else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}), | 6160 | }, |
| 6161 | }, | ||
| 6162 | } }, | ||
| 6163 | }); | ||
| 6164 | |||
| 6165 | return; | ||
| 6166 | }, | ||
| 5782 | }; | 6167 | }; |
| 5783 | 6168 | ||
| 5784 | _ = try func.addInst(.{ | 6169 | _ = try func.addInst(.{ |
| ... | @@ -5793,7 +6178,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5793,7 +6178,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5793 | }, | 6178 | }, |
| 5794 | .lea_symbol => |sym_off| { | 6179 | .lea_symbol => |sym_off| { |
| 5795 | assert(sym_off.off == 0); | 6180 | assert(sym_off.off == 0); |
| 5796 | |||
| 5797 | const atom_index = try func.symbolIndex(); | 6181 | const atom_index = try func.symbolIndex(); |
| 5798 | 6182 | ||
| 5799 | _ = try func.addInst(.{ | 6183 | _ = try func.addInst(.{ |
| ... | @@ -5826,6 +6210,8 @@ fn genSetMem( | ... | @@ -5826,6 +6210,8 @@ fn genSetMem( |
| 5826 | src_mcv: MCValue, | 6210 | src_mcv: MCValue, |
| 5827 | ) InnerError!void { | 6211 | ) InnerError!void { |
| 5828 | const pt = func.pt; | 6212 | const pt = func.pt; |
| 6213 | const zcu = pt.zcu; | ||
| 6214 | |||
| 5829 | const abi_size: u32 = @intCast(ty.abiSize(pt)); | 6215 | const abi_size: u32 = @intCast(ty.abiSize(pt)); |
| 5830 | const dst_ptr_mcv: MCValue = switch (base) { | 6216 | const dst_ptr_mcv: MCValue = switch (base) { |
| 5831 | .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, | 6217 | .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, |
| ... | @@ -5838,11 +6224,17 @@ fn genSetMem( | ... | @@ -5838,11 +6224,17 @@ fn genSetMem( |
| 5838 | .dead, | 6224 | .dead, |
| 5839 | .reserved_frame, | 6225 | .reserved_frame, |
| 5840 | => unreachable, | 6226 | => unreachable, |
| 5841 | .undef => try func.genInlineMemset( | 6227 | .undef => |sym_index| { |
| 5842 | dst_ptr_mcv, | 6228 | if (sym_index) |index| { |
| 5843 | src_mcv, | 6229 | return func.genSetMem(base, disp, ty, .{ .load_symbol = .{ .sym = index } }); |
| 5844 | .{ .immediate = abi_size }, | 6230 | } |
| 5845 | ), | 6231 | |
| 6232 | try func.genInlineMemset( | ||
| 6233 | dst_ptr_mcv, | ||
| 6234 | src_mcv, | ||
| 6235 | .{ .immediate = abi_size }, | ||
| 6236 | ); | ||
| 6237 | }, | ||
| 5846 | .register_offset, | 6238 | .register_offset, |
| 5847 | .memory, | 6239 | .memory, |
| 5848 | .indirect, | 6240 | .indirect, |
| ... | @@ -5853,12 +6245,12 @@ fn genSetMem( | ... | @@ -5853,12 +6245,12 @@ fn genSetMem( |
| 5853 | => switch (abi_size) { | 6245 | => switch (abi_size) { |
| 5854 | 0 => {}, | 6246 | 0 => {}, |
| 5855 | 1, 2, 4, 8 => { | 6247 | 1, 2, 4, 8 => { |
| 5856 | // no matter what type, it should use an integer register | 6248 | const reg = try func.register_manager.allocReg(null, abi.Registers.Integer.temporary); |
| 5857 | const src_reg = try func.copyToTmpRegister(Type.usize, src_mcv); | 6249 | const src_lock = func.register_manager.lockRegAssumeUnused(reg); |
| 5858 | const src_lock = func.register_manager.lockRegAssumeUnused(src_reg); | ||
| 5859 | defer func.register_manager.unlockReg(src_lock); | 6250 | defer func.register_manager.unlockReg(src_lock); |
| 5860 | 6251 | ||
| 5861 | try func.genSetMem(base, disp, ty, .{ .register = src_reg }); | 6252 | try func.genSetReg(ty, reg, src_mcv); |
| 6253 | try func.genSetMem(base, disp, ty, .{ .register = reg }); | ||
| 5862 | }, | 6254 | }, |
| 5863 | else => try func.genInlineMemcpy( | 6255 | else => try func.genInlineMemcpy( |
| 5864 | dst_ptr_mcv, | 6256 | dst_ptr_mcv, |
| ... | @@ -5867,6 +6259,44 @@ fn genSetMem( | ... | @@ -5867,6 +6259,44 @@ fn genSetMem( |
| 5867 | ), | 6259 | ), |
| 5868 | }, | 6260 | }, |
| 5869 | .register => |reg| { | 6261 | .register => |reg| { |
| 6262 | if (reg.class() == .vector) { | ||
| 6263 | const addr_reg = try func.copyToTmpRegister(Type.usize, dst_ptr_mcv); | ||
| 6264 | |||
| 6265 | const num_elem = ty.vectorLen(zcu); | ||
| 6266 | const elem_size = ty.childType(zcu).bitSize(pt); | ||
| 6267 | |||
| 6268 | try func.setVl(.zero, num_elem, .{ | ||
| 6269 | .vsew = switch (elem_size) { | ||
| 6270 | 8 => .@"8", | ||
| 6271 | 16 => .@"16", | ||
| 6272 | 32 => .@"32", | ||
| 6273 | 64 => .@"64", | ||
| 6274 | else => unreachable, | ||
| 6275 | }, | ||
| 6276 | .vlmul = .m1, | ||
| 6277 | .vma = true, | ||
| 6278 | .vta = true, | ||
| 6279 | }); | ||
| 6280 | |||
| 6281 | _ = try func.addInst(.{ | ||
| 6282 | .tag = .pseudo, | ||
| 6283 | .ops = .pseudo_store_rm, | ||
| 6284 | .data = .{ .rm = .{ | ||
| 6285 | .r = reg, | ||
| 6286 | .m = .{ | ||
| 6287 | .base = .{ .reg = addr_reg }, | ||
| 6288 | .mod = .{ | ||
| 6289 | .disp = 0, | ||
| 6290 | .size = func.memSize(ty.childType(zcu)), | ||
| 6291 | .unsigned = false, | ||
| 6292 | }, | ||
| 6293 | }, | ||
| 6294 | } }, | ||
| 6295 | }); | ||
| 6296 | |||
| 6297 | return; | ||
| 6298 | } | ||
| 6299 | |||
| 5870 | const mem_size = switch (base) { | 6300 | const mem_size = switch (base) { |
| 5871 | .frame => |base_fi| mem_size: { | 6301 | .frame => |base_fi| mem_size: { |
| 5872 | assert(disp >= 0); | 6302 | assert(disp >= 0); |
| ... | @@ -6042,19 +6472,161 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -6042,19 +6472,161 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void { |
| 6042 | } | 6472 | } |
| 6043 | 6473 | ||
| 6044 | fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { | 6474 | fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { |
| 6045 | _ = inst; | 6475 | const pt = func.pt; |
| 6046 | return func.fail("TODO implement airCmpxchg for {}", .{func.target.cpu.arch}); | 6476 | const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 6477 | const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; | ||
| 6478 | |||
| 6479 | const op = extra.op(); | ||
| 6480 | const order = extra.ordering(); | ||
| 6481 | |||
| 6482 | const ptr_ty = func.typeOf(pl_op.operand); | ||
| 6483 | const ptr_mcv = try func.resolveInst(pl_op.operand); | ||
| 6484 | |||
| 6485 | const val_ty = func.typeOf(extra.operand); | ||
| 6486 | const val_size = val_ty.abiSize(pt); | ||
| 6487 | const val_mcv = try func.resolveInst(extra.operand); | ||
| 6488 | |||
| 6489 | if (!math.isPowerOfTwo(val_size)) | ||
| 6490 | return func.fail("TODO: airAtomicRmw non-pow 2", .{}); | ||
| 6491 | |||
| 6492 | switch (val_ty.zigTypeTag(pt.zcu)) { | ||
| 6493 | .Int => {}, | ||
| 6494 | inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}), | ||
| 6495 | else => unreachable, | ||
| 6496 | } | ||
| 6497 | |||
| 6498 | switch (val_size) { | ||
| 6499 | 1, 2 => return func.fail("TODO: airAtomicRmw Int {}", .{val_size}), | ||
| 6500 | 4, 8 => {}, | ||
| 6501 | else => unreachable, | ||
| 6502 | } | ||
| 6503 | |||
| 6504 | const ptr_register, const ptr_lock = try func.promoteReg(ptr_ty, ptr_mcv); | ||
| 6505 | defer if (ptr_lock) |lock| func.register_manager.unlockReg(lock); | ||
| 6506 | |||
| 6507 | const val_register, const val_lock = try func.promoteReg(val_ty, val_mcv); | ||
| 6508 | defer if (val_lock) |lock| func.register_manager.unlockReg(lock); | ||
| 6509 | |||
| 6510 | const result_mcv = try func.allocRegOrMem(val_ty, inst, true); | ||
| 6511 | assert(result_mcv == .register); // should fit into 8 bytes | ||
| 6512 | |||
| 6513 | const aq, const rl = switch (order) { | ||
| 6514 | .unordered => unreachable, | ||
| 6515 | .monotonic => .{ false, false }, | ||
| 6516 | .acquire => .{ true, false }, | ||
| 6517 | .release => .{ false, true }, | ||
| 6518 | .acq_rel => .{ true, true }, | ||
| 6519 | .seq_cst => .{ true, true }, | ||
| 6520 | }; | ||
| 6521 | |||
| 6522 | _ = try func.addInst(.{ | ||
| 6523 | .tag = .pseudo, | ||
| 6524 | .ops = .pseudo_amo, | ||
| 6525 | .data = .{ .amo = .{ | ||
| 6526 | .rd = result_mcv.register, | ||
| 6527 | .rs1 = ptr_register, | ||
| 6528 | .rs2 = val_register, | ||
| 6529 | .aq = if (aq) .aq else .none, | ||
| 6530 | .rl = if (rl) .rl else .none, | ||
| 6531 | .op = switch (op) { | ||
| 6532 | .Xchg => .SWAP, | ||
| 6533 | .Add => .ADD, | ||
| 6534 | .Sub => return func.fail("TODO: airAtomicRmw SUB", .{}), | ||
| 6535 | .And => .AND, | ||
| 6536 | .Nand => return func.fail("TODO: airAtomicRmw NAND", .{}), | ||
| 6537 | .Or => .OR, | ||
| 6538 | .Xor => .XOR, | ||
| 6539 | .Max => .MAX, | ||
| 6540 | .Min => .MIN, | ||
| 6541 | }, | ||
| 6542 | .ty = val_ty, | ||
| 6543 | } }, | ||
| 6544 | }); | ||
| 6545 | |||
| 6546 | return func.finishAir(inst, result_mcv, .{ pl_op.operand, extra.operand, .none }); | ||
| 6047 | } | 6547 | } |
| 6048 | 6548 | ||
| 6049 | fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void { | 6549 | fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void { |
| 6050 | _ = inst; | 6550 | const zcu = func.pt.zcu; |
| 6051 | return func.fail("TODO implement airAtomicLoad for {}", .{func.target.cpu.arch}); | 6551 | const atomic_load = func.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load; |
| 6552 | const order: std.builtin.AtomicOrder = atomic_load.order; | ||
| 6553 | |||
| 6554 | const ptr_ty = func.typeOf(atomic_load.ptr); | ||
| 6555 | const elem_ty = ptr_ty.childType(zcu); | ||
| 6556 | const ptr_mcv = try func.resolveInst(atomic_load.ptr); | ||
| 6557 | |||
| 6558 | const result_mcv = try func.allocRegOrMem(elem_ty, inst, true); | ||
| 6559 | assert(result_mcv == .register); // should be less than 8 bytes | ||
| 6560 | |||
| 6561 | if (order == .seq_cst) { | ||
| 6562 | _ = try func.addInst(.{ | ||
| 6563 | .tag = .pseudo, | ||
| 6564 | .ops = .pseudo_fence, | ||
| 6565 | .data = .{ | ||
| 6566 | .fence = .{ | ||
| 6567 | .pred = .rw, | ||
| 6568 | .succ = .rw, | ||
| 6569 | .fm = .none, | ||
| 6570 | }, | ||
| 6571 | }, | ||
| 6572 | }); | ||
| 6573 | } | ||
| 6574 | |||
| 6575 | try func.load(result_mcv, ptr_mcv, ptr_ty); | ||
| 6576 | |||
| 6577 | switch (order) { | ||
| 6578 | // Don't guarnetee other memory operations to be ordered after the load. | ||
| 6579 | .unordered => {}, | ||
| 6580 | .monotonic => {}, | ||
| 6581 | // Make sure all previous reads happen before any reading or writing accurs. | ||
| 6582 | .seq_cst, .acquire => { | ||
| 6583 | _ = try func.addInst(.{ | ||
| 6584 | .tag = .pseudo, | ||
| 6585 | .ops = .pseudo_fence, | ||
| 6586 | .data = .{ | ||
| 6587 | .fence = .{ | ||
| 6588 | .pred = .r, | ||
| 6589 | .succ = .rw, | ||
| 6590 | .fm = .none, | ||
| 6591 | }, | ||
| 6592 | }, | ||
| 6593 | }); | ||
| 6594 | }, | ||
| 6595 | else => unreachable, | ||
| 6596 | } | ||
| 6597 | |||
| 6598 | return func.finishAir(inst, result_mcv, .{ atomic_load.ptr, .none, .none }); | ||
| 6052 | } | 6599 | } |
| 6053 | 6600 | ||
| 6054 | fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { | 6601 | fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { |
| 6055 | _ = inst; | 6602 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6056 | _ = order; | 6603 | |
| 6057 | return func.fail("TODO implement airAtomicStore for {}", .{func.target.cpu.arch}); | 6604 | const ptr_ty = func.typeOf(bin_op.lhs); |
| 6605 | const ptr_mcv = try func.resolveInst(bin_op.lhs); | ||
| 6606 | |||
| 6607 | const val_ty = func.typeOf(bin_op.rhs); | ||
| 6608 | const val_mcv = try func.resolveInst(bin_op.rhs); | ||
| 6609 | |||
| 6610 | switch (order) { | ||
| 6611 | .unordered, .monotonic => {}, | ||
| 6612 | .release, .seq_cst => { | ||
| 6613 | _ = try func.addInst(.{ | ||
| 6614 | .tag = .pseudo, | ||
| 6615 | .ops = .pseudo_fence, | ||
| 6616 | .data = .{ | ||
| 6617 | .fence = .{ | ||
| 6618 | .pred = .rw, | ||
| 6619 | .succ = .w, | ||
| 6620 | .fm = .none, | ||
| 6621 | }, | ||
| 6622 | }, | ||
| 6623 | }); | ||
| 6624 | }, | ||
| 6625 | else => unreachable, | ||
| 6626 | } | ||
| 6627 | |||
| 6628 | try func.store(ptr_mcv, val_mcv, ptr_ty, val_ty); | ||
| 6629 | return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); | ||
| 6058 | } | 6630 | } |
| 6059 | 6631 | ||
| 6060 | fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void { | 6632 | fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void { |
| ... | @@ -6441,18 +7013,39 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking { | ... | @@ -6441,18 +7013,39 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking { |
| 6441 | 7013 | ||
| 6442 | fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { | 7014 | fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { |
| 6443 | const pt = func.pt; | 7015 | const pt = func.pt; |
| 6444 | const zcu = pt.zcu; | 7016 | const gpa = func.gpa; |
| 7017 | |||
| 7018 | const owner_decl_index = pt.zcu.funcOwnerDeclIndex(func.func_index); | ||
| 7019 | const lf = func.bin_file; | ||
| 7020 | const src_loc = func.src_loc; | ||
| 7021 | |||
| 7022 | if (val.isUndef(pt.zcu)) { | ||
| 7023 | const local_sym_index = lf.lowerUnnamedConst(pt, val, owner_decl_index) catch |err| { | ||
| 7024 | const msg = try ErrorMsg.create(gpa, src_loc, "lowering unnamed undefined constant failed: {s}", .{@errorName(err)}); | ||
| 7025 | func.err_msg = msg; | ||
| 7026 | return error.CodegenFail; | ||
| 7027 | }; | ||
| 7028 | switch (lf.tag) { | ||
| 7029 | .elf => { | ||
| 7030 | const elf_file = lf.cast(link.File.Elf).?; | ||
| 7031 | const local = elf_file.symbol(local_sym_index); | ||
| 7032 | return MCValue{ .undef = local.esym_index }; | ||
| 7033 | }, | ||
| 7034 | else => unreachable, | ||
| 7035 | } | ||
| 7036 | } | ||
| 7037 | |||
| 6445 | const result = try codegen.genTypedValue( | 7038 | const result = try codegen.genTypedValue( |
| 6446 | func.bin_file, | 7039 | lf, |
| 6447 | pt, | 7040 | pt, |
| 6448 | func.src_loc, | 7041 | src_loc, |
| 6449 | val, | 7042 | val, |
| 6450 | zcu.funcOwnerDeclIndex(func.func_index), | 7043 | owner_decl_index, |
| 6451 | ); | 7044 | ); |
| 6452 | const mcv: MCValue = switch (result) { | 7045 | const mcv: MCValue = switch (result) { |
| 6453 | .mcv => |mcv| switch (mcv) { | 7046 | .mcv => |mcv| switch (mcv) { |
| 6454 | .none => .none, | 7047 | .none => .none, |
| 6455 | .undef => .undef, | 7048 | .undef => unreachable, |
| 6456 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, | 7049 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, |
| 6457 | .immediate => |imm| .{ .immediate = imm }, | 7050 | .immediate => |imm| .{ .immediate = imm }, |
| 6458 | .memory => |addr| .{ .memory = addr }, | 7051 | .memory => |addr| .{ .memory = addr }, |
| ... | @@ -6670,9 +7263,7 @@ fn parseRegName(name: []const u8) ?Register { | ... | @@ -6670,9 +7263,7 @@ fn parseRegName(name: []const u8) ?Register { |
| 6670 | } | 7263 | } |
| 6671 | 7264 | ||
| 6672 | fn typeOf(func: *Func, inst: Air.Inst.Ref) Type { | 7265 | fn typeOf(func: *Func, inst: Air.Inst.Ref) Type { |
| 6673 | const pt = func.pt; | 7266 | return func.air.typeOf(inst, &func.pt.zcu.intern_pool); |
| 6674 | const zcu = pt.zcu; | ||
| 6675 | return func.air.typeOf(inst, &zcu.intern_pool); | ||
| 6676 | } | 7267 | } |
| 6677 | 7268 | ||
| 6678 | fn typeOfIndex(func: *Func, inst: Air.Inst.Index) Type { | 7269 | fn typeOfIndex(func: *Func, inst: Air.Inst.Index) Type { |
src/arch/riscv64/Emit.zig+2-2| ... | @@ -26,7 +26,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -26,7 +26,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 26 | mir_index, | 26 | mir_index, |
| 27 | @intCast(emit.code.items.len), | 27 | @intCast(emit.code.items.len), |
| 28 | ); | 28 | ); |
| 29 | const lowered = try emit.lower.lowerMir(mir_index); | 29 | const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true }); |
| 30 | var lowered_relocs = lowered.relocs; | 30 | var lowered_relocs = lowered.relocs; |
| 31 | for (lowered.insts, 0..) |lowered_inst, lowered_index| { | 31 | for (lowered.insts, 0..) |lowered_inst, lowered_index| { |
| 32 | const start_offset: u32 = @intCast(emit.code.items.len); | 32 | const start_offset: u32 = @intCast(emit.code.items.len); |
| ... | @@ -75,7 +75,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -75,7 +75,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 75 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type, | 75 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type, |
| 76 | .r_addend = 0, | 76 | .r_addend = 0, |
| 77 | }); | 77 | }); |
| 78 | } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{}); | 78 | } else unreachable; |
| 79 | }, | 79 | }, |
| 80 | .call_extern_fn_reloc => |symbol| { | 80 | .call_extern_fn_reloc => |symbol| { |
| 81 | if (emit.bin_file.cast(link.File.Elf)) |elf_file| { | 81 | if (emit.bin_file.cast(link.File.Elf)) |elf_file| { |
src/arch/riscv64/Encoding.zig+376-40| ... | @@ -2,37 +2,55 @@ mnemonic: Mnemonic, | ... | @@ -2,37 +2,55 @@ mnemonic: Mnemonic, |
| 2 | data: Data, | 2 | data: Data, |
| 3 | 3 | ||
| 4 | const OpCode = enum(u7) { | 4 | const OpCode = enum(u7) { |
| 5 | OP = 0b0110011, | 5 | LOAD = 0b0000011, |
| 6 | LOAD_FP = 0b0000111, | ||
| 7 | MISC_MEM = 0b0001111, | ||
| 6 | OP_IMM = 0b0010011, | 8 | OP_IMM = 0b0010011, |
| 9 | AUIPC = 0b0010111, | ||
| 7 | OP_IMM_32 = 0b0011011, | 10 | OP_IMM_32 = 0b0011011, |
| 8 | OP_32 = 0b0111011, | ||
| 9 | |||
| 10 | BRANCH = 0b1100011, | ||
| 11 | LOAD = 0b0000011, | ||
| 12 | STORE = 0b0100011, | 11 | STORE = 0b0100011, |
| 13 | SYSTEM = 0b1110011, | ||
| 14 | |||
| 15 | OP_FP = 0b1010011, | ||
| 16 | LOAD_FP = 0b0000111, | ||
| 17 | STORE_FP = 0b0100111, | 12 | STORE_FP = 0b0100111, |
| 18 | 13 | AMO = 0b0101111, | |
| 19 | JALR = 0b1100111, | 14 | OP_V = 0b1010111, |
| 20 | AUIPC = 0b0010111, | 15 | OP = 0b0110011, |
| 16 | OP_32 = 0b0111011, | ||
| 21 | LUI = 0b0110111, | 17 | LUI = 0b0110111, |
| 18 | MADD = 0b1000011, | ||
| 19 | MSUB = 0b1000111, | ||
| 20 | NMSUB = 0b1001011, | ||
| 21 | NMADD = 0b1001111, | ||
| 22 | OP_FP = 0b1010011, | ||
| 23 | OP_IMM_64 = 0b1011011, | ||
| 24 | BRANCH = 0b1100011, | ||
| 25 | JALR = 0b1100111, | ||
| 22 | JAL = 0b1101111, | 26 | JAL = 0b1101111, |
| 23 | NONE = 0b0000000, | 27 | SYSTEM = 0b1110011, |
| 28 | OP_64 = 0b1111011, | ||
| 29 | NONE = 0b00000000, | ||
| 24 | }; | 30 | }; |
| 25 | 31 | ||
| 26 | const Fmt = enum(u2) { | 32 | const FpFmt = enum(u2) { |
| 27 | /// 32-bit single-precision | 33 | /// 32-bit single-precision |
| 28 | S = 0b00, | 34 | S = 0b00, |
| 29 | /// 64-bit double-precision | 35 | /// 64-bit double-precision |
| 30 | D = 0b01, | 36 | D = 0b01, |
| 31 | _reserved = 0b10, | 37 | |
| 38 | // H = 0b10, unused in the G extension | ||
| 39 | |||
| 32 | /// 128-bit quad-precision | 40 | /// 128-bit quad-precision |
| 33 | Q = 0b11, | 41 | Q = 0b11, |
| 34 | }; | 42 | }; |
| 35 | 43 | ||
| 44 | const AmoWidth = enum(u3) { | ||
| 45 | W = 0b010, | ||
| 46 | D = 0b011, | ||
| 47 | }; | ||
| 48 | |||
| 49 | const FenceMode = enum(u4) { | ||
| 50 | none = 0b0000, | ||
| 51 | tso = 0b1000, | ||
| 52 | }; | ||
| 53 | |||
| 36 | const Enc = struct { | 54 | const Enc = struct { |
| 37 | opcode: OpCode, | 55 | opcode: OpCode, |
| 38 | 56 | ||
| ... | @@ -42,11 +60,19 @@ const Enc = struct { | ... | @@ -42,11 +60,19 @@ const Enc = struct { |
| 42 | funct3: u3, | 60 | funct3: u3, |
| 43 | funct7: u7, | 61 | funct7: u7, |
| 44 | }, | 62 | }, |
| 63 | amo: struct { | ||
| 64 | funct5: u5, | ||
| 65 | width: AmoWidth, | ||
| 66 | }, | ||
| 67 | fence: struct { | ||
| 68 | funct3: u3, | ||
| 69 | fm: FenceMode, | ||
| 70 | }, | ||
| 45 | /// funct5 + rm + fmt | 71 | /// funct5 + rm + fmt |
| 46 | fmt: struct { | 72 | fmt: struct { |
| 47 | funct5: u5, | 73 | funct5: u5, |
| 48 | rm: u3, | 74 | rm: u3, |
| 49 | fmt: Fmt, | 75 | fmt: FpFmt, |
| 50 | }, | 76 | }, |
| 51 | /// funct3 | 77 | /// funct3 |
| 52 | f: struct { | 78 | f: struct { |
| ... | @@ -58,9 +84,55 @@ const Enc = struct { | ... | @@ -58,9 +84,55 @@ const Enc = struct { |
| 58 | funct3: u3, | 84 | funct3: u3, |
| 59 | has_5: bool, | 85 | has_5: bool, |
| 60 | }, | 86 | }, |
| 87 | vecls: struct { | ||
| 88 | width: VecWidth, | ||
| 89 | umop: Umop, | ||
| 90 | vm: bool, | ||
| 91 | mop: Mop, | ||
| 92 | mew: bool, | ||
| 93 | nf: u3, | ||
| 94 | }, | ||
| 95 | vecmath: struct { | ||
| 96 | vm: bool, | ||
| 97 | funct6: u6, | ||
| 98 | funct3: VecType, | ||
| 99 | }, | ||
| 61 | /// U-type | 100 | /// U-type |
| 62 | none, | 101 | none, |
| 63 | }, | 102 | }, |
| 103 | |||
| 104 | const Mop = enum(u2) { | ||
| 105 | unit = 0b00, | ||
| 106 | unord = 0b01, | ||
| 107 | stride = 0b10, | ||
| 108 | ord = 0b11, | ||
| 109 | }; | ||
| 110 | |||
| 111 | const Umop = enum(u5) { | ||
| 112 | unit = 0b00000, | ||
| 113 | whole = 0b01000, | ||
| 114 | mask = 0b01011, | ||
| 115 | fault = 0b10000, | ||
| 116 | }; | ||
| 117 | |||
| 118 | const VecWidth = enum(u3) { | ||
| 119 | // zig fmt: off | ||
| 120 | @"8" = 0b000, | ||
| 121 | @"16" = 0b101, | ||
| 122 | @"32" = 0b110, | ||
| 123 | @"64" = 0b111, | ||
| 124 | // zig fmt: on | ||
| 125 | }; | ||
| 126 | |||
| 127 | const VecType = enum(u3) { | ||
| 128 | OPIVV = 0b000, | ||
| 129 | OPFVV = 0b001, | ||
| 130 | OPMVV = 0b010, | ||
| 131 | OPIVI = 0b011, | ||
| 132 | OPIVX = 0b100, | ||
| 133 | OPFVF = 0b101, | ||
| 134 | OPMVX = 0b110, | ||
| 135 | }; | ||
| 64 | }; | 136 | }; |
| 65 | 137 | ||
| 66 | pub const Mnemonic = enum { | 138 | pub const Mnemonic = enum { |
| ... | @@ -90,6 +162,9 @@ pub const Mnemonic = enum { | ... | @@ -90,6 +162,9 @@ pub const Mnemonic = enum { |
| 90 | addi, | 162 | addi, |
| 91 | jalr, | 163 | jalr, |
| 92 | 164 | ||
| 165 | vsetivli, | ||
| 166 | vsetvli, | ||
| 167 | |||
| 93 | // U Type | 168 | // U Type |
| 94 | lui, | 169 | lui, |
| 95 | auipc, | 170 | auipc, |
| ... | @@ -130,6 +205,8 @@ pub const Mnemonic = enum { | ... | @@ -130,6 +205,8 @@ pub const Mnemonic = enum { |
| 130 | ebreak, | 205 | ebreak, |
| 131 | unimp, | 206 | unimp, |
| 132 | 207 | ||
| 208 | csrrs, | ||
| 209 | |||
| 133 | // M extension | 210 | // M extension |
| 134 | mul, | 211 | mul, |
| 135 | mulw, | 212 | mulw, |
| ... | @@ -192,6 +269,58 @@ pub const Mnemonic = enum { | ... | @@ -192,6 +269,58 @@ pub const Mnemonic = enum { |
| 192 | fsgnjnd, | 269 | fsgnjnd, |
| 193 | fsgnjxd, | 270 | fsgnjxd, |
| 194 | 271 | ||
| 272 | // V Extension | ||
| 273 | vle8v, | ||
| 274 | vle16v, | ||
| 275 | vle32v, | ||
| 276 | vle64v, | ||
| 277 | |||
| 278 | vse8v, | ||
| 279 | vse16v, | ||
| 280 | vse32v, | ||
| 281 | vse64v, | ||
| 282 | |||
| 283 | vsoxei8v, | ||
| 284 | |||
| 285 | vaddvv, | ||
| 286 | vsubvv, | ||
| 287 | |||
| 288 | vfaddvv, | ||
| 289 | vfsubvv, | ||
| 290 | |||
| 291 | vadcvv, | ||
| 292 | |||
| 293 | vmvvx, | ||
| 294 | |||
| 295 | vslidedownvx, | ||
| 296 | |||
| 297 | // MISC | ||
| 298 | fence, | ||
| 299 | fencetso, | ||
| 300 | |||
| 301 | // AMO | ||
| 302 | amoswapw, | ||
| 303 | amoaddw, | ||
| 304 | amoandw, | ||
| 305 | amoorw, | ||
| 306 | amoxorw, | ||
| 307 | amomaxw, | ||
| 308 | amominw, | ||
| 309 | amomaxuw, | ||
| 310 | amominuw, | ||
| 311 | |||
| 312 | amoswapd, | ||
| 313 | amoaddd, | ||
| 314 | amoandd, | ||
| 315 | amoord, | ||
| 316 | amoxord, | ||
| 317 | amomaxd, | ||
| 318 | amomind, | ||
| 319 | amomaxud, | ||
| 320 | amominud, | ||
| 321 | |||
| 322 | // TODO: Q extension | ||
| 323 | |||
| 195 | pub fn encoding(mnem: Mnemonic) Enc { | 324 | pub fn encoding(mnem: Mnemonic) Enc { |
| 196 | return switch (mnem) { | 325 | return switch (mnem) { |
| 197 | // zig fmt: off | 326 | // zig fmt: off |
| ... | @@ -322,14 +451,25 @@ pub const Mnemonic = enum { | ... | @@ -322,14 +451,25 @@ pub const Mnemonic = enum { |
| 322 | // LOAD_FP | 451 | // LOAD_FP |
| 323 | 452 | ||
| 324 | .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } }, | 453 | .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } }, |
| 325 | .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } }, | 454 | .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } }, |
| 455 | |||
| 456 | .vle8v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } }, | ||
| 457 | .vle16v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } }, | ||
| 458 | .vle32v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } }, | ||
| 459 | .vle64v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } }, | ||
| 326 | 460 | ||
| 327 | 461 | ||
| 328 | // STORE_FP | 462 | // STORE_FP |
| 329 | 463 | ||
| 330 | .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } }, | 464 | .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } }, |
| 331 | .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } }, | 465 | .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } }, |
| 332 | 466 | ||
| 467 | .vse8v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } }, | ||
| 468 | .vse16v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } }, | ||
| 469 | .vse32v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } }, | ||
| 470 | .vse64v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } }, | ||
| 471 | |||
| 472 | .vsoxei8v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .ord, .mew = false, .nf = 0b000 } } }, | ||
| 333 | 473 | ||
| 334 | // JALR | 474 | // JALR |
| 335 | 475 | ||
| ... | @@ -360,6 +500,8 @@ pub const Mnemonic = enum { | ... | @@ -360,6 +500,8 @@ pub const Mnemonic = enum { |
| 360 | 500 | ||
| 361 | .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } }, | 501 | .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } }, |
| 362 | .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } }, | 502 | .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } }, |
| 503 | |||
| 504 | .csrrs => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b010 } } }, | ||
| 363 | 505 | ||
| 364 | 506 | ||
| 365 | // NONE | 507 | // NONE |
| ... | @@ -367,6 +509,52 @@ pub const Mnemonic = enum { | ... | @@ -367,6 +509,52 @@ pub const Mnemonic = enum { |
| 367 | .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } }, | 509 | .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } }, |
| 368 | 510 | ||
| 369 | 511 | ||
| 512 | // MISC_MEM | ||
| 513 | |||
| 514 | .fence => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .none } } }, | ||
| 515 | .fencetso => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .tso } } }, | ||
| 516 | |||
| 517 | |||
| 518 | // AMO | ||
| 519 | |||
| 520 | .amoaddw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00000 } } }, | ||
| 521 | .amoswapw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00001 } } }, | ||
| 522 | // LR.W | ||
| 523 | // SC.W | ||
| 524 | .amoxorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00100 } } }, | ||
| 525 | .amoandw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01100 } } }, | ||
| 526 | .amoorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01000 } } }, | ||
| 527 | .amominw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10000 } } }, | ||
| 528 | .amomaxw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10100 } } }, | ||
| 529 | .amominuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11000 } } }, | ||
| 530 | .amomaxuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11100 } } }, | ||
| 531 | |||
| 532 | .amoaddd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00000 } } }, | ||
| 533 | .amoswapd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00001 } } }, | ||
| 534 | // LR.D | ||
| 535 | // SC.D | ||
| 536 | .amoxord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00100 } } }, | ||
| 537 | .amoandd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01100 } } }, | ||
| 538 | .amoord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01000 } } }, | ||
| 539 | .amomind => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10000 } } }, | ||
| 540 | .amomaxd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10100 } } }, | ||
| 541 | .amominud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } }, | ||
| 542 | .amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } }, | ||
| 543 | |||
| 544 | // OP_V | ||
| 545 | .vsetivli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } }, | ||
| 546 | .vsetvli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } }, | ||
| 547 | .vaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } }, | ||
| 548 | .vsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPIVV } } }, | ||
| 549 | |||
| 550 | .vfaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPFVV } } }, | ||
| 551 | .vfsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPFVV } } }, | ||
| 552 | |||
| 553 | .vadcvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } }, | ||
| 554 | .vmvvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010111, .funct3 = .OPIVX } } }, | ||
| 555 | |||
| 556 | .vslidedownvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b001111, .funct3 = .OPIVX } } }, | ||
| 557 | |||
| 370 | // zig fmt: on | 558 | // zig fmt: on |
| 371 | }; | 559 | }; |
| 372 | } | 560 | } |
| ... | @@ -380,8 +568,8 @@ pub const InstEnc = enum { | ... | @@ -380,8 +568,8 @@ pub const InstEnc = enum { |
| 380 | B, | 568 | B, |
| 381 | U, | 569 | U, |
| 382 | J, | 570 | J, |
| 383 | 571 | fence, | |
| 384 | /// extras that have unusual op counts | 572 | amo, |
| 385 | system, | 573 | system, |
| 386 | 574 | ||
| 387 | pub fn fromMnemonic(mnem: Mnemonic) InstEnc { | 575 | pub fn fromMnemonic(mnem: Mnemonic) InstEnc { |
| ... | @@ -410,6 +598,10 @@ pub const InstEnc = enum { | ... | @@ -410,6 +598,10 @@ pub const InstEnc = enum { |
| 410 | 598 | ||
| 411 | .flw, | 599 | .flw, |
| 412 | .fld, | 600 | .fld, |
| 601 | |||
| 602 | .csrrs, | ||
| 603 | .vsetivli, | ||
| 604 | .vsetvli, | ||
| 413 | => .I, | 605 | => .I, |
| 414 | 606 | ||
| 415 | .lui, | 607 | .lui, |
| ... | @@ -503,26 +695,73 @@ pub const InstEnc = enum { | ... | @@ -503,26 +695,73 @@ pub const InstEnc = enum { |
| 503 | 695 | ||
| 504 | .fsgnjxs, | 696 | .fsgnjxs, |
| 505 | .fsgnjxd, | 697 | .fsgnjxd, |
| 698 | |||
| 699 | .vle8v, | ||
| 700 | .vle16v, | ||
| 701 | .vle32v, | ||
| 702 | .vle64v, | ||
| 703 | |||
| 704 | .vse8v, | ||
| 705 | .vse16v, | ||
| 706 | .vse32v, | ||
| 707 | .vse64v, | ||
| 708 | |||
| 709 | .vsoxei8v, | ||
| 710 | |||
| 711 | .vaddvv, | ||
| 712 | .vsubvv, | ||
| 713 | .vfaddvv, | ||
| 714 | .vfsubvv, | ||
| 715 | .vadcvv, | ||
| 716 | .vmvvx, | ||
| 717 | .vslidedownvx, | ||
| 506 | => .R, | 718 | => .R, |
| 507 | 719 | ||
| 508 | .ecall, | 720 | .ecall, |
| 509 | .ebreak, | 721 | .ebreak, |
| 510 | .unimp, | 722 | .unimp, |
| 511 | => .system, | 723 | => .system, |
| 724 | |||
| 725 | .fence, | ||
| 726 | .fencetso, | ||
| 727 | => .fence, | ||
| 728 | |||
| 729 | .amoswapw, | ||
| 730 | .amoaddw, | ||
| 731 | .amoandw, | ||
| 732 | .amoorw, | ||
| 733 | .amoxorw, | ||
| 734 | .amomaxw, | ||
| 735 | .amominw, | ||
| 736 | .amomaxuw, | ||
| 737 | .amominuw, | ||
| 738 | |||
| 739 | .amoswapd, | ||
| 740 | .amoaddd, | ||
| 741 | .amoandd, | ||
| 742 | .amoord, | ||
| 743 | .amoxord, | ||
| 744 | .amomaxd, | ||
| 745 | .amomind, | ||
| 746 | .amomaxud, | ||
| 747 | .amominud, | ||
| 748 | => .amo, | ||
| 512 | }; | 749 | }; |
| 513 | } | 750 | } |
| 514 | 751 | ||
| 515 | pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) { | 752 | pub fn opsList(enc: InstEnc) [5]std.meta.FieldEnum(Operand) { |
| 516 | return switch (enc) { | 753 | return switch (enc) { |
| 517 | // zig fmt: off | 754 | // zig fmt: off |
| 518 | .R => .{ .reg, .reg, .reg, .none }, | 755 | .R => .{ .reg, .reg, .reg, .none, .none, }, |
| 519 | .R4 => .{ .reg, .reg, .reg, .reg }, | 756 | .R4 => .{ .reg, .reg, .reg, .reg, .none, }, |
| 520 | .I => .{ .reg, .reg, .imm, .none }, | 757 | .I => .{ .reg, .reg, .imm, .none, .none, }, |
| 521 | .S => .{ .reg, .reg, .imm, .none }, | 758 | .S => .{ .reg, .reg, .imm, .none, .none, }, |
| 522 | .B => .{ .reg, .reg, .imm, .none }, | 759 | .B => .{ .reg, .reg, .imm, .none, .none, }, |
| 523 | .U => .{ .reg, .imm, .none, .none }, | 760 | .U => .{ .reg, .imm, .none, .none, .none, }, |
| 524 | .J => .{ .reg, .imm, .none, .none }, | 761 | .J => .{ .reg, .imm, .none, .none, .none, }, |
| 525 | .system => .{ .none, .none, .none, .none }, | 762 | .system => .{ .none, .none, .none, .none, .none, }, |
| 763 | .fence => .{ .barrier, .barrier, .none, .none, .none, }, | ||
| 764 | .amo => .{ .reg, .reg, .reg, .barrier, .barrier }, | ||
| 526 | // zig fmt: on | 765 | // zig fmt: on |
| 527 | }; | 766 | }; |
| 528 | } | 767 | } |
| ... | @@ -584,20 +823,38 @@ pub const Data = union(InstEnc) { | ... | @@ -584,20 +823,38 @@ pub const Data = union(InstEnc) { |
| 584 | imm1_10: u10, | 823 | imm1_10: u10, |
| 585 | imm20: u1, | 824 | imm20: u1, |
| 586 | }, | 825 | }, |
| 587 | system: void, | 826 | fence: packed struct { |
| 827 | opcode: u7, | ||
| 828 | rd: u5 = 0, | ||
| 829 | funct3: u3, | ||
| 830 | rs1: u5 = 0, | ||
| 831 | succ: u4, | ||
| 832 | pred: u4, | ||
| 833 | fm: u4, | ||
| 834 | }, | ||
| 835 | amo: packed struct { | ||
| 836 | opcode: u7, | ||
| 837 | rd: u5, | ||
| 838 | funct3: u3, | ||
| 839 | rs1: u5, | ||
| 840 | rs2: u5, | ||
| 841 | rl: bool, | ||
| 842 | aq: bool, | ||
| 843 | funct5: u5, | ||
| 844 | }, | ||
| 845 | system: u32, | ||
| 846 | |||
| 847 | comptime { | ||
| 848 | for (std.meta.fields(Data)) |field| { | ||
| 849 | assert(@bitSizeOf(field.type) == 32); | ||
| 850 | } | ||
| 851 | } | ||
| 588 | 852 | ||
| 589 | pub fn toU32(self: Data) u32 { | 853 | pub fn toU32(self: Data) u32 { |
| 590 | return switch (self) { | 854 | return switch (self) { |
| 591 | // zig fmt: off | 855 | .fence => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.rd)) << 7) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.succ)) << 20) + (@as(u32, @intCast(v.pred)) << 24) + (@as(u32, @intCast(v.fm)) << 28), |
| 592 | .R => |v| @bitCast(v), | 856 | inline else => |v| @bitCast(v), |
| 593 | .R4 => |v| @bitCast(v), | ||
| 594 | .I => |v| @bitCast(v), | ||
| 595 | .S => |v| @bitCast(v), | ||
| 596 | .B => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.imm11)) << 7) + (@as(u32, @intCast(v.imm1_4)) << 8) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.rs2)) << 20) + (@as(u32, @intCast(v.imm5_10)) << 25) + (@as(u32, @intCast(v.imm12)) << 31), | ||
| 597 | .U => |v| @bitCast(v), | ||
| 598 | .J => |v| @bitCast(v), | ||
| 599 | .system => unreachable, | 857 | .system => unreachable, |
| 600 | // zig fmt: on | ||
| 601 | }; | 858 | }; |
| 602 | } | 859 | } |
| 603 | 860 | ||
| ... | @@ -628,6 +885,25 @@ pub const Data = union(InstEnc) { | ... | @@ -628,6 +885,25 @@ pub const Data = union(InstEnc) { |
| 628 | }, | 885 | }, |
| 629 | }; | 886 | }; |
| 630 | }, | 887 | }, |
| 888 | .csrrs => { | ||
| 889 | assert(ops.len == 3); | ||
| 890 | |||
| 891 | const csr = ops[0].csr; | ||
| 892 | const rs1 = ops[1].reg; | ||
| 893 | const rd = ops[2].reg; | ||
| 894 | |||
| 895 | return .{ | ||
| 896 | .I = .{ | ||
| 897 | .rd = rd.encodeId(), | ||
| 898 | .rs1 = rs1.encodeId(), | ||
| 899 | |||
| 900 | .imm0_11 = @intFromEnum(csr), | ||
| 901 | |||
| 902 | .opcode = @intFromEnum(enc.opcode), | ||
| 903 | .funct3 = enc.data.f.funct3, | ||
| 904 | }, | ||
| 905 | }; | ||
| 906 | }, | ||
| 631 | else => {}, | 907 | else => {}, |
| 632 | } | 908 | } |
| 633 | 909 | ||
| ... | @@ -654,6 +930,25 @@ pub const Data = union(InstEnc) { | ... | @@ -654,6 +930,25 @@ pub const Data = union(InstEnc) { |
| 654 | .funct3 = fmt.rm, | 930 | .funct3 = fmt.rm, |
| 655 | .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt), | 931 | .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt), |
| 656 | }, | 932 | }, |
| 933 | .vecls => |vec| .{ | ||
| 934 | .rd = ops[0].reg.encodeId(), | ||
| 935 | .rs1 = ops[1].reg.encodeId(), | ||
| 936 | |||
| 937 | .rs2 = @intFromEnum(vec.umop), | ||
| 938 | |||
| 939 | .opcode = @intFromEnum(enc.opcode), | ||
| 940 | .funct3 = @intFromEnum(vec.width), | ||
| 941 | .funct7 = (@as(u7, vec.nf) << 4) | (@as(u7, @intFromBool(vec.mew)) << 3) | (@as(u7, @intFromEnum(vec.mop)) << 1) | @intFromBool(vec.vm), | ||
| 942 | }, | ||
| 943 | .vecmath => |vec| .{ | ||
| 944 | .rd = ops[0].reg.encodeId(), | ||
| 945 | .rs1 = ops[1].reg.encodeId(), | ||
| 946 | .rs2 = ops[2].reg.encodeId(), | ||
| 947 | |||
| 948 | .opcode = @intFromEnum(enc.opcode), | ||
| 949 | .funct3 = @intFromEnum(vec.funct3), | ||
| 950 | .funct7 = (@as(u7, vec.funct6) << 1) | @intFromBool(vec.vm), | ||
| 951 | }, | ||
| 657 | else => unreachable, | 952 | else => unreachable, |
| 658 | }, | 953 | }, |
| 659 | }; | 954 | }; |
| ... | @@ -748,7 +1043,48 @@ pub const Data = union(InstEnc) { | ... | @@ -748,7 +1043,48 @@ pub const Data = union(InstEnc) { |
| 748 | }, | 1043 | }, |
| 749 | }; | 1044 | }; |
| 750 | }, | 1045 | }, |
| 1046 | .fence => { | ||
| 1047 | assert(ops.len == 2); | ||
| 1048 | |||
| 1049 | const succ = ops[0].barrier; | ||
| 1050 | const pred = ops[1].barrier; | ||
| 1051 | |||
| 1052 | return .{ | ||
| 1053 | .fence = .{ | ||
| 1054 | .succ = @intFromEnum(succ), | ||
| 1055 | .pred = @intFromEnum(pred), | ||
| 1056 | |||
| 1057 | .opcode = @intFromEnum(enc.opcode), | ||
| 1058 | .funct3 = enc.data.fence.funct3, | ||
| 1059 | .fm = @intFromEnum(enc.data.fence.fm), | ||
| 1060 | }, | ||
| 1061 | }; | ||
| 1062 | }, | ||
| 1063 | .amo => { | ||
| 1064 | assert(ops.len == 5); | ||
| 1065 | |||
| 1066 | const rd = ops[0].reg; | ||
| 1067 | const rs1 = ops[1].reg; | ||
| 1068 | const rs2 = ops[2].reg; | ||
| 1069 | const rl = ops[3].barrier; | ||
| 1070 | const aq = ops[4].barrier; | ||
| 751 | 1071 | ||
| 1072 | return .{ | ||
| 1073 | .amo = .{ | ||
| 1074 | .rd = rd.encodeId(), | ||
| 1075 | .rs1 = rs1.encodeId(), | ||
| 1076 | .rs2 = rs2.encodeId(), | ||
| 1077 | |||
| 1078 | // TODO: https://github.com/ziglang/zig/issues/20113 | ||
| 1079 | .rl = if (rl == .rl) true else false, | ||
| 1080 | .aq = if (aq == .aq) true else false, | ||
| 1081 | |||
| 1082 | .opcode = @intFromEnum(enc.opcode), | ||
| 1083 | .funct3 = @intFromEnum(enc.data.amo.width), | ||
| 1084 | .funct5 = enc.data.amo.funct5, | ||
| 1085 | }, | ||
| 1086 | }; | ||
| 1087 | }, | ||
| 752 | else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}), | 1088 | else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}), |
| 753 | } | 1089 | } |
| 754 | } | 1090 | } |
src/arch/riscv64/Lower.zig+171-59| ... | @@ -40,7 +40,9 @@ pub const Reloc = struct { | ... | @@ -40,7 +40,9 @@ pub const Reloc = struct { |
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| 42 | /// The returned slice is overwritten by the next call to lowerMir. | 42 | /// The returned slice is overwritten by the next call to lowerMir. |
| 43 | pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | 43 | pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { |
| 44 | allow_frame_locs: bool, | ||
| 45 | }) Error!struct { | ||
| 44 | insts: []const Instruction, | 46 | insts: []const Instruction, |
| 45 | relocs: []const Reloc, | 47 | relocs: []const Reloc, |
| 46 | } { | 48 | } { |
| ... | @@ -69,64 +71,102 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -69,64 +71,102 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 69 | .pseudo_load_rm, .pseudo_store_rm => { | 71 | .pseudo_load_rm, .pseudo_store_rm => { |
| 70 | const rm = inst.data.rm; | 72 | const rm = inst.data.rm; |
| 71 | 73 | ||
| 72 | const frame_loc = rm.m.toFrameLoc(lower.mir); | 74 | const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs) |
| 75 | rm.m.toFrameLoc(lower.mir) | ||
| 76 | else | ||
| 77 | .{ .base = .s0, .disp = 0 }; | ||
| 73 | 78 | ||
| 74 | switch (inst.ops) { | 79 | switch (inst.ops) { |
| 75 | .pseudo_load_rm => { | 80 | .pseudo_load_rm => { |
| 76 | const dest_reg = rm.r; | 81 | const dest_reg = rm.r; |
| 77 | const dest_reg_class = dest_reg.class(); | 82 | const dest_reg_class = dest_reg.class(); |
| 78 | const float = dest_reg_class == .float; | ||
| 79 | 83 | ||
| 80 | const src_size = rm.m.mod.size; | 84 | const src_size = rm.m.mod.size; |
| 81 | const unsigned = rm.m.mod.unsigned; | 85 | const unsigned = rm.m.mod.unsigned; |
| 82 | 86 | ||
| 83 | const tag: Encoding.Mnemonic = if (!float) | 87 | const tag: Encoding.Mnemonic = switch (dest_reg_class) { |
| 84 | switch (src_size) { | 88 | .int => switch (src_size) { |
| 85 | .byte => if (unsigned) .lbu else .lb, | 89 | .byte => if (unsigned) .lbu else .lb, |
| 86 | .hword => if (unsigned) .lhu else .lh, | 90 | .hword => if (unsigned) .lhu else .lh, |
| 87 | .word => if (unsigned) .lwu else .lw, | 91 | .word => if (unsigned) .lwu else .lw, |
| 88 | .dword => .ld, | 92 | .dword => .ld, |
| 89 | } | 93 | }, |
| 90 | else switch (src_size) { | 94 | .float => switch (src_size) { |
| 91 | .byte => unreachable, // Zig does not support 8-bit floats | 95 | .byte => unreachable, // Zig does not support 8-bit floats |
| 92 | .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}), | 96 | .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}), |
| 93 | .word => .flw, | 97 | .word => .flw, |
| 94 | .dword => .fld, | 98 | .dword => .fld, |
| 99 | }, | ||
| 100 | .vector => switch (src_size) { | ||
| 101 | .byte => .vle8v, | ||
| 102 | .hword => .vle32v, | ||
| 103 | .word => .vle32v, | ||
| 104 | .dword => .vle64v, | ||
| 105 | }, | ||
| 95 | }; | 106 | }; |
| 96 | 107 | ||
| 97 | try lower.emit(tag, &.{ | 108 | switch (dest_reg_class) { |
| 98 | .{ .reg = rm.r }, | 109 | .int, .float => { |
| 99 | .{ .reg = frame_loc.base }, | 110 | try lower.emit(tag, &.{ |
| 100 | .{ .imm = Immediate.s(frame_loc.disp) }, | 111 | .{ .reg = rm.r }, |
| 101 | }); | 112 | .{ .reg = frame_loc.base }, |
| 113 | .{ .imm = Immediate.s(frame_loc.disp) }, | ||
| 114 | }); | ||
| 115 | }, | ||
| 116 | .vector => { | ||
| 117 | assert(frame_loc.disp == 0); | ||
| 118 | try lower.emit(tag, &.{ | ||
| 119 | .{ .reg = rm.r }, | ||
| 120 | .{ .reg = frame_loc.base }, | ||
| 121 | .{ .reg = .zero }, | ||
| 122 | }); | ||
| 123 | }, | ||
| 124 | } | ||
| 102 | }, | 125 | }, |
| 103 | .pseudo_store_rm => { | 126 | .pseudo_store_rm => { |
| 104 | const src_reg = rm.r; | 127 | const src_reg = rm.r; |
| 105 | const src_reg_class = src_reg.class(); | 128 | const src_reg_class = src_reg.class(); |
| 106 | const float = src_reg_class == .float; | ||
| 107 | 129 | ||
| 108 | // TODO: do we actually need this? are all stores not usize? | ||
| 109 | const dest_size = rm.m.mod.size; | 130 | const dest_size = rm.m.mod.size; |
| 110 | 131 | ||
| 111 | const tag: Encoding.Mnemonic = if (!float) | 132 | const tag: Encoding.Mnemonic = switch (src_reg_class) { |
| 112 | switch (dest_size) { | 133 | .int => switch (dest_size) { |
| 113 | .byte => .sb, | 134 | .byte => .sb, |
| 114 | .hword => .sh, | 135 | .hword => .sh, |
| 115 | .word => .sw, | 136 | .word => .sw, |
| 116 | .dword => .sd, | 137 | .dword => .sd, |
| 117 | } | 138 | }, |
| 118 | else switch (dest_size) { | 139 | .float => switch (dest_size) { |
| 119 | .byte => unreachable, // Zig does not support 8-bit floats | 140 | .byte => unreachable, // Zig does not support 8-bit floats |
| 120 | .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}), | 141 | .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}), |
| 121 | .word => .fsw, | 142 | .word => .fsw, |
| 122 | .dword => .fsd, | 143 | .dword => .fsd, |
| 144 | }, | ||
| 145 | .vector => switch (dest_size) { | ||
| 146 | .byte => .vse8v, | ||
| 147 | .hword => .vse16v, | ||
| 148 | .word => .vse32v, | ||
| 149 | .dword => .vse64v, | ||
| 150 | }, | ||
| 123 | }; | 151 | }; |
| 124 | 152 | ||
| 125 | try lower.emit(tag, &.{ | 153 | switch (src_reg_class) { |
| 126 | .{ .reg = frame_loc.base }, | 154 | .int, .float => { |
| 127 | .{ .reg = rm.r }, | 155 | try lower.emit(tag, &.{ |
| 128 | .{ .imm = Immediate.s(frame_loc.disp) }, | 156 | .{ .reg = frame_loc.base }, |
| 129 | }); | 157 | .{ .reg = rm.r }, |
| 158 | .{ .imm = Immediate.s(frame_loc.disp) }, | ||
| 159 | }); | ||
| 160 | }, | ||
| 161 | .vector => { | ||
| 162 | assert(frame_loc.disp == 0); | ||
| 163 | try lower.emit(tag, &.{ | ||
| 164 | .{ .reg = rm.r }, | ||
| 165 | .{ .reg = frame_loc.base }, | ||
| 166 | .{ .reg = .zero }, | ||
| 167 | }); | ||
| 168 | }, | ||
| 169 | } | ||
| 130 | }, | 170 | }, |
| 131 | else => unreachable, | 171 | else => unreachable, |
| 132 | } | 172 | } |
| ... | @@ -138,34 +178,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -138,34 +178,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 138 | const dst_class = rr.rd.class(); | 178 | const dst_class = rr.rd.class(); |
| 139 | const src_class = rr.rs.class(); | 179 | const src_class = rr.rs.class(); |
| 140 | 180 | ||
| 141 | assert(dst_class == src_class); | 181 | switch (src_class) { |
| 142 | 182 | .float => switch (dst_class) { | |
| 143 | switch (dst_class) { | 183 | .float => { |
| 144 | .float => { | 184 | try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{ |
| 145 | try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{ | 185 | .{ .reg = rr.rd }, |
| 146 | .{ .reg = rr.rd }, | 186 | .{ .reg = rr.rs }, |
| 147 | .{ .reg = rr.rs }, | 187 | .{ .reg = rr.rs }, |
| 148 | .{ .reg = rr.rs }, | 188 | }); |
| 149 | }); | 189 | }, |
| 190 | .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}), | ||
| 150 | }, | 191 | }, |
| 151 | .int => { | 192 | .int => switch (dst_class) { |
| 152 | try lower.emit(.addi, &.{ | 193 | .int => { |
| 153 | .{ .reg = rr.rd }, | 194 | try lower.emit(.addi, &.{ |
| 154 | .{ .reg = rr.rs }, | 195 | .{ .reg = rr.rd }, |
| 155 | .{ .imm = Immediate.s(0) }, | 196 | .{ .reg = rr.rs }, |
| 156 | }); | 197 | .{ .imm = Immediate.s(0) }, |
| 198 | }); | ||
| 199 | }, | ||
| 200 | .vector => { | ||
| 201 | try lower.emit(.vmvvx, &.{ | ||
| 202 | .{ .reg = rr.rd }, | ||
| 203 | .{ .reg = rr.rs }, | ||
| 204 | .{ .reg = .x0 }, | ||
| 205 | }); | ||
| 206 | }, | ||
| 207 | .float => return lower.fail("TODO: lowerMir pseudo_mv int -> {s}", .{@tagName(dst_class)}), | ||
| 208 | }, | ||
| 209 | .vector => switch (dst_class) { | ||
| 210 | .int => { | ||
| 211 | try lower.emit(.vadcvv, &.{ | ||
| 212 | .{ .reg = rr.rd }, | ||
| 213 | .{ .reg = .zero }, | ||
| 214 | .{ .reg = rr.rs }, | ||
| 215 | }); | ||
| 216 | }, | ||
| 217 | .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}), | ||
| 157 | }, | 218 | }, |
| 158 | } | 219 | } |
| 159 | }, | 220 | }, |
| 160 | 221 | ||
| 161 | .pseudo_ret => { | ||
| 162 | try lower.emit(.jalr, &.{ | ||
| 163 | .{ .reg = .zero }, | ||
| 164 | .{ .reg = .ra }, | ||
| 165 | .{ .imm = Immediate.s(0) }, | ||
| 166 | }); | ||
| 167 | }, | ||
| 168 | |||
| 169 | .pseudo_j => { | 222 | .pseudo_j => { |
| 170 | try lower.emit(.jal, &.{ | 223 | try lower.emit(.jal, &.{ |
| 171 | .{ .reg = .zero }, | 224 | .{ .reg = .zero }, |
| ... | @@ -204,7 +257,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -204,7 +257,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 204 | const rm = inst.data.rm; | 257 | const rm = inst.data.rm; |
| 205 | assert(rm.r.class() == .int); | 258 | assert(rm.r.class() == .int); |
| 206 | 259 | ||
| 207 | const frame = rm.m.toFrameLoc(lower.mir); | 260 | const frame: Mir.FrameLoc = if (options.allow_frame_locs) |
| 261 | rm.m.toFrameLoc(lower.mir) | ||
| 262 | else | ||
| 263 | .{ .base = .s0, .disp = 0 }; | ||
| 208 | 264 | ||
| 209 | try lower.emit(.addi, &.{ | 265 | try lower.emit(.addi, &.{ |
| 210 | .{ .reg = rm.r }, | 266 | .{ .reg = rm.r }, |
| ... | @@ -371,6 +427,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -371,6 +427,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 371 | }); | 427 | }); |
| 372 | }, | 428 | }, |
| 373 | }, | 429 | }, |
| 430 | .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}), | ||
| 374 | } | 431 | } |
| 375 | }, | 432 | }, |
| 376 | 433 | ||
| ... | @@ -378,7 +435,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -378,7 +435,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 378 | const rr = inst.data.rr; | 435 | const rr = inst.data.rr; |
| 379 | assert(rr.rs.class() == .int and rr.rd.class() == .int); | 436 | assert(rr.rs.class() == .int and rr.rd.class() == .int); |
| 380 | 437 | ||
| 381 | try lower.emit(.xori, &.{ | 438 | // mask out any other bits that aren't the boolean |
| 439 | try lower.emit(.andi, &.{ | ||
| 440 | .{ .reg = rr.rs }, | ||
| 441 | .{ .reg = rr.rs }, | ||
| 442 | .{ .imm = Immediate.s(1) }, | ||
| 443 | }); | ||
| 444 | |||
| 445 | try lower.emit(.sltiu, &.{ | ||
| 382 | .{ .reg = rr.rd }, | 446 | .{ .reg = rr.rd }, |
| 383 | .{ .reg = rr.rs }, | 447 | .{ .reg = rr.rs }, |
| 384 | .{ .imm = Immediate.s(1) }, | 448 | .{ .imm = Immediate.s(1) }, |
| ... | @@ -405,6 +469,44 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -405,6 +469,44 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 405 | }); | 469 | }); |
| 406 | }, | 470 | }, |
| 407 | 471 | ||
| 472 | .pseudo_amo => { | ||
| 473 | const amo = inst.data.amo; | ||
| 474 | const is_d = amo.ty.abiSize(pt) == 8; | ||
| 475 | const is_un = amo.ty.isUnsignedInt(pt.zcu); | ||
| 476 | |||
| 477 | const mnem: Encoding.Mnemonic = switch (amo.op) { | ||
| 478 | // zig fmt: off | ||
| 479 | .SWAP => if (is_d) .amoswapd else .amoswapw, | ||
| 480 | .ADD => if (is_d) .amoaddd else .amoaddw, | ||
| 481 | .AND => if (is_d) .amoandd else .amoandw, | ||
| 482 | .OR => if (is_d) .amoord else .amoorw, | ||
| 483 | .XOR => if (is_d) .amoxord else .amoxorw, | ||
| 484 | .MAX => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw, | ||
| 485 | .MIN => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw, | ||
| 486 | // zig fmt: on | ||
| 487 | }; | ||
| 488 | |||
| 489 | try lower.emit(mnem, &.{ | ||
| 490 | .{ .reg = inst.data.amo.rd }, | ||
| 491 | .{ .reg = inst.data.amo.rs1 }, | ||
| 492 | .{ .reg = inst.data.amo.rs2 }, | ||
| 493 | .{ .barrier = inst.data.amo.rl }, | ||
| 494 | .{ .barrier = inst.data.amo.aq }, | ||
| 495 | }); | ||
| 496 | }, | ||
| 497 | |||
| 498 | .pseudo_fence => { | ||
| 499 | const fence = inst.data.fence; | ||
| 500 | |||
| 501 | try lower.emit(switch (fence.fm) { | ||
| 502 | .tso => .fencetso, | ||
| 503 | .none => .fence, | ||
| 504 | }, &.{ | ||
| 505 | .{ .barrier = fence.succ }, | ||
| 506 | .{ .barrier = fence.pred }, | ||
| 507 | }); | ||
| 508 | }, | ||
| 509 | |||
| 408 | else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}), | 510 | else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}), |
| 409 | }, | 511 | }, |
| 410 | } | 512 | } |
| ... | @@ -447,6 +549,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { | ... | @@ -447,6 +549,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 447 | .{ .reg = inst.data.r_type.rs1 }, | 549 | .{ .reg = inst.data.r_type.rs1 }, |
| 448 | .{ .reg = inst.data.r_type.rs2 }, | 550 | .{ .reg = inst.data.r_type.rs2 }, |
| 449 | }, | 551 | }, |
| 552 | .csr => &.{ | ||
| 553 | .{ .csr = inst.data.csr.csr }, | ||
| 554 | .{ .reg = inst.data.csr.rs1 }, | ||
| 555 | .{ .reg = inst.data.csr.rd }, | ||
| 556 | }, | ||
| 450 | else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}), | 557 | else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}), |
| 451 | }); | 558 | }); |
| 452 | } | 559 | } |
| ... | @@ -473,17 +580,22 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register | ... | @@ -473,17 +580,22 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register |
| 473 | while (it.next()) |i| { | 580 | while (it.next()) |i| { |
| 474 | const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame)); | 581 | const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame)); |
| 475 | const reg = abi.Registers.all_preserved[i]; | 582 | const reg = abi.Registers.all_preserved[i]; |
| 583 | |||
| 476 | const reg_class = reg.class(); | 584 | const reg_class = reg.class(); |
| 477 | const is_float_reg = reg_class == .float; | 585 | const load_inst: Encoding.Mnemonic, const store_inst: Encoding.Mnemonic = switch (reg_class) { |
| 586 | .int => .{ .ld, .sd }, | ||
| 587 | .float => .{ .fld, .fsd }, | ||
| 588 | .vector => unreachable, | ||
| 589 | }; | ||
| 478 | 590 | ||
| 479 | if (spilling) { | 591 | if (spilling) { |
| 480 | try lower.emit(if (is_float_reg) .fsd else .sd, &.{ | 592 | try lower.emit(store_inst, &.{ |
| 481 | .{ .reg = frame.base }, | 593 | .{ .reg = frame.base }, |
| 482 | .{ .reg = abi.Registers.all_preserved[i] }, | 594 | .{ .reg = abi.Registers.all_preserved[i] }, |
| 483 | .{ .imm = Immediate.s(frame.disp + reg_i) }, | 595 | .{ .imm = Immediate.s(frame.disp + reg_i) }, |
| 484 | }); | 596 | }); |
| 485 | } else { | 597 | } else { |
| 486 | try lower.emit(if (is_float_reg) .fld else .ld, &.{ | 598 | try lower.emit(load_inst, &.{ |
| 487 | .{ .reg = abi.Registers.all_preserved[i] }, | 599 | .{ .reg = abi.Registers.all_preserved[i] }, |
| 488 | .{ .reg = frame.base }, | 600 | .{ .reg = frame.base }, |
| 489 | .{ .imm = Immediate.s(frame.disp + reg_i) }, | 601 | .{ .imm = Immediate.s(frame.disp + reg_i) }, |
src/arch/riscv64/Mir.zig+70-48| ... | @@ -31,6 +31,7 @@ pub const Inst = struct { | ... | @@ -31,6 +31,7 @@ pub const Inst = struct { |
| 31 | @"and", | 31 | @"and", |
| 32 | andi, | 32 | andi, |
| 33 | 33 | ||
| 34 | xori, | ||
| 34 | xor, | 35 | xor, |
| 35 | @"or", | 36 | @"or", |
| 36 | 37 | ||
| ... | @@ -133,6 +134,19 @@ pub const Inst = struct { | ... | @@ -133,6 +134,19 @@ pub const Inst = struct { |
| 133 | fltd, | 134 | fltd, |
| 134 | fled, | 135 | fled, |
| 135 | 136 | ||
| 137 | // Zicsr Extension Instructions | ||
| 138 | csrrs, | ||
| 139 | |||
| 140 | // V Extension Instructions | ||
| 141 | vsetvli, | ||
| 142 | vsetivli, | ||
| 143 | vsetvl, | ||
| 144 | vaddvv, | ||
| 145 | vfaddvv, | ||
| 146 | vsubvv, | ||
| 147 | vfsubvv, | ||
| 148 | vslidedownvx, | ||
| 149 | |||
| 136 | /// A pseudo-instruction. Used for anything that isn't 1:1 with an | 150 | /// A pseudo-instruction. Used for anything that isn't 1:1 with an |
| 137 | /// assembly instruction. | 151 | /// assembly instruction. |
| 138 | pseudo, | 152 | pseudo, |
| ... | @@ -142,91 +156,57 @@ pub const Inst = struct { | ... | @@ -142,91 +156,57 @@ pub const Inst = struct { |
| 142 | /// this union. `Ops` determines which union field is active, as well as | 156 | /// this union. `Ops` determines which union field is active, as well as |
| 143 | /// how to interpret the data within. | 157 | /// how to interpret the data within. |
| 144 | pub const Data = union { | 158 | pub const Data = union { |
| 145 | /// No additional data | ||
| 146 | /// | ||
| 147 | /// Used by e.g. ebreak | ||
| 148 | nop: void, | 159 | nop: void, |
| 149 | /// Another instruction. | ||
| 150 | /// | ||
| 151 | /// Used by e.g. b | ||
| 152 | inst: Index, | 160 | inst: Index, |
| 153 | /// Index into `extra`. Meaning of what can be found there is context-dependent. | ||
| 154 | /// | ||
| 155 | /// Used by e.g. load_memory | ||
| 156 | payload: u32, | 161 | payload: u32, |
| 157 | |||
| 158 | r_type: struct { | 162 | r_type: struct { |
| 159 | rd: Register, | 163 | rd: Register, |
| 160 | rs1: Register, | 164 | rs1: Register, |
| 161 | rs2: Register, | 165 | rs2: Register, |
| 162 | }, | 166 | }, |
| 163 | |||
| 164 | i_type: struct { | 167 | i_type: struct { |
| 165 | rd: Register, | 168 | rd: Register, |
| 166 | rs1: Register, | 169 | rs1: Register, |
| 167 | imm12: Immediate, | 170 | imm12: Immediate, |
| 168 | }, | 171 | }, |
| 169 | |||
| 170 | s_type: struct { | 172 | s_type: struct { |
| 171 | rs1: Register, | 173 | rs1: Register, |
| 172 | rs2: Register, | 174 | rs2: Register, |
| 173 | imm5: Immediate, | 175 | imm5: Immediate, |
| 174 | imm7: Immediate, | 176 | imm7: Immediate, |
| 175 | }, | 177 | }, |
| 176 | |||
| 177 | b_type: struct { | 178 | b_type: struct { |
| 178 | rs1: Register, | 179 | rs1: Register, |
| 179 | rs2: Register, | 180 | rs2: Register, |
| 180 | inst: Inst.Index, | 181 | inst: Inst.Index, |
| 181 | }, | 182 | }, |
| 182 | |||
| 183 | u_type: struct { | 183 | u_type: struct { |
| 184 | rd: Register, | 184 | rd: Register, |
| 185 | imm20: Immediate, | 185 | imm20: Immediate, |
| 186 | }, | 186 | }, |
| 187 | |||
| 188 | j_type: struct { | 187 | j_type: struct { |
| 189 | rd: Register, | 188 | rd: Register, |
| 190 | inst: Inst.Index, | 189 | inst: Inst.Index, |
| 191 | }, | 190 | }, |
| 192 | |||
| 193 | /// Debug info: line and column | ||
| 194 | /// | ||
| 195 | /// Used by e.g. pseudo_dbg_line | ||
| 196 | pseudo_dbg_line_column: struct { | 191 | pseudo_dbg_line_column: struct { |
| 197 | line: u32, | 192 | line: u32, |
| 198 | column: u32, | 193 | column: u32, |
| 199 | }, | 194 | }, |
| 200 | |||
| 201 | // Custom types to be lowered | ||
| 202 | |||
| 203 | /// Register + Memory | ||
| 204 | rm: struct { | 195 | rm: struct { |
| 205 | r: Register, | 196 | r: Register, |
| 206 | m: Memory, | 197 | m: Memory, |
| 207 | }, | 198 | }, |
| 208 | |||
| 209 | reg_list: Mir.RegisterList, | 199 | reg_list: Mir.RegisterList, |
| 210 | |||
| 211 | /// A register | ||
| 212 | /// | ||
| 213 | /// Used by e.g. blr | ||
| 214 | reg: Register, | 200 | reg: Register, |
| 215 | |||
| 216 | /// Two registers | ||
| 217 | /// | ||
| 218 | /// Used by e.g. mv | ||
| 219 | rr: struct { | 201 | rr: struct { |
| 220 | rd: Register, | 202 | rd: Register, |
| 221 | rs: Register, | 203 | rs: Register, |
| 222 | }, | 204 | }, |
| 223 | |||
| 224 | fabs: struct { | 205 | fabs: struct { |
| 225 | rd: Register, | 206 | rd: Register, |
| 226 | rs: Register, | 207 | rs: Register, |
| 227 | bits: u16, | 208 | bits: u16, |
| 228 | }, | 209 | }, |
| 229 | |||
| 230 | compare: struct { | 210 | compare: struct { |
| 231 | rd: Register, | 211 | rd: Register, |
| 232 | rs1: Register, | 212 | rs1: Register, |
| ... | @@ -241,11 +221,32 @@ pub const Inst = struct { | ... | @@ -241,11 +221,32 @@ pub const Inst = struct { |
| 241 | }, | 221 | }, |
| 242 | ty: Type, | 222 | ty: Type, |
| 243 | }, | 223 | }, |
| 244 | |||
| 245 | reloc: struct { | 224 | reloc: struct { |
| 246 | atom_index: u32, | 225 | atom_index: u32, |
| 247 | sym_index: u32, | 226 | sym_index: u32, |
| 248 | }, | 227 | }, |
| 228 | fence: struct { | ||
| 229 | pred: Barrier, | ||
| 230 | succ: Barrier, | ||
| 231 | fm: enum { | ||
| 232 | none, | ||
| 233 | tso, | ||
| 234 | }, | ||
| 235 | }, | ||
| 236 | amo: struct { | ||
| 237 | rd: Register, | ||
| 238 | rs1: Register, | ||
| 239 | rs2: Register, | ||
| 240 | aq: Barrier, | ||
| 241 | rl: Barrier, | ||
| 242 | op: AmoOp, | ||
| 243 | ty: Type, | ||
| 244 | }, | ||
| 245 | csr: struct { | ||
| 246 | csr: CSR, | ||
| 247 | rs1: Register, | ||
| 248 | rd: Register, | ||
| 249 | }, | ||
| 249 | }; | 250 | }; |
| 250 | 251 | ||
| 251 | pub const Ops = enum { | 252 | pub const Ops = enum { |
| ... | @@ -270,6 +271,9 @@ pub const Inst = struct { | ... | @@ -270,6 +271,9 @@ pub const Inst = struct { |
| 270 | /// Another instruction. | 271 | /// Another instruction. |
| 271 | inst, | 272 | inst, |
| 272 | 273 | ||
| 274 | /// Control and Status Register Instruction. | ||
| 275 | csr, | ||
| 276 | |||
| 273 | /// Pseudo-instruction that will generate a backpatched | 277 | /// Pseudo-instruction that will generate a backpatched |
| 274 | /// function prologue. | 278 | /// function prologue. |
| 275 | pseudo_prologue, | 279 | pseudo_prologue, |
| ... | @@ -298,11 +302,6 @@ pub const Inst = struct { | ... | @@ -298,11 +302,6 @@ pub const Inst = struct { |
| 298 | /// Uses `rm` payload. | 302 | /// Uses `rm` payload. |
| 299 | pseudo_lea_rm, | 303 | pseudo_lea_rm, |
| 300 | 304 | ||
| 301 | /// Shorthand for returning, aka jumping to ra register. | ||
| 302 | /// | ||
| 303 | /// Uses nop payload. | ||
| 304 | pseudo_ret, | ||
| 305 | |||
| 306 | /// Jumps. Uses `inst` payload. | 305 | /// Jumps. Uses `inst` payload. |
| 307 | pseudo_j, | 306 | pseudo_j, |
| 308 | 307 | ||
| ... | @@ -326,19 +325,19 @@ pub const Inst = struct { | ... | @@ -326,19 +325,19 @@ pub const Inst = struct { |
| 326 | pseudo_spill_regs, | 325 | pseudo_spill_regs, |
| 327 | 326 | ||
| 328 | pseudo_compare, | 327 | pseudo_compare, |
| 328 | |||
| 329 | /// NOT operation on booleans. Does an `andi reg, reg, 1` to mask out any other bits from the boolean. | ||
| 329 | pseudo_not, | 330 | pseudo_not, |
| 330 | 331 | ||
| 331 | /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc | 332 | /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc |
| 332 | pseudo_extern_fn_reloc, | 333 | pseudo_extern_fn_reloc, |
| 333 | }; | ||
| 334 | 334 | ||
| 335 | // Make sure we don't accidentally make instructions bigger than expected. | 335 | /// IORW, IORW |
| 336 | // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks. | 336 | pseudo_fence, |
| 337 | // comptime { | 337 | |
| 338 | // if (builtin.mode != .Debug) { | 338 | /// Ordering, Src, Addr, Dest |
| 339 | // assert(@sizeOf(Inst) == 8); | 339 | pseudo_amo, |
| 340 | // } | 340 | }; |
| 341 | // } | ||
| 342 | 341 | ||
| 343 | pub fn format( | 342 | pub fn format( |
| 344 | inst: Inst, | 343 | inst: Inst, |
| ... | @@ -365,6 +364,28 @@ pub const FrameLoc = struct { | ... | @@ -365,6 +364,28 @@ pub const FrameLoc = struct { |
| 365 | disp: i32, | 364 | disp: i32, |
| 366 | }; | 365 | }; |
| 367 | 366 | ||
| 367 | pub const Barrier = enum(u4) { | ||
| 368 | // Fence | ||
| 369 | w = 0b0001, | ||
| 370 | r = 0b0010, | ||
| 371 | rw = 0b0011, | ||
| 372 | |||
| 373 | // Amo | ||
| 374 | none, | ||
| 375 | aq, | ||
| 376 | rl, | ||
| 377 | }; | ||
| 378 | |||
| 379 | pub const AmoOp = enum(u5) { | ||
| 380 | SWAP, | ||
| 381 | ADD, | ||
| 382 | AND, | ||
| 383 | OR, | ||
| 384 | XOR, | ||
| 385 | MAX, | ||
| 386 | MIN, | ||
| 387 | }; | ||
| 388 | |||
| 368 | /// Returns the requested data, as well as the new index which is at the start of the | 389 | /// Returns the requested data, as well as the new index which is at the start of the |
| 369 | /// trailers for the object. | 390 | /// trailers for the object. |
| 370 | pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } { | 391 | pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } { |
| ... | @@ -437,6 +458,7 @@ const assert = std.debug.assert; | ... | @@ -437,6 +458,7 @@ const assert = std.debug.assert; |
| 437 | 458 | ||
| 438 | const bits = @import("bits.zig"); | 459 | const bits = @import("bits.zig"); |
| 439 | const Register = bits.Register; | 460 | const Register = bits.Register; |
| 461 | const CSR = bits.CSR; | ||
| 440 | const Immediate = bits.Immediate; | 462 | const Immediate = bits.Immediate; |
| 441 | const Memory = bits.Memory; | 463 | const Memory = bits.Memory; |
| 442 | const FrameIndex = bits.FrameIndex; | 464 | const FrameIndex = bits.FrameIndex; |
src/arch/riscv64/abi.zig+24-2| ... | @@ -193,6 +193,15 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass { | ... | @@ -193,6 +193,15 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass { |
| 193 | } | 193 | } |
| 194 | return memory_class; | 194 | return memory_class; |
| 195 | }, | 195 | }, |
| 196 | .Vector => { | ||
| 197 | // we pass vectors through integer registers if they are small enough to fit. | ||
| 198 | const vec_bits = ty.totalVectorBits(pt); | ||
| 199 | if (vec_bits <= 64) { | ||
| 200 | result[0] = .integer; | ||
| 201 | return result; | ||
| 202 | } | ||
| 203 | return memory_class; | ||
| 204 | }, | ||
| 196 | else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}), | 205 | else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}), |
| 197 | } | 206 | } |
| 198 | } | 207 | } |
| ... | @@ -254,15 +263,15 @@ fn classifyStruct( | ... | @@ -254,15 +263,15 @@ fn classifyStruct( |
| 254 | } | 263 | } |
| 255 | } | 264 | } |
| 256 | 265 | ||
| 257 | const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs; | 266 | const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs ++ Registers.Vector.all_regs; |
| 258 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); | 267 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); |
| 259 | 268 | ||
| 260 | // Register classes | ||
| 261 | const RegisterBitSet = RegisterManager.RegisterBitSet; | 269 | const RegisterBitSet = RegisterManager.RegisterBitSet; |
| 262 | 270 | ||
| 263 | pub const RegisterClass = enum { | 271 | pub const RegisterClass = enum { |
| 264 | int, | 272 | int, |
| 265 | float, | 273 | float, |
| 274 | vector, | ||
| 266 | }; | 275 | }; |
| 267 | 276 | ||
| 268 | pub const Registers = struct { | 277 | pub const Registers = struct { |
| ... | @@ -322,6 +331,19 @@ pub const Registers = struct { | ... | @@ -322,6 +331,19 @@ pub const Registers = struct { |
| 322 | 331 | ||
| 323 | pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs; | 332 | pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs; |
| 324 | }; | 333 | }; |
| 334 | |||
| 335 | pub const Vector = struct { | ||
| 336 | pub const general_purpose = initRegBitSet(Integer.all_regs.len + Float.all_regs.len, all_regs.len); | ||
| 337 | |||
| 338 | // zig fmt: off | ||
| 339 | pub const all_regs = [_]Register{ | ||
| 340 | .v0, .v1, .v2, .v3, .v4, .v5, .v6, .v7, | ||
| 341 | .v8, .v9, .v10, .v11, .v12, .v13, .v14, .v15, | ||
| 342 | .v16, .v17, .v18, .v19, .v20, .v21, .v22, .v23, | ||
| 343 | .v24, .v25, .v26, .v27, .v28, .v29, .v30, .v31, | ||
| 344 | }; | ||
| 345 | // zig fmt: on | ||
| 346 | }; | ||
| 325 | }; | 347 | }; |
| 326 | 348 | ||
| 327 | fn initRegBitSet(start: usize, length: usize) RegisterBitSet { | 349 | fn initRegBitSet(start: usize, length: usize) RegisterBitSet { |
src/arch/riscv64/bits.zig+42-2| ... | @@ -41,7 +41,7 @@ pub const Memory = struct { | ... | @@ -41,7 +41,7 @@ pub const Memory = struct { |
| 41 | 2...2 => .hword, | 41 | 2...2 => .hword, |
| 42 | 3...4 => .word, | 42 | 3...4 => .word, |
| 43 | 5...8 => .dword, | 43 | 5...8 => .dword, |
| 44 | else => unreachable, | 44 | else => std.debug.panic("fromByteSize {}", .{size}), |
| 45 | }; | 45 | }; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| ... | @@ -128,6 +128,12 @@ pub const Immediate = union(enum) { | ... | @@ -128,6 +128,12 @@ pub const Immediate = union(enum) { |
| 128 | } | 128 | } |
| 129 | }; | 129 | }; |
| 130 | 130 | ||
| 131 | pub const CSR = enum(u12) { | ||
| 132 | vl = 0xC20, | ||
| 133 | vtype = 0xC21, | ||
| 134 | vlenb = 0xC22, | ||
| 135 | }; | ||
| 136 | |||
| 131 | pub const Register = enum(u8) { | 137 | pub const Register = enum(u8) { |
| 132 | // zig fmt: off | 138 | // zig fmt: off |
| 133 | 139 | ||
| ... | @@ -169,6 +175,13 @@ pub const Register = enum(u8) { | ... | @@ -169,6 +175,13 @@ pub const Register = enum(u8) { |
| 169 | f16, f17, f18, f19, f20, f21, f22, f23, | 175 | f16, f17, f18, f19, f20, f21, f22, f23, |
| 170 | f24, f25, f26, f27, f28, f29, f30, f31, | 176 | f24, f25, f26, f27, f28, f29, f30, f31, |
| 171 | 177 | ||
| 178 | |||
| 179 | // V extension registers | ||
| 180 | v0, v1, v2, v3, v4, v5, v6, v7, | ||
| 181 | v8, v9, v10, v11, v12, v13, v14, v15, | ||
| 182 | v16, v17, v18, v19, v20, v21, v22, v23, | ||
| 183 | v24, v25, v26, v27, v28, v29, v30, v31, | ||
| 184 | |||
| 172 | // zig fmt: on | 185 | // zig fmt: on |
| 173 | 186 | ||
| 174 | /// in RISC-V registers are stored as 5 bit IDs and a register can have | 187 | /// in RISC-V registers are stored as 5 bit IDs and a register can have |
| ... | @@ -180,11 +193,12 @@ pub const Register = enum(u8) { | ... | @@ -180,11 +193,12 @@ pub const Register = enum(u8) { |
| 180 | /// The goal of this function is to return the same ID for `zero` and `x0` but two | 193 | /// The goal of this function is to return the same ID for `zero` and `x0` but two |
| 181 | /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers | 194 | /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers |
| 182 | /// and is repeated twice, once for the named version, once for the number version. | 195 | /// and is repeated twice, once for the named version, once for the number version. |
| 183 | pub fn id(reg: Register) u7 { | 196 | pub fn id(reg: Register) u8 { |
| 184 | const base = switch (@intFromEnum(reg)) { | 197 | const base = switch (@intFromEnum(reg)) { |
| 185 | // zig fmt: off | 198 | // zig fmt: off |
| 186 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero), | 199 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero), |
| 187 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0), | 200 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0), |
| 201 | @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => @intFromEnum(Register.v0), | ||
| 188 | else => unreachable, | 202 | else => unreachable, |
| 189 | // zig fmt: on | 203 | // zig fmt: on |
| 190 | }; | 204 | }; |
| ... | @@ -207,6 +221,7 @@ pub const Register = enum(u8) { | ... | @@ -207,6 +221,7 @@ pub const Register = enum(u8) { |
| 207 | // zig fmt: off | 221 | // zig fmt: off |
| 208 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64, | 222 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64, |
| 209 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32, | 223 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32, |
| 224 | @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => 256, // TODO: look at suggestVectorSize | ||
| 210 | else => unreachable, | 225 | else => unreachable, |
| 211 | // zig fmt: on | 226 | // zig fmt: on |
| 212 | }; | 227 | }; |
| ... | @@ -217,6 +232,7 @@ pub const Register = enum(u8) { | ... | @@ -217,6 +232,7 @@ pub const Register = enum(u8) { |
| 217 | // zig fmt: off | 232 | // zig fmt: off |
| 218 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int, | 233 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int, |
| 219 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float, | 234 | @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float, |
| 235 | @intFromEnum(Register.v0) ... @intFromEnum(Register.v31) => .vector, | ||
| 220 | else => unreachable, | 236 | else => unreachable, |
| 221 | // zig fmt: on | 237 | // zig fmt: on |
| 222 | }; | 238 | }; |
| ... | @@ -272,3 +288,27 @@ pub const Symbol = struct { | ... | @@ -272,3 +288,27 @@ pub const Symbol = struct { |
| 272 | /// Index into the linker's symbol table. | 288 | /// Index into the linker's symbol table. |
| 273 | sym_index: u32, | 289 | sym_index: u32, |
| 274 | }; | 290 | }; |
| 291 | |||
| 292 | pub const VType = packed struct(u8) { | ||
| 293 | vlmul: VlMul, | ||
| 294 | vsew: VSew, | ||
| 295 | vta: bool, | ||
| 296 | vma: bool, | ||
| 297 | }; | ||
| 298 | |||
| 299 | const VSew = enum(u3) { | ||
| 300 | @"8" = 0b000, | ||
| 301 | @"16" = 0b001, | ||
| 302 | @"32" = 0b010, | ||
| 303 | @"64" = 0b011, | ||
| 304 | }; | ||
| 305 | |||
| 306 | const VlMul = enum(u3) { | ||
| 307 | mf8 = 0b101, | ||
| 308 | mf4 = 0b110, | ||
| 309 | mf2 = 0b111, | ||
| 310 | m1 = 0b000, | ||
| 311 | m2 = 0b001, | ||
| 312 | m4 = 0b010, | ||
| 313 | m8 = 0b011, | ||
| 314 | }; |
src/arch/riscv64/encoder.zig+11-4| ... | @@ -1,26 +1,30 @@ | ... | @@ -1,26 +1,30 @@ |
| 1 | pub const Instruction = struct { | 1 | pub const Instruction = struct { |
| 2 | encoding: Encoding, | 2 | encoding: Encoding, |
| 3 | ops: [3]Operand = .{.none} ** 3, | 3 | ops: [5]Operand = .{.none} ** 5, |
| 4 | 4 | ||
| 5 | pub const Operand = union(enum) { | 5 | pub const Operand = union(enum) { |
| 6 | none, | 6 | none, |
| 7 | reg: Register, | 7 | reg: Register, |
| 8 | csr: CSR, | ||
| 8 | mem: Memory, | 9 | mem: Memory, |
| 9 | imm: Immediate, | 10 | imm: Immediate, |
| 11 | barrier: Mir.Barrier, | ||
| 10 | }; | 12 | }; |
| 11 | 13 | ||
| 12 | pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction { | 14 | pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction { |
| 13 | const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse { | 15 | const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse { |
| 14 | std.log.err("no encoding found for: {s} [{s} {s} {s}]", .{ | 16 | std.log.err("no encoding found for: {s} [{s} {s} {s} {s} {s}]", .{ |
| 15 | @tagName(mnemonic), | 17 | @tagName(mnemonic), |
| 16 | @tagName(if (ops.len > 0) ops[0] else .none), | 18 | @tagName(if (ops.len > 0) ops[0] else .none), |
| 17 | @tagName(if (ops.len > 1) ops[1] else .none), | 19 | @tagName(if (ops.len > 1) ops[1] else .none), |
| 18 | @tagName(if (ops.len > 2) ops[2] else .none), | 20 | @tagName(if (ops.len > 2) ops[2] else .none), |
| 21 | @tagName(if (ops.len > 3) ops[3] else .none), | ||
| 22 | @tagName(if (ops.len > 4) ops[4] else .none), | ||
| 19 | }); | 23 | }); |
| 20 | return error.InvalidInstruction; | 24 | return error.InvalidInstruction; |
| 21 | }; | 25 | }; |
| 22 | 26 | ||
| 23 | var result_ops: [3]Operand = .{.none} ** 3; | 27 | var result_ops: [5]Operand = .{.none} ** 5; |
| 24 | @memcpy(result_ops[0..ops.len], ops); | 28 | @memcpy(result_ops[0..ops.len], ops); |
| 25 | 29 | ||
| 26 | return .{ | 30 | return .{ |
| ... | @@ -53,7 +57,9 @@ pub const Instruction = struct { | ... | @@ -53,7 +57,9 @@ pub const Instruction = struct { |
| 53 | .none => unreachable, // it's sliced out above | 57 | .none => unreachable, // it's sliced out above |
| 54 | .reg => |reg| try writer.writeAll(@tagName(reg)), | 58 | .reg => |reg| try writer.writeAll(@tagName(reg)), |
| 55 | .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}), | 59 | .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}), |
| 56 | .mem => unreachable, // there is no "mem" operand in the actual instructions | 60 | .mem => try writer.writeAll("mem"), |
| 61 | .barrier => |barrier| try writer.writeAll(@tagName(barrier)), | ||
| 62 | .csr => |csr| try writer.writeAll(@tagName(csr)), | ||
| 57 | } | 63 | } |
| 58 | } | 64 | } |
| 59 | } | 65 | } |
| ... | @@ -67,6 +73,7 @@ const bits = @import("bits.zig"); | ... | @@ -67,6 +73,7 @@ const bits = @import("bits.zig"); |
| 67 | const Encoding = @import("Encoding.zig"); | 73 | const Encoding = @import("Encoding.zig"); |
| 68 | 74 | ||
| 69 | const Register = bits.Register; | 75 | const Register = bits.Register; |
| 76 | const CSR = bits.CSR; | ||
| 70 | const Memory = bits.Memory; | 77 | const Memory = bits.Memory; |
| 71 | const Immediate = bits.Immediate; | 78 | const Immediate = bits.Immediate; |
| 72 | 79 |
src/arch/x86_64/Lower.zig+2| ... | @@ -65,6 +65,8 @@ pub const Reloc = struct { | ... | @@ -65,6 +65,8 @@ pub const Reloc = struct { |
| 65 | }; | 65 | }; |
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | const Options = struct { allow_frame_locs: bool }; | ||
| 69 | |||
| 68 | /// The returned slice is overwritten by the next call to lowerMir. | 70 | /// The returned slice is overwritten by the next call to lowerMir. |
| 69 | pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | 71 | pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 70 | insts: []const Instruction, | 72 | insts: []const Instruction, |
src/codegen.zig+2-1| ... | @@ -987,8 +987,9 @@ pub fn genTypedValue( | ... | @@ -987,8 +987,9 @@ pub fn genTypedValue( |
| 987 | 987 | ||
| 988 | log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)}); | 988 | log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)}); |
| 989 | 989 | ||
| 990 | if (val.isUndef(zcu)) | 990 | if (val.isUndef(zcu)) { |
| 991 | return GenResult.mcv(.undef); | 991 | return GenResult.mcv(.undef); |
| 992 | } | ||
| 992 | 993 | ||
| 993 | const owner_decl = zcu.declPtr(owner_decl_index); | 994 | const owner_decl = zcu.declPtr(owner_decl_index); |
| 994 | const namespace = zcu.namespacePtr(owner_decl.src_namespace); | 995 | const namespace = zcu.namespacePtr(owner_decl.src_namespace); |
src/link/Elf/ZigObject.zig+11-7| ... | @@ -540,8 +540,8 @@ inline fn isGlobal(index: Symbol.Index) bool { | ... | @@ -540,8 +540,8 @@ inline fn isGlobal(index: Symbol.Index) bool { |
| 540 | 540 | ||
| 541 | pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index { | 541 | pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index { |
| 542 | const actual_index = index & symbol_mask; | 542 | const actual_index = index & symbol_mask; |
| 543 | if (isGlobal(index)) return self.global_symbols.items[actual_index]; | 543 | if (isGlobal(index)) return self.globals()[actual_index]; |
| 544 | return self.local_symbols.items[actual_index]; | 544 | return self.locals()[actual_index]; |
| 545 | } | 545 | } |
| 546 | 546 | ||
| 547 | pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym { | 547 | pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym { |
| ... | @@ -1334,11 +1334,15 @@ fn lowerConst( | ... | @@ -1334,11 +1334,15 @@ fn lowerConst( |
| 1334 | 1334 | ||
| 1335 | const sym_index = try self.addAtom(elf_file); | 1335 | const sym_index = try self.addAtom(elf_file); |
| 1336 | 1336 | ||
| 1337 | const res = try codegen.generateSymbol(&elf_file.base, pt, src_loc, val, &code_buffer, .{ | 1337 | const res = try codegen.generateSymbol( |
| 1338 | .none = {}, | 1338 | &elf_file.base, |
| 1339 | }, .{ | 1339 | pt, |
| 1340 | .parent_atom_index = sym_index, | 1340 | src_loc, |
| 1341 | }); | 1341 | val, |
| 1342 | &code_buffer, | ||
| 1343 | .{ .none = {} }, | ||
| 1344 | .{ .parent_atom_index = sym_index }, | ||
| 1345 | ); | ||
| 1342 | const code = switch (res) { | 1346 | const code = switch (res) { |
| 1343 | .ok => code_buffer.items, | 1347 | .ok => code_buffer.items, |
| 1344 | .fail => |em| return .{ .fail = em }, | 1348 | .fail => |em| return .{ .fail = em }, |
test/behavior/array.zig-2| ... | @@ -580,7 +580,6 @@ test "type coercion of anon struct literal to array" { | ... | @@ -580,7 +580,6 @@ test "type coercion of anon struct literal to array" { |
| 580 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 580 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 581 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 581 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 582 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 582 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 583 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 584 | 583 | ||
| 585 | const S = struct { | 584 | const S = struct { |
| 586 | const U = union { | 585 | const U = union { |
| ... | @@ -1011,7 +1010,6 @@ test "union that needs padding bytes inside an array" { | ... | @@ -1011,7 +1010,6 @@ test "union that needs padding bytes inside an array" { |
| 1011 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1010 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1012 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 1011 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1013 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1012 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1014 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1015 | 1013 | ||
| 1016 | const B = union(enum) { | 1014 | const B = union(enum) { |
| 1017 | D: u8, | 1015 | D: u8, |
test/behavior/atomics.zig-17| ... | @@ -42,7 +42,6 @@ test "fence" { | ... | @@ -42,7 +42,6 @@ test "fence" { |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 43 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 43 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 44 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 44 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 45 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 46 | 45 | ||
| 47 | var x: i32 = 1234; | 46 | var x: i32 = 1234; |
| 48 | @fence(.seq_cst); | 47 | @fence(.seq_cst); |
| ... | @@ -188,21 +187,6 @@ test "atomic store" { | ... | @@ -188,21 +187,6 @@ test "atomic store" { |
| 188 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 187 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 189 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 188 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 190 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 189 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 191 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 192 | |||
| 193 | var x: u32 = 0; | ||
| 194 | @atomicStore(u32, &x, 1, .seq_cst); | ||
| 195 | try expect(@atomicLoad(u32, &x, .seq_cst) == 1); | ||
| 196 | @atomicStore(u32, &x, 12345678, .seq_cst); | ||
| 197 | try expect(@atomicLoad(u32, &x, .seq_cst) == 12345678); | ||
| 198 | } | ||
| 199 | |||
| 200 | test "atomic store comptime" { | ||
| 201 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 202 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 203 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 204 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 205 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 206 | 190 | ||
| 207 | try comptime testAtomicStore(); | 191 | try comptime testAtomicStore(); |
| 208 | try testAtomicStore(); | 192 | try testAtomicStore(); |
| ... | @@ -451,7 +435,6 @@ test "return @atomicStore, using it as a void value" { | ... | @@ -451,7 +435,6 @@ test "return @atomicStore, using it as a void value" { |
| 451 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 435 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 452 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 436 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 453 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 437 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 454 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 455 | 438 | ||
| 456 | const S = struct { | 439 | const S = struct { |
| 457 | const A = struct { | 440 | const A = struct { |
test/behavior/bitcast.zig-2| ... | @@ -192,7 +192,6 @@ test "@bitCast packed structs at runtime and comptime" { | ... | @@ -192,7 +192,6 @@ test "@bitCast packed structs at runtime and comptime" { |
| 192 | test "@bitCast extern structs at runtime and comptime" { | 192 | test "@bitCast extern structs at runtime and comptime" { |
| 193 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 193 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 194 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 194 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 195 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 196 | 195 | ||
| 197 | const Full = extern struct { | 196 | const Full = extern struct { |
| 198 | number: u16, | 197 | number: u16, |
| ... | @@ -227,7 +226,6 @@ test "bitcast packed struct to integer and back" { | ... | @@ -227,7 +226,6 @@ test "bitcast packed struct to integer and back" { |
| 227 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 226 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 228 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 227 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 229 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 228 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 230 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 231 | 229 | ||
| 232 | const LevelUpMove = packed struct { | 230 | const LevelUpMove = packed struct { |
| 233 | move_id: u9, | 231 | move_id: u9, |
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1| ... | @@ -11,7 +11,6 @@ test { | ... | @@ -11,7 +11,6 @@ test { |
| 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 12 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 12 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 13 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 13 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 14 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 15 | 14 | ||
| 16 | var val: u8 = undefined; | 15 | var val: u8 = undefined; |
| 17 | try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered)); | 16 | try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered)); |
test/behavior/enum.zig-1| ... | @@ -908,7 +908,6 @@ test "enum literal casting to tagged union" { | ... | @@ -908,7 +908,6 @@ test "enum literal casting to tagged union" { |
| 908 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 908 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 909 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 909 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 910 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 910 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 911 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 912 | 911 | ||
| 913 | const Arch = union(enum) { | 912 | const Arch = union(enum) { |
| 914 | x86_64, | 913 | x86_64, |
test/behavior/error.zig-1| ... | @@ -535,7 +535,6 @@ test "return result loc as peer result loc in inferred error set function" { | ... | @@ -535,7 +535,6 @@ test "return result loc as peer result loc in inferred error set function" { |
| 535 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 535 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 536 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 536 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 538 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 539 | 538 | ||
| 540 | const S = struct { | 539 | const S = struct { |
| 541 | fn doTheTest() !void { | 540 | fn doTheTest() !void { |
test/behavior/eval.zig-2| ... | @@ -395,7 +395,6 @@ test "return 0 from function that has u0 return type" { | ... | @@ -395,7 +395,6 @@ test "return 0 from function that has u0 return type" { |
| 395 | test "statically initialized struct" { | 395 | test "statically initialized struct" { |
| 396 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 396 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 397 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 397 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 398 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 399 | 398 | ||
| 400 | st_init_str_foo.x += 1; | 399 | st_init_str_foo.x += 1; |
| 401 | try expect(st_init_str_foo.x == 14); | 400 | try expect(st_init_str_foo.x == 14); |
| ... | @@ -446,7 +445,6 @@ test "binary math operator in partially inlined function" { | ... | @@ -446,7 +445,6 @@ test "binary math operator in partially inlined function" { |
| 446 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 445 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 447 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 446 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 448 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 447 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 449 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 450 | 448 | ||
| 451 | var s: [4]u32 = undefined; | 449 | var s: [4]u32 = undefined; |
| 452 | var b: [16]u8 = undefined; | 450 | var b: [16]u8 = undefined; |
test/behavior/floatop.zig-1| ... | @@ -281,7 +281,6 @@ test "@sqrt f32/f64" { | ... | @@ -281,7 +281,6 @@ test "@sqrt f32/f64" { |
| 281 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 281 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 282 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 282 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 283 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 283 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 284 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 285 | 284 | ||
| 286 | try testSqrt(f32); | 285 | try testSqrt(f32); |
| 287 | try comptime testSqrt(f32); | 286 | try comptime testSqrt(f32); |
test/behavior/inline_switch.zig-1| ... | @@ -49,7 +49,6 @@ test "inline switch unions" { | ... | @@ -49,7 +49,6 @@ test "inline switch unions" { |
| 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 50 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 50 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 51 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 51 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 52 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 53 | 52 | ||
| 54 | var x: U = .a; | 53 | var x: U = .a; |
| 55 | _ = &x; | 54 | _ = &x; |
test/behavior/math.zig-1| ... | @@ -1269,7 +1269,6 @@ test "@subWithOverflow" { | ... | @@ -1269,7 +1269,6 @@ test "@subWithOverflow" { |
| 1269 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1269 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1270 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1270 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1271 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1271 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1272 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1273 | 1272 | ||
| 1274 | { | 1273 | { |
| 1275 | var a: u8 = 1; | 1274 | var a: u8 = 1; |
test/behavior/optional.zig-1| ... | @@ -397,7 +397,6 @@ test "array of optional unaligned types" { | ... | @@ -397,7 +397,6 @@ test "array of optional unaligned types" { |
| 397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 398 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 398 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 399 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 399 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 400 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 401 | 400 | ||
| 402 | const Enum = enum { one, two, three }; | 401 | const Enum = enum { one, two, three }; |
| 403 | 402 |
test/behavior/packed-struct.zig-1| ... | @@ -785,7 +785,6 @@ test "nested packed struct field access test" { | ... | @@ -785,7 +785,6 @@ test "nested packed struct field access test" { |
| 785 | test "nested packed struct at non-zero offset" { | 785 | test "nested packed struct at non-zero offset" { |
| 786 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 786 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 787 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 787 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 788 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 789 | 788 | ||
| 790 | const Pair = packed struct(u24) { | 789 | const Pair = packed struct(u24) { |
| 791 | a: u16 = 0, | 790 | a: u16 = 0, |
test/behavior/reflection.zig-1| ... | @@ -28,7 +28,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 { | ... | @@ -28,7 +28,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 { |
| 28 | test "reflection: @field" { | 28 | test "reflection: @field" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 30 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 30 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 32 | 31 | ||
| 33 | var f = Foo{ | 32 | var f = Foo{ |
| 34 | .one = 42, | 33 | .one = 42, |
test/behavior/struct.zig-3| ... | @@ -875,7 +875,6 @@ test "packed struct field passed to generic function" { | ... | @@ -875,7 +875,6 @@ test "packed struct field passed to generic function" { |
| 875 | test "anonymous struct literal syntax" { | 875 | test "anonymous struct literal syntax" { |
| 876 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 876 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 877 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 877 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 878 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 879 | 878 | ||
| 880 | const S = struct { | 879 | const S = struct { |
| 881 | const Point = struct { | 880 | const Point = struct { |
| ... | @@ -985,7 +984,6 @@ test "struct with union field" { | ... | @@ -985,7 +984,6 @@ test "struct with union field" { |
| 985 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 984 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 986 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 985 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 987 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 986 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 988 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 989 | 987 | ||
| 990 | const Value = struct { | 988 | const Value = struct { |
| 991 | ref: u32 = 2, | 989 | ref: u32 = 2, |
| ... | @@ -1368,7 +1366,6 @@ test "store to comptime field" { | ... | @@ -1368,7 +1366,6 @@ test "store to comptime field" { |
| 1368 | test "struct field init value is size of the struct" { | 1366 | test "struct field init value is size of the struct" { |
| 1369 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1370 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1368 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1371 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1372 | 1369 | ||
| 1373 | const namespace = struct { | 1370 | const namespace = struct { |
| 1374 | const S = extern struct { | 1371 | const S = extern struct { |
test/behavior/switch.zig-2| ... | @@ -256,7 +256,6 @@ test "switch on enum using pointer capture" { | ... | @@ -256,7 +256,6 @@ test "switch on enum using pointer capture" { |
| 256 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 256 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 257 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 257 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 258 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 258 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 259 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 260 | 259 | ||
| 261 | try testSwitchEnumPtrCapture(); | 260 | try testSwitchEnumPtrCapture(); |
| 262 | try comptime testSwitchEnumPtrCapture(); | 261 | try comptime testSwitchEnumPtrCapture(); |
| ... | @@ -693,7 +692,6 @@ test "switch capture copies its payload" { | ... | @@ -693,7 +692,6 @@ test "switch capture copies its payload" { |
| 693 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 692 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 694 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 693 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 695 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 694 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 696 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 697 | 695 | ||
| 698 | const S = struct { | 696 | const S = struct { |
| 699 | fn doTheTest() !void { | 697 | fn doTheTest() !void { |
test/behavior/this.zig-1| ... | @@ -27,7 +27,6 @@ test "this refer to module call private fn" { | ... | @@ -27,7 +27,6 @@ test "this refer to module call private fn" { |
| 27 | test "this refer to container" { | 27 | test "this refer to container" { |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 29 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 29 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 30 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 31 | 30 | ||
| 32 | var pt: Point(i32) = undefined; | 31 | var pt: Point(i32) = undefined; |
| 33 | pt.x = 12; | 32 | pt.x = 12; |
test/behavior/tuple.zig-1| ... | @@ -131,7 +131,6 @@ test "tuple initializer for var" { | ... | @@ -131,7 +131,6 @@ test "tuple initializer for var" { |
| 131 | test "array-like initializer for tuple types" { | 131 | test "array-like initializer for tuple types" { |
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 133 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 133 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 134 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 135 | 134 | ||
| 136 | const T = @Type(.{ | 135 | const T = @Type(.{ |
| 137 | .Struct = .{ | 136 | .Struct = .{ |
test/behavior/type.zig-1| ... | @@ -383,7 +383,6 @@ test "Type.Union" { | ... | @@ -383,7 +383,6 @@ test "Type.Union" { |
| 383 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 383 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 384 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 384 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 385 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 385 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 386 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 387 | 386 | ||
| 388 | const Untagged = @Type(.{ | 387 | const Untagged = @Type(.{ |
| 389 | .Union = .{ | 388 | .Union = .{ |
test/behavior/union.zig-23| ... | @@ -43,7 +43,6 @@ test "basic unions" { | ... | @@ -43,7 +43,6 @@ test "basic unions" { |
| 43 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 43 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 44 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 44 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 45 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 45 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 46 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 47 | 46 | ||
| 48 | var foo = Foo{ .int = 1 }; | 47 | var foo = Foo{ .int = 1 }; |
| 49 | try expect(foo.int == 1); | 48 | try expect(foo.int == 1); |
| ... | @@ -276,7 +275,6 @@ test "comparison between union and enum literal" { | ... | @@ -276,7 +275,6 @@ test "comparison between union and enum literal" { |
| 276 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 275 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 277 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 278 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 279 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 280 | 278 | ||
| 281 | try testComparison(); | 279 | try testComparison(); |
| 282 | try comptime testComparison(); | 280 | try comptime testComparison(); |
| ... | @@ -292,7 +290,6 @@ test "cast union to tag type of union" { | ... | @@ -292,7 +290,6 @@ test "cast union to tag type of union" { |
| 292 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 290 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 293 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 291 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 294 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 292 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 295 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 296 | 293 | ||
| 297 | try testCastUnionToTag(); | 294 | try testCastUnionToTag(); |
| 298 | try comptime testCastUnionToTag(); | 295 | try comptime testCastUnionToTag(); |
| ... | @@ -314,7 +311,6 @@ test "cast tag type of union to union" { | ... | @@ -314,7 +311,6 @@ test "cast tag type of union to union" { |
| 314 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 311 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 312 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 316 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 313 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 317 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 318 | 314 | ||
| 319 | var x: Value2 = Letter2.B; | 315 | var x: Value2 = Letter2.B; |
| 320 | _ = &x; | 316 | _ = &x; |
| ... | @@ -331,7 +327,6 @@ test "implicit cast union to its tag type" { | ... | @@ -331,7 +327,6 @@ test "implicit cast union to its tag type" { |
| 331 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 327 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 332 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 328 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 333 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 329 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 334 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 335 | 330 | ||
| 336 | var x: Value2 = Letter2.B; | 331 | var x: Value2 = Letter2.B; |
| 337 | _ = &x; | 332 | _ = &x; |
| ... | @@ -353,7 +348,6 @@ test "constant packed union" { | ... | @@ -353,7 +348,6 @@ test "constant packed union" { |
| 353 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 348 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 354 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 349 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 355 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 350 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 356 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 357 | 351 | ||
| 358 | try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }}); | 352 | try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }}); |
| 359 | } | 353 | } |
| ... | @@ -503,7 +497,6 @@ test "initialize global array of union" { | ... | @@ -503,7 +497,6 @@ test "initialize global array of union" { |
| 503 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 497 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 504 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 498 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 505 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 499 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 506 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 507 | 500 | ||
| 508 | glbl_array[1] = FooUnion{ .U1 = 2 }; | 501 | glbl_array[1] = FooUnion{ .U1 = 2 }; |
| 509 | glbl_array[0] = FooUnion{ .U0 = 1 }; | 502 | glbl_array[0] = FooUnion{ .U0 = 1 }; |
| ... | @@ -515,7 +508,6 @@ test "update the tag value for zero-sized unions" { | ... | @@ -515,7 +508,6 @@ test "update the tag value for zero-sized unions" { |
| 515 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 508 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 516 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 509 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 517 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 510 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 518 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 519 | 511 | ||
| 520 | const S = union(enum) { | 512 | const S = union(enum) { |
| 521 | U0: void, | 513 | U0: void, |
| ... | @@ -636,7 +628,6 @@ test "tagged union with all void fields but a meaningful tag" { | ... | @@ -636,7 +628,6 @@ test "tagged union with all void fields but a meaningful tag" { |
| 636 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 628 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 637 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 629 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 638 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 630 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 639 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 640 | 631 | ||
| 641 | const S = struct { | 632 | const S = struct { |
| 642 | const B = union(enum) { | 633 | const B = union(enum) { |
| ... | @@ -758,7 +749,6 @@ test "@intFromEnum works on unions" { | ... | @@ -758,7 +749,6 @@ test "@intFromEnum works on unions" { |
| 758 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 749 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 759 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 750 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 760 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 751 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 761 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 762 | 752 | ||
| 763 | const Bar = union(enum) { | 753 | const Bar = union(enum) { |
| 764 | A: bool, | 754 | A: bool, |
| ... | @@ -874,7 +864,6 @@ test "@unionInit can modify a union type" { | ... | @@ -874,7 +864,6 @@ test "@unionInit can modify a union type" { |
| 874 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 864 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 875 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 865 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 876 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 866 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 877 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 878 | 867 | ||
| 879 | const UnionInitEnum = union(enum) { | 868 | const UnionInitEnum = union(enum) { |
| 880 | Boolean: bool, | 869 | Boolean: bool, |
| ... | @@ -898,7 +887,6 @@ test "@unionInit can modify a pointer value" { | ... | @@ -898,7 +887,6 @@ test "@unionInit can modify a pointer value" { |
| 898 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 887 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 899 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 888 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 900 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 889 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 901 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 902 | 890 | ||
| 903 | const UnionInitEnum = union(enum) { | 891 | const UnionInitEnum = union(enum) { |
| 904 | Boolean: bool, | 892 | Boolean: bool, |
| ... | @@ -1089,7 +1077,6 @@ test "switching on non exhaustive union" { | ... | @@ -1089,7 +1077,6 @@ test "switching on non exhaustive union" { |
| 1089 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1077 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1090 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1078 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1091 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1079 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1092 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1093 | 1080 | ||
| 1094 | const S = struct { | 1081 | const S = struct { |
| 1095 | const E = enum(u8) { | 1082 | const E = enum(u8) { |
| ... | @@ -1199,7 +1186,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel | ... | @@ -1199,7 +1186,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel |
| 1199 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1186 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1200 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1187 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1201 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1188 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1202 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1203 | 1189 | ||
| 1204 | const T = struct { | 1190 | const T = struct { |
| 1205 | const U = union(enum) { | 1191 | const U = union(enum) { |
| ... | @@ -1352,7 +1338,6 @@ test "noreturn field in union" { | ... | @@ -1352,7 +1338,6 @@ test "noreturn field in union" { |
| 1352 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1338 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1353 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1339 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1354 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1340 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1355 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1356 | 1341 | ||
| 1357 | const U = union(enum) { | 1342 | const U = union(enum) { |
| 1358 | a: u32, | 1343 | a: u32, |
| ... | @@ -1434,7 +1419,6 @@ test "union field ptr - zero sized payload" { | ... | @@ -1434,7 +1419,6 @@ test "union field ptr - zero sized payload" { |
| 1434 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1419 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1435 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1420 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1436 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1421 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1437 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1438 | 1422 | ||
| 1439 | const U = union { | 1423 | const U = union { |
| 1440 | foo: void, | 1424 | foo: void, |
| ... | @@ -1449,7 +1433,6 @@ test "union field ptr - zero sized field" { | ... | @@ -1449,7 +1433,6 @@ test "union field ptr - zero sized field" { |
| 1449 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1433 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1450 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1434 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1451 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1435 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1452 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1453 | 1436 | ||
| 1454 | const U = union { | 1437 | const U = union { |
| 1455 | foo: void, | 1438 | foo: void, |
| ... | @@ -1589,7 +1572,6 @@ test "reinterpreting enum value inside packed union" { | ... | @@ -1589,7 +1572,6 @@ test "reinterpreting enum value inside packed union" { |
| 1589 | 1572 | ||
| 1590 | test "access the tag of a global tagged union" { | 1573 | test "access the tag of a global tagged union" { |
| 1591 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1574 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1592 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1593 | 1575 | ||
| 1594 | const U = union(enum) { | 1576 | const U = union(enum) { |
| 1595 | a, | 1577 | a, |
| ... | @@ -1601,7 +1583,6 @@ test "access the tag of a global tagged union" { | ... | @@ -1601,7 +1583,6 @@ test "access the tag of a global tagged union" { |
| 1601 | 1583 | ||
| 1602 | test "coerce enum literal to union in result loc" { | 1584 | test "coerce enum literal to union in result loc" { |
| 1603 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1585 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1604 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1605 | 1586 | ||
| 1606 | const U = union(enum) { | 1587 | const U = union(enum) { |
| 1607 | a, | 1588 | a, |
| ... | @@ -1864,7 +1845,6 @@ test "reinterpret extern union" { | ... | @@ -1864,7 +1845,6 @@ test "reinterpret extern union" { |
| 1864 | 1845 | ||
| 1865 | test "reinterpret packed union" { | 1846 | test "reinterpret packed union" { |
| 1866 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 1847 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 1867 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1868 | 1848 | ||
| 1869 | const U = packed union { | 1849 | const U = packed union { |
| 1870 | foo: u8, | 1850 | foo: u8, |
| ... | @@ -2044,7 +2024,6 @@ test "extern union initialized via reintepreted struct field initializer" { | ... | @@ -2044,7 +2024,6 @@ test "extern union initialized via reintepreted struct field initializer" { |
| 2044 | 2024 | ||
| 2045 | test "packed union initialized via reintepreted struct field initializer" { | 2025 | test "packed union initialized via reintepreted struct field initializer" { |
| 2046 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 2026 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 2047 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 2048 | 2027 | ||
| 2049 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; | 2028 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 2050 | 2029 | ||
| ... | @@ -2065,7 +2044,6 @@ test "packed union initialized via reintepreted struct field initializer" { | ... | @@ -2065,7 +2044,6 @@ test "packed union initialized via reintepreted struct field initializer" { |
| 2065 | 2044 | ||
| 2066 | test "store of comptime reinterpreted memory to extern union" { | 2045 | test "store of comptime reinterpreted memory to extern union" { |
| 2067 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 2046 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 2068 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 2069 | 2047 | ||
| 2070 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; | 2048 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 2071 | 2049 | ||
| ... | @@ -2088,7 +2066,6 @@ test "store of comptime reinterpreted memory to extern union" { | ... | @@ -2088,7 +2066,6 @@ test "store of comptime reinterpreted memory to extern union" { |
| 2088 | 2066 | ||
| 2089 | test "store of comptime reinterpreted memory to packed union" { | 2067 | test "store of comptime reinterpreted memory to packed union" { |
| 2090 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 2068 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 2091 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 2092 | 2069 | ||
| 2093 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; | 2070 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 2094 | 2071 |
test/behavior/vector.zig+28-19| ... | @@ -97,29 +97,40 @@ test "vector int operators" { | ... | @@ -97,29 +97,40 @@ test "vector int operators" { |
| 97 | 97 | ||
| 98 | test "vector float operators" { | 98 | test "vector float operators" { |
| 99 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 99 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 100 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 101 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 100 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 102 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 101 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 103 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 102 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 104 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 103 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 105 | if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; | 104 | if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; |
| 106 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 105 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 106 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 107 | 107 | ||
| 108 | inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| { | 108 | const S = struct { |
| 109 | const S = struct { | 109 | fn doTheTest(T: type) !void { |
| 110 | fn doTheTest() !void { | 110 | var v: @Vector(4, T) = .{ 10, 20, 30, 40 }; |
| 111 | var v: @Vector(4, T) = [4]T{ 10, 20, 30, 40 }; | 111 | var x: @Vector(4, T) = .{ 1, 2, 3, 4 }; |
| 112 | var x: @Vector(4, T) = [4]T{ 1, 2, 3, 4 }; | 112 | _ = .{ &v, &x }; |
| 113 | _ = .{ &v, &x }; | 113 | try expectEqual(v + x, .{ 11, 22, 33, 44 }); |
| 114 | try expect(mem.eql(T, &@as([4]T, v + x), &[4]T{ 11, 22, 33, 44 })); | 114 | try expectEqual(v - x, .{ 9, 18, 27, 36 }); |
| 115 | try expect(mem.eql(T, &@as([4]T, v - x), &[4]T{ 9, 18, 27, 36 })); | 115 | try expectEqual(v * x, .{ 10, 40, 90, 160 }); |
| 116 | try expect(mem.eql(T, &@as([4]T, v * x), &[4]T{ 10, 40, 90, 160 })); | 116 | try expectEqual(-x, .{ -1, -2, -3, -4 }); |
| 117 | try expect(mem.eql(T, &@as([4]T, -x), &[4]T{ -1, -2, -3, -4 })); | 117 | } |
| 118 | } | 118 | }; |
| 119 | }; | 119 | |
| 120 | try S.doTheTest(); | 120 | try S.doTheTest(f32); |
| 121 | try comptime S.doTheTest(); | 121 | try comptime S.doTheTest(f32); |
| 122 | } | 122 | |
| 123 | try S.doTheTest(f64); | ||
| 124 | try comptime S.doTheTest(f64); | ||
| 125 | |||
| 126 | try S.doTheTest(f16); | ||
| 127 | try comptime S.doTheTest(f16); | ||
| 128 | |||
| 129 | try S.doTheTest(f80); | ||
| 130 | try comptime S.doTheTest(f80); | ||
| 131 | |||
| 132 | try S.doTheTest(f128); | ||
| 133 | try comptime S.doTheTest(f128); | ||
| 123 | } | 134 | } |
| 124 | 135 | ||
| 125 | test "vector bit operators" { | 136 | test "vector bit operators" { |
| ... | @@ -1245,7 +1256,6 @@ test "array of vectors is copied" { | ... | @@ -1245,7 +1256,6 @@ test "array of vectors is copied" { |
| 1245 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1256 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1246 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1257 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1247 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1258 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1248 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1249 | 1259 | ||
| 1250 | const Vec3 = @Vector(3, i32); | 1260 | const Vec3 = @Vector(3, i32); |
| 1251 | var points = [_]Vec3{ | 1261 | var points = [_]Vec3{ |
| ... | @@ -1316,6 +1326,7 @@ test "zero multiplicand" { | ... | @@ -1316,6 +1326,7 @@ test "zero multiplicand" { |
| 1316 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1326 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1317 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1327 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1318 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1328 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1329 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1319 | 1330 | ||
| 1320 | const zeros = @Vector(2, u32){ 0.0, 0.0 }; | 1331 | const zeros = @Vector(2, u32){ 0.0, 0.0 }; |
| 1321 | var ones = @Vector(2, u32){ 1.0, 1.0 }; | 1332 | var ones = @Vector(2, u32){ 1.0, 1.0 }; |
| ... | @@ -1410,7 +1421,6 @@ test "store to vector in slice" { | ... | @@ -1410,7 +1421,6 @@ test "store to vector in slice" { |
| 1410 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1421 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1411 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1422 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1412 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 1423 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 1413 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1414 | 1424 | ||
| 1415 | var v = [_]@Vector(3, f32){ | 1425 | var v = [_]@Vector(3, f32){ |
| 1416 | .{ 1, 1, 1 }, | 1426 | .{ 1, 1, 1 }, |
| ... | @@ -1608,7 +1618,6 @@ test "@reduce on bool vector" { | ... | @@ -1608,7 +1618,6 @@ test "@reduce on bool vector" { |
| 1608 | test "bitcast vector to array of smaller vectors" { | 1618 | test "bitcast vector to array of smaller vectors" { |
| 1609 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1619 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1610 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1620 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1611 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | ||
| 1612 | 1621 | ||
| 1613 | const u8x32 = @Vector(32, u8); | 1622 | const u8x32 = @Vector(32, u8); |
| 1614 | const u8x64 = @Vector(64, u8); | 1623 | const u8x64 = @Vector(64, u8); |
test/tests.zig+6-5| ... | @@ -436,11 +436,12 @@ const test_targets = blk: { | ... | @@ -436,11 +436,12 @@ const test_targets = blk: { |
| 436 | //}, | 436 | //}, |
| 437 | 437 | ||
| 438 | .{ | 438 | .{ |
| 439 | .target = .{ | 439 | .target = std.Target.Query.parse( |
| 440 | .cpu_arch = .riscv64, | 440 | .{ |
| 441 | .os_tag = .linux, | 441 | .arch_os_abi = "riscv64-linux-musl", |
| 442 | .abi = .musl, | 442 | .cpu_features = "baseline+v", |
| 443 | }, | 443 | }, |
| 444 | ) catch @panic("OOM"), | ||
| 444 | .use_llvm = false, | 445 | .use_llvm = false, |
| 445 | .use_lld = false, | 446 | .use_lld = false, |
| 446 | }, | 447 | }, |