| 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,10 +2595,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2595 | try self.asmRegisterMemory( | 2595 | try self.asmRegisterMemory( |
| 2596 | .mov, | 2596 | .mov, |
| 2597 | registerAlias(dst_mcv.register, elem_abi_size), | 2597 | registerAlias(dst_mcv.register, elem_abi_size), |
| 2598 | Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{ | 2598 | Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{ .base = dst_mcv.register }), |
| 2599 | .base = dst_mcv.register, | ||
| 2600 | .disp = 0, | ||
| 2601 | }), | ||
| 2602 | ); | 2599 | ); |
| 2603 | break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) }; | 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,21 +2953,197 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 2956 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | 3013 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 2960 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3014 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2961 | const result: MCValue = if (self.liveness.isUnused(inst)) | 3015 | const result = result: { |
| 2962 | .dead | 3016 | if (self.liveness.isUnused(inst)) break :result .dead; |
| 2963 | else | 3017 | |
| 2964 | return self.fail("TODO implement airByteSwap for {}", .{self.target.cpu.arch}); | 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 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3034 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2966 | } | 3035 | } |
| 2967 | 3036 | ||
| 2968 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { | 3037 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 2969 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3038 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2970 | const result: MCValue = if (self.liveness.isUnused(inst)) | 3039 | const result = result: { |
| 2971 | .dead | 3040 | if (self.liveness.isUnused(inst)) break :result .dead; |
| 2972 | else | 3041 | |
| 2973 | return self.fail("TODO implement airBitReverse for {}", .{self.target.cpu.arch}); | 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 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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,7 +3225,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 3052 | try self.asmRegisterMemory( | 3225 | try self.asmRegisterMemory( |
| 3053 | .mov, | 3226 | .mov, |
| 3054 | registerAlias(dst_reg, abi_size), | 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 | .stack_offset => |off| { | 3231 | .stack_offset => |off| { |
| ... | @@ -3167,7 +3340,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3167,7 +3340,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3167 | .eflags => |cc| { | 3340 | .eflags => |cc| { |
| 3168 | try self.asmSetccMemory(Memory.sib( | 3341 | try self.asmSetccMemory(Memory.sib( |
| 3169 | Memory.PtrSize.fromSize(abi_size), | 3342 | Memory.PtrSize.fromSize(abi_size), |
| 3170 | .{ .base = reg.to64(), .disp = 0 }, | 3343 | .{ .base = reg.to64() }, |
| 3171 | ), cc); | 3344 | ), cc); |
| 3172 | }, | 3345 | }, |
| 3173 | .undef => { | 3346 | .undef => { |
| ... | @@ -3187,10 +3360,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3187,10 +3360,10 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3187 | Immediate.s(@intCast(i32, @bitCast(i64, imm))) | 3360 | Immediate.s(@intCast(i32, @bitCast(i64, imm))) |
| 3188 | else | 3361 | else |
| 3189 | Immediate.u(@truncate(u32, imm)); | 3362 | Immediate.u(@truncate(u32, imm)); |
| 3190 | try self.asmMemoryImmediate(.mov, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | 3363 | try self.asmMemoryImmediate(.mov, Memory.sib( |
| 3191 | .base = reg.to64(), | 3364 | Memory.PtrSize.fromSize(abi_size), |
| 3192 | .disp = 0, | 3365 | .{ .base = reg.to64() }, |
| 3193 | }), immediate); | 3366 | ), immediate); |
| 3194 | }, | 3367 | }, |
| 3195 | 8 => { | 3368 | 8 => { |
| 3196 | // TODO: optimization: if the imm is only using the lower | 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,10 +3435,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3262 | try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr); | 3435 | try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr); |
| 3263 | 3436 | ||
| 3264 | // To get the actual address of the value we want to modify we have to go through the GOT | 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, .{ | 3438 | try self.asmRegisterMemory( |
| 3266 | .base = addr_reg.to64(), | 3439 | .mov, |
| 3267 | .disp = 0, | 3440 | addr_reg.to64(), |
| 3268 | })); | 3441 | Memory.sib(.qword, .{ .base = addr_reg.to64() }), |
| 3442 | ); | ||
| 3269 | 3443 | ||
| 3270 | const new_ptr = MCValue{ .register = addr_reg.to64() }; | 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,10 +3461,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3287 | return self.fail("TODO imm64 would get incorrectly sign extended", .{}); | 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), .{ | 3464 | try self.asmMemoryImmediate( |
| 3291 | .base = addr_reg.to64(), | 3465 | .mov, |
| 3292 | .disp = 0, | 3466 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg.to64() }), |
| 3293 | }), Immediate.u(@intCast(u32, imm))); | 3467 | Immediate.u(@intCast(u32, imm)), |
| 3468 | ); | ||
| 3294 | }, | 3469 | }, |
| 3295 | .register => { | 3470 | .register => { |
| 3296 | return self.store(new_ptr, value, ptr_ty, value_ty); | 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,10 +3477,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3302 | defer self.register_manager.unlockReg(tmp_reg_lock); | 3477 | defer self.register_manager.unlockReg(tmp_reg_lock); |
| 3303 | 3478 | ||
| 3304 | try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value); | 3479 | try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value); |
| 3305 | try self.asmRegisterMemory(.mov, tmp_reg, Memory.sib(.qword, .{ | 3480 | try self.asmRegisterMemory( |
| 3306 | .base = tmp_reg, | 3481 | .mov, |
| 3307 | .disp = 0, | 3482 | tmp_reg, |
| 3308 | })); | 3483 | Memory.sib(.qword, .{ .base = tmp_reg }), |
| 3484 | ); | ||
| 3309 | 3485 | ||
| 3310 | return self.store(new_ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | 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,15 +3780,16 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue |
| 3604 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv); | 3780 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv); |
| 3605 | 3781 | ||
| 3606 | // To get the actual address of the value we want to modify we have to go through the GOT | 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, .{ | 3783 | try self.asmRegisterMemory( |
| 3608 | .base = addr_reg, | 3784 | .mov, |
| 3609 | .disp = 0, | 3785 | addr_reg, |
| 3610 | })); | 3786 | Memory.sib(.qword, .{ .base = addr_reg }), |
| 3787 | ); | ||
| 3611 | 3788 | ||
| 3612 | try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | 3789 | try self.asmMemory( |
| 3613 | .base = addr_reg, | 3790 | mir_tag, |
| 3614 | .disp = 0, | 3791 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), |
| 3615 | })); | 3792 | ); |
| 3616 | }, | 3793 | }, |
| 3617 | } | 3794 | } |
| 3618 | } | 3795 | } |
| ... | @@ -4117,17 +4294,15 @@ fn genBinOp( | ... | @@ -4117,17 +4294,15 @@ fn genBinOp( |
| 4117 | 4294 | ||
| 4118 | // To get the actual address of the value we want to modify we | 4295 | // To get the actual address of the value we want to modify we |
| 4119 | // we have to go through the GOT | 4296 | // we have to go through the GOT |
| 4120 | try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ | 4297 | try self.asmRegisterMemory( |
| 4121 | .base = addr_reg, | 4298 | .mov, |
| 4122 | .disp = 0, | 4299 | addr_reg, |
| 4123 | })); | 4300 | Memory.sib(.qword, .{ .base = addr_reg }), |
| 4301 | ); | ||
| 4124 | 4302 | ||
| 4125 | try self.asmCmovccRegisterMemory( | 4303 | try self.asmCmovccRegisterMemory( |
| 4126 | registerAlias(dst_reg, abi_size), | 4304 | registerAlias(dst_reg, abi_size), |
| 4127 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ | 4305 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), |
| 4128 | .base = addr_reg, | ||
| 4129 | .disp = 0, | ||
| 4130 | }), | ||
| 4131 | cc, | 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,10 +5350,11 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 5175 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv); | 5350 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv); |
| 5176 | 5351 | ||
| 5177 | // To get the actual address of the value we want to modify we have to go through the GOT | 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, .{ | 5353 | try self.asmRegisterMemory( |
| 5179 | .base = addr_reg, | 5354 | .mov, |
| 5180 | .disp = 0, | 5355 | addr_reg, |
| 5181 | })); | 5356 | Memory.sib(.qword, .{ .base = addr_reg }), |
| 5357 | ); | ||
| 5182 | 5358 | ||
| 5183 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | 5359 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); |
| 5184 | try self.asmMemoryImmediate(.cmp, Memory.sib( | 5360 | try self.asmMemoryImmediate(.cmp, Memory.sib( |
| ... | @@ -6374,10 +6550,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -6374,10 +6550,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6374 | .f64 => .qword, | 6550 | .f64 => .qword, |
| 6375 | else => unreachable, | 6551 | else => unreachable, |
| 6376 | }; | 6552 | }; |
| 6377 | return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{ | 6553 | return self.asmRegisterMemory( |
| 6378 | .base = base_reg.to64(), | 6554 | tag, |
| 6379 | .disp = 0, | 6555 | reg.to128(), |
| 6380 | })); | 6556 | Memory.sib(ptr_size, .{ .base = base_reg.to64() }), |
| 6557 | ); | ||
| 6381 | } | 6558 | } |
| 6382 | 6559 | ||
| 6383 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); | 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,7 +6564,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6387 | try self.asmRegisterMemory( | 6564 | try self.asmRegisterMemory( |
| 6388 | .mov, | 6565 | .mov, |
| 6389 | registerAlias(reg, abi_size), | 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,10 +6585,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6408 | .f64 => .qword, | 6585 | .f64 => .qword, |
| 6409 | else => unreachable, | 6586 | else => unreachable, |
| 6410 | }; | 6587 | }; |
| 6411 | return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{ | 6588 | return self.asmRegisterMemory( |
| 6412 | .base = base_reg.to64(), | 6589 | tag, |
| 6413 | .disp = 0, | 6590 | reg.to128(), |
| 6414 | })); | 6591 | Memory.sib(ptr_size, .{ .base = base_reg.to64() }), |
| 6592 | ); | ||
| 6415 | } | 6593 | } |
| 6416 | 6594 | ||
| 6417 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); | 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,7 +6625,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6447 | try self.asmRegisterMemory( | 6625 | try self.asmRegisterMemory( |
| 6448 | .mov, | 6626 | .mov, |
| 6449 | registerAlias(reg, abi_size), | 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,12 +6816,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 6638 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); | 6816 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 6639 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); | 6817 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 6640 | const ptr_mem: Memory = switch (ptr_mcv) { | 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 | .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }), | 6820 | .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }), |
| 6643 | else => Memory.sib(ptr_size, .{ | 6821 | else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }), |
| 6644 | .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv), | ||
| 6645 | .disp = 0, | ||
| 6646 | }), | ||
| 6647 | }; | 6822 | }; |
| 6648 | const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null; | 6823 | const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null; |
| 6649 | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); | 6824 | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -6692,12 +6867,9 @@ fn atomicOp( | ... | @@ -6692,12 +6867,9 @@ fn atomicOp( |
| 6692 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); | 6867 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 6693 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); | 6868 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 6694 | const ptr_mem: Memory = switch (ptr_mcv) { | 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 | .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }), | 6871 | .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }), |
| 6697 | else => Memory.sib(ptr_size, .{ | 6872 | else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }), |
| 6698 | .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv), | ||
| 6699 | .disp = 0, | ||
| 6700 | }), | ||
| 6701 | }; | 6873 | }; |
| 6702 | const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null; | 6874 | const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null; |
| 6703 | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); | 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,10 +7033,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 6861 | .linker_load, .memory => { | 7033 | .linker_load, .memory => { |
| 6862 | const reg = try self.register_manager.allocReg(null, gp); | 7034 | const reg = try self.register_manager.allocReg(null, gp); |
| 6863 | try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr); | 7035 | try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr); |
| 6864 | try self.asmRegisterMemory(.mov, reg, Memory.sib(.qword, .{ | 7036 | try self.asmRegisterMemory(.mov, reg, Memory.sib(.qword, .{ .base = reg })); |
| 6865 | .base = reg, | ||
| 6866 | .disp = 0, | ||
| 6867 | })); | ||
| 6868 | break :blk MCValue{ .register = reg }; | 7037 | break :blk MCValue{ .register = reg }; |
| 6869 | }, | 7038 | }, |
| 6870 | else => break :blk src_ptr, | 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,6 +75,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 75 | .@"and", | 75 | .@"and", |
| 76 | .bsf, | 76 | .bsf, |
| 77 | .bsr, | 77 | .bsr, |
| 78 | .bswap, | ||
| 78 | .bt, | 79 | .bt, |
| 79 | .btc, | 80 | .btc, |
| 80 | .btr, | 81 | .btr, |
| ... | @@ -100,6 +101,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { | ... | @@ -100,6 +101,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 100 | .lzcnt, | 101 | .lzcnt, |
| 101 | .mfence, | 102 | .mfence, |
| 102 | .mov, | 103 | .mov, |
| 104 | .movbe, | ||
| 103 | .movzx, | 105 | .movzx, |
| 104 | .mul, | 106 | .mul, |
| 105 | .neg, | 107 | .neg, |
| ... | @@ -109,7 +111,11 @@ pub fn lowerMir(emit: *Emit) InnerError!void { | ... | @@ -109,7 +111,11 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 109 | .pop, | 111 | .pop, |
| 110 | .popcnt, | 112 | .popcnt, |
| 111 | .push, | 113 | .push, |
| 114 | .rcl, | ||
| 115 | .rcr, | ||
| 112 | .ret, | 116 | .ret, |
| 117 | .rol, | ||
| 118 | .ror, | ||
| 113 | .sal, | 119 | .sal, |
| 114 | .sar, | 120 | .sar, |
| 115 | .sbb, | 121 | .sbb, |
src/arch/x86_64/Encoding.zig+3-3| ... | @@ -307,7 +307,7 @@ pub const Mnemonic = enum { | ... | @@ -307,7 +307,7 @@ pub const Mnemonic = enum { |
| 307 | // zig fmt: off | 307 | // zig fmt: off |
| 308 | // General-purpose | 308 | // General-purpose |
| 309 | adc, add, @"and", | 309 | adc, add, @"and", |
| 310 | bsf, bsr, bt, btc, btr, bts, | 310 | bsf, bsr, bswap, bt, btc, btr, bts, |
| 311 | call, cbw, cdq, cdqe, | 311 | call, cbw, cdq, cdqe, |
| 312 | cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna, | 312 | cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna, |
| 313 | cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno, | 313 | cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno, |
| ... | @@ -325,13 +325,13 @@ pub const Mnemonic = enum { | ... | @@ -325,13 +325,13 @@ pub const Mnemonic = enum { |
| 325 | lea, lfence, | 325 | lea, lfence, |
| 326 | lods, lodsb, lodsd, lodsq, lodsw, | 326 | lods, lodsb, lodsd, lodsq, lodsw, |
| 327 | lzcnt, | 327 | lzcnt, |
| 328 | mfence, mov, | 328 | mfence, mov, movbe, |
| 329 | movs, movsb, movsd, movsq, movsw, | 329 | movs, movsb, movsd, movsq, movsw, |
| 330 | movsx, movsxd, movzx, mul, | 330 | movsx, movsxd, movzx, mul, |
| 331 | neg, nop, not, | 331 | neg, nop, not, |
| 332 | @"or", | 332 | @"or", |
| 333 | pop, popcnt, push, | 333 | pop, popcnt, push, |
| 334 | ret, | 334 | rcl, rcr, ret, rol, ror, |
| 335 | sal, sar, sbb, | 335 | sal, sar, sbb, |
| 336 | scas, scasb, scasd, scasq, scasw, | 336 | scas, scasb, scasd, scasq, scasw, |
| 337 | shl, shr, sub, syscall, | 337 | shl, shr, sub, syscall, |
src/arch/x86_64/Mir.zig+12| ... | @@ -42,6 +42,8 @@ pub const Inst = struct { | ... | @@ -42,6 +42,8 @@ pub const Inst = struct { |
| 42 | bsf, | 42 | bsf, |
| 43 | /// Bit scan reverse | 43 | /// Bit scan reverse |
| 44 | bsr, | 44 | bsr, |
| 45 | /// Byte swap | ||
| 46 | bswap, | ||
| 45 | /// Bit test | 47 | /// Bit test |
| 46 | bt, | 48 | bt, |
| 47 | /// Bit test and complement | 49 | /// Bit test and complement |
| ... | @@ -94,6 +96,8 @@ pub const Inst = struct { | ... | @@ -94,6 +96,8 @@ pub const Inst = struct { |
| 94 | mfence, | 96 | mfence, |
| 95 | /// Move | 97 | /// Move |
| 96 | mov, | 98 | mov, |
| 99 | /// Move data after swapping bytes | ||
| 100 | movbe, | ||
| 97 | /// Move with sign extension | 101 | /// Move with sign extension |
| 98 | movsx, | 102 | movsx, |
| 99 | /// Move with zero extension | 103 | /// Move with zero extension |
| ... | @@ -114,8 +118,16 @@ pub const Inst = struct { | ... | @@ -114,8 +118,16 @@ pub const Inst = struct { |
| 114 | popcnt, | 118 | popcnt, |
| 115 | /// Push | 119 | /// Push |
| 116 | push, | 120 | push, |
| 121 | /// Rotate left through carry | ||
| 122 | rcl, | ||
| 123 | /// Rotate right through carry | ||
| 124 | rcr, | ||
| 117 | /// Return | 125 | /// Return |
| 118 | ret, | 126 | ret, |
| 127 | /// Rotate left | ||
| 128 | rol, | ||
| 129 | /// Rotate right | ||
| 130 | ror, | ||
| 119 | /// Arithmetic shift left | 131 | /// Arithmetic shift left |
| 120 | sal, | 132 | sal, |
| 121 | /// Arithmetic shift right | 133 | /// Arithmetic shift right |
src/arch/x86_64/bits.zig+1-1| ... | @@ -472,7 +472,7 @@ pub const Memory = union(enum) { | ... | @@ -472,7 +472,7 @@ pub const Memory = union(enum) { |
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | pub fn sib(ptr_size: PtrSize, args: struct { | 474 | pub fn sib(ptr_size: PtrSize, args: struct { |
| 475 | disp: i32, | 475 | disp: i32 = 0, |
| 476 | base: ?Register = null, | 476 | base: ?Register = null, |
| 477 | scale_index: ?ScaleIndex = null, | 477 | scale_index: ?ScaleIndex = null, |
| 478 | }) Memory { | 478 | }) Memory { |
src/arch/x86_64/encoder.zig+49-72| ... | @@ -211,14 +211,12 @@ pub const Instruction = struct { | ... | @@ -211,14 +211,12 @@ pub const Instruction = struct { |
| 211 | 211 | ||
| 212 | fn encodeOpcode(inst: Instruction, encoder: anytype) !void { | 212 | fn encodeOpcode(inst: Instruction, encoder: anytype) !void { |
| 213 | const opcode = inst.encoding.opcode(); | 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 | switch (inst.encoding.op_en) { | 217 | switch (inst.encoding.op_en) { |
| 215 | .o, .oi => try encoder.opcode_withReg(opcode[0], inst.op1.reg.lowEnc()), | 218 | .o, .oi => try encoder.opcode_withReg(opcode[final], inst.op1.reg.lowEnc()), |
| 216 | else => { | 219 | else => try encoder.opcode_1byte(opcode[final]), |
| 217 | const index: usize = if (inst.encoding.mandatoryPrefix()) |_| 1 else 0; | ||
| 218 | for (opcode[index..]) |byte| { | ||
| 219 | try encoder.opcode_1byte(byte); | ||
| 220 | } | ||
| 221 | }, | ||
| 222 | } | 220 | } |
| 223 | } | 221 | } |
| 224 | 222 | ||
| ... | @@ -896,10 +894,10 @@ test "lower MI encoding" { | ... | @@ -896,10 +894,10 @@ test "lower MI encoding" { |
| 896 | try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); | 894 | try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); |
| 897 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); | 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, .{ | 897 | try enc.encode(.mov, .{ |
| 900 | .base = .r12, | 898 | .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) }, |
| 901 | .disp = 0, | 899 | .op2 = .{ .imm = Immediate.u(0x10) }, |
| 902 | }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); | 900 | }); |
| 903 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); | 901 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); |
| 904 | 902 | ||
| 905 | try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); | 903 | try enc.encode(.mov, .{ .op1 = .{ .reg = .r12 }, .op2 = .{ .imm = Immediate.u(0x1000) } }); |
| ... | @@ -911,10 +909,10 @@ test "lower MI encoding" { | ... | @@ -911,10 +909,10 @@ test "lower MI encoding" { |
| 911 | try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } }); | 909 | try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .imm = Immediate.u(0x10) } }); |
| 912 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); | 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, .{ | 912 | try enc.encode(.mov, .{ |
| 915 | .base = .r11, | 913 | .op1 = .{ .mem = Memory.sib(.dword, .{ .base = .r11 }) }, |
| 916 | .disp = 0, | 914 | .op2 = .{ .imm = Immediate.u(0x10) }, |
| 917 | }) }, .op2 = .{ .imm = Immediate.u(0x10) } }); | 915 | }); |
| 918 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); | 916 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); |
| 919 | 917 | ||
| 920 | try enc.encode(.mov, .{ | 918 | try enc.encode(.mov, .{ |
| ... | @@ -1030,10 +1028,10 @@ test "lower MI encoding" { | ... | @@ -1030,10 +1028,10 @@ test "lower MI encoding" { |
| 1030 | test "lower RM encoding" { | 1028 | test "lower RM encoding" { |
| 1031 | var enc = TestEncode{}; | 1029 | var enc = TestEncode{}; |
| 1032 | 1030 | ||
| 1033 | try enc.encode(.mov, .{ .op1 = .{ .reg = .rax }, .op2 = .{ .mem = Memory.sib(.qword, .{ | 1031 | try enc.encode(.mov, .{ |
| 1034 | .base = .r11, | 1032 | .op1 = .{ .reg = .rax }, |
| 1035 | .disp = 0, | 1033 | .op2 = .{ .mem = Memory.sib(.qword, .{ .base = .r11 }) }, |
| 1036 | }) } }); | 1034 | }); |
| 1037 | try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); | 1035 | try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); |
| 1038 | 1036 | ||
| 1039 | try enc.encode(.mov, .{ .op1 = .{ .reg = .rbx }, .op2 = .{ .mem = Memory.sib(.qword, .{ | 1037 | try enc.encode(.mov, .{ .op1 = .{ .reg = .rbx }, .op2 = .{ .mem = Memory.sib(.qword, .{ |
| ... | @@ -1116,20 +1114,16 @@ test "lower RM encoding" { | ... | @@ -1116,20 +1114,16 @@ test "lower RM encoding" { |
| 1116 | try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .reg = .bl } }); | 1114 | try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .reg = .bl } }); |
| 1117 | try expectEqualHexStrings("\x66\x0F\xBE\xC3", enc.code(), "movsx ax, bl"); | 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, .{ | 1117 | try enc.encode(.movsx, .{ |
| 1120 | .base = .rbp, | 1118 | .op1 = .{ .reg = .eax }, |
| 1121 | .disp = 0, | 1119 | .op2 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) }, |
| 1122 | }) } }); | 1120 | }); |
| 1123 | try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]"); | 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, .{ | 1123 | try enc.encode(.movsx, .{ |
| 1126 | .base = null, | 1124 | .op1 = .{ .reg = .eax }, |
| 1127 | .scale_index = .{ | 1125 | .op2 = .{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) }, |
| 1128 | .index = .rax, | 1126 | }); |
| 1129 | .scale = 2, | ||
| 1130 | }, | ||
| 1131 | .disp = 0, | ||
| 1132 | }) } }); | ||
| 1133 | try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]"); | 1127 | try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]"); |
| 1134 | 1128 | ||
| 1135 | try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } }); | 1129 | try enc.encode(.movsx, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } }); |
| ... | @@ -1156,14 +1150,13 @@ test "lower RM encoding" { | ... | @@ -1156,14 +1150,13 @@ test "lower RM encoding" { |
| 1156 | try enc.encode(.lea, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } }); | 1150 | try enc.encode(.lea, .{ .op1 = .{ .reg = .ax }, .op2 = .{ .mem = Memory.rip(.byte, 0x10) } }); |
| 1157 | try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]"); | 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, .{ | 1153 | try enc.encode(.lea, .{ |
| 1160 | .base = .rbp, | 1154 | .op1 = .{ .reg = .rsi }, |
| 1161 | .scale_index = .{ | 1155 | .op2 = .{ .mem = Memory.sib(.qword, .{ |
| 1162 | .scale = 1, | 1156 | .base = .rbp, |
| 1163 | .index = .rcx, | 1157 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1164 | }, | 1158 | }) }, |
| 1165 | .disp = 0, | 1159 | }); |
| 1166 | }) } }); | ||
| 1167 | try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", enc.code(), "lea rsi, QWORD PTR [rbp + rcx*1 + 0]"); | 1160 | try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", enc.code(), "lea rsi, QWORD PTR [rbp + rcx*1 + 0]"); |
| 1168 | 1161 | ||
| 1169 | try enc.encode(.add, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{ | 1162 | try enc.encode(.add, .{ .op1 = .{ .reg = .r11 }, .op2 = .{ .mem = Memory.sib(.qword, .{ |
| ... | @@ -1319,51 +1312,35 @@ test "lower M encoding" { | ... | @@ -1319,51 +1312,35 @@ test "lower M encoding" { |
| 1319 | try enc.encode(.call, .{ .op1 = .{ .reg = .r12 } }); | 1312 | try enc.encode(.call, .{ .op1 = .{ .reg = .r12 } }); |
| 1320 | try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); | 1313 | try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); |
| 1321 | 1314 | ||
| 1322 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ | 1315 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .r12 }) } }); |
| 1323 | .base = .r12, | ||
| 1324 | .disp = 0, | ||
| 1325 | }) } }); | ||
| 1326 | try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]"); | 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, .{ | 1318 | try enc.encode(.call, .{ |
| 1329 | .base = null, | 1319 | .op1 = .{ .mem = Memory.sib(.qword, .{ |
| 1330 | .scale_index = .{ | 1320 | .base = null, |
| 1331 | .index = .r11, | 1321 | .scale_index = .{ .index = .r11, .scale = 2 }, |
| 1332 | .scale = 2, | 1322 | }) }, |
| 1333 | }, | 1323 | }); |
| 1334 | .disp = 0, | ||
| 1335 | }) } }); | ||
| 1336 | try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]"); | 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, .{ | 1326 | try enc.encode(.call, .{ |
| 1339 | .base = null, | 1327 | .op1 = .{ .mem = Memory.sib(.qword, .{ |
| 1340 | .scale_index = .{ | 1328 | .base = null, |
| 1341 | .index = .r12, | 1329 | .scale_index = .{ .index = .r12, .scale = 2 }, |
| 1342 | .scale = 2, | 1330 | }) }, |
| 1343 | }, | 1331 | }); |
| 1344 | .disp = 0, | ||
| 1345 | }) } }); | ||
| 1346 | try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]"); | 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, .{ | 1334 | try enc.encode(.call, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .gs }) } }); |
| 1349 | .base = .gs, | ||
| 1350 | .disp = 0, | ||
| 1351 | }) } }); | ||
| 1352 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); | 1335 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); |
| 1353 | 1336 | ||
| 1354 | try enc.encode(.call, .{ .op1 = .{ .imm = Immediate.s(0) } }); | 1337 | try enc.encode(.call, .{ .op1 = .{ .imm = Immediate.s(0) } }); |
| 1355 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); | 1338 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); |
| 1356 | 1339 | ||
| 1357 | try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ | 1340 | try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.qword, .{ .base = .rbp }) } }); |
| 1358 | .base = .rbp, | ||
| 1359 | .disp = 0, | ||
| 1360 | }) } }); | ||
| 1361 | try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); | 1341 | try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1362 | 1342 | ||
| 1363 | try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{ | 1343 | try enc.encode(.push, .{ .op1 = .{ .mem = Memory.sib(.word, .{ .base = .rbp }) } }); |
| 1364 | .base = .rbp, | ||
| 1365 | .disp = 0, | ||
| 1366 | }) } }); | ||
| 1367 | try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); | 1344 | try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1368 | 1345 | ||
| 1369 | try enc.encode(.pop, .{ .op1 = .{ .mem = Memory.rip(.qword, 0) } }); | 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,7 +1468,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, args: Instruction.Init) !void { |
| 1491 | 1468 | ||
| 1492 | test "cannot encode" { | 1469 | test "cannot encode" { |
| 1493 | try cannotEncode(.@"test", .{ | 1470 | try cannotEncode(.@"test", .{ |
| 1494 | .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12, .disp = 0 }) }, | 1471 | .op1 = .{ .mem = Memory.sib(.byte, .{ .base = .r12 }) }, |
| 1495 | .op2 = .{ .reg = .ah }, | 1472 | .op2 = .{ .reg = .ah }, |
| 1496 | }); | 1473 | }); |
| 1497 | try cannotEncode(.@"test", .{ | 1474 | try cannotEncode(.@"test", .{ |
src/arch/x86_64/encodings.zig+74| ... | @@ -89,6 +89,9 @@ pub const table = &[_]Entry{ | ... | @@ -89,6 +89,9 @@ pub const table = &[_]Entry{ |
| 89 | .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none }, | 89 | .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none }, |
| 90 | .{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long }, | 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 | .{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, | 95 | .{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, |
| 93 | .{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, | 96 | .{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, |
| 94 | .{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long }, | 97 | .{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long }, |
| ... | @@ -387,6 +390,13 @@ pub const table = &[_]Entry{ | ... | @@ -387,6 +390,13 @@ pub const table = &[_]Entry{ |
| 387 | .{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none }, | 390 | .{ .mov, .mi, .rm32, .imm32, .none, .none, &.{ 0xc7 }, 0, .none }, |
| 388 | .{ .mov, .mi, .rm64, .imm32s, .none, .none, &.{ 0xc7 }, 0, .long }, | 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 | .{ .movs, .np, .m8, .m8, .none, .none, &.{ 0xa4 }, 0, .none }, | 400 | .{ .movs, .np, .m8, .m8, .none, .none, &.{ 0xa4 }, 0, .none }, |
| 391 | .{ .movs, .np, .m16, .m16, .none, .none, &.{ 0xa5 }, 0, .none }, | 401 | .{ .movs, .np, .m16, .m16, .none, .none, &.{ 0xa5 }, 0, .none }, |
| 392 | .{ .movs, .np, .m32, .m32, .none, .none, &.{ 0xa5 }, 0, .none }, | 402 | .{ .movs, .np, .m32, .m32, .none, .none, &.{ 0xa5 }, 0, .none }, |
| ... | @@ -476,6 +486,70 @@ pub const table = &[_]Entry{ | ... | @@ -476,6 +486,70 @@ pub const table = &[_]Entry{ |
| 476 | 486 | ||
| 477 | .{ .ret, .np, .none, .none, .none, .none, &.{ 0xc3 }, 0, .none }, | 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 | .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none }, | 553 | .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none }, |
| 480 | .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex }, | 554 | .{ .sal, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex }, |
| 481 | .{ .sal, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none }, | 555 | .{ .sal, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none }, |