From 4a8ac8de1ddfeaadb9ff13ce361bfc6435f18028 Mon Sep 17 00:00:00 2001 From: Joerg Sonnenberger Date: Mon, 4 Apr 2011 16:58:13 +0000 Subject: [PATCH] Add support for the VIA PadLock instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@128826 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../X86/Disassembler/X86DisassemblerDecoder.c | 30 +++++++++++ .../X86DisassemblerDecoderCommon.h | 8 ++- lib/Target/X86/X86CodeEmitter.cpp | 8 +++ lib/Target/X86/X86InstrFormats.td | 4 +- lib/Target/X86/X86InstrInfo.h | 5 +- lib/Target/X86/X86InstrSystem.td | 20 +++++++ lib/Target/X86/X86MCCodeEmitter.cpp | 10 ++++ test/MC/X86/padlock.s | 53 +++++++++++++++++++ utils/TableGen/DisassemblerEmitter.cpp | 12 ++--- utils/TableGen/X86DisassemblerTables.cpp | 2 + utils/TableGen/X86DisassemblerTables.h | 9 ++-- utils/TableGen/X86RecognizableInstr.cpp | 18 ++++++- 12 files changed, 165 insertions(+), 14 deletions(-) create mode 100644 test/MC/X86/padlock.s diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c index 06300a68686..de1610ba3d6 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c @@ -75,6 +75,12 @@ static int modRMRequired(OpcodeType type, case THREEBYTE_3A: decision = &THREEBYTE3A_SYM; break; + case THREEBYTE_A6: + decision = &THREEBYTEA6_SYM; + break; + case THREEBYTE_A7: + decision = &THREEBYTEA7_SYM; + break; } return decision->opcodeDecisions[insnContext].modRMDecisions[opcode]. @@ -115,6 +121,12 @@ static InstrUID decode(OpcodeType type, case THREEBYTE_3A: dec = &THREEBYTE3A_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; + case THREEBYTE_A6: + dec = &THREEBYTEA6_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; + break; + case THREEBYTE_A7: + dec = &THREEBYTEA7_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; + break; } switch (dec->modrm_type) { @@ -580,6 +592,24 @@ static int readOpcode(struct InternalInstruction* insn) { return -1; insn->opcodeType = THREEBYTE_3A; + } else if (current == 0xa6) { + dbgprintf(insn, "Found a three-byte escape prefix (0x%hhx)", current); + + insn->threeByteEscape = current; + + if (consumeByte(insn, ¤t)) + return -1; + + insn->opcodeType = THREEBYTE_A6; + } else if (current == 0xa7) { + dbgprintf(insn, "Found a three-byte escape prefix (0x%hhx)", current); + + insn->threeByteEscape = current; + + if (consumeByte(insn, ¤t)) + return -1; + + insn->opcodeType = THREEBYTE_A7; } else { dbgprintf(insn, "Didn't find a three-byte escape prefix"); diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h index bc35be80c83..70315ed572b 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h @@ -30,6 +30,8 @@ #define TWOBYTE_SYM x86DisassemblerTwoByteOpcodes #define THREEBYTE38_SYM x86DisassemblerThreeByte38Opcodes #define THREEBYTE3A_SYM x86DisassemblerThreeByte3AOpcodes +#define THREEBYTEA6_SYM x86DisassemblerThreeByteA6Opcodes +#define THREEBYTEA7_SYM x86DisassemblerThreeByteA7Opcodes #define INSTRUCTIONS_STR "x86DisassemblerInstrSpecifiers" #define CONTEXTS_STR "x86DisassemblerContexts" @@ -37,6 +39,8 @@ #define TWOBYTE_STR "x86DisassemblerTwoByteOpcodes" #define THREEBYTE38_STR "x86DisassemblerThreeByte38Opcodes" #define THREEBYTE3A_STR "x86DisassemblerThreeByte3AOpcodes" +#define THREEBYTEA6_STR "x86DisassemblerThreeByteA6Opcodes" +#define THREEBYTEA7_STR "x86DisassemblerThreeByteA7Opcodes" /* * Attributes of an instruction that must be known before the opcode can be @@ -119,7 +123,9 @@ typedef enum { ONEBYTE = 0, TWOBYTE = 1, THREEBYTE_38 = 2, - THREEBYTE_3A = 3 + THREEBYTE_3A = 3, + THREEBYTE_A6 = 4, + THREEBYTE_A7 = 5 } OpcodeType; /* diff --git a/lib/Target/X86/X86CodeEmitter.cpp b/lib/Target/X86/X86CodeEmitter.cpp index 60d9d4ad064..421e221d205 100644 --- a/lib/Target/X86/X86CodeEmitter.cpp +++ b/lib/Target/X86/X86CodeEmitter.cpp @@ -652,6 +652,8 @@ void Emitter::emitInstruction(MachineInstr &MI, case X86II::TB: // Two-byte opcode prefix case X86II::T8: // 0F 38 case X86II::TA: // 0F 3A + case X86II::A6: // 0F A6 + case X86II::A7: // 0F A7 Need0FPrefix = true; break; case X86II::TF: // F2 0F 38 @@ -695,6 +697,12 @@ void Emitter::emitInstruction(MachineInstr &MI, case X86II::TA: // 0F 3A MCE.emitByte(0x3A); break; + case X86II::A6: // 0F A6 + MCE.emitByte(0xA6); + break; + case X86II::A7: // 0F A7 + MCE.emitByte(0xA7); + break; } // If this is a two-address instruction, skip one of the register operands. diff --git a/lib/Target/X86/X86InstrFormats.td b/lib/Target/X86/X86InstrFormats.td index cafe37b0995..7daa2649227 100644 --- a/lib/Target/X86/X86InstrFormats.td +++ b/lib/Target/X86/X86InstrFormats.td @@ -105,7 +105,9 @@ class XD { bits<5> Prefix = 11; } class XS { bits<5> Prefix = 12; } class T8 { bits<5> Prefix = 13; } class TA { bits<5> Prefix = 14; } -class TF { bits<5> Prefix = 15; } +class A6 { bits<5> Prefix = 15; } +class A7 { bits<5> Prefix = 16; } +class TF { bits<5> Prefix = 17; } class VEX { bit hasVEXPrefix = 1; } class VEX_W { bit hasVEX_WPrefix = 1; } class VEX_4V : VEX { bit hasVEX_4VPrefix = 1; } diff --git a/lib/Target/X86/X86InstrInfo.h b/lib/Target/X86/X86InstrInfo.h index 6c0aa594c24..39448cabb49 100644 --- a/lib/Target/X86/X86InstrInfo.h +++ b/lib/Target/X86/X86InstrInfo.h @@ -368,11 +368,12 @@ namespace X86II { // floating point operations performed in the SSE registers. XD = 11 << Op0Shift, XS = 12 << Op0Shift, - // T8, TA - Prefix after the 0x0F prefix. + // T8, TA, A6, A7 - Prefix after the 0x0F prefix. T8 = 13 << Op0Shift, TA = 14 << Op0Shift, + A6 = 15 << Op0Shift, A7 = 16 << Op0Shift, // TF - Prefix before and after 0x0F - TF = 15 << Op0Shift, + TF = 17 << Op0Shift, //===------------------------------------------------------------------===// // REX_W - REX prefixes are instruction prefixes used in 64-bit mode. diff --git a/lib/Target/X86/X86InstrSystem.td b/lib/Target/X86/X86InstrSystem.td index be7d5efa5a9..2710425628a 100644 --- a/lib/Target/X86/X86InstrSystem.td +++ b/lib/Target/X86/X86InstrSystem.td @@ -398,3 +398,23 @@ let Defs = [RDX, RAX], Uses = [RCX] in let Uses = [RDX, RAX, RCX] in def XSETBV : I<0x01, MRM_D1, (outs), (ins), "xsetbv", []>, TB; + +//===----------------------------------------------------------------------===// +// VIA PadLock crypto instructions +let Defs = [RAX, RDI], Uses = [RDX, RDI] in + def XSTORE : I<0xc0, RawFrm, (outs), (ins), "xstore", []>, A7; + +let Defs = [RSI, RDI], Uses = [RBX, RDX, RSI, RDI] in { + def XCRYPTECB : I<0xc8, RawFrm, (outs), (ins), "xcryptecb", []>, A7; + def XCRYPTCBC : I<0xd0, RawFrm, (outs), (ins), "xcryptcbc", []>, A7; + def XCRYPTCTR : I<0xd8, RawFrm, (outs), (ins), "xcryptctr", []>, A7; + def XCRYPTCFB : I<0xe0, RawFrm, (outs), (ins), "xcryptcfb", []>, A7; + def XCRYPTOFB : I<0xe8, RawFrm, (outs), (ins), "xcryptofb", []>, A7; +} + +let Defs = [RAX, RSI, RDI], Uses = [RAX, RSI, RDI] in { + def XSHA1 : I<0xc8, RawFrm, (outs), (ins), "xsha1", []>, A6; + def XSHA256 : I<0xd0, RawFrm, (outs), (ins), "xsha256", []>, A6; +} +let Defs = [RAX, RDX, RSI], Uses = [RAX, RSI] in + def MONTMUL : I<0xc0, RawFrm, (outs), (ins), "montmul", []>, A6; diff --git a/lib/Target/X86/X86MCCodeEmitter.cpp b/lib/Target/X86/X86MCCodeEmitter.cpp index 50a96c85ef7..a2bd638c29a 100644 --- a/lib/Target/X86/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/X86MCCodeEmitter.cpp @@ -470,6 +470,8 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, case X86II::XD: // F2 0F VEX_PP = 0x3; break; + case X86II::A6: // Bypass: Not used by VEX + case X86II::A7: // Bypass: Not used by VEX case X86II::TB: // Bypass: Not used by VEX case 0: break; // No prefix! @@ -742,6 +744,8 @@ void X86MCCodeEmitter::EmitOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, case X86II::TB: // Two-byte opcode prefix case X86II::T8: // 0F 38 case X86II::TA: // 0F 3A + case X86II::A6: // 0F A6 + case X86II::A7: // 0F A7 Need0FPrefix = true; break; case X86II::TF: // F2 0F 38 @@ -786,6 +790,12 @@ void X86MCCodeEmitter::EmitOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, case X86II::TA: // 0F 3A EmitByte(0x3A, CurByte, OS); break; + case X86II::A6: // 0F A6 + EmitByte(0xA6, CurByte, OS); + break; + case X86II::A7: // 0F A7 + EmitByte(0xA7, CurByte, OS); + break; } } diff --git a/test/MC/X86/padlock.s b/test/MC/X86/padlock.s new file mode 100644 index 00000000000..874786f9071 --- /dev/null +++ b/test/MC/X86/padlock.s @@ -0,0 +1,53 @@ +// RUN: llvm-mc -triple i386-unknown-unknown --show-encoding %s | FileCheck %s + + xstore +// CHECK: xstore +// CHECK: encoding: [0x0f,0xa7,0xc0] + + rep xcryptecb +// CHECK: rep +// CHECK: encoding: [0xf3] +// CHECK: xcryptecb +// CHECK: encoding: [0x0f,0xa7,0xc8] + + rep xcryptcbc +// CHECK: rep +// CHECK: encoding: [0xf3] +// CHECK: xcryptcbc +// CHECK: encoding: [0x0f,0xa7,0xd0] + + rep xcryptctr +// CHECK: rep +// CHECK: encoding: [0xf3] +// CHECK: xcryptctr +// CHECK: encoding: [0x0f,0xa7,0xd8] + + rep xcryptcfb +// CHECK: rep +// CHECK: encoding: [0xf3] +// CHECK: xcryptcfb +// CHECK: encoding: [0x0f,0xa7,0xe0] + + rep xcryptofb +// CHECK: rep +// CHECK: encoding: [0xf3] +// CHECK: xcryptofb +// CHECK: encoding: [0x0f,0xa7,0xe8] + + rep xsha1 +// CHECK: rep +// CHECK: encoding: [0xf3] +// CHECK: xsha1 +// CHECK: encoding: [0x0f,0xa6,0xc8] + + rep xsha256 +// CHECK: rep +// CHECK: encoding: [0xf3] +// CHECK: xsha256 +// CHECK: encoding: [0x0f,0xa6,0xd0] + + rep montmul +// CHECK: rep +// CHECK: encoding: [0xf3] +// CHECK: montmul +// CHECK: encoding: [0x0f,0xa6,0xc0] diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp index 90a2af21f3a..d68d3b00e66 100644 --- a/utils/TableGen/DisassemblerEmitter.cpp +++ b/utils/TableGen/DisassemblerEmitter.cpp @@ -40,12 +40,12 @@ using namespace llvm::X86Disassembler; /// all cases as a 64-bit instruction with only OPSIZE set. (The XS prefix /// may have effects on its execution, but does not change the instruction /// returned.) This allows considerable space savings in other tables. -/// - Four tables (ONEBYTE_SYM, TWOBYTE_SYM, THREEBYTE38_SYM, and -/// THREEBYTE3A_SYM) contain the hierarchy that the decoder traverses while -/// decoding an instruction. At the lowest level of this hierarchy are -/// instruction UIDs, 16-bit integers that can be used to uniquely identify -/// the instruction and correspond exactly to its position in the list of -/// CodeGenInstructions for the target. +/// - Six tables (ONEBYTE_SYM, TWOBYTE_SYM, THREEBYTE38_SYM, THREEBYTE3A_SYM, +/// THREEBYTEA6_SYM, and THREEBYTEA7_SYM contain the hierarchy that the +/// decoder traverses while decoding an instruction. At the lowest level of +/// this hierarchy are instruction UIDs, 16-bit integers that can be used to +/// uniquely identify the instruction and correspond exactly to its position +/// in the list of CodeGenInstructions for the target. /// - One table (INSTRUCTIONS_SYM) contains information about the operands of /// each instruction and how to decode them. /// diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index cbd02339c2b..74310593d29 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -566,6 +566,8 @@ void DisassemblerTables::emitContextDecisions(raw_ostream &o1, emitContextDecision(o1, o2, i1, i2, *Tables[1], TWOBYTE_STR); emitContextDecision(o1, o2, i1, i2, *Tables[2], THREEBYTE38_STR); emitContextDecision(o1, o2, i1, i2, *Tables[3], THREEBYTE3A_STR); + emitContextDecision(o1, o2, i1, i2, *Tables[4], THREEBYTEA6_STR); + emitContextDecision(o1, o2, i1, i2, *Tables[5], THREEBYTEA7_STR); } void DisassemblerTables::emit(raw_ostream &o) const { diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h index 08eba019c09..fe4ad6f00da 100644 --- a/utils/TableGen/X86DisassemblerTables.h +++ b/utils/TableGen/X86DisassemblerTables.h @@ -39,7 +39,9 @@ private: /// [1] two-byte opcodes of the form 0f __ /// [2] three-byte opcodes of the form 0f 38 __ /// [3] three-byte opcodes of the form 0f 3a __ - ContextDecision* Tables[4]; + /// [4] three-byte opcodes of the form 0f a6 __ + /// [5] three-byte opcodes of the form 0f a7 __ + ContextDecision* Tables[6]; /// The instruction information table std::vector InstructionSpecifiers; @@ -141,8 +143,9 @@ private: /// } /// } /// - /// NAME is the name of the ContextDecision (typically one of the four names - /// ONEBYTE_SYM, TWOBYTE_SYM, THREEBYTE38_SYM, and THREEBYTE3A_SYM from + /// NAME is the name of the ContextDecision (typically one of the four names + /// ONEBYTE_SYM, TWOBYTE_SYM, THREEBYTE38_SYM, THREEBYTE3A_SYM, + /// THREEBYTEA6_SYM, and THREEBYTEA7_SYM from /// X86DisassemblerDecoderCommon.h). /// IC is one of the contexts in InstructionContext. There is an opcode /// decision for each possible context. diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 805cae7b3e6..f7518a988cc 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -68,7 +68,7 @@ namespace X86Local { DC = 7, DD = 8, DE = 9, DF = 10, XD = 11, XS = 12, T8 = 13, P_TA = 14, - P_0F_AE = 16, P_0F_01 = 17 + A6 = 15, A7 = 16 }; } @@ -796,6 +796,22 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { filter = new DumbFilter(); opcodeToSet = Opcode; break; + case X86Local::A6: + opcodeType = THREEBYTE_A6; + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + opcodeToSet = Opcode; + break; + case X86Local::A7: + opcodeType = THREEBYTE_A7; + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + opcodeToSet = Opcode; + break; case X86Local::D8: case X86Local::D9: case X86Local::DA: