Skip to content

Commit

Permalink
[AArch64] Add support for Transactional Memory Extension (TME)
Browse files Browse the repository at this point in the history
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)

Patch by Javed Absar and Momchil Velikov

Differential Revision: https://reviews.llvm.org/D64416

llvm-svn: 366322
  • Loading branch information
momchil-velikov committed Jul 17, 2019
1 parent 2889fe6 commit 4b8da3a
Show file tree
Hide file tree
Showing 25 changed files with 350 additions and 13 deletions.
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/BuiltinsAArch64.def
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ LANGBUILTIN(__sevl, "v", "", ALL_MS_LANGUAGES)
// Misc
BUILTIN(__builtin_sponentry, "v*", "c")

// Transactional Memory Extension
BUILTIN(__builtin_arm_tstart, "WUi", "nj")
BUILTIN(__builtin_arm_tcommit, "v", "n")
BUILTIN(__builtin_arm_tcancel, "vWUIi", "nr")
BUILTIN(__builtin_arm_ttest, "WUi", "nc")

TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasMTE)
Builder.defineMacro("__ARM_FEATURE_MEMORY_TAGGING", "1");

if (HasTME)
Builder.defineMacro("__ARM_FEATURE_TME", "1");

if ((FPU & NeonMode) && HasFP16FML)
Builder.defineMacro("__ARM_FEATURE_FP16FML", "1");

Expand Down Expand Up @@ -270,6 +273,7 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasDotProd = false;
HasFP16FML = false;
HasMTE = false;
HasTME = false;
ArchKind = llvm::AArch64::ArchKind::ARMV8A;

for (const auto &Feature : Features) {
Expand Down Expand Up @@ -301,6 +305,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasFP16FML = true;
if (Feature == "+mte")
HasMTE = true;
if (Feature == "+tme")
HasTME = true;
}

setDataLayout();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
bool HasDotProd;
bool HasFP16FML;
bool HasMTE;
bool HasTME;

llvm::AArch64::ArchKind ArchKind;

Expand Down
24 changes: 23 additions & 1 deletion clang/lib/Headers/arm_acle.h
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ __jcvt(double __a) {
#define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v)
#define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v)

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

/* Transactional Memory Extension (TME) Intrinsics */
#if __ARM_FEATURE_TME

#define _TMFAILURE_REASON 0x00007fffu
#define _TMFAILURE_RTRY 0x00008000u
#define _TMFAILURE_CNCL 0x00010000u
#define _TMFAILURE_MEM 0x00020000u
#define _TMFAILURE_IMP 0x00040000u
#define _TMFAILURE_ERR 0x00080000u
#define _TMFAILURE_SIZE 0x00100000u
#define _TMFAILURE_NEST 0x00200000u
#define _TMFAILURE_DBG 0x00400000u
#define _TMFAILURE_INT 0x00800000u
#define _TMFAILURE_TRIVIAL 0x01000000u

#define __tstart() __builtin_arm_tstart()
#define __tcommit() __builtin_arm_tcommit()
#define __tcancel(__arg) __builtin_arm_tcancel(__arg)
#define __ttest() __builtin_arm_ttest()

#endif /* __ARM_FEATURE_TME */

#if defined(__cplusplus)
}
#endif
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1928,6 +1928,7 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
case AArch64::BI__builtin_arm_dmb:
case AArch64::BI__builtin_arm_dsb:
case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break;
}

return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
Expand Down
10 changes: 10 additions & 0 deletions clang/test/CodeGen/aarch64-tme-tcancel-arg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 -triple aarch64-eabi -target-feature +tme -S -emit-llvm %s -o - | FileCheck %s

#define A -1
constexpr int f() { return 65536; }

void t_cancel() {
__builtin_arm_tcancel(f() + A);
}

// CHECK: call void @llvm.aarch64.tcancel(i64 65535)
36 changes: 36 additions & 0 deletions clang/test/CodeGen/aarch64-tme.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %clang_cc1 -triple aarch64-eabi -target-feature +tme -S -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -DUSE_ACLE -triple aarch64-eabi -target-feature +tme -S -emit-llvm %s -o - | FileCheck %s

#ifdef USE_ACLE
#include "arm_acle.h"
void test_tme_funcs() {
__tstart();
(void)__ttest();
__tcommit();
__tcancel(0x789a);
}
#else
void test_tme_funcs() {
__builtin_arm_tstart();
(void)__builtin_arm_ttest();
__builtin_arm_tcommit();
__builtin_arm_tcancel(0x789a);
}
#endif
// CHECK: call i64 @llvm.aarch64.tstart()
// CHECK: call i64 @llvm.aarch64.ttest()
// CHECK: call void @llvm.aarch64.tcommit()
// CHECK: call void @llvm.aarch64.tcancel(i64 30874)

// CHECK: declare i64 @llvm.aarch64.tstart() #1
// CHECK: declare i64 @llvm.aarch64.ttest() #1
// CHECK: declare void @llvm.aarch64.tcommit() #1
// CHECK: declare void @llvm.aarch64.tcancel(i64 immarg) #2

#ifdef __ARM_FEATURE_TME
void arm_feature_tme_defined() {}
#endif
// CHECK: define void @arm_feature_tme_defined()

// CHECK: attributes #1 = { nounwind }
// CHECK: attributes #2 = { noreturn nounwind }
8 changes: 8 additions & 0 deletions clang/test/Sema/aarch64-tme-errors.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: %clang_cc1 -triple aarch64-eabi -verify %s

#include "arm_acle.h"

void test_no_tme_funcs() {
__tstart(); // expected-warning{{implicit declaration of function '__tstart'}}
__builtin_tstart(); // expected-error{{use of unknown builtin '__builtin_tstart'}}
}
4 changes: 4 additions & 0 deletions clang/test/Sema/aarch64-tme-tcancel-const-error.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// RUN: %clang_cc1 -triple aarch64-eabi -target-feature +tme -verify %s
void t_cancel(unsigned short u) {
__builtin_arm_tcancel(u); // expected-error{{argument to '__builtin_arm_tcancel' must be a constant integer}}
}
4 changes: 4 additions & 0 deletions clang/test/Sema/aarch64-tme-tcancel-range-error.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// RUN: %clang_cc1 -triple aarch64-eabi -target-feature +tme -verify %s
void t_cancel() {
__builtin_arm_tcancel(0x12345u); // expected-error{{argument value 74565 is outside the valid range [0, 65535]}}
}
17 changes: 17 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsAArch64.td
Original file line number Diff line number Diff line change
Expand Up @@ -703,3 +703,20 @@ def int_aarch64_stg : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty],
def int_aarch64_subp : Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_ptr_ty],
[IntrNoMem]>;
}

// Transactional Memory Extension (TME) Intrinsics
let TargetPrefix = "aarch64" in {
def int_aarch64_tstart : GCCBuiltin<"__builtin_arm_tstart">,
Intrinsic<[llvm_i64_ty]>;

def int_aarch64_tcommit : GCCBuiltin<"__builtin_arm_tcommit">, Intrinsic<[]>;

def int_aarch64_tcancel : GCCBuiltin<"__builtin_arm_tcancel">,
Intrinsic<[], [llvm_i64_ty],
[ImmArg<0>, IntrNoMem, IntrHasSideEffects,
IntrNoReturn]>;

def int_aarch64_ttest : GCCBuiltin<"__builtin_arm_ttest">,
Intrinsic<[llvm_i64_ty], [],
[IntrNoMem, IntrHasSideEffects]>;
}
1 change: 1 addition & 0 deletions llvm/include/llvm/Support/AArch64TargetParser.def
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ AARCH64_ARCH_EXT_NAME("memtag", AArch64::AEK_MTE, "+mte", "-mte")
AARCH64_ARCH_EXT_NAME("ssbs", AArch64::AEK_SSBS, "+ssbs", "-ssbs")
AARCH64_ARCH_EXT_NAME("sb", AArch64::AEK_SB, "+sb", "-sb")
AARCH64_ARCH_EXT_NAME("predres", AArch64::AEK_PREDRES, "+predres", "-predres")
AARCH64_ARCH_EXT_NAME("tme", AArch64::AEK_TME, "+tme", "-tme")
#undef AARCH64_ARCH_EXT_NAME

#ifndef AARCH64_CPU_NAME
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Support/AArch64TargetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ enum ArchExtKind : unsigned {
AEK_SVE2SM4 = 1 << 25,
AEK_SVE2SHA3 = 1 << 26,
AEK_BITPERM = 1 << 27,
AEK_TME = 1 << 28,
};

enum class ArchKind {
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/AArch64/AArch64.td
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ def FeatureRandGen : SubtargetFeature<"rand", "HasRandGen",
def FeatureMTE : SubtargetFeature<"mte", "HasMTE",
"true", "Enable Memory Tagging Extension" >;

def FeatureTME : SubtargetFeature<"tme", "HasTME",
"true", "Enable Transactional Memory Extension" >;

//===----------------------------------------------------------------------===//
// Architectures.
//
Expand Down
55 changes: 49 additions & 6 deletions llvm/lib/Target/AArch64/AArch64InstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -714,12 +714,15 @@ def logical_imm64_not : Operand<i64> {
let ParserMatchClass = LogicalImm64NotOperand;
}

// imm0_65535 predicate - True if the immediate is in the range [0,65535].
def imm0_65535 : Operand<i32>, ImmLeaf<i32, [{
// iXX_imm0_65535 predicates - True if the immediate is in the range [0,65535].
let ParserMatchClass = AsmImmRange<0, 65535>, PrintMethod = "printImmHex" in {
def i32_imm0_65535 : Operand<i32>, ImmLeaf<i32, [{
return ((uint32_t)Imm) < 65536;
}]> {
let ParserMatchClass = AsmImmRange<0, 65535>;
let PrintMethod = "printImmHex";
}]>;

def i64_imm0_65535 : Operand<i64>, ImmLeaf<i64, [{
return ((uint64_t)Imm) < 65536;
}]>;
}

// imm0_255 predicate - True if the immediate is in the range [0,255].
Expand Down Expand Up @@ -1082,6 +1085,46 @@ class RtSystemI<bit L, dag oops, dag iops, string asm, string operands>
let Inst{4-0} = Rt;
}

// System instructions for transactional memory extension
class TMBaseSystemI<bit L, bits<4> CRm, bits<3> op2, dag oops, dag iops,
string asm, string operands, list<dag> pattern>
: BaseSystemI<L, oops, iops, asm, operands, pattern>,
Sched<[WriteSys]> {
let Inst{20-12} = 0b000110011;
let Inst{11-8} = CRm;
let Inst{7-5} = op2;
let DecoderMethod = "";

let mayLoad = 1;
let mayStore = 1;
}

// System instructions for transactional memory - single input operand
class TMSystemI<bits<4> CRm, string asm, list<dag> pattern>
: TMBaseSystemI<0b1, CRm, 0b011,
(outs GPR64:$Rt), (ins), asm, "\t$Rt", pattern> {
bits<5> Rt;
let Inst{4-0} = Rt;
}

// System instructions for transactional memory - no operand
class TMSystemINoOperand<bits<4> CRm, string asm, list<dag> pattern>
: TMBaseSystemI<0b0, CRm, 0b011, (outs), (ins), asm, "", pattern> {
let Inst{4-0} = 0b11111;
}

// System instructions for exit from transactions
let mayLoad = 0, mayStore = 0, hasSideEffects = 1 in
class TMSystemException<bits<3> op1, string asm, list<dag> pattern>
: I<(outs), (ins i64_imm0_65535:$imm), asm, "\t$imm", "", pattern>,
Sched<[WriteSys]> {
bits<16> imm;
let Inst{31-24} = 0b11010100;
let Inst{23-21} = op1;
let Inst{20-5} = imm;
let Inst{4-0} = 0b00000;
}

// Hint instructions that take both a CRm and a 3-bit immediate.
// NOTE: ideally, this would have mayStore = 0, mayLoad = 0, but we cannot
// model patterns with sufficiently fine granularity
Expand Down Expand Up @@ -4086,7 +4129,7 @@ multiclass MemTagStore<bits<2> opc1, string insn> {

let mayLoad = 0, mayStore = 0, hasSideEffects = 1 in
class ExceptionGeneration<bits<3> op1, bits<2> ll, string asm>
: I<(outs), (ins imm0_65535:$imm), asm, "\t$imm", "", []>,
: I<(outs), (ins i32_imm0_65535:$imm), asm, "\t$imm", "", []>,
Sched<[WriteSys]> {
bits<16> imm;
let Inst{31-24} = 0b11010100;
Expand Down
29 changes: 23 additions & 6 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ def HasBTI : Predicate<"Subtarget->hasBTI()">,
AssemblerPredicate<"FeatureBranchTargetId", "bti">;
def HasMTE : Predicate<"Subtarget->hasMTE()">,
AssemblerPredicate<"FeatureMTE", "mte">;
def HasTME : Predicate<"Subtarget->hasTME()">,
AssemblerPredicate<"FeatureTME", "tme">;
def IsLE : Predicate<"Subtarget->isLittleEndian()">;
def IsBE : Predicate<"!Subtarget->isLittleEndian()">;
def IsWindows : Predicate<"Subtarget->isTargetWindows()">;
Expand Down Expand Up @@ -798,6 +800,21 @@ def : InstAlias<"sys $op1, $Cn, $Cm, $op2",
(SYSxt imm0_7:$op1, sys_cr_op:$Cn,
sys_cr_op:$Cm, imm0_7:$op2, XZR)>;


let Predicates = [HasTME] in {

def TSTART : TMSystemI<0b0000, "tstart", [(set GPR64:$Rt, (int_aarch64_tstart))]>;

def TCOMMIT : TMSystemINoOperand<0b0000, "tcommit", [(int_aarch64_tcommit)]>;

let mayLoad = 0, mayStore = 0 in {
def TTEST : TMSystemI<0b0001, "ttest", [(set GPR64:$Rt, (int_aarch64_ttest))]>;
def TCANCEL : TMSystemException<0b011, "tcancel", [(int_aarch64_tcancel i64_imm0_65535:$imm)]> {
let isBarrier = 1;
}
}
} // HasTME

//===----------------------------------------------------------------------===//
// Move immediate instructions.
//===----------------------------------------------------------------------===//
Expand All @@ -809,12 +826,12 @@ let PostEncoderMethod = "fixMOVZ" in
defm MOVZ : MoveImmediate<0b10, "movz">;

// First group of aliases covers an implicit "lsl #0".
def : InstAlias<"movk $dst, $imm", (MOVKWi GPR32:$dst, imm0_65535:$imm, 0), 0>;
def : InstAlias<"movk $dst, $imm", (MOVKXi GPR64:$dst, imm0_65535:$imm, 0), 0>;
def : InstAlias<"movn $dst, $imm", (MOVNWi GPR32:$dst, imm0_65535:$imm, 0)>;
def : InstAlias<"movn $dst, $imm", (MOVNXi GPR64:$dst, imm0_65535:$imm, 0)>;
def : InstAlias<"movz $dst, $imm", (MOVZWi GPR32:$dst, imm0_65535:$imm, 0)>;
def : InstAlias<"movz $dst, $imm", (MOVZXi GPR64:$dst, imm0_65535:$imm, 0)>;
def : InstAlias<"movk $dst, $imm", (MOVKWi GPR32:$dst, i32_imm0_65535:$imm, 0), 0>;
def : InstAlias<"movk $dst, $imm", (MOVKXi GPR64:$dst, i32_imm0_65535:$imm, 0), 0>;
def : InstAlias<"movn $dst, $imm", (MOVNWi GPR32:$dst, i32_imm0_65535:$imm, 0)>;
def : InstAlias<"movn $dst, $imm", (MOVNXi GPR64:$dst, i32_imm0_65535:$imm, 0)>;
def : InstAlias<"movz $dst, $imm", (MOVZWi GPR32:$dst, i32_imm0_65535:$imm, 0)>;
def : InstAlias<"movz $dst, $imm", (MOVZXi GPR64:$dst, i32_imm0_65535:$imm, 0)>;

// Next, we have various ELF relocations with the ":XYZ_g0:sym" syntax.
def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movz_symbol_g3:$sym, 48)>;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/AArch64Subtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
bool HasBTI = false;
bool HasRandGen = false;
bool HasMTE = false;
bool HasTME = false;

// Arm SVE2 extensions
bool HasSVE2AES = false;
Expand Down Expand Up @@ -380,6 +381,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
bool hasBTI() const { return HasBTI; }
bool hasRandGen() const { return HasRandGen; }
bool hasMTE() const { return HasMTE; }
bool hasTME() const { return HasTME; }
// Arm SVE2 extensions
bool hasSVE2AES() const { return HasSVE2AES; }
bool hasSVE2SM4() const { return HasSVE2SM4; }
Expand Down
16 changes: 16 additions & 0 deletions llvm/test/CodeGen/AArch64/tme-tcancel.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
; RUN: llc %s -o - | FileCheck %s

target triple = "aarch64-unknown-unknown-eabi"

define void @test_tcancel() #0 {
tail call void @llvm.aarch64.tcancel(i64 0) #1
unreachable
}

declare void @llvm.aarch64.tcancel(i64 immarg) #1

attributes #0 = { "target-features"="+tme" }
attributes #1 = { nounwind noreturn }

; CHECK-LABEL: test_tcancel
; CHECK: tcancel
16 changes: 16 additions & 0 deletions llvm/test/CodeGen/AArch64/tme-tcommit.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
; RUN: llc %s -o - | FileCheck %s

target triple = "aarch64-unknown-unknown-eabi"

define void @test_tcommit() #0 {
tail call void @llvm.aarch64.tcommit()
ret void
}

declare void @llvm.aarch64.tcommit() #1

attributes #0 = { "target-features"="+tme" }
attributes #1 = { nounwind }

; CHECK-LABEL: test_tcommit
; CHECK: tcommit
Loading

0 comments on commit 4b8da3a

Please sign in to comment.