[AArch64][v8.5A] Add Branch Target Identification instructions

This adds new instructions used by the Branch Target Identification
feature. When this is enabled, these are the only instructions which can
be targeted by indirect branch instructions.

Patch by Pablo Barrio!

Differential revision: https://reviews.llvm.org/D52485

llvm-svn: 343225
This commit is contained in:
Oliver Stannard 2018-09-27 14:54:33 +00:00
parent bb898704e9
commit a9a5eee169
13 changed files with 206 additions and 1 deletions

View File

@ -223,6 +223,9 @@ def FeaturePredCtrl : SubtargetFeature<"predctrl", "HasPredCtrl", "true",
def FeatureCacheDeepPersist : SubtargetFeature<"ccdp", "HasCCDP", def FeatureCacheDeepPersist : SubtargetFeature<"ccdp", "HasCCDP",
"true", "Enable Cache Clean to Point of Deep Persistence" >; "true", "Enable Cache Clean to Point of Deep Persistence" >;
def FeatureBranchTargetId : SubtargetFeature<"bti", "HasBTI",
"true", "Enable Branch Target Identification" >;
def FeatureRandGen : SubtargetFeature<"rand", "HasRandGen", def FeatureRandGen : SubtargetFeature<"rand", "HasRandGen",
"true", "Enable Random Number generation instructions" >; "true", "Enable Random Number generation instructions" >;
@ -245,7 +248,8 @@ def HasV8_4aOps : SubtargetFeature<"v8.4a", "HasV8_4aOps", "true",
def HasV8_5aOps : SubtargetFeature< def HasV8_5aOps : SubtargetFeature<
"v8.5a", "HasV8_5aOps", "true", "Support ARM v8.5a instructions", "v8.5a", "HasV8_5aOps", "true", "Support ARM v8.5a instructions",
[HasV8_4aOps, FeatureAltFPCmp, FeatureFRInt3264, FeatureSpecRestrict, [HasV8_4aOps, FeatureAltFPCmp, FeatureFRInt3264, FeatureSpecRestrict,
FeatureSpecCtrl, FeaturePredCtrl, FeatureCacheDeepPersist] FeatureSpecCtrl, FeaturePredCtrl, FeatureCacheDeepPersist,
FeatureBranchTargetId]
>; >;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -1149,6 +1149,21 @@ def psbhint_op : Operand<i32> {
}]; }];
} }
def BTIHintOperand : AsmOperandClass {
let Name = "BTIHint";
let ParserMethod = "tryParseBTIHint";
}
def btihint_op : Operand<i32> {
let ParserMatchClass = BTIHintOperand;
let PrintMethod = "printBTIHintOp";
let MCOperandPredicate = [{
// "bti" is an alias to "hint" only for certain values of CRm:Op2 fields.
if (!MCOp.isImm())
return false;
return AArch64BTIHint::lookupBTIByEncoding((MCOp.getImm() ^ 32) >> 1) != nullptr;
}];
}
class MRSI : RtSystemI<1, (outs GPR64:$Rt), (ins mrs_sysreg_op:$systemreg), class MRSI : RtSystemI<1, (outs GPR64:$Rt), (ins mrs_sysreg_op:$systemreg),
"mrs", "\t$Rt, $systemreg"> { "mrs", "\t$Rt, $systemreg"> {
bits<16> systemreg; bits<16> systemreg;

View File

@ -72,6 +72,8 @@ def HasPredCtrl : Predicate<"Subtarget->hasPredCtrl()">,
AssemblerPredicate<"FeaturePredCtrl", "predctrl">; AssemblerPredicate<"FeaturePredCtrl", "predctrl">;
def HasCCDP : Predicate<"Subtarget->hasCCDP()">, def HasCCDP : Predicate<"Subtarget->hasCCDP()">,
AssemblerPredicate<"FeatureCacheDeepPersist", "ccdp">; AssemblerPredicate<"FeatureCacheDeepPersist", "ccdp">;
def HasBTI : Predicate<"Subtarget->hasBTI()">,
AssemblerPredicate<"FeatureBranchTargetId", "bti">;
def IsLE : Predicate<"Subtarget->isLittleEndian()">; def IsLE : Predicate<"Subtarget->isLittleEndian()">;
def IsBE : Predicate<"!Subtarget->isLittleEndian()">; def IsBE : Predicate<"!Subtarget->isLittleEndian()">;
def UseAlternateSExtLoadCVTF32 def UseAlternateSExtLoadCVTF32
@ -454,6 +456,8 @@ def : InstAlias<"sev", (HINT 0b100)>;
def : InstAlias<"sevl", (HINT 0b101)>; def : InstAlias<"sevl", (HINT 0b101)>;
def : InstAlias<"esb", (HINT 0b10000)>, Requires<[HasRAS]>; def : InstAlias<"esb", (HINT 0b10000)>, Requires<[HasRAS]>;
def : InstAlias<"csdb", (HINT 20)>; def : InstAlias<"csdb", (HINT 20)>;
def : InstAlias<"bti", (HINT 32)>, Requires<[HasBTI]>;
def : InstAlias<"bti $op", (HINT btihint_op:$op)>, Requires<[HasBTI]>;
// v8.2a Statistical Profiling extension // v8.2a Statistical Profiling extension
def : InstAlias<"psb $op", (HINT psbhint_op:$op)>, Requires<[HasSPE]>; def : InstAlias<"psb $op", (HINT psbhint_op:$op)>, Requires<[HasSPE]>;

View File

@ -101,6 +101,7 @@ protected:
bool HasSpecCtrl = false; bool HasSpecCtrl = false;
bool HasPredCtrl = false; bool HasPredCtrl = false;
bool HasCCDP = false; bool HasCCDP = false;
bool HasBTI = false;
bool HasRandGen = false; bool HasRandGen = false;
// HasZeroCycleRegMove - Has zero-cycle register mov instructions. // HasZeroCycleRegMove - Has zero-cycle register mov instructions.
@ -321,6 +322,7 @@ public:
bool hasSpecCtrl() { return HasSpecCtrl; } bool hasSpecCtrl() { return HasSpecCtrl; }
bool hasPredCtrl() { return HasPredCtrl; } bool hasPredCtrl() { return HasPredCtrl; }
bool hasCCDP() { return HasCCDP; } bool hasCCDP() { return HasCCDP; }
bool hasBTI() { return HasBTI; }
bool hasRandGen() { return HasRandGen; } bool hasRandGen() { return HasRandGen; }
bool isLittleEndian() const { return IsLittle; } bool isLittleEndian() const { return IsLittle; }

View File

@ -320,6 +320,23 @@ class PSB<string name, bits<5> encoding> : SearchableTable {
def : PSB<"csync", 0x11>; def : PSB<"csync", 0x11>;
//===----------------------------------------------------------------------===//
// BTI instruction options.
//===----------------------------------------------------------------------===//
class BTI<string name, bits<2> encoding> : SearchableTable {
let SearchableFields = ["Name", "Encoding"];
let EnumValueField = "Encoding";
string Name = name;
bits<2> Encoding;
let Encoding = encoding;
}
def : BTI<"c", 0b01>;
def : BTI<"j", 0b10>;
def : BTI<"jc", 0b11>;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// TLBI (translation lookaside buffer invalidate) instruction options. // TLBI (translation lookaside buffer invalidate) instruction options.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -202,6 +202,7 @@ private:
template <bool IsSVEPrefetch = false> template <bool IsSVEPrefetch = false>
OperandMatchResultTy tryParsePrefetch(OperandVector &Operands); OperandMatchResultTy tryParsePrefetch(OperandVector &Operands);
OperandMatchResultTy tryParsePSBHint(OperandVector &Operands); OperandMatchResultTy tryParsePSBHint(OperandVector &Operands);
OperandMatchResultTy tryParseBTIHint(OperandVector &Operands);
OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands); OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands);
OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands); OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands);
template<bool AddFPZeroAsLiteral> template<bool AddFPZeroAsLiteral>
@ -284,6 +285,7 @@ private:
k_FPImm, k_FPImm,
k_Barrier, k_Barrier,
k_PSBHint, k_PSBHint,
k_BTIHint,
} Kind; } Kind;
SMLoc StartLoc, EndLoc; SMLoc StartLoc, EndLoc;
@ -387,6 +389,12 @@ private:
unsigned Val; unsigned Val;
}; };
struct BTIHintOp {
const char *Data;
unsigned Length;
unsigned Val;
};
struct ExtendOp { struct ExtendOp {
unsigned Val; unsigned Val;
}; };
@ -405,6 +413,7 @@ private:
struct SysCRImmOp SysCRImm; struct SysCRImmOp SysCRImm;
struct PrefetchOp Prefetch; struct PrefetchOp Prefetch;
struct PSBHintOp PSBHint; struct PSBHintOp PSBHint;
struct BTIHintOp BTIHint;
struct ShiftExtendOp ShiftExtend; struct ShiftExtendOp ShiftExtend;
}; };
@ -459,6 +468,9 @@ public:
case k_PSBHint: case k_PSBHint:
PSBHint = o.PSBHint; PSBHint = o.PSBHint;
break; break;
case k_BTIHint:
BTIHint = o.BTIHint;
break;
case k_ShiftExtend: case k_ShiftExtend:
ShiftExtend = o.ShiftExtend; ShiftExtend = o.ShiftExtend;
break; break;
@ -570,6 +582,16 @@ public:
return StringRef(PSBHint.Data, PSBHint.Length); return StringRef(PSBHint.Data, PSBHint.Length);
} }
unsigned getBTIHint() const {
assert(Kind == k_BTIHint && "Invalid access!");
return BTIHint.Val;
}
StringRef getBTIHintName() const {
assert(Kind == k_BTIHint && "Invalid access!");
return StringRef(BTIHint.Data, BTIHint.Length);
}
StringRef getPrefetchName() const { StringRef getPrefetchName() const {
assert(Kind == k_Prefetch && "Invalid access!"); assert(Kind == k_Prefetch && "Invalid access!");
return StringRef(Prefetch.Data, Prefetch.Length); return StringRef(Prefetch.Data, Prefetch.Length);
@ -1188,6 +1210,7 @@ public:
bool isSysCR() const { return Kind == k_SysCR; } bool isSysCR() const { return Kind == k_SysCR; }
bool isPrefetch() const { return Kind == k_Prefetch; } bool isPrefetch() const { return Kind == k_Prefetch; }
bool isPSBHint() const { return Kind == k_PSBHint; } bool isPSBHint() const { return Kind == k_PSBHint; }
bool isBTIHint() const { return Kind == k_BTIHint; }
bool isShiftExtend() const { return Kind == k_ShiftExtend; } bool isShiftExtend() const { return Kind == k_ShiftExtend; }
bool isShifter() const { bool isShifter() const {
if (!isShiftExtend()) if (!isShiftExtend())
@ -1705,6 +1728,11 @@ public:
Inst.addOperand(MCOperand::createImm(getPSBHint())); Inst.addOperand(MCOperand::createImm(getPSBHint()));
} }
void addBTIHintOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::createImm(getBTIHint()));
}
void addShifterOperands(MCInst &Inst, unsigned N) const { void addShifterOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!"); assert(N == 1 && "Invalid number of operands!");
unsigned Imm = unsigned Imm =
@ -1953,6 +1981,19 @@ public:
return Op; return Op;
} }
static std::unique_ptr<AArch64Operand> CreateBTIHint(unsigned Val,
StringRef Str,
SMLoc S,
MCContext &Ctx) {
auto Op = make_unique<AArch64Operand>(k_BTIHint, Ctx);
Op->BTIHint.Val = Val << 1 | 32;
Op->BTIHint.Data = Str.data();
Op->BTIHint.Length = Str.size();
Op->StartLoc = S;
Op->EndLoc = S;
return Op;
}
static std::unique_ptr<AArch64Operand> static std::unique_ptr<AArch64Operand>
CreateShiftExtend(AArch64_AM::ShiftExtendType ShOp, unsigned Val, CreateShiftExtend(AArch64_AM::ShiftExtendType ShOp, unsigned Val,
bool HasExplicitAmount, SMLoc S, SMLoc E, MCContext &Ctx) { bool HasExplicitAmount, SMLoc S, SMLoc E, MCContext &Ctx) {
@ -2033,6 +2074,9 @@ void AArch64Operand::print(raw_ostream &OS) const {
if (!getShiftExtendAmount() && !hasShiftExtendAmount()) if (!getShiftExtendAmount() && !hasShiftExtendAmount())
break; break;
LLVM_FALLTHROUGH; LLVM_FALLTHROUGH;
case k_BTIHint:
OS << getBTIHintName();
break;
case k_ShiftExtend: case k_ShiftExtend:
OS << "<" << AArch64_AM::getShiftExtendName(getShiftExtendType()) << " #" OS << "<" << AArch64_AM::getShiftExtendName(getShiftExtendType()) << " #"
<< getShiftExtendAmount(); << getShiftExtendAmount();
@ -2398,6 +2442,29 @@ AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
return MatchOperand_Success; return MatchOperand_Success;
} }
/// tryParseBTIHint - Try to parse a BTI operand, mapped to Hint command
OperandMatchResultTy
AArch64AsmParser::tryParseBTIHint(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = getLoc();
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier)) {
TokError("invalid operand for instruction");
return MatchOperand_ParseFail;
}
auto BTI = AArch64BTIHint::lookupBTIByName(Tok.getString());
if (!BTI) {
TokError("invalid operand for instruction");
return MatchOperand_ParseFail;
}
Parser.Lex(); // Eat identifier token.
Operands.push_back(AArch64Operand::CreateBTIHint(
BTI->Encoding, Tok.getString(), S, getContext()));
return MatchOperand_Success;
}
/// tryParseAdrpLabel - Parse and validate a source label for the ADRP /// tryParseAdrpLabel - Parse and validate a source label for the ADRP
/// instruction. /// instruction.
OperandMatchResultTy OperandMatchResultTy

View File

@ -1122,6 +1122,17 @@ void AArch64InstPrinter::printPSBHintOp(const MCInst *MI, unsigned OpNum,
O << '#' << formatImm(psbhintop); O << '#' << formatImm(psbhintop);
} }
void AArch64InstPrinter::printBTIHintOp(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned btihintop = (MI->getOperand(OpNum).getImm() ^ 32) >> 1;
auto BTI = AArch64BTIHint::lookupBTIByEncoding(btihintop);
if (BTI)
O << BTI->Name;
else
O << '#' << formatImm(btihintop);
}
void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum, void AArch64InstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, const MCSubtargetInfo &STI,
raw_ostream &O) { raw_ostream &O) {

View File

@ -131,6 +131,9 @@ protected:
void printPSBHintOp(const MCInst *MI, unsigned OpNum, void printPSBHintOp(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O); const MCSubtargetInfo &STI, raw_ostream &O);
void printBTIHintOp(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O);
void printFPImmOperand(const MCInst *MI, unsigned OpNum, void printFPImmOperand(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O); const MCSubtargetInfo &STI, raw_ostream &O);

View File

@ -110,6 +110,13 @@ namespace llvm {
} }
} }
namespace llvm {
namespace AArch64BTIHint {
#define GET_BTI_IMPL
#include "AArch64GenSystemOperands.inc"
}
}
namespace llvm { namespace llvm {
namespace AArch64SysReg { namespace AArch64SysReg {
#define GET_SYSREG_IMPL #define GET_SYSREG_IMPL

View File

@ -388,6 +388,14 @@ namespace AArch64PSBHint {
#include "AArch64GenSystemOperands.inc" #include "AArch64GenSystemOperands.inc"
} }
namespace AArch64BTIHint {
struct BTI : SysAlias {
using SysAlias::SysAlias;
};
#define GET_BTI_DECL
#include "AArch64GenSystemOperands.inc"
}
namespace AArch64SE { namespace AArch64SE {
enum ShiftExtSpecifiers { enum ShiftExtSpecifiers {
Invalid = -1, Invalid = -1,

View File

@ -0,0 +1,12 @@
// RUN: not llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+bti < %s 2>&1 | FileCheck %s
bti cj
bti a
bti x0
// CHECK: invalid operand for instruction
// CHECK-NEXT: cj
// CHECK: invalid operand for instruction
// CHECK-NEXT: a
// CHECK: invalid operand for instruction
// CHECK-NEXT: x0

View File

@ -0,0 +1,37 @@
// RUN: llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+bti < %s | FileCheck %s
// RUN: llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+v8.5a < %s | FileCheck %s
// RUN: not llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=-bti < %s 2>&1 | FileCheck %s --check-prefix=NOBTI
bti
bti c
bti j
bti jc
// CHECK: bti // encoding: [0x1f,0x24,0x03,0xd5]
// CHECK: bti c // encoding: [0x5f,0x24,0x03,0xd5]
// CHECK: bti j // encoding: [0x9f,0x24,0x03,0xd5]
// CHECK: bti jc // encoding: [0xdf,0x24,0x03,0xd5]
// NOBTI: instruction requires: bti
// NOBTI-NEXT: bti
// NOBTI: instruction requires: bti
// NOBTI-NEXT: bti
// NOBTI: instruction requires: bti
// NOBTI-NEXT: bti
// NOBTI: instruction requires: bti
// NOBTI-NEXT: bti
hint #32
hint #34
hint #36
hint #38
// CHECK: bti // encoding: [0x1f,0x24,0x03,0xd5]
// CHECK: bti c // encoding: [0x5f,0x24,0x03,0xd5]
// CHECK: bti j // encoding: [0x9f,0x24,0x03,0xd5]
// CHECK: bti jc // encoding: [0xdf,0x24,0x03,0xd5]
// NOBTI: hint #32 // encoding: [0x1f,0x24,0x03,0xd5]
// NOBTI: hint #34 // encoding: [0x5f,0x24,0x03,0xd5]
// NOBTI: hint #36 // encoding: [0x9f,0x24,0x03,0xd5]
// NOBTI: hint #38 // encoding: [0xdf,0x24,0x03,0xd5]

View File

@ -0,0 +1,18 @@
# RUN: llvm-mc -triple=aarch64 -mattr=+bti -disassemble < %s | FileCheck %s
# RUN: llvm-mc -triple=aarch64 -mattr=+v8.5a -disassemble < %s | FileCheck %s
# RUN: llvm-mc -triple=aarch64 -mattr=-bti -disassemble < %s 2>&1 | FileCheck %s --check-prefix=NOBTI
[0x1f 0x24 0x03 0xd5]
[0x5f 0x24 0x03 0xd5]
[0x9f 0x24 0x03 0xd5]
[0xdf 0x24 0x03 0xd5]
# CHECK: bti
# CHECK: bti c
# CHECK: bti j
# CHECK: bti jc
# NOBTI: hint #32
# NOBTI: hint #34
# NOBTI: hint #36
# NOBTI: hint #38