Index: lib/Target/X86/AsmParser/X86AsmParser.cpp =================================================================== --- lib/Target/X86/AsmParser/X86AsmParser.cpp +++ lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -2312,6 +2312,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 @@ -971,6 +971,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 @@ -566,7 +566,13 @@ /// Explicitly specified rounding control EVEX_RCShift = MemOp4Shift + 1, - EVEX_RC = 1ULL << EVEX_RCShift + EVEX_RC = 1ULL << EVEX_RCShift, + + /// Not-Taken (2Eh) / Taken (3Eh) branch prediction hints. + PredNShift = EVEX_RCShift + 1, + PredN = 1ULL << PredNShift, + PredTShift = PredNShift + 1, + PredT = 1ULL << PredTShift }; // getBaseOpcodeFor - This function returns the "base" X86 opcode for the Index: lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp =================================================================== --- lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -1203,6 +1203,12 @@ EmitSegmentOverridePrefix(CurByte, MemoryOperand+X86::AddrSegmentReg, MI, OS); + // Emit the PN/PT opcode "prefixes". + if (TSFlags & X86II::PredN) + EmitByte(0x2E, CurByte, OS); + else if (TSFlags & X86II::PredT) + EmitByte(0x3E, CurByte, OS); + // Emit the repeat opcode prefix as needed. if (TSFlags & X86II::REP) EmitByte(0xF3, CurByte, OS); Index: lib/Target/X86/X86InstrControl.td =================================================================== --- lib/Target/X86/X86InstrControl.td +++ lib/Target/X86/X86InstrControl.td @@ -82,34 +82,45 @@ // 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, 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; + def _2 : Ii16PCRel, OpSize16, TB; + def _4 : Ii32PCRel, TB, OpSize32; } } } -defm JO : ICBr<0x70, 0x80, "jo\t$dst" , X86_COND_O>; -defm JNO : ICBr<0x71, 0x81, "jno\t$dst", X86_COND_NO>; -defm JB : ICBr<0x72, 0x82, "jb\t$dst" , X86_COND_B>; -defm JAE : ICBr<0x73, 0x83, "jae\t$dst", X86_COND_AE>; -defm JE : ICBr<0x74, 0x84, "je\t$dst" , X86_COND_E>; -defm JNE : ICBr<0x75, 0x85, "jne\t$dst", X86_COND_NE>; -defm JBE : ICBr<0x76, 0x86, "jbe\t$dst", X86_COND_BE>; -defm JA : ICBr<0x77, 0x87, "ja\t$dst" , X86_COND_A>; -defm JS : ICBr<0x78, 0x88, "js\t$dst" , X86_COND_S>; -defm JNS : ICBr<0x79, 0x89, "jns\t$dst", X86_COND_NS>; -defm JP : ICBr<0x7A, 0x8A, "jp\t$dst" , X86_COND_P>; -defm JNP : ICBr<0x7B, 0x8B, "jnp\t$dst", X86_COND_NP>; -defm JL : ICBr<0x7C, 0x8C, "jl\t$dst" , X86_COND_L>; -defm JGE : ICBr<0x7D, 0x8D, "jge\t$dst", X86_COND_GE>; -defm JLE : ICBr<0x7E, 0x8E, "jle\t$dst", X86_COND_LE>; -defm JG : ICBr<0x7F, 0x8F, "jg\t$dst" , X86_COND_G>; +multiclass ICBr opc1, bits<8> opc4, string asm, PatFrag Cond> { + defm NAME : ICBrBase; + // Each conditonal branch also has two alternate forms, with prediction hints. + let isAsmParserOnly = 1 in { + defm _PN : ICBrBase, PredN; + defm _PT : ICBrBase, PredT; + } +} + +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>; +defm JAE : ICBr<0x73, 0x83, "jae", X86_COND_AE>; +defm JE : ICBr<0x74, 0x84, "je" , X86_COND_E>; +defm JNE : ICBr<0x75, 0x85, "jne", X86_COND_NE>; +defm JBE : ICBr<0x76, 0x86, "jbe", X86_COND_BE>; +defm JA : ICBr<0x77, 0x87, "ja" , X86_COND_A>; +defm JS : ICBr<0x78, 0x88, "js" , X86_COND_S>; +defm JNS : ICBr<0x79, 0x89, "jns", X86_COND_NS>; +defm JP : ICBr<0x7A, 0x8A, "jp" , X86_COND_P>; +defm JNP : ICBr<0x7B, 0x8B, "jnp", X86_COND_NP>; +defm JL : ICBr<0x7C, 0x8C, "jl" , X86_COND_L>; +defm JGE : ICBr<0x7D, 0x8D, "jge", X86_COND_GE>; +defm JLE : ICBr<0x7E, 0x8E, "jle", X86_COND_LE>; +defm JG : ICBr<0x7F, 0x8F, "jg" , X86_COND_G>; // jcx/jecx/jrcx instructions. let isBranch = 1, isTerminator = 1, hasSideEffects = 0, SchedRW = [WriteJump] in { Index: lib/Target/X86/X86InstrFormats.td =================================================================== --- lib/Target/X86/X86InstrFormats.td +++ lib/Target/X86/X86InstrFormats.td @@ -169,6 +169,8 @@ class REX_W { bit hasREX_WPrefix = 1; } class LOCK { bit hasLockPrefix = 1; } class REP { bit hasREPPrefix = 1; } +class PredN { bit hasPredNPrefix = 1; } +class PredT { bit hasPredTPrefix = 1; } class TB { Map OpMap = TB; } class T8 { Map OpMap = T8; } class TA { Map OpMap = TA; } @@ -301,6 +303,10 @@ CD8_EltSize, !srl(VectSize, CD8_Form{1-0}))), 0); + bit hasPredNPrefix = 0; // Does this inst have a Predicted-Not-Taken prefix? + bit hasPredTPrefix = 0; // Does this inst have a Predicted-Taken prefix? + + // TSFlags layout should be kept in sync with X86BaseInfo.h. let TSFlags{6-0} = FormBits; let TSFlags{8-7} = OpSizeBits; @@ -330,6 +336,8 @@ let TSFlags{56} = has3DNow0F0FOpcode; let TSFlags{57} = hasMemOp4Prefix; let TSFlags{58} = hasEVEX_RC; + let TSFlags{59} = hasPredNPrefix; + let TSFlags{60} = hasPredTPrefix; } class PseudoI pattern> 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