| author | |
| committer | |
| log | c58b5732f381fe4f145537501e29347be01e2a44 |
| tree | 10dbb755d5323d9ca4fd3ddfb88c78a8bd980ce7 |
| parent | f316cb29cc094c37be191f1eb72ee70eb0dc99ee |
7 files changed, 388 insertions(+), 150 deletions(-)
src/arch/x86_64/CodeGen.zig+243-74| ... | ... | @@ -2595,10 +2595,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2595 | 2595 | try self.asmRegisterMemory( |
| 2596 | 2596 | .mov, |
| 2597 | 2597 | registerAlias(dst_mcv.register, elem_abi_size), |
| 2598 | Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{ | |
| 2599 | .base = dst_mcv.register, | |
| 2600 | .disp = 0, | |
| 2601 | }), | |
| 2598 | Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{ .base = dst_mcv.register }), | |
| 2602 | 2599 | ); |
| 2603 | 2600 | break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) }; |
| 2604 | 2601 | } |
| ... | ... | @@ -2956,21 +2953,197 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 2956 | 2953 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2957 | 2954 | } |
| 2958 | 2955 | |
| 2956 | fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, mem_ok: bool) !MCValue { | |
| 2957 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | |
| 2958 | ||
| 2959 | const src_bits = self.regBitSize(src_ty); | |
| 2960 | const src_lock = switch (src_mcv) { | |
| 2961 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | |
| 2962 | else => null, | |
| 2963 | }; | |
| 2964 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | |
| 2965 | ||
| 2966 | switch (src_bits) { | |
| 2967 | else => unreachable, | |
| 2968 | 8 => return if ((mem_ok or src_mcv.isRegister()) and | |
| 2969 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | |
| 2970 | src_mcv | |
| 2971 | else | |
| 2972 | try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv), | |
| 2973 | 16 => if ((mem_ok or src_mcv.isRegister()) and | |
| 2974 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | |
| 2975 | { | |
| 2976 | try self.genBinOpMir(.rol, src_ty, src_mcv, .{ .immediate = 8 }); | |
| 2977 | return src_mcv; | |
| 2978 | }, | |
| 2979 | 32, 64 => if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) { | |
| 2980 | try self.genUnOpMir(.bswap, src_ty, src_mcv); | |
| 2981 | return src_mcv; | |
| 2982 | }, | |
| 2983 | } | |
| 2984 | ||
| 2985 | if (src_mcv.isRegister()) { | |
| 2986 | const dst_mcv: MCValue = if (mem_ok) | |
| 2987 | try self.allocRegOrMem(inst, true) | |
| 2988 | else | |
| 2989 | .{ .register = try self.register_manager.allocReg(inst, gp) }; | |
| 2990 | if (dst_mcv.isRegister()) { | |
| 2991 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_mcv.register); | |
| 2992 | defer self.register_manager.unlockReg(dst_lock); | |
| 2993 | ||
| 2994 | try self.genSetReg(src_ty, dst_mcv.register, src_mcv); | |
| 2995 | switch (src_bits) { | |
| 2996 | else => unreachable, | |
| 2997 | 16 => try self.genBinOpMir(.rol, src_ty, dst_mcv, .{ .immediate = 8 }), | |
| 2998 | 32, 64 => try self.genUnOpMir(.bswap, src_ty, dst_mcv), | |
| 2999 | } | |
| 3000 | } else try self.genBinOpMir(.movbe, src_ty, dst_mcv, src_mcv); | |
| 3001 | return dst_mcv; | |
| 3002 | } | |
| 3003 | ||
| 3004 | const dst_reg = try self.register_manager.allocReg(inst, gp); | |
| 3005 | const dst_mcv = MCValue{ .register = dst_reg }; | |
| 3006 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | |
| 3007 | defer self.register_manager.unlockReg(dst_lock); | |
| 3008 | ||
| 3009 | try self.genBinOpMir(.movbe, src_ty, dst_mcv, src_mcv); | |
| 3010 | return dst_mcv; | |
| 3011 | } | |
| 3012 | ||
| 2959 | 3013 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 2960 | 3014 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2961 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 2962 | .dead | |
| 2963 | else | |
| 2964 | return self.fail("TODO implement airByteSwap for {}", .{self.target.cpu.arch}); | |
| 3015 | const result = result: { | |
| 3016 | if (self.liveness.isUnused(inst)) break :result .dead; | |
| 3017 | ||
| 3018 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 3019 | const src_mcv = try self.resolveInst(ty_op.operand); | |
| 3020 | ||
| 3021 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true); | |
| 3022 | switch (self.regExtraBits(src_ty)) { | |
| 3023 | 0 => {}, | |
| 3024 | else => |extra| try self.genBinOpMir( | |
| 3025 | if (src_ty.isSignedInt()) .sar else .shr, | |
| 3026 | src_ty, | |
| 3027 | dst_mcv, | |
| 3028 | .{ .immediate = extra }, | |
| 3029 | ), | |
| 3030 | } | |
| 3031 | break :result dst_mcv; | |
| 3032 | }; | |
| 3033 | ||
| 2965 | 3034 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2966 | 3035 | } |
| 2967 | 3036 | |
| 2968 | 3037 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 2969 | 3038 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2970 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 2971 | .dead | |
| 2972 | else | |
| 2973 | return self.fail("TODO implement airBitReverse for {}", .{self.target.cpu.arch}); | |
| 3039 | const result = result: { | |
| 3040 | if (self.liveness.isUnused(inst)) break :result .dead; | |
| 3041 | ||
| 3042 | const src_ty = self.air.typeOf(ty_op.operand); | |
| 3043 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | |
| 3044 | const src_mcv = try self.resolveInst(ty_op.operand); | |
| 3045 | ||
| 3046 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, false); | |
| 3047 | const dst_reg = dst_mcv.register; | |
| 3048 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | |
| 3049 | defer self.register_manager.unlockReg(dst_lock); | |
| 3050 | ||
| 3051 | const tmp_reg = try self.register_manager.allocReg(null, gp); | |
| 3052 | const tmp_lock = self.register_manager.lockReg(tmp_reg); | |
| 3053 | defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock); | |
| 3054 | ||
| 3055 | { | |
| 3056 | const dst = registerAlias(dst_reg, src_abi_size); | |
| 3057 | const tmp = registerAlias(tmp_reg, src_abi_size); | |
| 3058 | const imm = if (src_abi_size > 4) | |
| 3059 | try self.register_manager.allocReg(null, gp) | |
| 3060 | else | |
| 3061 | undefined; | |
| 3062 | ||
| 3063 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - src_abi_size * 8); | |
| 3064 | const imm_0000_1111 = Immediate.u(mask / 0b0001_0001); | |
| 3065 | const imm_00_11 = Immediate.u(mask / 0b01_01); | |
| 3066 | const imm_0_1 = Immediate.u(mask / 0b1_1); | |
| 3067 | ||
| 3068 | // dst = temp1 = bswap(operand) | |
| 3069 | try self.asmRegisterRegister(.mov, tmp, dst); | |
| 3070 | // tmp = temp1 | |
| 3071 | try self.asmRegisterImmediate(.shr, dst, Immediate.u(4)); | |
| 3072 | // dst = temp1 >> 4 | |
| 3073 | if (src_abi_size > 4) { | |
| 3074 | try self.asmRegisterImmediate(.mov, imm, imm_0000_1111); | |
| 3075 | try self.asmRegisterRegister(.@"and", tmp, imm); | |
| 3076 | try self.asmRegisterRegister(.@"and", dst, imm); | |
| 3077 | } else { | |
| 3078 | try self.asmRegisterImmediate(.@"and", tmp, imm_0000_1111); | |
| 3079 | try self.asmRegisterImmediate(.@"and", dst, imm_0000_1111); | |
| 3080 | } | |
| 3081 | // tmp = temp1 & 0x0F...0F | |
| 3082 | // dst = (temp1 >> 4) & 0x0F...0F | |
| 3083 | try self.asmRegisterImmediate(.shl, tmp, Immediate.u(4)); | |
| 3084 | // tmp = (temp1 & 0x0F...0F) << 4 | |
| 3085 | try self.asmRegisterRegister(.@"or", dst, tmp); | |
| 3086 | // dst = temp2 = ((temp1 >> 4) & 0x0F...0F) | ((temp1 & 0x0F...0F) << 4) | |
| 3087 | try self.asmRegisterRegister(.mov, tmp, dst); | |
| 3088 | // tmp = temp2 | |
| 3089 | try self.asmRegisterImmediate(.shr, dst, Immediate.u(2)); | |
| 3090 | // dst = temp2 >> 2 | |
| 3091 | if (src_abi_size > 4) { | |
| 3092 | try self.asmRegisterImmediate(.mov, imm, imm_00_11); | |
| 3093 | try self.asmRegisterRegister(.@"and", tmp, imm); | |
| 3094 | try self.asmRegisterRegister(.@"and", dst, imm); | |
| 3095 | } else { | |
| 3096 | try self.asmRegisterImmediate(.@"and", tmp, imm_00_11); | |
| 3097 | try self.asmRegisterImmediate(.@"and", dst, imm_00_11); | |
| 3098 | } | |
| 3099 | // tmp = temp2 & 0x33...33 | |
| 3100 | // dst = (temp2 >> 2) & 0x33...33 | |
| 3101 | try self.asmRegisterMemory( | |
| 3102 | .lea, | |
| 3103 | if (src_abi_size > 4) tmp.to64() else tmp.to32(), | |
| 3104 | Memory.sib(.qword, .{ | |
| 3105 | .base = dst.to64(), | |
| 3106 | .scale_index = .{ .index = tmp.to64(), .scale = 1 << 2 }, | |
| 3107 | }), | |
| 3108 | ); | |
| 3109 | // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2) | |
| 3110 | try self.asmRegisterRegister(.mov, dst, tmp); | |
| 3111 | // dst = temp3 | |
| 3112 | try self.asmRegisterImmediate(.shr, tmp, Immediate.u(1)); | |
| 3113 | // tmp = temp3 >> 1 | |
| 3114 | if (src_abi_size > 4) { | |
| 3115 | try self.asmRegisterImmediate(.mov, imm, imm_0_1); | |
| 3116 | try self.asmRegisterRegister(.@"and", dst, imm); | |
| 3117 | try self.asmRegisterRegister(.@"and", tmp, imm); | |
| 3118 | } else { | |
| 3119 | try self.asmRegisterImmediate(.@"and", dst, imm_0_1); | |
| 3120 | try self.asmRegisterImmediate(.@"and", tmp, imm_0_1); | |
| 3121 | } | |
| 3122 | // dst = temp3 & 0x55...55 | |
| 3123 | // tmp = (temp3 >> 1) & 0x55...55 | |
| 3124 | try self.asmRegisterMemory( | |
| 3125 | .lea, | |
| 3126 | if (src_abi_size > 4) dst.to64() else dst.to32(), | |
| 3127 | Memory.sib(.qword, .{ | |
| 3128 | .base = tmp.to64(), | |
| 3129 | .scale_index = .{ .index = dst.to64(), .scale = 1 << 1 }, | |
| 3130 | }), | |
| 3131 | ); | |
| 3132 | // dst = ((temp3 >> 1) & 0x55...55) + ((temp3 & 0x55...55) << 1) | |
| 3133 | } | |
| 3134 | ||
| 3135 | switch (self.regExtraBits(src_ty)) { | |
| 3136 | 0 => {}, | |
| 3137 | else => |extra| try self.genBinOpMir( | |
| 3138 | if (src_ty.isSignedInt()) .sar else .shr, | |
| 3139 | src_ty, | |
| 3140 | dst_mcv, | |
| 3141 | .{ .immediate = extra }, | |
| 3142 | ), | |
| 3143 | } | |
| 3144 | break :result dst_mcv; | |
| 3145 | }; | |
| 3146 | ||
| 2974 | 3147 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2975 | 3148 | } |
| 2976 | 3149 | |
| ... | ... | @@ -3052,7 +3225,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 3052 | 3225 | try self.asmRegisterMemory( |
| 3053 | 3226 | .mov, |
| 3054 | 3227 | registerAlias(dst_reg, abi_size), |
| 3055 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg, .disp = 0 }), | |
| 3228 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg }), | |
| 3056 | 3229 | ); |
| 3057 | 3230 | }, |
| 3058 | 3231 | .stack_offset => |off| { |
| ... | ... | @@ -3167,7 +3340,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3167 | 3340 | .eflags => |cc| { |
| 3168 | 3341 | try self.asmSetccMemory(Memory.sib( |
| 3169 | 3342 | Memory.PtrSize.fromSize(abi_size), |
| 3170 | .{ .base = reg.to64(), .disp = 0 }, | |
| 3343 | .{ .base = reg.to64() }, | |
| 3171 | 3344 | ), cc); |
| 3172 | 3345 | }, |
| 3173 | 3346 | .undef => { |
| ... | ... | @@ -3187,10 +3360,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3187 | 3360 | Immediate.s(@intCast(i32, @bitCast(i64, imm))) |
| 3188 | 3361 | else |
| 3189 | 3362 | Immediate.u(@truncate(u32, imm)); |
| 3190 | try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | |
| 3191 | .base = reg.to64(), | |
| 3192 | .disp = 0, | |
| 3193 | }), immediate); | |
| 3363 | try self.asmMemoryImmediate(.mov, Memory.sib( | |
| 3364 | Memory.PtrSize.fromSize(abi_size), | |
| 3365 | .{ .base = reg.to64() }, | |
| 3366 | ), immediate); | |
| 3194 | 3367 | }, |
| 3195 | 3368 | 8 => { |
| 3196 | 3369 | // TODO: optimization: if the imm is only using the lower |
| ... | ... | @@ -3262,10 +3435,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3262 | 3435 | try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr); |
| 3263 | 3436 | |
| 3264 | 3437 | // To get the actual address of the value we want to modify we have to go through the GOT |
| 3265 | try self.asmRegisterMemory(.mov, addr_reg.to64(), Memory.sib(.qword, .{ | |
| 3266 | .base = addr_reg.to64(), | |
| 3267 | .disp = 0, | |
| 3268 | })); | |
| 3438 | try self.asmRegisterMemory( | |
| 3439 | .mov, | |
| 3440 | addr_reg.to64(), | |
| 3441 | Memory.sib(.qword, .{ .base = addr_reg.to64() }), | |
| 3442 | ); | |
| 3269 | 3443 | |
| 3270 | 3444 | const new_ptr = MCValue{ .register = addr_reg.to64() }; |
| 3271 | 3445 | |
| ... | ... | @@ -3287,10 +3461,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3287 | 3461 | return self.fail("TODO imm64 would get incorrectly sign extended", .{}); |
| 3288 | 3462 | } |
| 3289 | 3463 | } |
| 3290 | try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | |
| 3291 | .base = addr_reg.to64(), | |
| 3292 | .disp = 0, | |
| 3293 | }), Immediate.u(@intCast(u32, imm))); | |
| 3464 | try self.asmMemoryImmediate( | |
| 3465 | .mov, | |
| 3466 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg.to64() }), | |
| 3467 | Immediate.u(@intCast(u32, imm)), | |
| 3468 | ); | |
| 3294 | 3469 | }, |
| 3295 | 3470 | .register => { |
| 3296 | 3471 | return self.store(new_ptr, value, ptr_ty, value_ty); |
| ... | ... | @@ -3302,10 +3477,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3302 | 3477 | defer self.register_manager.unlockReg(tmp_reg_lock); |
| 3303 | 3478 | |
| 3304 | 3479 | try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value); |
| 3305 | try self.asmRegisterMemory(.mov, tmp_reg, Memory.sib(.qword, .{ | |
| 3306 | .base = tmp_reg, | |
| 3307 | .disp = 0, | |
| 3308 | })); | |
| 3480 | try self.asmRegisterMemory( | |
| 3481 | .mov, | |
| 3482 | tmp_reg, | |
| 3483 | Memory.sib(.qword, .{ .base = tmp_reg }), | |
| 3484 | ); | |
| 3309 | 3485 | |
| 3310 | 3486 | return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); |
| 3311 | 3487 | } |
| ... | ... | @@ -3604,15 +3780,16 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue |
| 3604 | 3780 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv); |
| 3605 | 3781 | |
| 3606 | 3782 | // To get the actual address of the value we want to modify we have to go through the GOT |
| 3607 | try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ | |
| 3608 | .base = addr_reg, | |
| 3609 | .disp = 0, | |
| 3610 | })); | |
| 3783 | try self.asmRegisterMemory( | |
| 3784 | .mov, | |
| 3785 | addr_reg, | |
| 3786 | Memory.sib(.qword, .{ .base = addr_reg }), | |
| 3787 | ); | |
| 3611 | 3788 | |
| 3612 | try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | |
| 3613 | .base = addr_reg, | |
| 3614 | .disp = 0, | |
| 3615 | })); | |
| 3789 | try self.asmMemory( | |
| 3790 | mir_tag, | |
| 3791 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), | |
| 3792 | ); | |
| 3616 | 3793 | }, |
| 3617 | 3794 | } |
| 3618 | 3795 | } |
| ... | ... | @@ -4117,17 +4294,15 @@ fn genBinOp( |
| 4117 | 4294 | |
| 4118 | 4295 | // To get the actual address of the value we want to modify we |
| 4119 | 4296 | // we have to go through the GOT |
| 4120 | try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ | |
| 4121 | .base = addr_reg, | |
| 4122 | .disp = 0, | |
| 4123 | })); | |
| 4297 | try self.asmRegisterMemory( | |
| 4298 | .mov, | |
| 4299 | addr_reg, | |
| 4300 | Memory.sib(.qword, .{ .base = addr_reg }), | |
| 4301 | ); | |
| 4124 | 4302 | |
| 4125 | 4303 | try self.asmCmovccRegisterMemory( |
| 4126 | 4304 | registerAlias(dst_reg, abi_size), |
| 4127 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | |
| 4128 | .base = addr_reg, | |
| 4129 | .disp = 0, | |
| 4130 | }), | |
| 4305 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), | |
| 4131 | 4306 | cc, |
| 4132 | 4307 | ); |
| 4133 | 4308 | }, |
| ... | ... | @@ -5175,10 +5350,11 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 5175 | 5350 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv); |
| 5176 | 5351 | |
| 5177 | 5352 | // To get the actual address of the value we want to modify we have to go through the GOT |
| 5178 | try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ | |
| 5179 | .base = addr_reg, | |
| 5180 | .disp = 0, | |
| 5181 | })); | |
| 5353 | try self.asmRegisterMemory( | |
| 5354 | .mov, | |
| 5355 | addr_reg, | |
| 5356 | Memory.sib(.qword, .{ .base = addr_reg }), | |
| 5357 | ); | |
| 5182 | 5358 | |
| 5183 | 5359 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); |
| 5184 | 5360 | try self.asmMemoryImmediate(.cmp, Memory.sib( |
| ... | ... | @@ -6374,10 +6550,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6374 | 6550 | .f64 => .qword, |
| 6375 | 6551 | else => unreachable, |
| 6376 | 6552 | }; |
| 6377 | return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{ | |
| 6378 | .base = base_reg.to64(), | |
| 6379 | .disp = 0, | |
| 6380 | })); | |
| 6553 | return self.asmRegisterMemory( | |
| 6554 | tag, | |
| 6555 | reg.to128(), | |
| 6556 | Memory.sib(ptr_size, .{ .base = base_reg.to64() }), | |
| 6557 | ); | |
| 6381 | 6558 | } |
| 6382 | 6559 | |
| 6383 | 6560 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); |
| ... | ... | @@ -6387,7 +6564,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6387 | 6564 | try self.asmRegisterMemory( |
| 6388 | 6565 | .mov, |
| 6389 | 6566 | registerAlias(reg, abi_size), |
| 6390 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64(), .disp = 0 }), | |
| 6567 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | |
| 6391 | 6568 | ); |
| 6392 | 6569 | }, |
| 6393 | 6570 | } |
| ... | ... | @@ -6408,10 +6585,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6408 | 6585 | .f64 => .qword, |
| 6409 | 6586 | else => unreachable, |
| 6410 | 6587 | }; |
| 6411 | return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{ | |
| 6412 | .base = base_reg.to64(), | |
| 6413 | .disp = 0, | |
| 6414 | })); | |
| 6588 | return self.asmRegisterMemory( | |
| 6589 | tag, | |
| 6590 | reg.to128(), | |
| 6591 | Memory.sib(ptr_size, .{ .base = base_reg.to64() }), | |
| 6592 | ); | |
| 6415 | 6593 | } |
| 6416 | 6594 | |
| 6417 | 6595 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); |
| ... | ... | @@ -6447,7 +6625,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6447 | 6625 | try self.asmRegisterMemory( |
| 6448 | 6626 | .mov, |
| 6449 | 6627 | registerAlias(reg, abi_size), |
| 6450 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64(), .disp = 0 }), | |
| 6628 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), | |
| 6451 | 6629 | ); |
| 6452 | 6630 | } |
| 6453 | 6631 | } |
| ... | ... | @@ -6638,12 +6816,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 6638 | 6816 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 6639 | 6817 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 6640 | 6818 | const ptr_mem: Memory = switch (ptr_mcv) { |
| 6641 | .register => |reg| Memory.sib(ptr_size, .{ .base = reg, .disp = 0 }), | |
| 6819 | .register => |reg| Memory.sib(ptr_size, .{ .base = reg }), | |
| 6642 | 6820 | .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }), |
| 6643 | else => Memory.sib(ptr_size, .{ | |
| 6644 | .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv), | |
| 6645 | .disp = 0, | |
| 6646 | }), | |
| 6821 | else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }), | |
| 6647 | 6822 | }; |
| 6648 | 6823 | const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null; |
| 6649 | 6824 | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -6692,12 +6867,9 @@ fn atomicOp( |
| 6692 | 6867 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 6693 | 6868 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 6694 | 6869 | const ptr_mem: Memory = switch (ptr_mcv) { |
| 6695 | .register => |reg| Memory.sib(ptr_size, .{ .base = reg, .disp = 0 }), | |
| 6870 | .register => |reg| Memory.sib(ptr_size, .{ .base = reg }), | |
| 6696 | 6871 | .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }), |
| 6697 | else => Memory.sib(ptr_size, .{ | |
| 6698 | .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv), | |
| 6699 | .disp = 0, | |
| 6700 | }), | |
| 6872 | else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }), | |
| 6701 | 6873 | }; |
| 6702 | 6874 | const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null; |
| 6703 | 6875 | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -6861,10 +7033,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 6861 | 7033 | .linker_load, .memory => { |
| 6862 | 7034 | const reg = try self.register_manager.allocReg(null, gp); |
| 6863 | 7035 | try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr); |
| 6864 | try self.asmRegisterMemory(.mov, reg, Memory.sib(.qword, .{ | |
| 6865 | .base = reg, | |
| 6866 | .disp = 0, | |
| 6867 | })); | |
| 7036 | try self.asmRegisterMemory(.mov, reg, Memory.sib(.qword, .{ .base = reg })); | |
| 6868 | 7037 | break :blk MCValue{ .register = reg }; |
| 6869 | 7038 | }, |
| 6870 | 7039 | else => break :blk src_ptr, |
src/arch/x86_64/Emit.zig+6| ... | ... | @@ -75,6 +75,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 75 | 75 | .@"and", |
| 76 | 76 | .bsf, |
| 77 | 77 | .bsr, |
| 78 | .bswap, | |
| 78 | 79 | .bt, |
| 79 | 80 | .btc, |
| 80 | 81 | .btr, |
| ... | ... | @@ -100,6 +101,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 100 | 101 | .lzcnt, |
| 101 | 102 | .mfence, |
| 102 | 103 | .mov, |
| 104 | .movbe, | |
| 103 | 105 | .movzx, |
| 104 | 106 | .mul, |
| 105 | 107 | .neg, |
| ... | ... | @@ -109,7 +111,11 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 109 | 111 | .pop, |
| 110 | 112 | .popcnt, |
| 111 | 113 | .push, |
| 114 | .rcl, | |
| 115 | .rcr, | |
| 112 | 116 | .ret, |
| 117 | .rol, | |
| 118 | .ror, | |
| 113 | 119 | .sal, |
| 114 | 120 | .sar, |
| 115 | 121 | .sbb, |
src/arch/x86_64/Encoding.zig+3-3| ... | ... | @@ -307,7 +307,7 @@ pub const Mnemonic = enum { |
| 307 | 307 | // zig fmt: off |
| 308 | 308 | // General-purpose |
| 309 | 309 | adc, add, @"and", |
| 310 | bsf, bsr, bt, btc, btr, bts, | |
| 310 | bsf, bsr, bswap, bt, btc, btr, bts, | |
| 311 | 311 | call, cbw, cdq, cdqe, |
| 312 | 312 | cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna, |
| 313 | 313 | cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno, |
| ... | ... | @@ -325,13 +325,13 @@ pub const Mnemonic = enum { |
| 325 | 325 | lea, lfence, |
| 326 | 326 | lods, lodsb, lodsd, lodsq, lodsw, |
| 327 | 327 | lzcnt, |
| 328 | mfence, mov, | |
| 328 | mfence, mov, movbe, | |
| 329 | 329 | movs, movsb, movsd, movsq, movsw, |
| 330 | 330 | movsx, movsxd, movzx, mul, |
| 331 | 331 | neg, nop, not, |
| 332 | 332 | @"or", |
| 333 | 333 | pop, popcnt, push, |
| 334 | ret, | |
| 334 | rcl, rcr, ret, rol, ror, | |
| 335 | 335 | sal, sar, sbb, |
| 336 | 336 | scas, scasb, scasd, scasq, scasw, |
| 337 | 337 | shl, shr, sub, syscall, |
src/arch/x86_64/Mir.zig+12| ... | ... | @@ -42,6 +42,8 @@ pub const Inst = struct { |
| 42 | 42 | bsf, |
| 43 | 43 | /// Bit scan reverse |
| 44 | 44 | bsr, |
| 45 | /// Byte swap | |
| 46 | bswap, | |
| 45 | 47 | /// Bit test |
| 46 | 48 | bt, |
| 47 | 49 | /// Bit test and complement |
| ... | ... | @@ -94,6 +96,8 @@ pub const Inst = struct { |
| 94 | 96 | mfence, |
| 95 | 97 | /// Move |
| 96 | 98 | mov, |
| 99 | /// Move data after swapping bytes | |
| 100 | movbe, | |
| 97 | 101 | /// Move with sign extension |
| 98 | 102 | movsx, |
| 99 | 103 | /// Move with zero extension |
| ... | ... | @@ -114,8 +118,16 @@ pub const Inst = struct { |
| 114 | 118 | popcnt, |
| 115 | 119 | /// Push |
| 116 | 120 | push, |
| 121 | /// Rotate left through carry | |
| 122 | rcl, | |
| 123 | /// Rotate right through carry | |
| 124 | rcr, | |
| 117 | 125 | /// Return |
| 118 | 126 | ret, |
| 127 | /// Rotate left | |
| 128 | rol, | |
| 129 | /// Rotate right | |
| 130 | ror, | |
| 119 | 131 | /// Arithmetic shift left |
| 120 | 132 | sal, |
| 121 | 133 | /// Arithmetic shift right |
src/arch/x86_64/bits.zig+1-1| ... | ... | @@ -472,7 +472,7 @@ pub const Memory = union(enum) { |
| 472 | 472 | } |
| 473 | 473 | |
| 474 | 474 | pub fn sib(ptr_size: PtrSize, args: struct { |
| 475 | disp: i32, | |
| 475 | disp: i32 = 0, | |
| 476 | 476 | base: ?Register = null, |
| 477 | 477 | scale_index: ?ScaleIndex = null, |
| 478 | 478 | }) Memory { |
src/arch/x86_64/encoder.zig+49-72| ... | ... | @@ -211,14 +211,12 @@ pub const Instruction = struct { |
| 211 | 211 | |
| 212 | 212 | fn encodeOpcode(inst: Instruction, encoder: anytype) !void { |
| 213 | 213 | const opcode = inst.encoding.opcode(); |
| 214 | const first = @boolToInt(inst.encoding.mandatoryPrefix() != null); | |
| 215 | const final = opcode.len - 1; | |
| 216 | for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte); | |
| 214 | 217 | switch (inst.encoding.op_en) { |
| 215 | .o, .oi => try encoder.opcode_withReg(opcode[0], inst.op1.reg.lowEnc()), | |
| 216 | else => { | |
| 217 | const index: usize = if (inst.encoding.mandatoryPrefix()) |_| 1 else 0; | |
| 218 | for (opcode[index..]) |byte| { | |
| 219 | try encoder.opcode_1byte(byte); | |
| 220 | } | |
| 221 | }, | |
| 218 | .o, .oi => try encoder.opcode_withReg(opcode[final], inst.op1.reg.lowEnc()), | |
| 219 | else => try encoder.opcode_1byte(opcode[final]), | |
| 222 | 220 | } |
| 223 | 221 | } |
| 224 | 222 | |
| ... | ... | @@ -896,10 +894,10 @@ test "lower MI encoding" { |
| 896 | 894 | try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); |
| 897 | 895 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 898 | 896 | |
| 899 | try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.byte, .{ | |
| 900 | .base = .r12, | |
| 901 | .disp = 0, | |
| 902 | }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); | |
| 897 | try enc.encode(.mov, .{ | |
| 898 | .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) }, | |
| 899 | .op2 = .{ .imm = Immediate.u(0x10) }, | |
| 900 | }); | |
| 903 | 901 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); |
| 904 | 902 | |
| 905 | 903 | try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); |
| ... | ... | @@ -911,10 +909,10 @@ test "lower MI encoding" { |
| 911 | 909 | try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } }); |
| 912 | 910 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); |
| 913 | 911 | |
| 914 | try enc.encode(.mov, .{ .op1 = .{ .mem = Memory.sib(.dword, .{ | |
| 915 | .base = .r11, | |
| 916 | .disp = 0, | |
| 917 | }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); | |
| 912 | try enc.encode(.mov, .{ | |
| 913 | .op1 = .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) }, | |
| 914 | .op2 = .{ .imm = Immediate.u(0x10) }, | |
| 915 | }); | |
| 918 | 916 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); |
| 919 | 917 | |
| 920 | 918 | try enc.encode(.mov, .{ |
| ... | ... | @@ -1030,10 +1028,10 @@ test "lower MI encoding" { |
| 1030 | 1028 | test "lower RM encoding" { |
| 1031 | 1029 | var enc = TestEncode{}; |
| 1032 | 1030 | |
| 1033 | try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{ | |
| 1034 | .base = .r11, | |
| 1035 | .disp = 0, | |
| 1036 | }) } }); | |
| 1031 | try enc.encode(.mov, .{ | |
| 1032 | .op1 = .{ .reg = .rax }, | |
| 1033 | .op2 = .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) }, | |
| 1034 | }); | |
| 1037 | 1035 | try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); |
| 1038 | 1036 | |
| 1039 | 1037 | try enc.encode(.mov, .{ .op1 = .{ .reg = .rbx }, .op2 = .{ .mem = Memory.sib(.qword, .{ |
| ... | ... | @@ -1116,20 +1114,16 @@ test "lower RM encoding" { |
| 1116 | 1114 | try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .reg = .bl } }); |
| 1117 | 1115 | try expectEqualHexStrings("\x66\x0F\xBE\xC3", enc.code(), "movsx ax, bl"); |
| 1118 | 1116 | |
| 1119 | try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.sib(.word, .{ | |
| 1120 | .base = .rbp, | |
| 1121 | .disp = 0, | |
| 1122 | }) } }); | |
| 1117 | try enc.encode(.movsx, .{ | |
| 1118 | .op1 = .{ .reg = .eax }, | |
| 1119 | .op2 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) }, | |
| 1120 | }); | |
| 1123 | 1121 | try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]"); |
| 1124 | 1122 | |
| 1125 | try enc.encode(.movsx, .{ .op1 = .{ .reg = .eax }, .op2 = .{ .mem = Memory.sib(.byte, .{ | |
| 1126 | .base = null, | |
| 1127 | .scale_index = .{ | |
| 1128 | .index = .rax, | |
| 1129 | .scale = 2, | |
| 1130 | }, | |
| 1131 | .disp = 0, | |
| 1132 | }) } }); | |
| 1123 | try enc.encode(.movsx, .{ | |
| 1124 | .op1 = .{ .reg = .eax }, | |
| 1125 | .op2 = .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) }, | |
| 1126 | }); | |
| 1133 | 1127 | try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]"); |
| 1134 | 1128 | |
| 1135 | 1129 | try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } }); |
| ... | ... | @@ -1156,14 +1150,13 @@ test "lower RM encoding" { |
| 1156 | 1150 | try enc.encode(.lea, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } }); |
| 1157 | 1151 | try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]"); |
| 1158 | 1152 | |
| 1159 | try enc.encode(.lea, .{ .op1 = .{ .reg = .rsi }, .op2 = .{ .mem = Memory.sib(.qword, .{ | |
| 1160 | .base = .rbp, | |
| 1161 | .scale_index = .{ | |
| 1162 | .scale = 1, | |
| 1163 | .index = .rcx, | |
| 1164 | }, | |
| 1165 | .disp = 0, | |
| 1166 | }) } }); | |
| 1153 | try enc.encode(.lea, .{ | |
| 1154 | .op1 = .{ .reg = .rsi }, | |
| 1155 | .op2 = .{ .mem = Memory.sib(.qword, .{ | |
| 1156 | .base = .rbp, | |
| 1157 | .scale_index = .{ .scale = 1, .index = .rcx }, | |
| 1158 | }) }, | |
| 1159 | }); | |
| 1167 | 1160 | try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", enc.code(), "lea rsi, QWORD PTR [rbp + rcx*1 + 0]"); |
| 1168 | 1161 | |
| 1169 | 1162 | try enc.encode(.add, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{ |
| ... | ... | @@ -1319,51 +1312,35 @@ test "lower M encoding" { |
| 1319 | 1312 | try enc.encode(.call, .{ .op1 = .{ .reg = .r12 } }); |
| 1320 | 1313 | try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); |
| 1321 | 1314 | |
| 1322 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ | |
| 1323 | .base = .r12, | |
| 1324 | .disp = 0, | |
| 1325 | }) } }); | |
| 1315 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .r12 }) } }); | |
| 1326 | 1316 | try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]"); |
| 1327 | 1317 | |
| 1328 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ | |
| 1329 | .base = null, | |
| 1330 | .scale_index = .{ | |
| 1331 | .index = .r11, | |
| 1332 | .scale = 2, | |
| 1333 | }, | |
| 1334 | .disp = 0, | |
| 1335 | }) } }); | |
| 1318 | try enc.encode(.call, .{ | |
| 1319 | .op1 = .{ .mem = Memory.sib(.qword, .{ | |
| 1320 | .base = null, | |
| 1321 | .scale_index = .{ .index = .r11, .scale = 2 }, | |
| 1322 | }) }, | |
| 1323 | }); | |
| 1336 | 1324 | try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]"); |
| 1337 | 1325 | |
| 1338 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ | |
| 1339 | .base = null, | |
| 1340 | .scale_index = .{ | |
| 1341 | .index = .r12, | |
| 1342 | .scale = 2, | |
| 1343 | }, | |
| 1344 | .disp = 0, | |
| 1345 | }) } }); | |
| 1326 | try enc.encode(.call, .{ | |
| 1327 | .op1 = .{ .mem = Memory.sib(.qword, .{ | |
| 1328 | .base = null, | |
| 1329 | .scale_index = .{ .index = .r12, .scale = 2 }, | |
| 1330 | }) }, | |
| 1331 | }); | |
| 1346 | 1332 | try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]"); |
| 1347 | 1333 | |
| 1348 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ | |
| 1349 | .base = .gs, | |
| 1350 | .disp = 0, | |
| 1351 | }) } }); | |
| 1334 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .gs }) } }); | |
| 1352 | 1335 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); |
| 1353 | 1336 | |
| 1354 | 1337 | try enc.encode(.call, .{ .op1 = .{ .imm = Immediate.s(0) } }); |
| 1355 | 1338 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); |
| 1356 | 1339 | |
| 1357 | try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ | |
| 1358 | .base = .rbp, | |
| 1359 | .disp = 0, | |
| 1360 | }) } }); | |
| 1340 | try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .rbp }) } }); | |
| 1361 | 1341 | try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1362 | 1342 | |
| 1363 | try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{ | |
| 1364 | .base = .rbp, | |
| 1365 | .disp = 0, | |
| 1366 | }) } }); | |
| 1343 | try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) } }); | |
| 1367 | 1344 | try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1368 | 1345 | |
| 1369 | 1346 | try enc.encode(.pop, .{ .op1 = .{ .mem = Memory.rip(.qword, 0) } }); |
| ... | ... | @@ -1491,7 +1468,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void { |
| 1491 | 1468 | |
| 1492 | 1469 | test "cannot encode" { |
| 1493 | 1470 | try cannotEncode(.@"test", .{ |
| 1494 | .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12, .disp = 0 }) }, | |
| 1471 | .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) }, | |
| 1495 | 1472 | .op2 = .{ .reg = .ah }, |
| 1496 | 1473 | }); |
| 1497 | 1474 | try cannotEncode(.@"test", .{ |
src/arch/x86_64/encodings.zig+74| ... | ... | @@ -89,6 +89,9 @@ pub const table = &[_]Entry{ |
| 89 | 89 | .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none }, |
| 90 | 90 | .{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long }, |
| 91 | 91 | |
| 92 | .{ .bswap, .o, .r32, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .none }, | |
| 93 | .{ .bswap, .o, .r64, .none, .none, .none, &.{ 0x0f, 0xc8 }, 0, .long }, | |
| 94 | ||
| 92 | 95 | .{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, |
| 93 | 96 | .{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, |
| 94 | 97 | .{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long }, |
| ... | ... | @@ -387,6 +390,13 @@ pub const table = &[_]Entry{ |
| 387 | 390 | .{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none }, |
| 388 | 391 | .{ .mov, .mi, .rm64, .imm32s, .none, .none, &.{ 0xc7 }, 0, .long }, |
| 389 | 392 | |
| 393 | .{ .movbe, .rm, .r16, .m16, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none }, | |
| 394 | .{ .movbe, .rm, .r32, .m32, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .none }, | |
| 395 | .{ .movbe, .rm, .r64, .m64, .none, .none, &.{ 0x0f, 0x38, 0xf0 }, 0, .long }, | |
| 396 | .{ .movbe, .mr, .m16, .r16, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none }, | |
| 397 | .{ .movbe, .mr, .m32, .r32, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .none }, | |
| 398 | .{ .movbe, .mr, .m64, .r64, .none, .none, &.{ 0x0f, 0x38, 0xf1 }, 0, .long }, | |
| 399 | ||
| 390 | 400 | .{ .movs, .np, .m8, .m8, .none, .none, &.{ 0xa4 }, 0, .none }, |
| 391 | 401 | .{ .movs, .np, .m16, .m16, .none, .none, &.{ 0xa5 }, 0, .none }, |
| 392 | 402 | .{ .movs, .np, .m32, .m32, .none, .none, &.{ 0xa5 }, 0, .none }, |
| ... | ... | @@ -476,6 +486,70 @@ pub const table = &[_]Entry{ |
| 476 | 486 | |
| 477 | 487 | .{ .ret, .np, .none, .none, .none, .none, &.{ 0xc3 }, 0, .none }, |
| 478 | 488 | |
| 489 | .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .none }, | |
| 490 | .{ .rcl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 2, .rex }, | |
| 491 | .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .none }, | |
| 492 | .{ .rcl, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 2, .rex }, | |
| 493 | .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .none }, | |
| 494 | .{ .rcl, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 2, .rex }, | |
| 495 | .{ .rcl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 2, .none }, | |
| 496 | .{ .rcl, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 2, .none }, | |
| 497 | .{ .rcl, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 2, .none }, | |
| 498 | .{ .rcl, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 2, .none }, | |
| 499 | .{ .rcl, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 2, .long }, | |
| 500 | .{ .rcl, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 2, .none }, | |
| 501 | .{ .rcl, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 2, .long }, | |
| 502 | .{ .rcl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 2, .none }, | |
| 503 | .{ .rcl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 2, .long }, | |
| 504 | ||
| 505 | .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .none }, | |
| 506 | .{ .rcr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 3, .rex }, | |
| 507 | .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .none }, | |
| 508 | .{ .rcr, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 3, .rex }, | |
| 509 | .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .none }, | |
| 510 | .{ .rcr, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 3, .rex }, | |
| 511 | .{ .rcr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 3, .none }, | |
| 512 | .{ .rcr, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 3, .none }, | |
| 513 | .{ .rcr, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 3, .none }, | |
| 514 | .{ .rcr, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 3, .none }, | |
| 515 | .{ .rcr, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 3, .long }, | |
| 516 | .{ .rcr, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 3, .none }, | |
| 517 | .{ .rcr, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 3, .long }, | |
| 518 | .{ .rcr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 3, .none }, | |
| 519 | .{ .rcr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 3, .long }, | |
| 520 | ||
| 521 | .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .none }, | |
| 522 | .{ .rol, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 0, .rex }, | |
| 523 | .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .none }, | |
| 524 | .{ .rol, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 0, .rex }, | |
| 525 | .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .none }, | |
| 526 | .{ .rol, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 0, .rex }, | |
| 527 | .{ .rol, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 0, .none }, | |
| 528 | .{ .rol, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 0, .none }, | |
| 529 | .{ .rol, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 0, .none }, | |
| 530 | .{ .rol, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 0, .none }, | |
| 531 | .{ .rol, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 0, .long }, | |
| 532 | .{ .rol, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 0, .none }, | |
| 533 | .{ .rol, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 0, .long }, | |
| 534 | .{ .rol, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 0, .none }, | |
| 535 | .{ .rol, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 0, .long }, | |
| 536 | ||
| 537 | .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .none }, | |
| 538 | .{ .ror, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 1, .rex }, | |
| 539 | .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .none }, | |
| 540 | .{ .ror, .mc, .rm8, .cl, .none, .none, &.{ 0xd2 }, 1, .rex }, | |
| 541 | .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .none }, | |
| 542 | .{ .ror, .mi, .rm8, .imm8, .none, .none, &.{ 0xc0 }, 1, .rex }, | |
| 543 | .{ .ror, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 1, .none }, | |
| 544 | .{ .ror, .mc, .rm16, .cl, .none, .none, &.{ 0xd3 }, 1, .none }, | |
| 545 | .{ .ror, .mi, .rm16, .imm8, .none, .none, &.{ 0xc1 }, 1, .none }, | |
| 546 | .{ .ror, .m1, .rm32, .unity, .none, .none, &.{ 0xd1 }, 1, .none }, | |
| 547 | .{ .ror, .m1, .rm64, .unity, .none, .none, &.{ 0xd1 }, 1, .long }, | |
| 548 | .{ .ror, .mc, .rm32, .cl, .none, .none, &.{ 0xd3 }, 1, .none }, | |
| 549 | .{ .ror, .mc, .rm64, .cl, .none, .none, &.{ 0xd3 }, 1, .long }, | |
| 550 | .{ .ror, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 1, .none }, | |
| 551 | .{ .ror, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 1, .long }, | |
| 552 | ||
| 479 | 553 | .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none }, |
| 480 | 554 | .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex }, |
| 481 | 555 | .{ .sal, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none }, |