Skip to content

Commit 79c083e

Browse files
authored
UImm encoding for mov operations (ruby#147)
1 parent 6af33b7 commit 79c083e

File tree

3 files changed

+71
-8
lines changed

3 files changed

+71
-8
lines changed

yjit/src/asm/x86_64/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,33 @@ pub fn mov(cb: &mut CodeBlock, dst: X86Opnd, src: X86Opnd) {
12011201
cb.write_int(imm.value as u64, reg.num_bits.into());
12021202
}
12031203
},
1204+
// R + UImm
1205+
(X86Opnd::Reg(reg), X86Opnd::UImm(uimm)) => {
1206+
assert!(uimm.num_bits <= reg.num_bits);
1207+
1208+
// In case the source immediate could be zero extended to be 64
1209+
// bit, we can use the 32-bit operands version of the instruction.
1210+
// For example, we can turn mov(rax, 0x34) into the equivalent
1211+
// mov(eax, 0x34).
1212+
if (reg.num_bits == 64) && (uimm.value <= u32::MAX.into()) {
1213+
if dst.rex_needed() {
1214+
write_rex(cb, false, 0, 0, reg.reg_no);
1215+
}
1216+
write_opcode(cb, 0xB8, reg);
1217+
cb.write_int(uimm.value, 32);
1218+
} else {
1219+
if reg.num_bits == 16 {
1220+
cb.write_byte(0x66);
1221+
}
1222+
1223+
if dst.rex_needed() || reg.num_bits == 64 {
1224+
write_rex(cb, reg.num_bits == 64, 0, 0, reg.reg_no);
1225+
}
1226+
1227+
write_opcode(cb, if reg.num_bits == 8 { 0xb0 } else { 0xb8 }, reg);
1228+
cb.write_int(uimm.value, reg.num_bits.into());
1229+
}
1230+
},
12041231
// M + Imm
12051232
(X86Opnd::Mem(mem), X86Opnd::Imm(imm)) => {
12061233
assert!(imm.num_bits <= mem.num_bits);

yjit/src/asm/x86_64/tests.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,47 @@ fn test_mov() {
162162
check_bytes("48c742f8f4ffffff", |cb| mov(cb, mem_opnd(64, RDX, -8), imm_opnd(-12)));
163163
}
164164

165+
#[test]
166+
fn test_mov_unsigned() {
167+
// MOV AL, moffs8
168+
check_bytes("b001", |cb| mov(cb, AL, uimm_opnd(1)));
169+
check_bytes("b0ff", |cb| mov(cb, AL, uimm_opnd(u8::MAX.into())));
170+
171+
// MOV AX, moffs16
172+
check_bytes("66b80100", |cb| mov(cb, AX, uimm_opnd(1)));
173+
check_bytes("66b8ffff", |cb| mov(cb, AX, uimm_opnd(u16::MAX.into())));
174+
175+
// MOV EAX, moffs32
176+
check_bytes("b801000000", |cb| mov(cb, EAX, uimm_opnd(1)));
177+
check_bytes("b8ffffffff", |cb| mov(cb, EAX, uimm_opnd(u32::MAX.into())));
178+
179+
// MOV RAX, moffs64, will move down into EAX since it fits into 32 bits
180+
check_bytes("b801000000", |cb| mov(cb, RAX, uimm_opnd(1)));
181+
check_bytes("b8ffffffff", |cb| mov(cb, RAX, uimm_opnd(u32::MAX.into())));
182+
183+
// MOV RAX, moffs64, will not move down into EAX since it does not fit into 32 bits
184+
check_bytes("48b80000000001000000", |cb| mov(cb, RAX, uimm_opnd(u32::MAX as u64 + 1)));
185+
check_bytes("48b8ffffffffffffffff", |cb| mov(cb, RAX, uimm_opnd(u64::MAX.into())));
186+
187+
// MOV r8, imm8
188+
check_bytes("41b001", |cb| mov(cb, R8B, uimm_opnd(1)));
189+
check_bytes("41b0ff", |cb| mov(cb, R8B, uimm_opnd(u8::MAX.into())));
190+
191+
// MOV r16, imm16
192+
check_bytes("6641b80100", |cb| mov(cb, R8W, uimm_opnd(1)));
193+
check_bytes("6641b8ffff", |cb| mov(cb, R8W, uimm_opnd(u16::MAX.into())));
194+
195+
// MOV r32, imm32
196+
check_bytes("41b801000000", |cb| mov(cb, R8D, uimm_opnd(1)));
197+
check_bytes("41b8ffffffff", |cb| mov(cb, R8D, uimm_opnd(u32::MAX.into())));
198+
199+
// MOV r64, imm64, will move down into 32 bit since it fits into 32 bits
200+
check_bytes("41b801000000", |cb| mov(cb, R8, uimm_opnd(1)));
201+
202+
// MOV r64, imm64, will not move down into 32 bit since it does not fit into 32 bits
203+
check_bytes("49b8ffffffffffffffff", |cb| mov(cb, R8, uimm_opnd(u64::MAX)));
204+
}
205+
165206
#[test]
166207
fn test_movsx() {
167208
check_bytes("660fbec0", |cb| movsx(cb, AX, AL));

yjit/src/codegen.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,13 +437,9 @@ fn gen_exit(exit_pc: *mut VALUE, ctx: &Context, cb: &mut CodeBlock) -> CodePtr
437437
pop(cb, REG_EC);
438438
pop(cb, REG_CFP);
439439

440-
//mov(cb, RAX, uimm_opnd(Qundef.into()));
440+
mov(cb, RAX, uimm_opnd(Qundef.into()));
441441
ret(cb);
442442

443-
444-
todo!("missing uimm");
445-
446-
447443
return code_ptr;
448444
}
449445

@@ -1137,9 +1133,8 @@ mod tests {
11371133
fn test_gen_exit() {
11381134
let (_, ctx, mut cb, _) = setup_codegen();
11391135

1140-
// TODO: missing encoding of uimm operands
1141-
//gen_exit(0 as *mut VALUE, &ctx, &mut cb);
1142-
//assert!(cb.get_write_pos() > 0);
1136+
gen_exit(0 as *mut VALUE, &ctx, &mut cb);
1137+
assert!(cb.get_write_pos() > 0);
11431138
}
11441139

11451140
#[test]

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy