Skip to content

Commit a36d314

Browse files
[AArch64] Add support for Transactional Memory Extension (TME)
Re-commit r366322 after some fixes TME is a future architecture technology, documented in https://developer.arm.com/architectures/cpu-architecture/a-profile/exploration-tools https://developer.arm.com/docs/ddi0601/a More about the future architectures: https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/new-technologies-for-the-arm-a-profile-architecture This patch adds support for the TME instructions TSTART, TTEST, TCOMMIT, and TCANCEL and the target feature/arch extension "tme". It also implements TME builtin functions, defined in ACLE Q2 2019 (https://developer.arm.com/docs/101028/latest) Differential Revision: https://reviews.llvm.org/D64416 Patch by Javed Absar and Momchil Velikov llvm-svn: 367428
1 parent 10dd296 commit a36d314

File tree

20 files changed

+326
-13
lines changed

20 files changed

+326
-13
lines changed

clang/include/clang/Basic/BuiltinsAArch64.def

+6
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ LANGBUILTIN(__sevl, "v", "", ALL_MS_LANGUAGES)
9191
// Misc
9292
BUILTIN(__builtin_sponentry, "v*", "c")
9393

94+
// Transactional Memory Extension
95+
BUILTIN(__builtin_arm_tstart, "WUi", "nj")
96+
BUILTIN(__builtin_arm_tcommit, "v", "n")
97+
BUILTIN(__builtin_arm_tcancel, "vWUIi", "n")
98+
BUILTIN(__builtin_arm_ttest, "WUi", "nc")
99+
94100
TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
95101
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
96102
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")

clang/lib/Basic/Targets/AArch64.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
216216
if (HasMTE)
217217
Builder.defineMacro("__ARM_FEATURE_MEMORY_TAGGING", "1");
218218

219+
if (HasTME)
220+
Builder.defineMacro("__ARM_FEATURE_TME", "1");
221+
219222
if ((FPU & NeonMode) && HasFP16FML)
220223
Builder.defineMacro("__ARM_FEATURE_FP16FML", "1");
221224

@@ -267,6 +270,7 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
267270
HasDotProd = false;
268271
HasFP16FML = false;
269272
HasMTE = false;
273+
HasTME = false;
270274
ArchKind = llvm::AArch64::ArchKind::ARMV8A;
271275

272276
for (const auto &Feature : Features) {
@@ -298,6 +302,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
298302
HasFP16FML = true;
299303
if (Feature == "+mte")
300304
HasMTE = true;
305+
if (Feature == "+tme")
306+
HasTME = true;
301307
}
302308

303309
setDataLayout();

clang/lib/Basic/Targets/AArch64.h

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
3535
bool HasDotProd;
3636
bool HasFP16FML;
3737
bool HasMTE;
38+
bool HasTME;
3839

3940
llvm::AArch64::ArchKind ArchKind;
4041

clang/lib/Headers/arm_acle.h

+23-1
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ __jcvt(double __a) {
613613
#define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v)
614614
#define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v)
615615

616-
// Memory Tagging Extensions (MTE) Intrinsics
616+
/* Memory Tagging Extensions (MTE) Intrinsics */
617617
#if __ARM_FEATURE_MEMORY_TAGGING
618618
#define __arm_mte_create_random_tag(__ptr, __mask) __builtin_arm_irg(__ptr, __mask)
619619
#define __arm_mte_increment_tag(__ptr, __tag_offset) __builtin_arm_addg(__ptr, __tag_offset)
@@ -623,6 +623,28 @@ __jcvt(double __a) {
623623
#define __arm_mte_ptrdiff(__ptra, __ptrb) __builtin_arm_subp(__ptra, __ptrb)
624624
#endif
625625

626+
/* Transactional Memory Extension (TME) Intrinsics */
627+
#if __ARM_FEATURE_TME
628+
629+
#define _TMFAILURE_REASON 0x00007fffu
630+
#define _TMFAILURE_RTRY 0x00008000u
631+
#define _TMFAILURE_CNCL 0x00010000u
632+
#define _TMFAILURE_MEM 0x00020000u
633+
#define _TMFAILURE_IMP 0x00040000u
634+
#define _TMFAILURE_ERR 0x00080000u
635+
#define _TMFAILURE_SIZE 0x00100000u
636+
#define _TMFAILURE_NEST 0x00200000u
637+
#define _TMFAILURE_DBG 0x00400000u
638+
#define _TMFAILURE_INT 0x00800000u
639+
#define _TMFAILURE_TRIVIAL 0x01000000u
640+
641+
#define __tstart() __builtin_arm_tstart()
642+
#define __tcommit() __builtin_arm_tcommit()
643+
#define __tcancel(__arg) __builtin_arm_tcancel(__arg)
644+
#define __ttest() __builtin_arm_ttest()
645+
646+
#endif /* __ARM_FEATURE_TME */
647+
626648
#if defined(__cplusplus)
627649
}
628650
#endif

clang/lib/Sema/SemaChecking.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,7 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
19321932
case AArch64::BI__builtin_arm_dmb:
19331933
case AArch64::BI__builtin_arm_dsb:
19341934
case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
1935+
case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break;
19351936
}
19361937

19371938
return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);

clang/test/CodeGen/aarch64-tme.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %clang_cc1 -triple aarch64-eabi -target-feature +tme -S -emit-llvm %s -o - | FileCheck %s
2+
// RUN: %clang_cc1 -DUSE_ACLE -triple aarch64-eabi -target-feature +tme -S -emit-llvm %s -o - | FileCheck %s
3+
4+
#define A -1
5+
constexpr int f() { return 65536; }
6+
7+
#ifdef USE_ACLE
8+
#include "arm_acle.h"
9+
void test_tme_funcs() {
10+
__tstart();
11+
(void)__ttest();
12+
__tcommit();
13+
__tcancel(0x789a);
14+
__tcancel(f() + A);
15+
}
16+
#else
17+
void test_tme_funcs() {
18+
__builtin_arm_tstart();
19+
(void)__builtin_arm_ttest();
20+
__builtin_arm_tcommit();
21+
__builtin_arm_tcancel(0x789a);
22+
__builtin_arm_tcancel(f() + A);
23+
}
24+
#endif
25+
// CHECK: call i64 @llvm.aarch64.tstart()
26+
// CHECK: call i64 @llvm.aarch64.ttest()
27+
// CHECK: call void @llvm.aarch64.tcommit()
28+
// CHECK: call void @llvm.aarch64.tcancel(i64 30874)
29+
// CHECK: call void @llvm.aarch64.tcancel(i64 65535)
30+
31+
// CHECK: declare i64 @llvm.aarch64.tstart() #1
32+
// CHECK: declare i64 @llvm.aarch64.ttest() #1
33+
// CHECK: declare void @llvm.aarch64.tcommit() #1
34+
// CHECK: declare void @llvm.aarch64.tcancel(i64 immarg) #1
35+
36+
#ifdef __ARM_FEATURE_TME
37+
extern "C" void arm_feature_tme_defined() {}
38+
#endif
39+
// CHECK: define void @arm_feature_tme_defined()
40+
41+
// CHECK: attributes #1 = { nounwind }
42+

clang/test/Sema/aarch64-tme-errors.c

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %clang_cc1 -triple aarch64-eabi -verify %s
2+
3+
#include "arm_acle.h"
4+
5+
void test_no_tme_funcs() {
6+
__tstart(); // expected-warning{{implicit declaration of function '__tstart'}}
7+
__builtin_tstart(); // expected-error{{use of unknown builtin '__builtin_tstart'}}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 -triple aarch64-eabi -target-feature +tme -verify %s
2+
void t_cancel_const(unsigned short u) {
3+
__builtin_arm_tcancel(u); // expected-error{{argument to '__builtin_arm_tcancel' must be a constant integer}}
4+
}
5+
6+
// RUN: %clang_cc1 -triple aarch64-eabi -target-feature +tme -verify %s
7+
void t_cancel_range() {
8+
__builtin_arm_tcancel(0x12345u); // expected-error{{argument value 74565 is outside the valid range [0, 65535]}}
9+
}

llvm/include/llvm/IR/IntrinsicsAArch64.td

+15
Original file line numberDiff line numberDiff line change
@@ -733,3 +733,18 @@ def int_aarch64_settag_zero : Intrinsic<[], [llvm_ptr_ty, llvm_i64_ty],
733733
def int_aarch64_stgp : Intrinsic<[], [llvm_ptr_ty, llvm_i64_ty, llvm_i64_ty],
734734
[IntrWriteMem, IntrArgMemOnly, NoCapture<0>, WriteOnly<0>]>;
735735
}
736+
737+
// Transactional Memory Extension (TME) Intrinsics
738+
let TargetPrefix = "aarch64" in {
739+
def int_aarch64_tstart : GCCBuiltin<"__builtin_arm_tstart">,
740+
Intrinsic<[llvm_i64_ty]>;
741+
742+
def int_aarch64_tcommit : GCCBuiltin<"__builtin_arm_tcommit">, Intrinsic<[]>;
743+
744+
def int_aarch64_tcancel : GCCBuiltin<"__builtin_arm_tcancel">,
745+
Intrinsic<[], [llvm_i64_ty], [ImmArg<0>]>;
746+
747+
def int_aarch64_ttest : GCCBuiltin<"__builtin_arm_ttest">,
748+
Intrinsic<[llvm_i64_ty], [],
749+
[IntrNoMem, IntrHasSideEffects]>;
750+
}

llvm/include/llvm/Support/AArch64TargetParser.def

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ AARCH64_ARCH_EXT_NAME("memtag", AArch64::AEK_MTE, "+mte", "-mte"
7979
AARCH64_ARCH_EXT_NAME("ssbs", AArch64::AEK_SSBS, "+ssbs", "-ssbs")
8080
AARCH64_ARCH_EXT_NAME("sb", AArch64::AEK_SB, "+sb", "-sb")
8181
AARCH64_ARCH_EXT_NAME("predres", AArch64::AEK_PREDRES, "+predres", "-predres")
82+
AARCH64_ARCH_EXT_NAME("tme", AArch64::AEK_TME, "+tme", "-tme")
8283
#undef AARCH64_ARCH_EXT_NAME
8384

8485
#ifndef AARCH64_CPU_NAME

llvm/include/llvm/Support/AArch64TargetParser.h

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ enum ArchExtKind : unsigned {
5454
AEK_SVE2SM4 = 1 << 25,
5555
AEK_SVE2SHA3 = 1 << 26,
5656
AEK_SVE2BITPERM = 1 << 27,
57+
AEK_TME = 1 << 28,
5758
};
5859

5960
enum class ArchKind {

llvm/lib/Target/AArch64/AArch64.td

+3
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,9 @@ def FeatureETE : SubtargetFeature<"ete", "HasETE",
352352
"true", "Enable Embedded Trace Extension",
353353
[FeatureTRBE]>;
354354

355+
def FeatureTME : SubtargetFeature<"tme", "HasTME",
356+
"true", "Enable Transactional Memory Extension" >;
357+
355358
//===----------------------------------------------------------------------===//
356359
// Architectures.
357360
//

llvm/lib/Target/AArch64/AArch64InstrFormats.td

+48-6
Original file line numberDiff line numberDiff line change
@@ -678,12 +678,15 @@ def logical_imm64_not : Operand<i64> {
678678
let ParserMatchClass = LogicalImm64NotOperand;
679679
}
680680

681-
// imm0_65535 predicate - True if the immediate is in the range [0,65535].
682-
def imm0_65535 : Operand<i32>, ImmLeaf<i32, [{
681+
// iXX_imm0_65535 predicates - True if the immediate is in the range [0,65535].
682+
let ParserMatchClass = AsmImmRange<0, 65535>, PrintMethod = "printImmHex" in {
683+
def i32_imm0_65535 : Operand<i32>, ImmLeaf<i32, [{
683684
return ((uint32_t)Imm) < 65536;
684-
}]> {
685-
let ParserMatchClass = AsmImmRange<0, 65535>;
686-
let PrintMethod = "printImmHex";
685+
}]>;
686+
687+
def i64_imm0_65535 : Operand<i64>, ImmLeaf<i64, [{
688+
return ((uint64_t)Imm) < 65536;
689+
}]>;
687690
}
688691

689692
// imm0_255 predicate - True if the immediate is in the range [0,255].
@@ -1046,6 +1049,45 @@ class RtSystemI<bit L, dag oops, dag iops, string asm, string operands>
10461049
let Inst{4-0} = Rt;
10471050
}
10481051

1052+
// System instructions for transactional memory extension
1053+
class TMBaseSystemI<bit L, bits<4> CRm, bits<3> op2, dag oops, dag iops,
1054+
string asm, string operands, list<dag> pattern>
1055+
: BaseSystemI<L, oops, iops, asm, operands, pattern>,
1056+
Sched<[WriteSys]> {
1057+
let Inst{20-12} = 0b000110011;
1058+
let Inst{11-8} = CRm;
1059+
let Inst{7-5} = op2;
1060+
let DecoderMethod = "";
1061+
1062+
let mayLoad = 1;
1063+
let mayStore = 1;
1064+
}
1065+
1066+
// System instructions for transactional memory - single input operand
1067+
class TMSystemI<bits<4> CRm, string asm, list<dag> pattern>
1068+
: TMBaseSystemI<0b1, CRm, 0b011,
1069+
(outs GPR64:$Rt), (ins), asm, "\t$Rt", pattern> {
1070+
bits<5> Rt;
1071+
let Inst{4-0} = Rt;
1072+
}
1073+
1074+
// System instructions for transactional memory - no operand
1075+
class TMSystemINoOperand<bits<4> CRm, string asm, list<dag> pattern>
1076+
: TMBaseSystemI<0b0, CRm, 0b011, (outs), (ins), asm, "", pattern> {
1077+
let Inst{4-0} = 0b11111;
1078+
}
1079+
1080+
// System instructions for exit from transactions
1081+
class TMSystemException<bits<3> op1, string asm, list<dag> pattern>
1082+
: I<(outs), (ins i64_imm0_65535:$imm), asm, "\t$imm", "", pattern>,
1083+
Sched<[WriteSys]> {
1084+
bits<16> imm;
1085+
let Inst{31-24} = 0b11010100;
1086+
let Inst{23-21} = op1;
1087+
let Inst{20-5} = imm;
1088+
let Inst{4-0} = 0b00000;
1089+
}
1090+
10491091
// Hint instructions that take both a CRm and a 3-bit immediate.
10501092
// NOTE: ideally, this would have mayStore = 0, mayLoad = 0, but we cannot
10511093
// model patterns with sufficiently fine granularity
@@ -4050,7 +4092,7 @@ multiclass MemTagStore<bits<2> opc1, string insn> {
40504092

40514093
let mayLoad = 0, mayStore = 0, hasSideEffects = 1 in
40524094
class ExceptionGeneration<bits<3> op1, bits<2> ll, string asm>
4053-
: I<(outs), (ins imm0_65535:$imm), asm, "\t$imm", "", []>,
4095+
: I<(outs), (ins i32_imm0_65535:$imm), asm, "\t$imm", "", []>,
40544096
Sched<[WriteSys]> {
40554097
bits<16> imm;
40564098
let Inst{31-24} = 0b11010100;

llvm/lib/Target/AArch64/AArch64InstrInfo.td

+25-6
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ def HasBTI : Predicate<"Subtarget->hasBTI()">,
133133
AssemblerPredicate<"FeatureBranchTargetId", "bti">;
134134
def HasMTE : Predicate<"Subtarget->hasMTE()">,
135135
AssemblerPredicate<"FeatureMTE", "mte">;
136+
def HasTME : Predicate<"Subtarget->hasTME()">,
137+
AssemblerPredicate<"FeatureTME", "tme">;
136138
def HasETE : Predicate<"Subtarget->hasETE()">,
137139
AssemblerPredicate<"FeatureETE", "ete">;
138140
def HasTRBE : Predicate<"Subtarget->hasTRBE()">,
@@ -808,6 +810,23 @@ def : InstAlias<"sys $op1, $Cn, $Cm, $op2",
808810
(SYSxt imm0_7:$op1, sys_cr_op:$Cn,
809811
sys_cr_op:$Cm, imm0_7:$op2, XZR)>;
810812

813+
814+
let Predicates = [HasTME] in {
815+
816+
def TSTART : TMSystemI<0b0000, "tstart",
817+
[(set GPR64:$Rt, (int_aarch64_tstart))]>;
818+
819+
def TCOMMIT : TMSystemINoOperand<0b0000, "tcommit", [(int_aarch64_tcommit)]>;
820+
821+
def TCANCEL : TMSystemException<0b011, "tcancel",
822+
[(int_aarch64_tcancel i64_imm0_65535:$imm)]>;
823+
824+
def TTEST : TMSystemI<0b0001, "ttest", [(set GPR64:$Rt, (int_aarch64_ttest))]> {
825+
let mayLoad = 0;
826+
let mayStore = 0;
827+
}
828+
} // HasTME
829+
811830
//===----------------------------------------------------------------------===//
812831
// Move immediate instructions.
813832
//===----------------------------------------------------------------------===//
@@ -819,12 +838,12 @@ let PostEncoderMethod = "fixMOVZ" in
819838
defm MOVZ : MoveImmediate<0b10, "movz">;
820839

821840
// First group of aliases covers an implicit "lsl #0".
822-
def : InstAlias<"movk $dst, $imm", (MOVKWi GPR32:$dst, imm0_65535:$imm, 0), 0>;
823-
def : InstAlias<"movk $dst, $imm", (MOVKXi GPR64:$dst, imm0_65535:$imm, 0), 0>;
824-
def : InstAlias<"movn $dst, $imm", (MOVNWi GPR32:$dst, imm0_65535:$imm, 0)>;
825-
def : InstAlias<"movn $dst, $imm", (MOVNXi GPR64:$dst, imm0_65535:$imm, 0)>;
826-
def : InstAlias<"movz $dst, $imm", (MOVZWi GPR32:$dst, imm0_65535:$imm, 0)>;
827-
def : InstAlias<"movz $dst, $imm", (MOVZXi GPR64:$dst, imm0_65535:$imm, 0)>;
841+
def : InstAlias<"movk $dst, $imm", (MOVKWi GPR32:$dst, i32_imm0_65535:$imm, 0), 0>;
842+
def : InstAlias<"movk $dst, $imm", (MOVKXi GPR64:$dst, i32_imm0_65535:$imm, 0), 0>;
843+
def : InstAlias<"movn $dst, $imm", (MOVNWi GPR32:$dst, i32_imm0_65535:$imm, 0)>;
844+
def : InstAlias<"movn $dst, $imm", (MOVNXi GPR64:$dst, i32_imm0_65535:$imm, 0)>;
845+
def : InstAlias<"movz $dst, $imm", (MOVZWi GPR32:$dst, i32_imm0_65535:$imm, 0)>;
846+
def : InstAlias<"movz $dst, $imm", (MOVZXi GPR64:$dst, i32_imm0_65535:$imm, 0)>;
828847

829848
// Next, we have various ELF relocations with the ":XYZ_g0:sym" syntax.
830849
def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movw_symbol_g3:$sym, 48)>;

llvm/lib/Target/AArch64/AArch64Subtarget.h

+2
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
137137
bool HasBTI = false;
138138
bool HasRandGen = false;
139139
bool HasMTE = false;
140+
bool HasTME = false;
140141

141142
// Arm SVE2 extensions
142143
bool HasSVE2AES = false;
@@ -387,6 +388,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
387388
bool hasBTI() const { return HasBTI; }
388389
bool hasRandGen() const { return HasRandGen; }
389390
bool hasMTE() const { return HasMTE; }
391+
bool hasTME() const { return HasTME; }
390392
// Arm SVE2 extensions
391393
bool hasSVE2AES() const { return HasSVE2AES; }
392394
bool hasSVE2SM4() const { return HasSVE2SM4; }

llvm/test/CodeGen/AArch64/tme.ll

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
; RUN: llc %s -verify-machineinstrs -o - | FileCheck %s
2+
3+
target triple = "aarch64-unknown-unknown-eabi"
4+
5+
define i64 @test_tstart() #0 {
6+
%r = tail call i64 @llvm.aarch64.tstart()
7+
ret i64 %r
8+
}
9+
declare i64 @llvm.aarch64.tstart() #1
10+
; CHECK-LABEL: test_tstart
11+
; CHECK: tstart x
12+
13+
define i64 @test_ttest() #0 {
14+
%r = tail call i64 @llvm.aarch64.ttest()
15+
ret i64 %r
16+
}
17+
declare i64 @llvm.aarch64.ttest() #1
18+
; CHECK-LABEL: test_ttest
19+
; CHECK: ttest x
20+
21+
define void @test_tcommit() #0 {
22+
tail call void @llvm.aarch64.tcommit()
23+
ret void
24+
}
25+
declare void @llvm.aarch64.tcommit() #1
26+
; CHECK-LABEL: test_tcommit
27+
; CHECK: tcommit
28+
29+
define void @test_tcancel() #0 {
30+
tail call void @llvm.aarch64.tcancel(i64 0) #1
31+
tail call void @llvm.aarch64.tcancel(i64 1) #1
32+
tail call void @llvm.aarch64.tcancel(i64 65534) #1
33+
tail call void @llvm.aarch64.tcancel(i64 65535) #1
34+
ret void
35+
}
36+
declare void @llvm.aarch64.tcancel(i64 immarg) #1
37+
; CHECK-LABEL: test_tcancel
38+
; CHECK: tcancel #0
39+
; CHECK: tcancel #0x1
40+
; CHECK: tcancel #0xfffe
41+
; CHECK: tcancel #0xffff
42+
43+
attributes #0 = { "target-features"="+tme" }
44+
attributes #1 = { nounwind }

0 commit comments

Comments
 (0)