diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index 6b4f2e33f67de6..49c01d7b9ef0b7 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -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); @@ -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); diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h index 79f07d3c7792ac..b6e8d4813d4ca7 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -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 { diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp index abdc0f156b9f98..0de94cda2d7398 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -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 @@ -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; } @@ -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); @@ -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 @@ -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; } @@ -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? diff --git a/llvm/test/MC/X86/x86-64.s b/llvm/test/MC/X86/x86-64.s index 38d5c6173f3b4b..c61cae69c3ffee 100644 --- a/llvm/test/MC/X86/x86-64.s +++ b/llvm/test/MC/X86/x86-64.s @@ -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)