Skip to content

Commit

Permalink
[X86] Add assembler support for {disp8} and {disp32} to control the s…
Browse files Browse the repository at this point in the history
…ize of displacement used for memory operands.

These prefixes should override the default behavior and force a larger immediate size. I don't believe gas issues any warning if you use {disp8} when a 32-bit displacement is already required. And this patch doesn't either.

This completes the {disp8} and {disp32} support from PR46650.

Reviewed By: RKSimon

Differential Revision: https://reviews.llvm.org/D84793
  • Loading branch information
topperc committed Aug 1, 2020
1 parent 85b5315 commit e297d92
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 24 deletions.
12 changes: 12 additions & 0 deletions llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
Expand Up @@ -3572,6 +3572,12 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
if (ForcedVEXEncoding == VEXEncoding_VEX3)
Prefixes |= X86::IP_USE_VEX3;

// Set encoded flags for {disp8} and {disp32}.
if (ForcedDispEncoding == DispEncoding_Disp8)
Prefixes |= X86::IP_USE_DISP8;
else if (ForcedDispEncoding == DispEncoding_Disp32)
Prefixes |= X86::IP_USE_DISP32;

if (Prefixes)
Inst.setFlags(Prefixes);

Expand Down Expand Up @@ -3806,6 +3812,12 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
if (ForcedVEXEncoding == VEXEncoding_VEX3)
Prefixes |= X86::IP_USE_VEX3;

// Set encoded flags for {disp8} and {disp32}.
if (ForcedDispEncoding == DispEncoding_Disp8)
Prefixes |= X86::IP_USE_DISP8;
else if (ForcedDispEncoding == DispEncoding_Disp32)
Prefixes |= X86::IP_USE_DISP32;

if (Prefixes)
Inst.setFlags(Prefixes);

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
Expand Up @@ -62,6 +62,8 @@ namespace X86 {
IP_HAS_LOCK = 16,
IP_HAS_NOTRACK = 32,
IP_USE_VEX3 = 64,
IP_USE_DISP8 = 128,
IP_USE_DISP32 = 256,
};

enum OperandType : unsigned {
Expand Down
59 changes: 35 additions & 24 deletions llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
Expand Up @@ -505,12 +505,18 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op,
return;
}

// Determine whether a SIB byte is needed.
// If no BaseReg, issue a RIP relative instruction only if the MCE can
// resolve addresses on-the-fly, otherwise use SIB (Intel Manual 2A, table
// 2-7) and absolute references.
// Check for presence of {disp8} or {disp32} pseudo prefixes.
bool UseDisp8 = MI.getFlags() & X86::IP_USE_DISP8;
bool UseDisp32 = MI.getFlags() & X86::IP_USE_DISP32;

// We only allow no displacement if no pseudo prefix is present.
bool AllowNoDisp = !UseDisp8 && !UseDisp32;
// Disp8 is allowed unless the {disp32} prefix is present.
bool AllowDisp8 = !UseDisp32;

if ( // The SIB byte must be used if there is an index register.
// Determine whether a SIB byte is needed.
if (// The SIB byte must be used if there is an index register or the
// encoding requires a SIB byte.
!ForceSIB && IndexReg.getReg() == 0 &&
// The SIB byte must be used if the base is ESP/RSP/R12, all of which
// encode to an R/M value of 4, which indicates that a SIB byte is
Expand All @@ -526,12 +532,12 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op,
return;
}

// If the base is not EBP/ESP and there is no displacement, use simple
// indirect register encoding, this handles addresses like [EAX]. The
// encoding for [EBP] with no displacement means [disp32] so we handle it
// by emitting a displacement of 0 below.
// If the base is not EBP/ESP/R12/R13 and there is no displacement, use
// simple indirect register encoding, this handles addresses like [EAX].
// The encoding for [EBP] or[R13] with no displacement means [disp32] so we
// handle it by emitting a displacement of 0 later.
if (BaseRegNo != N86::EBP) {
if (Disp.isImm() && Disp.getImm() == 0) {
if (Disp.isImm() && Disp.getImm() == 0 && AllowNoDisp) {
emitByte(modRMByte(0, RegOpcodeField, BaseRegNo), OS);
return;
}
Expand All @@ -550,7 +556,10 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op,
}

// Otherwise, if the displacement fits in a byte, encode as [REG+disp8].
if (Disp.isImm()) {
// Including a compressed disp8 for EVEX instructions that support it.
// This also handles the 0 displacement for [EBP] or [R13]. We can't use
// disp8 if the {disp32} pseudo prefix is present.
if (Disp.isImm() && AllowDisp8) {
int ImmOffset = 0;
if (isDispOrCDisp8(TSFlags, Disp.getImm(), ImmOffset)) {
emitByte(modRMByte(1, RegOpcodeField, BaseRegNo), OS);
Expand All @@ -560,7 +569,9 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op,
}
}

// Otherwise, emit the most general non-SIB encoding: [REG+disp32]
// Otherwise, emit the most general non-SIB encoding: [REG+disp32].
// Displacement may be 0 for [EBP] or [R13] case if {disp32} pseudo prefix
// prevented using disp8 above.
emitByte(modRMByte(2, RegOpcodeField, BaseRegNo), OS);
unsigned Opcode = MI.getOpcode();
unsigned FixupKind = Opcode == X86::MOV32rm ? X86::reloc_signed_4byte_relax
Expand All @@ -580,21 +591,26 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op,
if (BaseReg == 0) {
// If there is no base register, we emit the special case SIB byte with
// MOD=0, BASE=5, to JUST get the index, scale, and displacement.
BaseRegNo = 5;
emitByte(modRMByte(0, RegOpcodeField, 4), OS);
ForceDisp32 = true;
} else if (Disp.isImm() && Disp.getImm() == 0 &&
// Base reg can't be anything that ends up with '5' as the base
// reg, it is the magic [*] nomenclature that indicates no base.
} else if (Disp.isImm() && Disp.getImm() == 0 && AllowNoDisp &&
// Base reg can't be EBP/RBP/R13 as that would end up with '5' as
// the base field, but that is the magic [*] nomenclature that
// indicates no base when mod=0. For these cases we'll emit a 0
// displacement instead.
BaseRegNo != N86::EBP) {
// Emit no displacement ModR/M byte
emitByte(modRMByte(0, RegOpcodeField, 4), OS);
} else if (Disp.isImm() &&
} else if (Disp.isImm() && AllowDisp8 &&
isDispOrCDisp8(TSFlags, Disp.getImm(), ImmOffset)) {
// Emit the disp8 encoding.
// Displacement fits in a byte or matches an EVEX compressed disp8, use
// disp8 encoding. This also handles EBP/R13 base with 0 displacement unless
// {disp32} pseudo prefix was used.
emitByte(modRMByte(1, RegOpcodeField, 4), OS);
ForceDisp8 = true; // Make sure to force 8 bit disp if Base=EBP
ForceDisp8 = true;
} else {
// Emit the normal disp32 encoding.
// Otherwise, emit the normal disp32 encoding.
emitByte(modRMByte(2, RegOpcodeField, 4), OS);
ForceDisp32 = true;
}
Expand All @@ -605,11 +621,6 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op,

unsigned IndexRegNo = IndexReg.getReg() ? getX86RegNum(IndexReg) : 4;

// Handle the SIB byte for the case where there is no base, see Intel
// Manual 2A, table 2-7. The displacement has already been output.
if (BaseReg == 0)
BaseRegNo = 5;

emitSIBByte(SS, IndexRegNo, BaseRegNo, OS);

// Do we need to output a displacement?
Expand Down
88 changes: 88 additions & 0 deletions llvm/test/MC/X86/x86-64.s
Expand Up @@ -1904,3 +1904,91 @@ ud1 %rdx, %rdi
// CHECK: ud1q (%rbx), %rcx
// CHECK: encoding: [0x48,0x0f,0xb9,0x0b]
ud2b (%rbx), %rcx

// Requires no displacement by default
// CHECK: movl $1, (%rax)
// CHECK: encoding: [0xc7,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%rax)
// CHECK: encoding: [0xc7,0x40,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%rax)
// CHECK: encoding: [0xc7,0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
movl $1, (%rax)
{disp8} movl $1, (%rax)
{disp32} movl $1, (%rax)

// Requires disp8 by default
// CHECK: movl $1, (%rbp)
// CHECK: encoding: [0xc7,0x45,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%rbp)
// CHECK: encoding: [0xc7,0x45,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%rbp)
// CHECK: encoding: [0xc7,0x85,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
movl $1, (%rbp)
{disp8} movl $1, (%rbp)
{disp32} movl $1, (%rbp)

// Requires disp8 by default
// CHECK: movl $1, (%r13)
// CHECK: encoding: [0x41,0xc7,0x45,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%r13)
// CHECK: encoding: [0x41,0xc7,0x45,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%r13)
// CHECK: encoding: [0x41,0xc7,0x85,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
movl $1, (%r13)
{disp8} movl $1, (%r13)
{disp32} movl $1, (%r13)

// Requires disp8 by default
// CHECK: movl $1, 8(%rax)
// CHECK: encoding: [0xc7,0x40,0x08,0x01,0x00,0x00,0x00]
// CHECK: movl $1, 8(%rax)
// CHECK: encoding: [0xc7,0x40,0x08,0x01,0x00,0x00,0x00]
// CHECK: movl $1, 8(%rax)
// CHECK: encoding: [0xc7,0x80,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
movl $1, 8(%rax)
{disp8} movl $1, 8(%rax)
{disp32} movl $1, 8(%rax)

// Requires no displacement by default
// CHECK: movl $1, (%rax,%rbx,4)
// CHECK: encoding: [0xc7,0x04,0x98,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%rax,%rbx,4)
// CHECK: encoding: [0xc7,0x44,0x98,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%rax,%rbx,4)
// CHECK: encoding: [0xc7,0x84,0x98,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
movl $1, (%rax,%rbx,4)
{disp8} movl $1, (%rax,%rbx,4)
{disp32} movl $1, (%rax,%rbx,4)

// Requires disp8 by default.
// CHECK: movl $1, 8(%rax,%rbx,4)
// CHECK: encoding: [0xc7,0x44,0x98,0x08,0x01,0x00,0x00,0x00]
// CHECK: movl $1, 8(%rax,%rbx,4)
// CHECK: encoding: [0xc7,0x44,0x98,0x08,0x01,0x00,0x00,0x00]
// CHECK: movl $1, 8(%rax,%rbx,4)
// CHECK: encoding: [0xc7,0x84,0x98,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
movl $1, 8(%rax,%rbx,4)
{disp8} movl $1, 8(%rax,%rbx,4)
{disp32} movl $1, 8(%rax,%rbx,4)

// Requires disp8 by default.
// CHECK: movl $1, (%rbp,%rbx,4)
// CHECK: encoding: [0xc7,0x44,0x9d,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%rbp,%rbx,4)
// CHECK: encoding: [0xc7,0x44,0x9d,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%rbp,%rbx,4)
// CHECK: encoding: [0xc7,0x84,0x9d,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
movl $1, (%rbp,%rbx,4)
{disp8} movl $1, (%rbp,%rbx,4)
{disp32} movl $1, (%rbp,%rbx,4)

// Requires disp8 by default.
// CHECK: movl $1, (%r13,%rbx,4)
// CHECK: encoding: [0x41,0xc7,0x44,0x9d,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%r13,%rbx,4)
// CHECK: encoding: [0x41,0xc7,0x44,0x9d,0x00,0x01,0x00,0x00,0x00]
// CHECK: movl $1, (%r13,%rbx,4)
// CHECK: encoding: [0x41,0xc7,0x84,0x9d,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
movl $1, (%r13,%rbx,4)
{disp8} movl $1, (%r13,%rbx,4)
{disp32} movl $1, (%r13,%rbx,4)

0 comments on commit e297d92

Please sign in to comment.