Index: lib/Target/AArch64/AArch64.td =================================================================== --- lib/Target/AArch64/AArch64.td +++ lib/Target/AArch64/AArch64.td @@ -223,6 +223,9 @@ 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_5aOps : SubtargetFeature< "v8.5a", "HasV8_5aOps", "true", "Support ARM v8.5a instructions", [HasV8_4aOps, FeatureAltFPCmp, FeatureFRIntNNT, FeatureSpecRestrict, - FeatureSpecCtrl, FeaturePredCtrl, FeatureCacheDeepPersist] + FeatureSpecCtrl, FeaturePredCtrl, FeatureCacheDeepPersist, + FeatureBranchTargetId] >; //===----------------------------------------------------------------------===// Index: lib/Target/AArch64/AArch64InstrFormats.td =================================================================== --- lib/Target/AArch64/AArch64InstrFormats.td +++ lib/Target/AArch64/AArch64InstrFormats.td @@ -1149,6 +1149,21 @@ }]; } +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; Index: lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.td +++ lib/Target/AArch64/AArch64InstrInfo.td @@ -72,6 +72,8 @@ 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<"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]>; Index: lib/Target/AArch64/AArch64Subtarget.h =================================================================== --- lib/Target/AArch64/AArch64Subtarget.h +++ lib/Target/AArch64/AArch64Subtarget.h @@ -101,6 +101,7 @@ 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 @@ 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; } Index: lib/Target/AArch64/AArch64SystemOperands.td =================================================================== --- lib/Target/AArch64/AArch64SystemOperands.td +++ lib/Target/AArch64/AArch64SystemOperands.td @@ -321,6 +321,23 @@ 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. //===----------------------------------------------------------------------===// Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -201,6 +201,7 @@ template OperandMatchResultTy tryParsePrefetch(OperandVector &Operands); OperandMatchResultTy tryParsePSBHint(OperandVector &Operands); + OperandMatchResultTy tryParseBTIHint(OperandVector &Operands); OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands); OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands); template @@ -283,6 +284,7 @@ k_FPImm, k_Barrier, k_PSBHint, + k_BTIHint, } Kind; SMLoc StartLoc, EndLoc; @@ -386,6 +388,12 @@ unsigned Val; }; + struct BTIHintOp { + const char *Data; + unsigned Length; + unsigned Val; + }; + struct ExtendOp { unsigned Val; }; @@ -404,6 +412,7 @@ struct SysCRImmOp SysCRImm; struct PrefetchOp Prefetch; struct PSBHintOp PSBHint; + struct BTIHintOp BTIHint; struct ShiftExtendOp ShiftExtend; }; @@ -458,6 +467,9 @@ case k_PSBHint: PSBHint = o.PSBHint; break; + case k_BTIHint: + BTIHint = o.BTIHint; + break; case k_ShiftExtend: ShiftExtend = o.ShiftExtend; break; @@ -569,6 +581,16 @@ 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); @@ -1187,6 +1209,7 @@ 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()) @@ -1704,6 +1727,11 @@ 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 = @@ -1952,6 +1980,19 @@ 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) { @@ -2032,6 +2073,9 @@ if (!getShiftExtendAmount() && !hasShiftExtendAmount()) break; LLVM_FALLTHROUGH; + case k_BTIHint: + OS << getBTIHintName(); + break; case k_ShiftExtend: OS << "<" << AArch64_AM::getShiftExtendName(getShiftExtendType()) << " #" << getShiftExtendAmount(); @@ -2397,6 +2441,29 @@ 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 Index: lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h =================================================================== --- lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h +++ lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h @@ -131,6 +131,9 @@ 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); Index: lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp =================================================================== --- lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp @@ -1122,6 +1122,17 @@ 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) { Index: lib/Target/AArch64/Utils/AArch64BaseInfo.h =================================================================== --- lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -388,6 +388,14 @@ #include "AArch64GenSystemOperands.inc" } +namespace AArch64BTIHint { + struct BTI : SysAlias { + using SysAlias::SysAlias; + }; + #define GET_BTI_DECL + #include "AArch64GenSystemOperands.inc" +} + namespace AArch64SE { enum ShiftExtSpecifiers { Invalid = -1, Index: lib/Target/AArch64/Utils/AArch64BaseInfo.cpp =================================================================== --- lib/Target/AArch64/Utils/AArch64BaseInfo.cpp +++ lib/Target/AArch64/Utils/AArch64BaseInfo.cpp @@ -111,6 +111,13 @@ } namespace llvm { + namespace AArch64BTIHint { +#define GET_BTI_IMPL +#include "AArch64GenSystemOperands.inc" + } +} + +namespace llvm { namespace AArch64SysReg { #define GET_SYSREG_IMPL #include "AArch64GenSystemOperands.inc" Index: test/MC/AArch64/armv8.5a-bti-error.s =================================================================== --- /dev/null +++ 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 Index: test/MC/AArch64/armv8.5a-bti.s =================================================================== --- /dev/null +++ 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] Index: test/MC/Disassembler/AArch64/armv8.5a-bti.txt =================================================================== --- /dev/null +++ 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