Index: lib/Target/X86/AsmParser/X86AsmParser.cpp =================================================================== --- lib/Target/X86/AsmParser/X86AsmParser.cpp +++ lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -2170,6 +2170,17 @@ if (getLexer().is(AsmToken::Star)) Operands.push_back(X86Operand::CreateToken("*", consumeToken())); + // Parse ',pn'/',pt' branch hints. + else if (getLexer().is(AsmToken::Comma)) { + consumeToken(); + if (!getLexer().is(AsmToken::Identifier) || + !getLexer().getTok().getIdentifier().startswith("p")) + return ErrorAndEatStatement(getLexer().getLoc(), + "unexpected token in argument list"); + StringRef BrHint = getLexer().getTok().getIdentifier(); + Operands.push_back(X86Operand::CreateToken(BrHint, consumeToken())); + } + // Read the operands. while(1) { if (std::unique_ptr Op = ParseOperand()) { Index: lib/Target/X86/Disassembler/X86Disassembler.cpp =================================================================== --- lib/Target/X86/Disassembler/X86Disassembler.cpp +++ lib/Target/X86/Disassembler/X86Disassembler.cpp @@ -967,6 +967,43 @@ mcInst.setOpcode(X86::XACQUIRE_PREFIX); } + // CS/DS on a conditional branch has special meaning: it indicates a + // static predicted taken/not-taken hint. + // Match that directly. + if ((((insn.opcode & 0xf0) == 0x70) || ((insn.opcode & 0xf0) == 0x80)) && + (insn.segmentOverride == SEG_OVERRIDE_CS || + insn.segmentOverride == SEG_OVERRIDE_DS)) { + bool isPN = (insn.segmentOverride == SEG_OVERRIDE_CS); + unsigned NewOpc = mcInst.getOpcode(); + switch (mcInst.getOpcode()) { +#define HANDLE_JCC_BRHINT(I) \ + case I##_1: NewOpc = isPN ? I##_PN_1 : I##_PT_1; break; \ + case I##_2: NewOpc = isPN ? I##_PN_2 : I##_PT_2; break; \ + case I##_4: NewOpc = isPN ? I##_PN_4 : I##_PT_4; break + + HANDLE_JCC_BRHINT(X86::JO); + HANDLE_JCC_BRHINT(X86::JNO); + HANDLE_JCC_BRHINT(X86::JB); + HANDLE_JCC_BRHINT(X86::JAE); + HANDLE_JCC_BRHINT(X86::JE); + HANDLE_JCC_BRHINT(X86::JNE); + HANDLE_JCC_BRHINT(X86::JBE); + HANDLE_JCC_BRHINT(X86::JA); + HANDLE_JCC_BRHINT(X86::JS); + HANDLE_JCC_BRHINT(X86::JNS); + HANDLE_JCC_BRHINT(X86::JP); + HANDLE_JCC_BRHINT(X86::JNP); + HANDLE_JCC_BRHINT(X86::JL); + HANDLE_JCC_BRHINT(X86::JGE); + HANDLE_JCC_BRHINT(X86::JLE); + HANDLE_JCC_BRHINT(X86::JG); +#undef HANDLE_JCC_BRHINT + default: + break; // For the other instructions with an opcode ending in 70h/80h. + } + mcInst.setOpcode(NewOpc); + } + insn.numImmediatesTranslated = 0; for (const auto &Op : insn.operands) { Index: lib/Target/X86/MCTargetDesc/X86BaseInfo.h =================================================================== --- lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -283,6 +283,11 @@ /// manual, this operand is described as pntr16:32 and pntr16:16 RawFrmImm16 = 12, + /// JccPNFrm and JccPTFrm are used for JCC instructions that are preceded + /// by a static branch prediction hint prefix (0x2E resp. 0x3E). + /// They behave like RawFrm otherwise. + JccPNFrm = 13, JccPTFrm = 14, + /// MRMX[rm] - The forms are used to represent instructions that use a /// Mod/RM byte, and don't use the middle field for anything. MRMXr = 15, MRMXm = 16, @@ -666,6 +671,8 @@ default: llvm_unreachable("Unknown FormMask value in getMemoryOperandNo!"); case X86II::Pseudo: case X86II::RawFrm: + case X86II::JccPNFrm: + case X86II::JccPTFrm: case X86II::AddRegFrm: case X86II::MRMDestReg: case X86II::MRMSrcReg: Index: lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp =================================================================== --- lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -1275,6 +1275,14 @@ EmitByte(BaseOpcode, CurByte, OS); break; } + case X86II::JccPNFrm: + EmitByte(0x2E, CurByte, OS); + EmitByte(BaseOpcode, CurByte, OS); + break; + case X86II::JccPTFrm: + EmitByte(0x3E, CurByte, OS); + EmitByte(BaseOpcode, CurByte, OS); + break; case X86II::RawFrm: EmitByte(BaseOpcode, CurByte, OS); break; Index: lib/Target/X86/X86InstrControl.td =================================================================== --- lib/Target/X86/X86InstrControl.td +++ lib/Target/X86/X86InstrControl.td @@ -69,18 +69,28 @@ // Conditional Branches. let isBranch = 1, isTerminator = 1, Uses = [EFLAGS], SchedRW = [WriteJump] in { - multiclass ICBr opc1, bits<8> opc4, string asm, PatFrag Cond> { - def _1 : Ii8PCRel ; + multiclass ICBrBase opc1, bits<8> opc4, Format Frm, string asm, + list Patterns> { + def _1 : Ii8PCRel ; let hasSideEffects = 0, isCodeGenOnly = 1, ForceDisassemble = 1 in { - def _2 : Ii16PCRel, OpSize16, TB; - def _4 : Ii32PCRel, TB, OpSize32; } } } +multiclass ICBr opc1, bits<8> opc4, string asm, PatFrag Cond> { + defm NAME : ICBrBase; + let isAsmParserOnly = 1 in { + defm _PN : ICBrBase; + defm _PT : ICBrBase; + } +} + defm JO : ICBr<0x70, 0x80, "jo" , X86_COND_O>; defm JNO : ICBr<0x71, 0x81, "jno", X86_COND_NO>; defm JB : ICBr<0x72, 0x82, "jb" , X86_COND_B>; Index: lib/Target/X86/X86InstrFormats.td =================================================================== --- lib/Target/X86/X86InstrFormats.td +++ lib/Target/X86/X86InstrFormats.td @@ -26,6 +26,7 @@ def RawFrmDstSrc: Format<10>; def RawFrmImm8 : Format<11>; def RawFrmImm16 : Format<12>; +def JccPNFrm : Format<13>; def JccPTFrm : Format<14>; def MRMXr : Format<15>; def MRMXm : Format<16>; def MRM0r : Format<17>; def MRM1r : Format<18>; def MRM2r : Format<19>; Index: test/MC/Disassembler/X86/branch-hint-prefix.s =================================================================== --- /dev/null +++ test/MC/Disassembler/X86/branch-hint-prefix.s @@ -0,0 +1,113 @@ +## RUN: llvm-mc -disassemble -triple x86_64-unknown-unknown < %s | FileCheck %s + +## CHECK: jo -1 +0x70,0xff +## CHECK: jo,pn -1 +0x2e,0x70,0xff +## CHECK: jo,pt -1 +0x3e,0x70,0xff + +## CHECK: jno -1 +0x71,0xff +## CHECK: jno,pn -1 +0x2e,0x71,0xff +## CHECK: jno,pt -1 +0x3e,0x71,0xff + +## CHECK: jb -1 +0x72,0xff +## CHECK: jb,pn -1 +0x2e,0x72,0xff +## CHECK: jb,pt -1 +0x3e,0x72,0xff + +## CHECK: jae -1 +0x73,0xff +## CHECK: jae,pn -1 +0x2e,0x73,0xff +## CHECK: jae,pt -1 +0x3e,0x73,0xff + +## CHECK: je -1 +0x74,0xff +## CHECK: je,pn -1 +0x2e,0x74,0xff +## CHECK: je,pt -1 +0x3e,0x74,0xff + +## CHECK: jne -1 +0x75,0xff +## CHECK: jne,pn -1 +0x2e,0x75,0xff +## CHECK: jne,pt -1 +0x3e,0x75,0xff + +## CHECK: jbe -1 +0x76,0xff +## CHECK: jbe,pn -1 +0x2e,0x76,0xff +## CHECK: jbe,pt -1 +0x3e,0x76,0xff + +## CHECK: ja -1 +0x77,0xff +## CHECK: ja,pn -1 +0x2e,0x77,0xff +## CHECK: ja,pt -1 +0x3e,0x77,0xff + +## CHECK: js -1 +0x78,0xff +## CHECK: js,pn -1 +0x2e,0x78,0xff +## CHECK: js,pt -1 +0x3e,0x78,0xff + +## CHECK: jns -1 +0x79,0xff +## CHECK: jns,pn -1 +0x2e,0x79,0xff +## CHECK: jns,pt -1 +0x3e,0x79,0xff + +## CHECK: jp -1 +0x7a,0xff +## CHECK: jp,pn -1 +0x2e,0x7a,0xff +## CHECK: jp,pt -1 +0x3e,0x7a,0xff + +## CHECK: jnp -1 +0x7b,0xff +## CHECK: jnp,pn -1 +0x2e,0x7b,0xff +## CHECK: jnp,pt -1 +0x3e,0x7b,0xff + +## CHECK: jl -1 +0x7c,0xff +## CHECK: jl,pn -1 +0x2e,0x7c,0xff +## CHECK: jl,pt -1 +0x3e,0x7c,0xff + +## CHECK: jge -1 +0x7d,0xff +## CHECK: jge,pn -1 +0x2e,0x7d,0xff +## CHECK: jge,pt -1 +0x3e,0x7d,0xff + +## CHECK: jle -1 +0x7e,0xff +## CHECK: jle,pn -1 +0x2e,0x7e,0xff +## CHECK: jle,pt -1 +0x3e,0x7e,0xff + +## CHECK: jg -1 +0x7f,0xff +## CHECK: jg,pn -1 +0x2e,0x7f,0xff +## CHECK: jg,pt -1 +0x3e,0x7f,0xff Index: test/MC/X86/branch-hint-prefix.s =================================================================== --- /dev/null +++ test/MC/X86/branch-hint-prefix.s @@ -0,0 +1,161 @@ +// RUN: llvm-mc -triple x86_64-unknown-unknown -show-encoding < %s | FileCheck %s + +// CHECK: jo -1 +// CHECK: encoding: [0x70,A] +jo -1 +// CHECK: jo,pn -1 +// CHECK: encoding: [0x2e,0x70,A] +jo,pn -1 +// CHECK: jo,pt -1 +// CHECK: encoding: [0x3e,0x70,A] +jo,pt -1 + +// CHECK: jno -1 +// CHECK: encoding: [0x71,A] +jno -1 +// CHECK: jno,pn -1 +// CHECK: encoding: [0x2e,0x71,A] +jno,pn -1 +// CHECK: jno,pt -1 +// CHECK: encoding: [0x3e,0x71,A] +jno,pt -1 + +// CHECK: jb -1 +// CHECK: encoding: [0x72,A] +jb -1 +// CHECK: jb,pn -1 +// CHECK: encoding: [0x2e,0x72,A] +jb,pn -1 +// CHECK: jb,pt -1 +// CHECK: encoding: [0x3e,0x72,A] +jb,pt -1 + +// CHECK: jae -1 +// CHECK: encoding: [0x73,A] +jae -1 +// CHECK: jae,pn -1 +// CHECK: encoding: [0x2e,0x73,A] +jae,pn -1 +// CHECK: jae,pt -1 +// CHECK: encoding: [0x3e,0x73,A] +jae,pt -1 + +// CHECK: je -1 +// CHECK: encoding: [0x74,A] +je -1 +// CHECK: je,pn -1 +// CHECK: encoding: [0x2e,0x74,A] +je,pn -1 +// CHECK: je,pt -1 +// CHECK: encoding: [0x3e,0x74,A] +je,pt -1 + +// CHECK: jne -1 +// CHECK: encoding: [0x75,A] +jne -1 +// CHECK: jne,pn -1 +// CHECK: encoding: [0x2e,0x75,A] +jne,pn -1 +// CHECK: jne,pt -1 +// CHECK: encoding: [0x3e,0x75,A] +jne,pt -1 + +// CHECK: jbe -1 +// CHECK: encoding: [0x76,A] +jbe -1 +// CHECK: jbe,pn -1 +// CHECK: encoding: [0x2e,0x76,A] +jbe,pn -1 +// CHECK: jbe,pt -1 +// CHECK: encoding: [0x3e,0x76,A] +jbe,pt -1 + +// CHECK: ja -1 +// CHECK: encoding: [0x77,A] +ja -1 +// CHECK: ja,pn -1 +// CHECK: encoding: [0x2e,0x77,A] +ja,pn -1 +// CHECK: ja,pt -1 +// CHECK: encoding: [0x3e,0x77,A] +ja,pt -1 + +// CHECK: js -1 +// CHECK: encoding: [0x78,A] +js -1 +// CHECK: js,pn -1 +// CHECK: encoding: [0x2e,0x78,A] +js,pn -1 +// CHECK: js,pt -1 +// CHECK: encoding: [0x3e,0x78,A] +js,pt -1 + +// CHECK: jns -1 +// CHECK: encoding: [0x79,A] +jns -1 +// CHECK: jns,pn -1 +// CHECK: encoding: [0x2e,0x79,A] +jns,pn -1 +// CHECK: jns,pt -1 +// CHECK: encoding: [0x3e,0x79,A] +jns,pt -1 + +// CHECK: jp -1 +// CHECK: encoding: [0x7a,A] +jp -1 +// CHECK: jp,pn -1 +// CHECK: encoding: [0x2e,0x7a,A] +jp,pn -1 +// CHECK: jp,pt -1 +// CHECK: encoding: [0x3e,0x7a,A] +jp,pt -1 + +// CHECK: jnp -1 +// CHECK: encoding: [0x7b,A] +jnp -1 +// CHECK: jnp,pn -1 +// CHECK: encoding: [0x2e,0x7b,A] +jnp,pn -1 +// CHECK: jnp,pt -1 +// CHECK: encoding: [0x3e,0x7b,A] +jnp,pt -1 + +// CHECK: jl -1 +// CHECK: encoding: [0x7c,A] +jl -1 +// CHECK: jl,pn -1 +// CHECK: encoding: [0x2e,0x7c,A] +jl,pn -1 +// CHECK: jl,pt -1 +// CHECK: encoding: [0x3e,0x7c,A] +jl,pt -1 + +// CHECK: jge -1 +// CHECK: encoding: [0x7d,A] +jge -1 +// CHECK: jge,pn -1 +// CHECK: encoding: [0x2e,0x7d,A] +jge,pn -1 +// CHECK: jge,pt -1 +// CHECK: encoding: [0x3e,0x7d,A] +jge,pt -1 + +// CHECK: jle -1 +// CHECK: encoding: [0x7e,A] +jle -1 +// CHECK: jle,pn -1 +// CHECK: encoding: [0x2e,0x7e,A] +jle,pn -1 +// CHECK: jle,pt -1 +// CHECK: encoding: [0x3e,0x7e,A] +jle,pt -1 + +// CHECK: jg -1 +// CHECK: encoding: [0x7f,A] +jg -1 +// CHECK: jg,pn -1 +// CHECK: encoding: [0x2e,0x7f,A] +jg,pn -1 +// CHECK: jg,pt -1 +// CHECK: encoding: [0x3e,0x7f,A] +jg,pt -1 Index: utils/TableGen/X86RecognizableInstr.cpp =================================================================== --- utils/TableGen/X86RecognizableInstr.cpp +++ utils/TableGen/X86RecognizableInstr.cpp @@ -104,6 +104,8 @@ RawFrmDstSrc = 10, RawFrmImm8 = 11, RawFrmImm16 = 12, + JccPNFrm = 13, + JccPTFrm = 14, MRMXr = 15, MRMXm = 16, MRM0r = 17, MRM1r = 18, MRM2r = 19, MRM3r = 20, MRM4r = 21, MRM5r = 22, MRM6r = 23, MRM7r = 24, @@ -583,6 +585,8 @@ HANDLE_OPERAND(relocation); return; case X86Local::RawFrm: + case X86Local::JccPNFrm: + case X86Local::JccPTFrm: // Operand 1 (optional) is an address or immediate. // Operand 2 (optional) is an immediate. assert(numPhysicalOperands <= 2 &&