From a9a5eee1694833989739fc31045b48bdaacafaff Mon Sep 17 00:00:00 2001 From: Oliver Stannard Date: Thu, 27 Sep 2018 14:54:33 +0000 Subject: [PATCH] [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 --- llvm/lib/Target/AArch64/AArch64.td | 6 +- .../lib/Target/AArch64/AArch64InstrFormats.td | 15 +++++ llvm/lib/Target/AArch64/AArch64InstrInfo.td | 4 ++ llvm/lib/Target/AArch64/AArch64Subtarget.h | 2 + .../Target/AArch64/AArch64SystemOperands.td | 17 +++++ .../AArch64/AsmParser/AArch64AsmParser.cpp | 67 +++++++++++++++++++ .../InstPrinter/AArch64InstPrinter.cpp | 11 +++ .../AArch64/InstPrinter/AArch64InstPrinter.h | 3 + .../Target/AArch64/Utils/AArch64BaseInfo.cpp | 7 ++ .../Target/AArch64/Utils/AArch64BaseInfo.h | 8 +++ llvm/test/MC/AArch64/armv8.5a-bti-error.s | 12 ++++ llvm/test/MC/AArch64/armv8.5a-bti.s | 37 ++++++++++ .../MC/Disassembler/AArch64/armv8.5a-bti.txt | 18 +++++ 13 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 llvm/test/MC/AArch64/armv8.5a-bti-error.s create mode 100644 llvm/test/MC/AArch64/armv8.5a-bti.s create mode 100644 llvm/test/MC/Disassembler/AArch64/armv8.5a-bti.txt diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td index b522c897498b..587a4e1b92a9 100644 --- a/llvm/lib/Target/AArch64/AArch64.td +++ b/llvm/lib/Target/AArch64/AArch64.td @@ -223,6 +223,9 @@ def FeaturePredCtrl : SubtargetFeature<"predctrl", "HasPredCtrl", "true", def FeatureCacheDeepPersist : SubtargetFeature<"ccdp", "HasCCDP", "true", "Enable Cache Clean to Point of Deep Persistence" >; +def FeatureBranchTargetId : SubtargetFeature<"bti", "HasBTI", + "true", "Enable Branch Target Identification" >; + def FeatureRandGen : SubtargetFeature<"rand", "HasRandGen", "true", "Enable Random Number generation instructions" >; @@ -245,7 +248,8 @@ def HasV8_4aOps : SubtargetFeature<"v8.4a", "HasV8_4aOps", "true", def HasV8_5aOps : SubtargetFeature< "v8.5a", "HasV8_5aOps", "true", "Support ARM v8.5a instructions", [HasV8_4aOps, FeatureAltFPCmp, FeatureFRInt3264, FeatureSpecRestrict, - FeatureSpecCtrl, FeaturePredCtrl, FeatureCacheDeepPersist] + FeatureSpecCtrl, FeaturePredCtrl, FeatureCacheDeepPersist, + FeatureBranchTargetId] >; //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td index 8a24650610eb..3920cdbfbb16 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -1149,6 +1149,21 @@ def psbhint_op : Operand { }]; } +def BTIHintOperand : AsmOperandClass { + let Name = "BTIHint"; + let ParserMethod = "tryParseBTIHint"; +} +def btihint_op : Operand { + 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), "mrs", "\t$Rt, $systemreg"> { bits<16> systemreg; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 004639e0b91c..f6b798724d37 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -72,6 +72,8 @@ def HasPredCtrl : Predicate<"Subtarget->hasPredCtrl()">, AssemblerPredicate<"FeaturePredCtrl", "predctrl">; def HasCCDP : Predicate<"Subtarget->hasCCDP()">, AssemblerPredicate<"FeatureCacheDeepPersist", "ccdp">; +def HasBTI : Predicate<"Subtarget->hasBTI()">, + AssemblerPredicate<"FeatureBranchTargetId", "bti">; def IsLE : Predicate<"Subtarget->isLittleEndian()">; def IsBE : Predicate<"!Subtarget->isLittleEndian()">; def UseAlternateSExtLoadCVTF32 @@ -454,6 +456,8 @@ def : InstAlias<"sev", (HINT 0b100)>; def : InstAlias<"sevl", (HINT 0b101)>; def : InstAlias<"esb", (HINT 0b10000)>, Requires<[HasRAS]>; 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 def : InstAlias<"psb $op", (HINT psbhint_op:$op)>, Requires<[HasSPE]>; diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h index 5e6a4ec58619..e1d970345cbe 100644 --- a/llvm/lib/Target/AArch64/AArch64Subtarget.h +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -101,6 +101,7 @@ protected: bool HasSpecCtrl = false; bool HasPredCtrl = false; bool HasCCDP = false; + bool HasBTI = false; bool HasRandGen = false; // HasZeroCycleRegMove - Has zero-cycle register mov instructions. @@ -321,6 +322,7 @@ public: bool hasSpecCtrl() { return HasSpecCtrl; } bool hasPredCtrl() { return HasPredCtrl; } bool hasCCDP() { return HasCCDP; } + bool hasBTI() { return HasBTI; } bool hasRandGen() { return HasRandGen; } bool isLittleEndian() const { return IsLittle; } diff --git a/llvm/lib/Target/AArch64/AArch64SystemOperands.td b/llvm/lib/Target/AArch64/AArch64SystemOperands.td index ab7d17691373..fe8c797b216c 100644 --- a/llvm/lib/Target/AArch64/AArch64SystemOperands.td +++ b/llvm/lib/Target/AArch64/AArch64SystemOperands.td @@ -320,6 +320,23 @@ class PSB encoding> : SearchableTable { def : PSB<"csync", 0x11>; +//===----------------------------------------------------------------------===// +// BTI instruction options. +//===----------------------------------------------------------------------===// + +class BTI 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. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index d028cdc3d1c5..a2c060ab2f29 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -202,6 +202,7 @@ private: template OperandMatchResultTy tryParsePrefetch(OperandVector &Operands); OperandMatchResultTy tryParsePSBHint(OperandVector &Operands); + OperandMatchResultTy tryParseBTIHint(OperandVector &Operands); OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands); OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands); template @@ -284,6 +285,7 @@ private: k_FPImm, k_Barrier, k_PSBHint, + k_BTIHint, } Kind; SMLoc StartLoc, EndLoc; @@ -387,6 +389,12 @@ private: unsigned Val; }; + struct BTIHintOp { + const char *Data; + unsigned Length; + unsigned Val; + }; + struct ExtendOp { unsigned Val; }; @@ -405,6 +413,7 @@ private: struct SysCRImmOp SysCRImm; struct PrefetchOp Prefetch; struct PSBHintOp PSBHint; + struct BTIHintOp BTIHint; struct ShiftExtendOp ShiftExtend; }; @@ -459,6 +468,9 @@ public: case k_PSBHint: PSBHint = o.PSBHint; break; + case k_BTIHint: + BTIHint = o.BTIHint; + break; case k_ShiftExtend: ShiftExtend = o.ShiftExtend; break; @@ -570,6 +582,16 @@ public: 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 { assert(Kind == k_Prefetch && "Invalid access!"); return StringRef(Prefetch.Data, Prefetch.Length); @@ -1188,6 +1210,7 @@ public: bool isSysCR() const { return Kind == k_SysCR; } bool isPrefetch() const { return Kind == k_Prefetch; } bool isPSBHint() const { return Kind == k_PSBHint; } + bool isBTIHint() const { return Kind == k_BTIHint; } bool isShiftExtend() const { return Kind == k_ShiftExtend; } bool isShifter() const { if (!isShiftExtend()) @@ -1705,6 +1728,11 @@ public: 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 { assert(N == 1 && "Invalid number of operands!"); unsigned Imm = @@ -1953,6 +1981,19 @@ public: return Op; } + static std::unique_ptr CreateBTIHint(unsigned Val, + StringRef Str, + SMLoc S, + MCContext &Ctx) { + auto Op = make_unique(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 CreateShiftExtend(AArch64_AM::ShiftExtendType ShOp, unsigned Val, bool HasExplicitAmount, SMLoc S, SMLoc E, MCContext &Ctx) { @@ -2033,6 +2074,9 @@ void AArch64Operand::print(raw_ostream &OS) const { if (!getShiftExtendAmount() && !hasShiftExtendAmount()) break; LLVM_FALLTHROUGH; + case k_BTIHint: + OS << getBTIHintName(); + break; case k_ShiftExtend: OS << "<" << AArch64_AM::getShiftExtendName(getShiftExtendType()) << " #" << getShiftExtendAmount(); @@ -2398,6 +2442,29 @@ AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) { 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 /// instruction. OperandMatchResultTy diff --git a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp index da8b28127347..dcf2dd251149 100644 --- a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp @@ -1122,6 +1122,17 @@ void AArch64InstPrinter::printPSBHintOp(const MCInst *MI, unsigned OpNum, 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, const MCSubtargetInfo &STI, raw_ostream &O) { diff --git a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h index 8dc9264f94a1..4e9982f5b7be 100644 --- a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h +++ b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h @@ -131,6 +131,9 @@ protected: void printPSBHintOp(const MCInst *MI, unsigned OpNum, 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, const MCSubtargetInfo &STI, raw_ostream &O); diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp index 9c415aa8496a..c88155db7037 100644 --- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp +++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp @@ -110,6 +110,13 @@ namespace llvm { } } +namespace llvm { + namespace AArch64BTIHint { +#define GET_BTI_IMPL +#include "AArch64GenSystemOperands.inc" + } +} + namespace llvm { namespace AArch64SysReg { #define GET_SYSREG_IMPL diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h index 675adad2a691..b8d0977ae547 100644 --- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -388,6 +388,14 @@ namespace AArch64PSBHint { #include "AArch64GenSystemOperands.inc" } +namespace AArch64BTIHint { + struct BTI : SysAlias { + using SysAlias::SysAlias; + }; + #define GET_BTI_DECL + #include "AArch64GenSystemOperands.inc" +} + namespace AArch64SE { enum ShiftExtSpecifiers { Invalid = -1, diff --git a/llvm/test/MC/AArch64/armv8.5a-bti-error.s b/llvm/test/MC/AArch64/armv8.5a-bti-error.s new file mode 100644 index 000000000000..bb0dea03ec80 --- /dev/null +++ b/llvm/test/MC/AArch64/armv8.5a-bti-error.s @@ -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 diff --git a/llvm/test/MC/AArch64/armv8.5a-bti.s b/llvm/test/MC/AArch64/armv8.5a-bti.s new file mode 100644 index 000000000000..ca55516890c4 --- /dev/null +++ b/llvm/test/MC/AArch64/armv8.5a-bti.s @@ -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] diff --git a/llvm/test/MC/Disassembler/AArch64/armv8.5a-bti.txt b/llvm/test/MC/Disassembler/AArch64/armv8.5a-bti.txt new file mode 100644 index 000000000000..e15dcf5e3b77 --- /dev/null +++ b/llvm/test/MC/Disassembler/AArch64/armv8.5a-bti.txt @@ -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