authorgravatar for noam@pixelhero.devNoam Preil <noam@pixelhero.dev> 2020-05-29 00:23:53-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-29 13:33:09-04:00
log834e8ac2dcdec6e1055a6c90600bcc120484176e
tree85f9c43ead7177fd1415e74dd75f6b790be95029
parentdc4fea983d358125a3b2a80dc169cad7649de6a9

[Stage2/Codegen] Extract REX


1 files changed, 48 insertions(+), 32 deletions(-)

src-self-hosted/codegen.zig+48-32
...@@ -376,6 +376,34 @@ const Function = struct {...@@ -376,6 +376,34 @@ const Function = struct {
376 }376 }
377 }377 }
378378
379 /// Encodes a REX prefix as specified, and appends it to the instruction
380 /// stream. This only modifies the instruction stream if at least one bit
381 /// is set true, which has a few implications:
382 ///
383 /// * The length of the instruction buffer will be modified *if* the
384 /// resulting REX is meaningful, but will remain the same if it is not.
385 /// * Deliberately inserting a "meaningless REX" requires explicit usage of
386 /// 0x40, and cannot be done via this function.
387 fn REX(self: *Function, arg: struct { B: bool = false, W: bool = false, X: bool = false, R: bool = false }) !void {
388 // From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB.
389 var value: u8 = 0x40;
390 if (arg.B) {
391 value |= 0x1;
392 }
393 if (arg.X) {
394 value |= 0x2;
395 }
396 if (arg.R) {
397 value |= 0x4;
398 }
399 if (arg.W) {
400 value |= 0x8;
401 }
402 if (value != 0x40) {
403 try self.code.append(value);
404 }
405 }
406
379 fn genSetReg(self: *Function, src: usize, comptime arch: Target.Cpu.Arch, reg: Reg(arch), mcv: MCValue) error{ CodegenFail, OutOfMemory }!void {407 fn genSetReg(self: *Function, src: usize, comptime arch: Target.Cpu.Arch, reg: Reg(arch), mcv: MCValue) error{ CodegenFail, OutOfMemory }!void {
380 switch (arch) {408 switch (arch) {
381 .x86_64 => switch (mcv) {409 .x86_64 => switch (mcv) {
...@@ -395,24 +423,14 @@ const Function = struct {...@@ -395,24 +423,14 @@ const Function = struct {
395 // then three bits for the operand. Since we're zeroing a register, the two three-bit423 // then three bits for the operand. Since we're zeroing a register, the two three-bit
396 // values will be identical, and the mode is three (the raw register value).424 // values will be identical, and the mode is three (the raw register value).
397 //425 //
398 if (reg.isExtended()) {426 // If we're accessing e.g. r8d, we need to use a REX prefix before the actual operation. Since
399 // If we're accessing e.g. r8d, we need to use a REX prefix before the actual operation. Since427 // this is a 32-bit operation, the W flag is set to zero. X is also zero, as we're not using a SIB.
400 // this is a 32-bit operation, the W flag is set to zero. X is also zero, as we're not using a SIB.428 // Both R and B are set, as we're extending, in effect, the register bits *and* the operand.
401 // Both R and B are set, as we're extending, in effect, the register bits *and* the operand.429 try self.REX(.{ .R = reg.isExtended(), .B = reg.isExtended() });
402 //430 const id = @as(u8, reg.id() & 0b111);
403 // From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB. In this case, that's431 return self.code.appendSlice(&[_]u8{
404 // b01000101, or 0x45.432 0x31, 0xC0 | id << 3 | id,
405 return self.code.appendSlice(&[_]u8{433 });
406 0x45,
407 0x31,
408 0xC0 | (@as(u8, reg.id() & 0b111) << 3) | @truncate(u3, reg.id()),
409 });
410 } else {
411 return self.code.appendSlice(&[_]u8{
412 0x31,
413 0xC0 | (@as(u8, reg.id()) << 3) | reg.id(),
414 });
415 }
416 }434 }
417 if (x <= std.math.maxInt(u32)) {435 if (x <= std.math.maxInt(u32)) {
418 // Next best case: if we set the lower four bytes, the upper four will be zeroed.436 // Next best case: if we set the lower four bytes, the upper four will be zeroed.
...@@ -445,9 +463,9 @@ const Function = struct {...@@ -445,9 +463,9 @@ const Function = struct {
445 // Since we always need a REX here, let's just check if we also need to set REX.B.463 // Since we always need a REX here, let's just check if we also need to set REX.B.
446 //464 //
447 // In this case, the encoding of the REX byte is 0b0100100B465 // In this case, the encoding of the REX byte is 0b0100100B
448 const REX = 0x48 | (if (reg.isExtended()) @as(u8, 0x01) else 0);466
449 try self.code.resize(self.code.items.len + 10);467 try self.REX(.{ .W = true, .B = reg.isExtended() });
450 self.code.items[self.code.items.len - 10] = REX;468 try self.code.resize(self.code.items.len + 9);
451 self.code.items[self.code.items.len - 9] = 0xB8 | @as(u8, reg.id() & 0b111);469 self.code.items[self.code.items.len - 9] = 0xB8 | @as(u8, reg.id() & 0b111);
452 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];470 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];
453 mem.writeIntLittle(u64, imm_ptr, x);471 mem.writeIntLittle(u64, imm_ptr, x);
...@@ -463,12 +481,11 @@ const Function = struct {...@@ -463,12 +481,11 @@ const Function = struct {
463 // but the operation size is unchanged. Since we're using a disp32, we want mode 0 and lower three481 // but the operation size is unchanged. Since we're using a disp32, we want mode 0 and lower three
464 // bits as five.482 // bits as five.
465 // REX 0x8D 0b00RRR101, where RRR is the lower three bits of the id.483 // REX 0x8D 0b00RRR101, where RRR is the lower three bits of the id.
466 try self.code.resize(self.code.items.len + 7);484 try self.REX(.{ .W = true, .B = reg.isExtended() });
467 const REX = 0x48 | if (reg.isExtended()) @as(u8, 1) else 0;485 try self.code.resize(self.code.items.len + 6);
468 const rip = self.code.items.len;486 const rip = self.code.items.len;
469 const big_offset = @intCast(i64, code_offset) - @intCast(i64, rip);487 const big_offset = @intCast(i64, code_offset) - @intCast(i64, rip);
470 const offset = @intCast(i32, big_offset);488 const offset = @intCast(i32, big_offset);
471 self.code.items[self.code.items.len - 7] = REX;
472 self.code.items[self.code.items.len - 6] = 0x8D;489 self.code.items[self.code.items.len - 6] = 0x8D;
473 self.code.items[self.code.items.len - 5] = 0b101 | (@as(u8, reg.id() & 0b111) << 3);490 self.code.items[self.code.items.len - 5] = 0b101 | (@as(u8, reg.id() & 0b111) << 3);
474 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];491 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
...@@ -485,9 +502,9 @@ const Function = struct {...@@ -485,9 +502,9 @@ const Function = struct {
485 // If the *source* is extended, the B field must be 1.502 // If the *source* is extended, the B field must be 1.
486 // Since the register is being accessed directly, the R/M mode is three. The reg field (the middle503 // Since the register is being accessed directly, the R/M mode is three. The reg field (the middle
487 // three bits) contain the destination, and the R/M field (the lower three bits) contain the source.504 // three bits) contain the destination, and the R/M field (the lower three bits) contain the source.
488 const REX = 0x48 | (if (reg.isExtended()) @as(u8, 4) else 0) | (if (src_reg.isExtended()) @as(u8, 1) else 0);505 try self.REX(.{ .W = true, .R = reg.isExtended(), .B = src_reg.isExtended() });
489 const R = 0xC0 | (@as(u8, reg.id() & 0b111) << 3) | @truncate(u3, src_reg.id());506 const R = 0xC0 | (@as(u8, reg.id() & 0b111) << 3) | @as(u8, src_reg.id() & 0b111);
490 try self.code.appendSlice(&[_]u8{ REX, 0x8B, R });507 try self.code.appendSlice(&[_]u8{ 0x8B, R });
491 },508 },
492 .memory => |x| {509 .memory => |x| {
493 if (reg.size() != 64) {510 if (reg.size() != 64) {
...@@ -501,10 +518,9 @@ const Function = struct {...@@ -501,10 +518,9 @@ const Function = struct {
501 // The SIB must be 0x25, to indicate a disp32 with no scaled index.518 // The SIB must be 0x25, to indicate a disp32 with no scaled index.
502 // 0b00RRR100, where RRR is the lower three bits of the register ID.519 // 0b00RRR100, where RRR is the lower three bits of the register ID.
503 // The instruction is thus eight bytes; REX 0x8B 0b00RRR100 0x25 followed by a four-byte disp32.520 // The instruction is thus eight bytes; REX 0x8B 0b00RRR100 0x25 followed by a four-byte disp32.
504 try self.code.resize(self.code.items.len + 8);521 try self.REX(.{ .W = true, .B = reg.isExtended() });
505 const REX = 0x48 | if (reg.isExtended()) @as(u8, 1) else 0;522 try self.code.resize(self.code.items.len + 7);
506 const r = 0x04 | (@as(u8, reg.id() & 0b111) << 3);523 const r = 0x04 | (@as(u8, reg.id() & 0b111) << 3);
507 self.code.items[self.code.items.len - 8] = REX;
508 self.code.items[self.code.items.len - 7] = 0x8B;524 self.code.items[self.code.items.len - 7] = 0x8B;
509 self.code.items[self.code.items.len - 6] = r;525 self.code.items[self.code.items.len - 6] = r;
510 self.code.items[self.code.items.len - 5] = 0x25;526 self.code.items[self.code.items.len - 5] = 0x25;
...@@ -546,9 +562,9 @@ const Function = struct {...@@ -546,9 +562,9 @@ const Function = struct {
546 //562 //
547 // Furthermore, if this is an extended register, both B and R must be set in the REX byte, as *both*563 // Furthermore, if this is an extended register, both B and R must be set in the REX byte, as *both*
548 // register operands need to be marked as extended.564 // register operands need to be marked as extended.
549 const REX = 0x48 | if (reg.isExtended()) @as(u8, 0b0101) else 0;565 try self.REX(.{ .W = true, .B = reg.isExtended(), .R = reg.isExtended() });
550 const RM = (@as(u8, reg.id() & 0b111) << 3) | @truncate(u3, reg.id());566 const RM = (@as(u8, reg.id() & 0b111) << 3) | @truncate(u3, reg.id());
551 try self.code.appendSlice(&[_]u8{ REX, 0x8B, RM });567 try self.code.appendSlice(&[_]u8{ 0x8B, RM });
552 }568 }
553 }569 }
554 },570 },