Index: lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.td +++ lib/Target/AArch64/AArch64InstrInfo.td @@ -20,6 +20,8 @@ AssemblerPredicate<"HasV8_2aOps", "armv8.2a">; def HasV8_3a : Predicate<"Subtarget->hasV8_3aOps()">, AssemblerPredicate<"HasV8_3aOps", "armv8.3a">; +def HasV8_4a : Predicate<"Subtarget->hasV8_4aOps()">, + AssemblerPredicate<"HasV8_4aOps", "armv8.4a">; def HasFPARMv8 : Predicate<"Subtarget->hasFPARMv8()">, AssemblerPredicate<"FeatureFPARMv8", "fp-armv8">; def HasNEON : Predicate<"Subtarget->hasNEON()">, @@ -449,6 +451,12 @@ def ISB : CRmSystemI; + +def TSB : CRmSystemI { + let CRm = 0b0010; + let Inst{12} = 0; + let Predicates = [HasV8_4a]; +} } // ARMv8.2 Dot Product Index: lib/Target/AArch64/AArch64SystemOperands.td =================================================================== --- lib/Target/AArch64/AArch64SystemOperands.td +++ lib/Target/AArch64/AArch64SystemOperands.td @@ -143,6 +143,23 @@ def : ISB<"sy", 0xf>; //===----------------------------------------------------------------------===// +// TSB (Trace synchronization barrier) instruction options. +//===----------------------------------------------------------------------===// + +class TSB encoding> : SearchableTable{ + let SearchableFields = ["Name", "Encoding"]; + let EnumValueField = "Encoding"; + + string Name = name; + bits<4> Encoding; + let Encoding = encoding; + + code Requires = [{ {AArch64::HasV8_4aOps} }]; +} + +def : TSB<"csync", 0>; + +//===----------------------------------------------------------------------===// // PRFM (prefetch) instruction options. //===----------------------------------------------------------------------===// Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -2630,6 +2630,10 @@ Str += "ARMv8.1a"; else if (FBS[AArch64::HasV8_2aOps]) Str += "ARMv8.2a"; + else if (FBS[AArch64::HasV8_3aOps]) + Str += "ARMv8.3a"; + else if (FBS[AArch64::HasV8_4aOps]) + Str += "ARMv8.4a"; else Str += "(unknown)"; } @@ -2740,9 +2744,11 @@ MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); + if (Mnemonic == "tsb" && Tok.isNot(AsmToken::Identifier)) { + TokError("'csync' operand expected"); + return MatchOperand_ParseFail; // Can be either a #imm style literal or an option name - if (parseOptionalToken(AsmToken::Hash) || - Tok.is(AsmToken::Integer)) { + } else if (parseOptionalToken(AsmToken::Hash) || Tok.is(AsmToken::Integer)) { // Immediate operand. const MCExpr *ImmVal; SMLoc ExprLoc = getLoc(); @@ -2768,18 +2774,23 @@ return MatchOperand_ParseFail; } + auto TSB = AArch64TSB::lookupTSBByName(Tok.getString()); // The only valid named option for ISB is 'sy' auto DB = AArch64DB::lookupDBByName(Tok.getString()); if (Mnemonic == "isb" && (!DB || DB->Encoding != AArch64DB::sy)) { TokError("'sy' or #imm operand expected"); return MatchOperand_ParseFail; - } else if (!DB) { + // The only valid named option for TSB is 'csync' + } else if (Mnemonic == "tsb" && (!TSB || TSB->Encoding != AArch64TSB::csync)) { + TokError("'csync' operand expected"); + return MatchOperand_ParseFail; + } else if (!DB && !TSB) { TokError("invalid barrier option name"); return MatchOperand_ParseFail; } Operands.push_back(AArch64Operand::CreateBarrier( - DB->Encoding, Tok.getString(), getLoc(), getContext())); + DB ? DB->Encoding : TSB->Encoding, Tok.getString(), getLoc(), getContext())); Parser.Lex(); // Consume the option return MatchOperand_Success; Index: lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp =================================================================== --- lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp @@ -282,6 +282,13 @@ return; } + // Instruction TSB is specified as a one operand instruction, but 'csync' is + // not encoded, so for printing it is treated as a special case here: + if (Opcode == AArch64::TSB) { + O << "\ttsb\tcsync"; + return; + } + if (!printAliasInstr(MI, STI, O)) printInstruction(MI, STI, O); @@ -1329,6 +1336,9 @@ if (Opcode == AArch64::ISB) { auto ISB = AArch64ISB::lookupISBByEncoding(Val); Name = ISB ? ISB->Name : ""; + } else if (Opcode == AArch64::TSB) { + auto TSB = AArch64TSB::lookupTSBByEncoding(Val); + Name = TSB ? TSB->Name : ""; } else { auto DB = AArch64DB::lookupDBByEncoding(Val); Name = DB ? DB->Name : ""; Index: lib/Target/AArch64/Utils/AArch64BaseInfo.h =================================================================== --- lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -327,6 +327,14 @@ #include "AArch64GenSystemOperands.inc" } +namespace AArch64TSB { + struct TSB : SysAlias { + using SysAlias::SysAlias; + }; + #define GET_TSB_DECL + #include "AArch64GenSystemOperands.inc" +} + namespace AArch64PRFM { struct PRFM : SysAlias { using SysAlias::SysAlias; Index: lib/Target/AArch64/Utils/AArch64BaseInfo.cpp =================================================================== --- lib/Target/AArch64/Utils/AArch64BaseInfo.cpp +++ lib/Target/AArch64/Utils/AArch64BaseInfo.cpp @@ -53,6 +53,14 @@ #include "AArch64GenSystemOperands.inc" } } + +namespace llvm { + namespace AArch64TSB { +#define GET_TSB_IMPL +#include "AArch64GenSystemOperands.inc" + } +} + namespace llvm { namespace AArch64PRFM { #define GET_PRFM_IMPL Index: lib/Target/ARM/ARMInstrInfo.td =================================================================== --- lib/Target/ARM/ARMInstrInfo.td +++ lib/Target/ARM/ARMInstrInfo.td @@ -4819,6 +4819,15 @@ let DecoderMethod = "DecodeInstSyncBarrierOption"; } +def TraceSyncBarrierOptOperand : AsmOperandClass { + let Name = "TraceSyncBarrierOpt"; + let ParserMethod = "parseTraceSyncBarrierOptOperand"; +} +def tsb_opt : Operand { + let PrintMethod = "printTraceSyncBOption"; + let ParserMatchClass = TraceSyncBarrierOptOperand; +} + // Memory barriers protect the atomic sequences let hasSideEffects = 1 in { def DMB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, @@ -4845,6 +4854,13 @@ let Inst{31-4} = 0xf57ff06; let Inst{3-0} = opt; } + +let hasNoSchedulingInfo = 1 in +def TSB : AInoP<(outs), (ins tsb_opt:$opt), MiscFrm, NoItinerary, + "tsb", "\t$opt", []>, Requires<[IsARM, HasV8_4a]> { + let Inst{31-0} = 0xe320f012; +} + } let usesCustomInserter = 1, Defs = [CPSR] in { Index: lib/Target/ARM/ARMInstrThumb2.td =================================================================== --- lib/Target/ARM/ARMInstrThumb2.td +++ lib/Target/ARM/ARMInstrThumb2.td @@ -3209,6 +3209,12 @@ let Inst{31-4} = 0xf3bf8f6; let Inst{3-0} = opt; } + +let hasNoSchedulingInfo = 1 in +def t2TSB : T2I<(outs), (ins tsb_opt:$opt), NoItinerary, + "tsb", "\t$opt", []>, Requires<[IsThumb, HasV8_4a]> { + let Inst{31-0} = 0xf3af8012; +} } class T2I_ldrex opcod, dag oops, dag iops, AddrMode am, int sz, Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -527,6 +527,7 @@ OperandMatchResultTy parseCoprocRegOperand(OperandVector &); OperandMatchResultTy parseCoprocOptionOperand(OperandVector &); OperandMatchResultTy parseMemBarrierOptOperand(OperandVector &); + OperandMatchResultTy parseTraceSyncBarrierOptOperand(OperandVector &); OperandMatchResultTy parseInstSyncBarrierOptOperand(OperandVector &); OperandMatchResultTy parseProcIFlagsOperand(OperandVector &); OperandMatchResultTy parseMSRMaskOperand(OperandVector &); @@ -646,6 +647,7 @@ k_Immediate, k_MemBarrierOpt, k_InstSyncBarrierOpt, + k_TraceSyncBarrierOpt, k_Memory, k_PostIndexRegister, k_MSRMask, @@ -696,6 +698,10 @@ ARM_ISB::InstSyncBOpt Val; }; + struct TSBOptOp { + ARM_TSB::TraceSyncBOpt Val; + }; + struct IFlagsOp { ARM_PROC::IFlags Val; }; @@ -792,6 +798,7 @@ struct CoprocOptionOp CoprocOption; struct MBOptOp MBOpt; struct ISBOptOp ISBOpt; + struct TSBOptOp TSBOpt; struct ITMaskOp ITMask; struct IFlagsOp IFlags; struct MMaskOp MMask; @@ -881,6 +888,11 @@ return ISBOpt.Val; } + ARM_TSB::TraceSyncBOpt getTraceSyncBarrierOpt() const { + assert(Kind == k_TraceSyncBarrierOpt && "Invalid access!"); + return TSBOpt.Val; + } + ARM_PROC::IFlags getProcIFlags() const { assert(Kind == k_ProcIFlags && "Invalid access!"); return IFlags.Val; @@ -1152,6 +1164,7 @@ bool isToken() const override { return Kind == k_Token; } bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; } bool isInstSyncBarrierOpt() const { return Kind == k_InstSyncBarrierOpt; } + bool isTraceSyncBarrierOpt() const { return Kind == k_TraceSyncBarrierOpt; } bool isMem() const override { if (Kind != k_Memory) return false; @@ -2287,6 +2300,11 @@ Inst.addOperand(MCOperand::createImm(unsigned(getInstSyncBarrierOpt()))); } + void addTraceSyncBarrierOptOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(unsigned(getTraceSyncBarrierOpt()))); + } + void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); @@ -3142,6 +3160,15 @@ return Op; } + static std::unique_ptr + CreateTraceSyncBarrierOpt(ARM_TSB::TraceSyncBOpt Opt, SMLoc S) { + auto Op = make_unique(k_TraceSyncBarrierOpt); + Op->TSBOpt.Val = Opt; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + static std::unique_ptr CreateProcIFlags(ARM_PROC::IFlags IFlags, SMLoc S) { auto Op = make_unique(k_ProcIFlags); @@ -3211,6 +3238,9 @@ case k_InstSyncBarrierOpt: OS << ""; break; + case k_TraceSyncBarrierOpt: + OS << ""; + break; case k_Memory: OS << "getOperand(OpNum).getImm(); + O << ARM_TSB::TraceSyncBOptToString(val); +} + void ARMInstPrinter::printShiftImmOperand(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O) { Index: lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h +++ lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h @@ -98,6 +98,20 @@ } } // namespace ARM_MB +namespace ARM_TSB { + enum TraceSyncBOpt { + CSYNC = 0 + }; + + inline static const char *TraceSyncBOptToString(unsigned val) { + switch (val) { + default: + llvm_unreachable("Unknown trace synchronization barrier operation"); + case CSYNC: return "csync"; + } + } +} // namespace ARM_TSB + namespace ARM_ISB { enum InstSyncBOpt { RESERVED_0 = 0, Index: test/MC/AArch64/armv8.4a-trace-error.s =================================================================== --- /dev/null +++ test/MC/AArch64/armv8.4a-trace-error.s @@ -0,0 +1,23 @@ +// RUN: not llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+v8.4a < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR + +//------------------------------------------------------------------------------ +// ARMV8.4-A Debug, Trace and PMU Extensions +//------------------------------------------------------------------------------ + +tsb +tsb foo +tsb #0 +tsb 0 + +//CHECK-ERROR: error: too few operands for instruction +//CHECK-ERROR: tsb +//CHECK-ERROR: ^ +//CHECK-ERROR: error: 'csync' operand expected +//CHECK-ERROR: tsb foo +//CHECK-ERROR: ^ +//CHECK-ERROR: error: 'csync' operand expected +//CHECK-ERROR: tsb #0 +//CHECK-ERROR: ^ +//CHECK-ERROR: error: 'csync' operand expected +//CHECK-ERROR: tsb 0 +//CHECK-ERROR: ^ Index: test/MC/AArch64/armv8.4a-trace.s =================================================================== --- test/MC/AArch64/armv8.4a-trace.s +++ test/MC/AArch64/armv8.4a-trace.s @@ -13,6 +13,8 @@ mrs x0, TRFCR_EL2 mrs x0, TRFCR_EL12 +tsb csync + //CHECK: msr TRFCR_EL1, x0 // encoding: [0x20,0x12,0x18,0xd5] //CHECK: msr TRFCR_EL2, x0 // encoding: [0x20,0x12,0x1c,0xd5] //CHECK: msr TRFCR_EL12, x0 // encoding: [0x20,0x12,0x1d,0xd5] @@ -21,6 +23,8 @@ //CHECK: mrs x0, TRFCR_EL2 // encoding: [0x20,0x12,0x3c,0xd5] //CHECK: mrs x0, TRFCR_EL12 // encoding: [0x20,0x12,0x3d,0xd5] +//CHECK: tsb csync // encoding: [0x5f,0x22,0x03,0xd5] + //CHECK-ERROR: error: expected writable system register or pstate //CHECK-ERROR: msr TRFCR_EL1, x0 //CHECK-ERROR: ^ @@ -40,3 +44,5 @@ //CHECK-ERROR: error: expected readable system register //CHECK-ERROR: mrs x0, TRFCR_EL12 //CHECK-ERROR: ^ + +//CHECK-ERROR: error: instruction requires: armv8.4a Index: test/MC/ARM/armv8.4a-trace-error.s =================================================================== --- /dev/null +++ test/MC/ARM/armv8.4a-trace-error.s @@ -0,0 +1,20 @@ +// RUN: not llvm-mc -triple arm -mattr=+v8.4a -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: not llvm-mc -triple thumb -mattr=+v8.4a -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR + +tsb +tsb 0 +tsb #0 +tsb foo + +//CHECK-ERROR: error: too few operands for instruction +//CHECK-ERROR: tsb +//CHECK-ERROR: ^ +//CHECK-ERROR: error: invalid operand for instruction +//CHECK-ERROR: tsb 0 +//CHECK-ERROR: ^ +//CHECK-ERROR: error: invalid operand for instruction +//CHECK-ERROR: tsb #0 +//CHECK-ERROR: ^ +//CHECK-ERROR: error: invalid operand for instruction +//CHECK-ERROR: tsb foo +//CHECK-ERROR: ^ Index: test/MC/ARM/armv8.4a-trace.s =================================================================== --- /dev/null +++ test/MC/ARM/armv8.4a-trace.s @@ -0,0 +1,12 @@ +// RUN: llvm-mc -triple arm -mattr=+v8.4a -show-encoding < %s | FileCheck %s --check-prefix=CHECK-A32 +// RUN: llvm-mc -triple thumb -mattr=+v8.4a -show-encoding < %s | FileCheck %s --check-prefix=CHECK-T32 +// RUN: not llvm-mc -triple arm -mattr=-v8.4a -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=CHECK-NO-V84 + +tsb csync + +//CHECK-A32: tsb csync @ encoding: [0x12,0xf0,0x20,0xe3] +//CHECK-T32: tsb csync @ encoding: [0xaf,0xf3,0x12,0x80] + +//CHECK-NO-V84: error: invalid instruction +//CHECK-NO-V84: tsb csync +//CHECK-NO-V84: ^ Index: test/MC/Disassembler/AArch64/armv8.4a-trace.txt =================================================================== --- test/MC/Disassembler/AArch64/armv8.4a-trace.txt +++ test/MC/Disassembler/AArch64/armv8.4a-trace.txt @@ -7,6 +7,7 @@ [0x20,0x12,0x38,0xd5] [0x20,0x12,0x3c,0xd5] [0x20,0x12,0x3d,0xd5] +[0x5f,0x22,0x03,0xd5] #CHECK: msr TRFCR_EL1, x0 #CHECK: msr TRFCR_EL2, x0 @@ -14,6 +15,7 @@ #CHECK: mrs x0, TRFCR_EL1 #CHECK: mrs x0, TRFCR_EL2 #CHECK: mrs x0, TRFCR_EL12 +#CHECK: tsb csync #CHECK-NO-V84: msr S3_0_C1_C2_1, x0 #CHECK-NO-V84: msr S3_4_C1_C2_1, x0 @@ -21,3 +23,4 @@ #CHECK-NO-V84: mrs x0, S3_0_C1_C2_1 #CHECK-NO-V84: mrs x0, S3_4_C1_C2_1 #CHECK-NO-V84: mrs x0, S3_5_C1_C2_1 +#CHECK-NO-V84: hint #18 Index: test/MC/Disassembler/ARM/armv8.4a-trace-a32.txt =================================================================== --- /dev/null +++ test/MC/Disassembler/ARM/armv8.4a-trace-a32.txt @@ -0,0 +1,10 @@ +# RUN: llvm-mc -triple arm-none-linux-gnu -mattr=+v8.4a --disassemble < %s | FileCheck %s +# RUN: not llvm-mc -triple arm-none-linux-gnu -mattr=-v8.4a --disassemble < %s 2>&1 | FileCheck %s --check-prefix=CHECK-NO-V84 + +[0x12,0xf0,0x20,0xe3] + +#CHECK: tsb csync + +#CHECK-NO-V84: warning: invalid instruction encoding +#CHECK-NO-V84: [0x12,0xf0,0x20,0xe3] +#CHECK-NO-V84: ^ Index: test/MC/Disassembler/ARM/armv8.4a-trace-t32.txt =================================================================== --- /dev/null +++ test/MC/Disassembler/ARM/armv8.4a-trace-t32.txt @@ -0,0 +1,10 @@ +# RUN: llvm-mc -triple thumb-none-linux-gnu -mattr=+v8.4a --disassemble < %s | FileCheck %s +# RUN: not llvm-mc -triple thumb-none-linux-gnu -mattr=-v8.4a --disassemble < %s 2>&1 | FileCheck %s --check-prefix=CHECK-NO-V84 + +[0xaf,0xf3,0x12,0x80] + +#CHECK: tsb csync + +#CHECK-NO-V84: warning: invalid instruction encoding +#CHECK-NO-V84: [0xaf,0xf3,0x12,0x80] +#CHECK-NO-V84: ^