diff --git a/clang/test/Driver/aarch64-vfat.c b/clang/test/Driver/aarch64-vfat.c new file mode 100644 index 0000000000000..bd5eed275489f --- /dev/null +++ b/clang/test/Driver/aarch64-vfat.c @@ -0,0 +1,7 @@ +// ===== Features supported on aarch64 ===== + +// FAT features (Future Architecture Technologies) + +// RUN: %clang -target aarch64 -march=armv9.7a+mops-go -### -c %s 2>&1 | FileCheck -check-prefix=VFAT-MOPS-GO %s +// RUN: %clang -target aarch64 -march=armv9.7-a+mops-go -### -c %s 2>&1 | FileCheck -check-prefix=VFAT-MOPS-GO %s +// VFAT-MOPS-GO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.7a"{{.*}} "-target-feature" "+mops-go" diff --git a/clang/test/Driver/print-supported-extensions-aarch64.c b/clang/test/Driver/print-supported-extensions-aarch64.c index 7294c33959e7e..f2da680b68d70 100644 --- a/clang/test/Driver/print-supported-extensions-aarch64.c +++ b/clang/test/Driver/print-supported-extensions-aarch64.c @@ -49,6 +49,7 @@ // CHECK-NEXT: lsui FEAT_LSUI Enable Armv9.6-A unprivileged load/store instructions // CHECK-NEXT: lut FEAT_LUT Enable Lookup Table instructions // CHECK-NEXT: mops FEAT_MOPS Enable Armv8.8-A memcpy and memset acceleration instructions +// CHECK-NEXT: mops-go FEAT_MOPS_GO Enable memset acceleration granule only // CHECK-NEXT: mpamv2 FEAT_MPAMv2 Enable Armv9.7-A MPAMv2 Lookaside Buffer Invalidate instructions // CHECK-NEXT: memtag FEAT_MTE, FEAT_MTE2 Enable Memory Tagging Extension // CHECK-NEXT: mtetc FEAT_MTETC Enable Virtual Memory Tagging Extension diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index c76717fdc990c..6f386b81476ac 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -104,6 +104,9 @@ Changes to the AArch64 Backend * Assembler/disassembler support has been added for Armv9.7-A (2025) architecture extensions. +* Assembler/disassembler support has been added for 'Virtual Tagging + Extension (vMTE)' Future Architecture Technologies extension. + Changes to the AMDGPU Backend ----------------------------- diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td index 0e94b78d11d83..7fd5254dfa536 100644 --- a/llvm/lib/Target/AArch64/AArch64Features.td +++ b/llvm/lib/Target/AArch64/AArch64Features.td @@ -625,6 +625,13 @@ def FeatureF16F32DOT : ExtensionWithMArch<"f16f32dot", "F16F32DOT", "FEAT_F16F32 def FeatureF16F32MM : ExtensionWithMArch<"f16f32mm", "F16F32MM", "FEAT_F16F32MM", "Enable Armv9.7-A Advanced SIMD half-precision matrix multiply-accumulate to single-precision", [FeatureNEON, FeatureFullFP16]>; +//===----------------------------------------------------------------------===// +// Future Architecture Technologies +//===----------------------------------------------------------------------===// + +def FeatureMOPS_GO: ExtensionWithMArch<"mops-go", "MOPS_GO", "FEAT_MOPS_GO", + "Enable memset acceleration granule only">; + //===----------------------------------------------------------------------===// // Other Features //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td index bb2f083db19ef..2bce5c89f8ba6 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -12588,12 +12588,10 @@ class MOPSMemoryCopy opcode, bits<2> op1, bits<2> op2, string asm> class MOPSMemoryMove opcode, bits<2> op1, bits<2> op2, string asm> : MOPSMemoryCopyMoveBase<1, opcode, op1, op2, asm>; -class MOPSMemorySetBase opcode, bit op1, bit op2, - string asm> - : I<(outs GPR64common:$Rd_wb, GPR64:$Rn_wb), - (ins GPR64common:$Rd, GPR64:$Rn, GPR64:$Rm), - asm, "\t[$Rd]!, $Rn!, $Rm", - "$Rd = $Rd_wb,$Rn = $Rn_wb", []>, +class MOPSMemorySetBase opcode, + bit op1, bit op2, bit op3, string asm> + : I<(outs GPR64common:$Rd_wb, GPR64:$Rn_wb), ins, + asm, operands, "$Rd = $Rd_wb,$Rn = $Rn_wb", []>, Sched<[]> { bits<5> Rd; bits<5> Rn; @@ -12605,20 +12603,34 @@ class MOPSMemorySetBase opcode, bit op1, bit op2, let Inst{15-14} = opcode; let Inst{13} = op2; let Inst{12} = op1; - let Inst{11-10} = 0b01; + let Inst{11} = 0b0; + let Inst{10} = op3; let Inst{9-5} = Rn; let Inst{4-0} = Rd; - let DecoderMethod = "DecodeSETMemOpInstruction"; let mayLoad = 0; let mayStore = 1; } -class MOPSMemorySet opcode, bit op1, bit op2, string asm> - : MOPSMemorySetBase<0, opcode, op1, op2, asm>; +class MOPSMemorySet opcode, bit op1, bit op2, bit op3, string asm> + : MOPSMemorySetBase<(ins GPR64common:$Rd, GPR64:$Rn, GPR64:$Rm), + "\t[$Rd]!, $Rn!, $Rm", 0, opcode, op1, op2, op3, asm> { + let DecoderMethod = "DecodeSETMemOpInstruction"; +} + +class MOPSMemorySetTagging opcode, bit op1, bit op2, bit op3, string asm> + : MOPSMemorySetBase<(ins GPR64common:$Rd, GPR64:$Rn, GPR64:$Rm), + "\t[$Rd]!, $Rn!, $Rm", 1, opcode, op1, op2, op3, asm> { + let DecoderMethod = "DecodeSETMemOpInstruction"; +} -class MOPSMemorySetTagging opcode, bit op1, bit op2, string asm> - : MOPSMemorySetBase<1, opcode, op1, op2, asm>; +class MOPSGoMemorySetTagging opcode, bit op1, bit op2, bit op3, string asm> + : MOPSMemorySetBase<(ins GPR64common:$Rd, GPR64:$Rn), + "\t[$Rd]!, $Rn!", 1, opcode, op1, op2, op3, asm> { + // No `Rm` operand, as all bits must be set to 1 + let Inst{20-16} = 0b11111; + let DecoderMethod = "DecodeSETMemGoOpInstruction"; +} multiclass MOPSMemoryCopyInsns opcode, string asm> { def "" : MOPSMemoryCopy; @@ -12659,17 +12671,27 @@ multiclass MOPSMemoryMoveInsns opcode, string asm> { } multiclass MOPSMemorySetInsns opcode, string asm> { - def "" : MOPSMemorySet; - def T : MOPSMemorySet; - def N : MOPSMemorySet; - def TN : MOPSMemorySet; + def "" : MOPSMemorySet; + def T : MOPSMemorySet; + def N : MOPSMemorySet; + def TN : MOPSMemorySet; } multiclass MOPSMemorySetTaggingInsns opcode, string asm> { - def "" : MOPSMemorySetTagging; - def T : MOPSMemorySetTagging; - def N : MOPSMemorySetTagging; - def TN : MOPSMemorySetTagging; + def "" : MOPSMemorySetTagging; + def T : MOPSMemorySetTagging; + def N : MOPSMemorySetTagging; + def TN : MOPSMemorySetTagging; +} + +//---------------------------------------------------------------------------- +// MOPS Granule Only - FEAT_MOPS_GO +//---------------------------------------------------------------------------- +multiclass MOPSGoMemorySetTaggingInsns opcode, string asm> { + def "" : MOPSGoMemorySetTagging; + def T : MOPSGoMemorySetTagging; + def N : MOPSGoMemorySetTagging; + def TN : MOPSGoMemorySetTagging; } //---------------------------------------------------------------------------- diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index b30e3d06b2c9f..34a20f09d2806 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -405,6 +405,8 @@ def HasMTETC : Predicate<"Subtarget->hasMTETC()">, AssemblerPredicateWithAll<(all_of FeatureMTETC), "mtetc">; def HasGCIE : Predicate<"Subtarget->hasGCIE()">, AssemblerPredicateWithAll<(all_of FeatureGCIE), "gcie">; +def HasMOPS_GO : Predicate<"Subtarget->hasMOPS_GO()">, + AssemblerPredicateWithAll<(all_of FeatureMOPS_GO), "mops-go">; def IsLE : Predicate<"Subtarget->isLittleEndian()">; def IsBE : Predicate<"!Subtarget->isLittleEndian()">; def IsWindows : Predicate<"Subtarget->isTargetWindows()">; @@ -10867,6 +10869,15 @@ let Predicates = [HasMOPS, HasMTE], Defs = [NZCV], Size = 12, mayLoad = 0, maySt [], "$Rd = $Rd_wb,$Rn = $Rn_wb">, Sched<[]>; } +//----------------------------------------------------------------------------- +// MOPS Granule Only Protection (FEAT_MOPS_GO) + +let Predicates = [HasMOPS_GO, HasMTE] in { + defm SETGOP : MOPSGoMemorySetTaggingInsns<0b00, "setgop">; + defm SETGOM : MOPSGoMemorySetTaggingInsns<0b01, "setgom">; + defm SETGOE : MOPSGoMemorySetTaggingInsns<0b10, "setgoe">; +} + //----------------------------------------------------------------------------- // v8.3 Pointer Authentication late patterns diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index f5dfbdc596510..7293b7fdb0d20 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -3893,6 +3893,7 @@ static const struct Extension { {"f16mm", {AArch64::FeatureF16MM}}, {"f16f32dot", {AArch64::FeatureF16F32DOT}}, {"f16f32mm", {AArch64::FeatureF16F32MM}}, + {"mops-go", {AArch64::FeatureMOPS_GO}}, }; static void setRequiredFeatureString(FeatureBitset FBS, std::string &Str) { @@ -5994,6 +5995,33 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc, " registers are the same"); break; } + case AArch64::SETGOP: + case AArch64::SETGOPT: + case AArch64::SETGOPN: + case AArch64::SETGOPTN: + case AArch64::SETGOM: + case AArch64::SETGOMT: + case AArch64::SETGOMN: + case AArch64::SETGOMTN: + case AArch64::SETGOE: + case AArch64::SETGOET: + case AArch64::SETGOEN: + case AArch64::SETGOETN: { + MCRegister Xd_wb = Inst.getOperand(0).getReg(); + MCRegister Xn_wb = Inst.getOperand(1).getReg(); + MCRegister Xd = Inst.getOperand(2).getReg(); + MCRegister Xn = Inst.getOperand(3).getReg(); + if (Xd_wb != Xd) + return Error(Loc[0], + "invalid SET instruction, Xd_wb and Xd do not match"); + if (Xn_wb != Xn) + return Error(Loc[0], + "invalid SET instruction, Xn_wb and Xn do not match"); + if (Xd == Xn) + return Error(Loc[0], "invalid SET instruction, destination and size" + " registers are the same"); + break; + } } // Now check immediate ranges. Separate from the above as there is overlap diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp index dc2feba42c871..4eb762a00d477 100644 --- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -1532,6 +1532,32 @@ static DecodeStatus DecodeSETMemOpInstruction(MCInst &Inst, uint32_t insn, return MCDisassembler::Success; } +static DecodeStatus DecodeSETMemGoOpInstruction(MCInst &Inst, uint32_t insn, + uint64_t Addr, + const MCDisassembler *Decoder) { + unsigned Rd = fieldFromInstruction(insn, 0, 5); + unsigned Rn = fieldFromInstruction(insn, 5, 5); + + // None of the registers may alias: if they do, then the instruction is not + // merely unpredictable but actually entirely unallocated. + if (Rd == Rn) + return MCDisassembler::Fail; + + // Rd and Rn register operands are written back, so they appear + // twice in the operand list, once as outputs and once as inputs. + if (!DecodeSimpleRegisterClass( + Inst, Rd, Addr, Decoder) || + !DecodeSimpleRegisterClass( + Inst, Rn, Addr, Decoder) || + !DecodeSimpleRegisterClass( + Inst, Rd, Addr, Decoder) || + !DecodeSimpleRegisterClass( + Inst, Rn, Addr, Decoder)) + return MCDisassembler::Fail; + + return MCDisassembler::Success; +} + static DecodeStatus DecodePRFMRegInstruction(MCInst &Inst, uint32_t insn, uint64_t Addr, const MCDisassembler *Decoder) { diff --git a/llvm/test/MC/AArch64/arm-mops-go-diagnostics.s b/llvm/test/MC/AArch64/arm-mops-go-diagnostics.s new file mode 100644 index 0000000000000..c22331b9f18e4 --- /dev/null +++ b/llvm/test/MC/AArch64/arm-mops-go-diagnostics.s @@ -0,0 +1,36 @@ +// RUN: not llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+mops-go,+mte < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR + +// Operands must be different from each other + +// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same +// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same +// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same +setgop [x0]!, x0! +setgom [x0]!, x0! +setgoe [x0]!, x0! + +// SP cannot be used as argument at any position + +// CHECK-ERROR: error: invalid operand for instruction +// CHECK-ERROR: error: invalid operand for instruction +setgop [sp]!, x1! +setgop [x0]!, sp! + +// CHECK-ERROR: error: invalid operand for instruction +// CHECK-ERROR: error: invalid operand for instruction +setgom [sp]!, x1! +setgom [x0]!, sp! + +// CHECK-ERROR: error: invalid operand for instruction +// CHECK-ERROR: error: invalid operand for instruction +setgoe [sp]!, x1! +setgoe [x0]!, sp! + +// CHECK-ERROR: error: invalid operand for instruction +setgop [xzr]!, x1! + +// CHECK-ERROR: error: invalid operand for instruction +setgom [xzr]!, x1! + +// CHECK-ERROR: error: invalid operand for instruction +setgoe [xzr]!, x1! diff --git a/llvm/test/MC/AArch64/arm-mops-go.s b/llvm/test/MC/AArch64/arm-mops-go.s new file mode 100644 index 0000000000000..0b7809c252b86 --- /dev/null +++ b/llvm/test/MC/AArch64/arm-mops-go.s @@ -0,0 +1,89 @@ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+mops-go,+mte < %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST +// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+mops-go,+mte < %s \ +// RUN: | llvm-objdump -d --mattr=+mops-go,+mte --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+mops-go,+mte < %s \ +// RUN: | llvm-objdump -d --mattr=-mops-go,-mte --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-UNKNOWN +// Disassemble encoding and check the re-encoding (-show-encoding) matches. +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+mops-go,+mte < %s \ +// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \ +// RUN: | llvm-mc -triple=aarch64 -mattr=+mops-go,+mte -disassemble -show-encoding \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST + +//------------------------------------------------------------------------------ +// FEAT_MOPS_GO Extension instructions +//------------------------------------------------------------------------------ + +setgop [x3]!, x2! +// CHECK-INST: setgop [x3]!, x2! +// CHECK-ENCODING: [0x43,0x00,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf0043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgom [x3]!, x2! +// CHECK-INST: setgom [x3]!, x2! +// CHECK-ENCODING: [0x43,0x40,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf4043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgoe [x3]!, x2! +// CHECK-INST: setgoe [x3]!, x2! +// CHECK-ENCODING: [0x43,0x80,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf8043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgopn [x3]!, x2! +// CHECK-INST: setgopn [x3]!, x2! +// CHECK-ENCODING: [0x43,0x20,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf2043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgomn [x3]!, x2! +// CHECK-INST: setgomn [x3]!, x2! +// CHECK-ENCODING: [0x43,0x60,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf6043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgoen [x3]!, x2! +// CHECK-INST: setgoen [x3]!, x2! +// CHECK-ENCODING: [0x43,0xa0,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddfa043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgopt [x3]!, x2! +// CHECK-INST: setgopt [x3]!, x2! +// CHECK-ENCODING: [0x43,0x10,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf1043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgomt [x3]!, x2! +// CHECK-INST: setgomt [x3]!, x2! +// CHECK-ENCODING: [0x43,0x50,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf5043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgoet [x3]!, x2! +// CHECK-INST: setgoet [x3]!, x2! +// CHECK-ENCODING: [0x43,0x90,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf9043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgoptn [x3]!, x2! +// CHECK-INST: setgoptn [x3]!, x2! +// CHECK-ENCODING: [0x43,0x30,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf3043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgomtn [x3]!, x2! +// CHECK-INST: setgomtn [x3]!, x2! +// CHECK-ENCODING: [0x43,0x70,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddf7043 +// CHECK-ERROR: instruction requires: mops-go mte + +setgoetn [x3]!, x2! +// CHECK-INST: setgoetn [x3]!, x2! +// CHECK-ENCODING: [0x43,0xb0,0xdf,0x1d] +// CHECK-UNKNOWN: 1ddfb043 +// CHECK-ERROR: instruction requires: mops-go mte diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp index 0e5d40ad3c7b1..328013e961411 100644 --- a/llvm/unittests/TargetParser/TargetParserTest.cpp +++ b/llvm/unittests/TargetParser/TargetParserTest.cpp @@ -1452,7 +1452,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) { AArch64::AEK_GCIE, AArch64::AEK_SME2P3, AArch64::AEK_SVE2P3, AArch64::AEK_SVE_B16MM, AArch64::AEK_F16MM, AArch64::AEK_F16F32DOT, - AArch64::AEK_F16F32MM, + AArch64::AEK_F16F32MM, AArch64::AEK_MOPS_GO, }; std::vector Features; @@ -1576,6 +1576,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) { EXPECT_TRUE(llvm::is_contained(Features, "+f16mm")); EXPECT_TRUE(llvm::is_contained(Features, "+f16f32dot")); EXPECT_TRUE(llvm::is_contained(Features, "+f16f32mm")); + EXPECT_TRUE(llvm::is_contained(Features, "+mops-go")); // Assuming we listed every extension above, this should produce the same // result. @@ -1754,6 +1755,7 @@ TEST(TargetParserTest, AArch64ArchExtFeature) { {"f16mm", "nof16mm", "+f16mm", "-f16mm"}, {"f16f32dot", "nof16f32dot", "+f16f32dot", "-f16f32dot"}, {"f16f32mm", "nof16f32mm", "+f16f32mm", "-f16f32mm"}, + {"mops-go", "nomops-go", "+mops-go", "-mops-go"}, }; for (unsigned i = 0; i < std::size(ArchExt); i++) {