diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -359,6 +359,15 @@ bool isS16ImmX4() const { return Kind == Expression || (Kind == Immediate && isInt<16>(getImm()) && (getImm() & 3) == 0); } + + bool isHashImmX8() const { + // The Hash Imm form is used for instructions that check or store a hash. + // These instructions have a small immediate range that spans between + // -8 and -512. + return (Kind == Immediate && getImm() <= -8 && getImm() >= -512 && + (getImm() & 7) == 0); + } + bool isS16ImmX16() const { return Kind == Expression || (Kind == Immediate && isInt<16>(getImm()) && (getImm() & 15) == 0); } diff --git a/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp b/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp --- a/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp +++ b/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp @@ -279,6 +279,23 @@ return MCDisassembler::Success; } +static DecodeStatus decodeMemRIHashOperands(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + // Decode the memrix field for a hash store or hash check operation. + // The field is composed of a register and an immediate value that is 6 bits + // and covers the range -8 to -512. The immediate is always negative and 2s + // complement which is why we sign extend a 7 bit value. + const uint64_t Base = Imm >> 6; + const int64_t Disp = SignExtend64<7>((Imm & 0x3F) + 64) * 8; + + assert(Base < 32 && "Invalid base register"); + + Inst.addOperand(MCOperand::createImm(Disp)); + Inst.addOperand(MCOperand::createReg(RRegs[Base])); + return MCDisassembler::Success; +} + static DecodeStatus decodeMemRIX16Operands(MCInst &Inst, uint64_t Imm, int64_t Address, const void *Decoder) { // Decode the memrix16 field (imm, reg), which has the low 12-bits as the diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h @@ -97,6 +97,8 @@ void printMemRegImm(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); + void printMemRegImmHash(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); void printMemRegImm34PCRel(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); void printMemRegImm34(const MCInst *MI, unsigned OpNo, diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp @@ -514,6 +514,15 @@ O << ')'; } +void PPCInstPrinter::printMemRegImmHash(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + O << MI->getOperand(OpNo).getImm(); + O << '('; + printOperand(MI, OpNo + 1, STI, O); + O << ')'; +} + void PPCInstPrinter::printMemRegImm34PCRel(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O) { diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h @@ -69,6 +69,9 @@ unsigned getMemRIX16Encoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned getMemRIHashEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; uint64_t getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -203,6 +203,24 @@ return RegBits; } +unsigned +PPCMCCodeEmitter::getMemRIHashEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + // Encode (imm, reg) for the hash load/store to stack for the ROP Protection + // instructions. + const MCOperand &RegMO = MI.getOperand(OpNo + 1); + const MCOperand &MO = MI.getOperand(OpNo); + + assert(RegMO.isReg() && "Base address must be a register."); + assert(MO.isImm() && "Expecting an immediate operand."); + assert(!(MO.getImm() % 8) && "Expecting offset to be 8 byte aligned."); + + unsigned RegBits = getMachineOpValue(MI, RegMO, Fixups, STI) << 6; + unsigned DX = (MO.getImm() >> 3) & 0x3F; + return RegBits | DX; +} + uint64_t PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, diff --git a/llvm/lib/Target/PowerPC/P9InstrResources.td b/llvm/lib/Target/PowerPC/P9InstrResources.td --- a/llvm/lib/Target/PowerPC/P9InstrResources.td +++ b/llvm/lib/Target/PowerPC/P9InstrResources.td @@ -1409,6 +1409,7 @@ (instregex "NOP_GT_PWR(6|7)$"), (instregex "TLB(IA|IVAX|SX|SX2|SX2D|LD|LI|RE|RE2|WE|WE2)$"), (instregex "WRTEE(I)?$"), + (instregex "HASH(ST|STP|CHK|CHKP)$"), ATTN, CLRBHRB, MFBHRBE, diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td --- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -1521,6 +1521,29 @@ [(set f64:$frD, (PPCany_fctiwuz f64:$frB))]>, isPPC64; } +// These instructions store a hash computed from the value of the link register +// and the value of the stack pointer. +let mayStore = 1 in { +def HASHST : XForm_XD6_RA5_RB5<31, 722, (outs), + (ins g8rc:$RB, memrihash:$D_RA_XD), + "hashst $RB, $D_RA_XD", IIC_IntGeneral, []>; +def HASHSTP : XForm_XD6_RA5_RB5<31, 658, (outs), + (ins g8rc:$RB, memrihash:$D_RA_XD), + "hashstp $RB, $D_RA_XD", IIC_IntGeneral, []>; +} + +// These instructions check a hash computed from the value of the link register +// and the value of the stack pointer. The hasSideEffects flag is needed as the +// instruction may TRAP if the hash does not match the hash stored at the +// specified address. +let mayLoad = 1, hasSideEffects = 1 in { +def HASHCHK : XForm_XD6_RA5_RB5<31, 754, (outs), + (ins g8rc:$RB, memrihash:$D_RA_XD), + "hashchk $RB, $D_RA_XD", IIC_IntGeneral, []>; +def HASHCHKP : XForm_XD6_RA5_RB5<31, 690, (outs), + (ins g8rc:$RB, memrihash:$D_RA_XD), + "hashchkp $RB, $D_RA_XD", IIC_IntGeneral, []>; +} //===----------------------------------------------------------------------===// // Instruction Patterns diff --git a/llvm/lib/Target/PowerPC/PPCInstrFormats.td b/llvm/lib/Target/PowerPC/PPCInstrFormats.td --- a/llvm/lib/Target/PowerPC/PPCInstrFormats.td +++ b/llvm/lib/Target/PowerPC/PPCInstrFormats.td @@ -1195,6 +1195,21 @@ let Inst{31} = XT{5}; } +class XForm_XD6_RA5_RB5 opcode, bits<10> xo, dag OOL, dag IOL, + string asmstr, InstrItinClass itin, list pattern> + : I { + bits<11> D_RA_XD; + bits<5> RB; + + let Pattern = pattern; + + let Inst{6-10} = D_RA_XD{4-0}; // D + let Inst{11-15} = D_RA_XD{10-6}; // RA + let Inst{16-20} = RB; + let Inst{21-30} = xo; + let Inst{31} = D_RA_XD{5}; // DX +} + class XX3Form opcode, bits<8> xo, dag OOL, dag IOL, string asmstr, InstrItinClass itin, list pattern> : I { diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -991,6 +991,13 @@ def dispRIX : Operand { let ParserMatchClass = PPCDispRIXOperand; } +def PPCDispRIHashOperand : AsmOperandClass { + let Name = "DispRIHash"; let PredicateMethod = "isHashImmX8"; + let RenderMethod = "addImmOperands"; +} +def dispRIHash : Operand { + let ParserMatchClass = PPCDispRIHashOperand; +} def PPCDispRIX16Operand : AsmOperandClass { let Name = "DispRIX16"; let PredicateMethod = "isS16ImmX16"; let RenderMethod = "addImmOperands"; @@ -1039,6 +1046,14 @@ let DecoderMethod = "decodeMemRIXOperands"; let OperandType = "OPERAND_MEMORY"; } +def memrihash : Operand { + // memrihash 8-aligned for ROP Protection Instructions. + let PrintMethod = "printMemRegImmHash"; + let MIOperandInfo = (ops dispRIHash:$imm, ptr_rc_nor0:$reg); + let EncoderMethod = "getMemRIHashEncoding"; + let DecoderMethod = "decodeMemRIHashOperands"; + let OperandType = "OPERAND_MEMORY"; +} def memrix16 : Operand { // memri, imm is 16-aligned, 12-bit, Inst{16:27} let PrintMethod = "printMemRegImm"; let MIOperandInfo = (ops dispRIX16:$imm, ptr_rc_nor0:$reg); diff --git a/llvm/test/MC/Disassembler/PowerPC/ppc64-encoding-ISA31.txt b/llvm/test/MC/Disassembler/PowerPC/ppc64-encoding-ISA31.txt --- a/llvm/test/MC/Disassembler/PowerPC/ppc64-encoding-ISA31.txt +++ b/llvm/test/MC/Disassembler/PowerPC/ppc64-encoding-ISA31.txt @@ -767,3 +767,40 @@ # CHECK: xvcvbf16spn 33, 34 0xf0 0x30 0x17 0x6f + +# CHECK: hashst 5, -8(1) +0x7f 0xe1 0x2d 0xa5 + +# CHECK: hashst 0, -8(30) +0x7f 0xfe 0x05 0xa5 + +# CHECK: hashst 5, -512(1) +0x7c 0x01 0x2d 0xa4 + +# CHECK: hashchk 5, -8(1) +0x7f 0xe1 0x2d 0xe5 + +# CHECK: hashchk 0, -8(30) +0x7f 0xfe 0x05 0xe5 + +# CHECK: hashchk 5, -512(1) +0x7c 0x01 0x2d 0xe4 + +# CHECK: hashstp 5, -8(1) +0x7f 0xe1 0x2d 0x25 + +# CHECK: hashstp 0, -8(30) +0x7f 0xfe 0x05 0x25 + +# CHECK: hashstp 5, -512(1) +0x7c 0x01 0x2d 0x24 + +# CHECK: hashchkp 5, -8(1) +0x7f 0xe1 0x2d 0x65 + +# CHECK: hashchkp 0, -8(30) +0x7f 0xfe 0x05 0x65 + +# CHECK: hashchkp 5, -512(1) +0x7c 0x01 0x2d 0x64 + diff --git a/llvm/test/MC/PowerPC/ppc64-encoding-ISA31.s b/llvm/test/MC/PowerPC/ppc64-encoding-ISA31.s --- a/llvm/test/MC/PowerPC/ppc64-encoding-ISA31.s +++ b/llvm/test/MC/PowerPC/ppc64-encoding-ISA31.s @@ -963,3 +963,39 @@ # CHECK-BE: xvcvbf16spn 33, 34 # encoding: [0xf0,0x30,0x17,0x6f] # CHECK-LE: xvcvbf16spn 33, 34 # encoding: [0x6f,0x17,0x30,0xf0] xvcvbf16spn 33, 34 +# CHECK-BE: hashst 5, -8(1) # encoding: [0x7f,0xe1,0x2d,0xa5] +# CHECK-LE: hashst 5, -8(1) # encoding: [0xa5,0x2d,0xe1,0x7f] + hashst 5, -8(1) +# CHECK-BE: hashst 0, -8(30) # encoding: [0x7f,0xfe,0x05,0xa5] +# CHECK-LE: hashst 0, -8(30) # encoding: [0xa5,0x05,0xfe,0x7f] + hashst 0, -8(30) +# CHECK-BE: hashst 5, -512(1) # encoding: [0x7c,0x01,0x2d,0xa4] +# CHECK-LE: hashst 5, -512(1) # encoding: [0xa4,0x2d,0x01,0x7c] + hashst 5, -512(1) +# CHECK-BE: hashchk 5, -8(1) # encoding: [0x7f,0xe1,0x2d,0xe5] +# CHECK-LE: hashchk 5, -8(1) # encoding: [0xe5,0x2d,0xe1,0x7f] + hashchk 5, -8(1) +# CHECK-BE: hashchk 0, -8(30) # encoding: [0x7f,0xfe,0x05,0xe5] +# CHECK-LE: hashchk 0, -8(30) # encoding: [0xe5,0x05,0xfe,0x7f] + hashchk 0, -8(30) +# CHECK-BE: hashchk 5, -512(1) # encoding: [0x7c,0x01,0x2d,0xe4] +# CHECK-LE: hashchk 5, -512(1) # encoding: [0xe4,0x2d,0x01,0x7c] + hashchk 5, -512(1) +# CHECK-BE: hashstp 5, -8(1) # encoding: [0x7f,0xe1,0x2d,0x25] +# CHECK-LE: hashstp 5, -8(1) # encoding: [0x25,0x2d,0xe1,0x7f] + hashstp 5, -8(1) +# CHECK-BE: hashstp 0, -8(30) # encoding: [0x7f,0xfe,0x05,0x25] +# CHECK-LE: hashstp 0, -8(30) # encoding: [0x25,0x05,0xfe,0x7f] + hashstp 0, -8(30) +# CHECK-BE: hashstp 5, -512(1) # encoding: [0x7c,0x01,0x2d,0x24] +# CHECK-LE: hashstp 5, -512(1) # encoding: [0x24,0x2d,0x01,0x7c] + hashstp 5, -512(1) +# CHECK-BE: hashchkp 5, -8(1) # encoding: [0x7f,0xe1,0x2d,0x65] +# CHECK-LE: hashchkp 5, -8(1) # encoding: [0x65,0x2d,0xe1,0x7f] + hashchkp 5, -8(1) +# CHECK-BE: hashchkp 0, -8(30) # encoding: [0x7f,0xfe,0x05,0x65] +# CHECK-LE: hashchkp 0, -8(30) # encoding: [0x65,0x05,0xfe,0x7f] + hashchkp 0, -8(30) +# CHECK-BE: hashchkp 5, -512(1) # encoding: [0x7c,0x01,0x2d,0x64] +# CHECK-LE: hashchkp 5, -512(1) # encoding: [0x64,0x2d,0x01,0x7c] + hashchkp 5, -512(1)