chill created this revision.
Herald added subscribers: llvm-commits, cfe-commits, hiraditya, kristof.beyls, 
javed.absar.
Herald added projects: clang, LLVM.

Change-Id: I49f5612ce6899004fa84b9a83c34dcd2d9af8224

Consistent types and naming for AArch64 target features (NFC)

Change-Id: I6bac2672de675a6e1c9c8867ed81bef879adc417

[AArch64] Add support for Transactional Memory Extension (TME)

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

This patch adds support for the TME instructions TSTART, TTEST, TCOMMIT, and
TCANCEL and the target feature/arch extension "tme".

It alaso implements TME builtin functions, defined in ACLE vX.Y spec.

Change-Id: If77e296a68d1e30d584808677b1ce96be1ac2420


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D64410

Files:
  clang/include/clang/Basic/BuiltinsAArch64.def
  clang/lib/Basic/Targets/AArch64.cpp
  clang/lib/Basic/Targets/AArch64.h
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/Headers/arm_acle.h
  clang/test/CodeGen/aarch64-tme-errors.c
  clang/test/CodeGen/aarch64-tme-tcancel-arg.cpp
  clang/test/CodeGen/aarch64-tme-tcancel-const-error.c
  clang/test/CodeGen/aarch64-tme-tcancel-range-error.c
  clang/test/CodeGen/aarch64-tme.c
  llvm/include/llvm/IR/IntrinsicsAArch64.td
  llvm/include/llvm/Support/AArch64TargetParser.def
  llvm/include/llvm/Support/AArch64TargetParser.h
  llvm/lib/Target/AArch64/AArch64.td
  llvm/lib/Target/AArch64/AArch64InstrFormats.td
  llvm/lib/Target/AArch64/AArch64InstrInfo.td
  llvm/lib/Target/AArch64/AArch64Subtarget.h
  llvm/test/CodeGen/AArch64/tme.ll
  llvm/test/MC/AArch64/tme-error.s
  llvm/test/MC/AArch64/tme.s
  llvm/test/MC/Disassembler/AArch64/tme.txt
  llvm/unittests/Support/TargetParserTest.cpp
  llvm/utils/TableGen/CodeGenDAGPatterns.cpp
  llvm/utils/TableGen/IntrinsicEmitter.cpp

Index: llvm/utils/TableGen/IntrinsicEmitter.cpp
===================================================================
--- llvm/utils/TableGen/IntrinsicEmitter.cpp
+++ llvm/utils/TableGen/IntrinsicEmitter.cpp
@@ -685,7 +685,7 @@
     }
 
     if (!intrinsic.canThrow ||
-        intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem ||
+        (intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem && !intrinsic.hasSideEffects) ||
         intrinsic.isNoReturn || intrinsic.isCold || intrinsic.isNoDuplicate ||
         intrinsic.isConvergent || intrinsic.isSpeculatable) {
       OS << "      const Attribute::AttrKind Atts[] = {";
@@ -727,6 +727,8 @@
 
       switch (intrinsic.ModRef) {
       case CodeGenIntrinsic::NoMem:
+        if (intrinsic.hasSideEffects)
+          break;
         if (addComma)
           OS << ",";
         OS << "Attribute::ReadNone";
Index: llvm/utils/TableGen/CodeGenDAGPatterns.cpp
===================================================================
--- llvm/utils/TableGen/CodeGenDAGPatterns.cpp
+++ llvm/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -2779,7 +2779,7 @@
     // chain.
     if (Int.IS.RetVTs.empty())
       Operator = getDAGPatterns().get_intrinsic_void_sdnode();
-    else if (Int.ModRef != CodeGenIntrinsic::NoMem)
+    else if (Int.ModRef != CodeGenIntrinsic::NoMem || Int.hasSideEffects)
       // Has side-effects, requires chain.
       Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode();
     else // Otherwise, no chain.
Index: llvm/unittests/Support/TargetParserTest.cpp
===================================================================
--- llvm/unittests/Support/TargetParserTest.cpp
+++ llvm/unittests/Support/TargetParserTest.cpp
@@ -1118,6 +1118,7 @@
                               {"rcpc", "norcpc", "+rcpc", "-rcpc" },
                               {"rng", "norng", "+rand", "-rand"},
                               {"memtag", "nomemtag", "+mte", "-mte"},
+                              {"tme", "notme", "+tme", "-tme"},
                               {"ssbs", "nossbs", "+ssbs", "-ssbs"},
                               {"sb", "nosb", "+sb", "-sb"},
                               {"predres", "nopredres", "+predres", "-predres"}
Index: llvm/test/MC/Disassembler/AArch64/tme.txt
===================================================================
--- /dev/null
+++ llvm/test/MC/Disassembler/AArch64/tme.txt
@@ -0,0 +1,19 @@
+# Tests for transaction memory extension instructions
+# RUN:     llvm-mc -triple=aarch64 -mattr=+tme   -disassemble < %s      | FileCheck %s
+# RUN: not llvm-mc -triple=aarch64 -mattr=-tme   -disassemble < %s 2>&1 | FileCheck %s --check-prefix=NOTME
+
+[0x63,0x30,0x23,0xd5]
+[0x64,0x31,0x23,0xd5]
+[0x7f,0x30,0x03,0xd5]
+[0x80,0x46,0x62,0xd4]
+
+# CHECK: tstart x3
+# CHECK: ttest  x4
+# CHECK: tcommit
+# CHECK: tcancel #0x1234
+
+# NOTEME: mrs
+# NOTEME-NEXT: mrs
+ NOTEME-NEXT: msr
+# NOTME:      warning: invalid instruction encoding
+# NOTME-NEXT: [0x80,0x46,0x62,0xd4]
Index: llvm/test/MC/AArch64/tme.s
===================================================================
--- /dev/null
+++ llvm/test/MC/AArch64/tme.s
@@ -0,0 +1,24 @@
+// Tests for transaction memory extension instructions
+//
+// RUN:     llvm-mc -triple aarch64 -show-encoding -mattr=+tme   < %s      | FileCheck %s
+// RUN: not llvm-mc -triple aarch64 -show-encoding -mattr=-tme   < %s 2>&1 | FileCheck %s --check-prefix=NOTME
+
+tstart x3
+ttest  x4
+tcommit
+tcancel #0x1234
+
+// CHECK: tstart x3         // encoding: [0x63,0x30,0x23,0xd5]
+// CHECK: ttest x4          // encoding: [0x64,0x31,0x23,0xd5]
+// CHECK: tcommit           // encoding: [0x7f,0x30,0x03,0xd5]
+// CHECK: tcancel #0x1234   // encoding: [0x80,0x46,0x62,0xd4]
+
+
+// NOTME: instruction requires: tme
+// NOTME-NEXT: tstart x3
+// NOTME: instruction requires: tme
+// NOTME-NEXT: ttest  x4
+// NOTME: instruction requires: tme
+// NOTME-NEXT: tcommit
+// NOTME: instruction requires: tme
+// NOTME-NEXT: tcancel #0x1234
Index: llvm/test/MC/AArch64/tme-error.s
===================================================================
--- /dev/null
+++ llvm/test/MC/AArch64/tme-error.s
@@ -0,0 +1,47 @@
+// Tests for transactional memory extension instructions
+// RUN: not llvm-mc -triple aarch64 -show-encoding -mattr=+tme < %s 2>&1   | FileCheck %s
+
+tstart
+// CHECK: error: too few operands for instruction
+// CHECK-NEXT: tstart
+tstart  x4, x5
+// CHECK: error: invalid operand for instruction
+// CHECK-NEXT: tstart x4, x5
+tstart  x4, #1
+// CHECK: error: invalid operand for instruction
+// CHECK-NEXT: tstart x4, #1
+tstart  sp
+// CHECK: error: invalid operand for instruction
+// CHECK-NEXT: tstart sp
+
+ttest
+// CHECK: error: too few operands for instruction
+// CHECK-NEXT: ttest
+ttest  x4, x5
+// CHECK: error: invalid operand for instruction
+// CHECK-NEXT: ttest x4, x5
+ttest  x4, #1
+// CHECK: error: invalid operand for instruction
+// CHECK-NEXT: ttest x4, #1
+ttest  sp
+// CHECK: error: invalid operand for instruction
+// CHECK-NEXT: ttest sp
+
+tcommit  x4
+// CHECK: error: invalid operand for instruction
+// CHECK-NEXT: tcommit x4
+tcommit  sp
+// CHECK: error: invalid operand for instruction
+// CHECK-NEXT: tcommit sp
+
+
+tcancel
+// CHECK: error: too few operands for instruction
+// CHECK-NEXT tcancel
+tcancel x0
+// CHECK: error: immediate must be an integer in range [0, 65535]
+// CHECK-NEXT tcancel
+tcancel #65536
+// CHECK: error: immediate must be an integer in range [0, 65535]
+// CHECK-NEXT: tcancel #65536
+
Index: llvm/test/CodeGen/AArch64/tme.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/AArch64/tme.ll
@@ -0,0 +1,99 @@
+; RUN: llc %s -o - | FileCheck %s
+
+; #include "arm_acle.h"
+;
+; _Bool cas(int *p, int old, int new) {
+;   uint64_t s;
+;   while ((s = __tstart()) != 0) {
+;     if ((s & _TMFAILURE_RTRY) == 0)
+;       return 0;
+;   }
+;
+;   if (__ttest() != 1)
+;     return 0;
+;
+;   if (*p != old)
+;     __tcancel(0);
+;
+;   *p = new;
+;   __tcommit();
+;   return 1;
+; }
+
+; ModuleID = 'cas.c'
+source_filename = "cas.c"
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-unknown-eabi"
+
+; Function Attrs: nounwind
+define dso_local i1 @cas(i32* nocapture %p, i32 %old, i32 %new) local_unnamed_addr #0 {
+entry:
+  br label %while.cond
+
+while.cond:                                       ; preds = %while.body, %entry
+  %0 = tail call i64 @llvm.aarch64.tstart()
+  %cmp = icmp eq i64 %0, 0
+  br i1 %cmp, label %while.end, label %while.body
+
+while.body:                                       ; preds = %while.cond
+  %and = and i64 %0, 32768
+  %cmp1 = icmp eq i64 %and, 0
+  br i1 %cmp1, label %cleanup, label %while.cond
+
+while.end:                                        ; preds = %while.cond
+  %1 = tail call i64 @llvm.aarch64.ttest()
+  %cmp2 = icmp eq i64 %1, 1
+  br i1 %cmp2, label %if.end4, label %cleanup
+
+if.end4:                                          ; preds = %while.end
+  %2 = load i32, i32* %p, align 4, !tbaa !2
+  %cmp5 = icmp eq i32 %2, %old
+  br i1 %cmp5, label %if.end7, label %if.then6
+
+if.then6:                                         ; preds = %if.end4
+  tail call void @llvm.aarch64.tcancel(i64 0) #1
+  unreachable
+
+if.end7:                                          ; preds = %if.end4
+  store i32 %new, i32* %p, align 4, !tbaa !2
+  tail call void @llvm.aarch64.tcommit()
+  br label %cleanup
+
+cleanup:                                          ; preds = %while.body, %while.end, %if.end7
+  %retval.0 = phi i1 [ true, %if.end7 ], [ false, %while.end ], [ false, %while.body ]
+  ret i1 %retval.0
+}
+
+; Function Attrs: nounwind
+declare i64 @llvm.aarch64.tstart() #1
+
+; Function Attrs: nounwind readnone
+declare i64 @llvm.aarch64.ttest() #2
+
+; Function Attrs: noreturn
+declare void @llvm.aarch64.tcancel(i64 immarg) #3
+
+; Function Attrs: nounwind
+declare void @llvm.aarch64.tcommit() #1
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon,+tme" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind readnone }
+attributes #3 = { noreturn }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 9.0.0 (https://github.com/llvm/llvm-project.git 910d27fbb1b1faef9f2fa6dedddb1edc6b12ebf3)"}
+!2 = !{!3, !3, i64 0}
+!3 = !{!"int", !4, i64 0}
+!4 = !{!"omnipotent char", !5, i64 0}
+!5 = !{!"Simple C/C++ TBAA"}
+
+; CHECK-LABEL: cas
+; CHECK: tstart x
+; CHECK: ttest x
+; CHECK: tcommit
+; CHECK: tcancel #0
+; CHECK-NEXT: .Lfunc_end0
Index: llvm/lib/Target/AArch64/AArch64Subtarget.h
===================================================================
--- llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -134,6 +134,7 @@
   bool HasBTI = false;
   bool HasRandGen = false;
   bool HasMTE = false;
+  bool HasTME = false;
 
   // Arm SVE2 extensions
   bool HasSVE2AES = false;
@@ -380,6 +381,7 @@
   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; }
Index: llvm/lib/Target/AArch64/AArch64InstrInfo.td
===================================================================
--- llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -133,6 +133,8 @@
                        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()">;
@@ -796,6 +798,36 @@
                 (SYSxt imm0_7:$op1, sys_cr_op:$Cn,
                  sys_cr_op:$Cm, imm0_7:$op2, XZR)>;
 
+// Transactional Memory Extension instructions
+let Predicates = [HasTME] in {
+
+def TSTART : TMEInst<(outs GPR64:$Rt), (ins), "tstart", "\t$Rt", [(set GPR64:$Rt, (int_aarch64_tstart))]> {
+  bits<5> Rt;
+  let Inst{21} = 1;
+  let Inst{4-0} = Rt;
+}
+
+def TTEST : TMEInst<(outs GPR64:$Rt), (ins), "ttest", "\t$Rt", [(set GPR64:$Rt, (int_aarch64_ttest))]> {
+  bits<5> Rt;
+  let Inst{21} = 1;
+  let Inst{8} = 1;
+  let Inst{4-0} = Rt;
+
+  let hasSideEffects = 0;
+}
+
+def TCANCEL : TMEInst<(outs), (ins i64_imm0_65535:$imm), "tcancel", "\t$imm", [(int_aarch64_tcancel i64_imm0_65535:$imm)]> {
+  bits<16> imm;
+  let Inst{24-21} = 0b0011;
+  let Inst{20-5} = imm;
+  let Inst{4-0} = 0b00000;
+
+  let isBarrier = 1;
+}
+
+def TCOMMIT : TMEInst<(outs), (ins), "tcommit", "", [(int_aarch64_tcommit)]>;
+}
+
 //===----------------------------------------------------------------------===//
 // Move immediate instructions.
 //===----------------------------------------------------------------------===//
@@ -807,12 +839,12 @@
 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)>;
Index: llvm/lib/Target/AArch64/AArch64InstrFormats.td
===================================================================
--- llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -714,12 +714,15 @@
   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].
@@ -1054,6 +1057,19 @@
 }
 
 
+// Transactional Memory Extension (TME) Instructions
+class TMEInst<dag oops, dag iops, string asm, string operands, list<dag> pattern = []>
+    : I<oops, iops, asm, operands, "", pattern>,
+      Sched<[WriteSys]> {
+  let Inst{31-0} = 0b11010101000000110011000001111111;
+  let DecoderMethod = "";
+
+  let mayLoad = 0;
+  let mayStore = 0;
+  let hasSideEffects = 1;
+}
+
+
 //---
 // System management
 //---
@@ -4086,7 +4102,7 @@
 
 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;
Index: llvm/lib/Target/AArch64/AArch64.td
===================================================================
--- llvm/lib/Target/AArch64/AArch64.td
+++ llvm/lib/Target/AArch64/AArch64.td
@@ -345,6 +345,9 @@
 def FeatureMTE : SubtargetFeature<"mte", "HasMTE",
     "true", "Enable Memory Tagging Extension" >;
 
+def FeatureTME : SubtargetFeature<"tme", "HasTME",
+    "true", "Enable Transactional Memory Extension" >;
+
 //===----------------------------------------------------------------------===//
 // Architectures.
 //
Index: llvm/include/llvm/Support/AArch64TargetParser.h
===================================================================
--- llvm/include/llvm/Support/AArch64TargetParser.h
+++ llvm/include/llvm/Support/AArch64TargetParser.h
@@ -54,6 +54,7 @@
   AEK_SVE2SM4 =     1 << 25,
   AEK_SVE2SHA3 =    1 << 26,
   AEK_BITPERM =     1 << 27,
+  AEK_TME =         1 << 28,
 };
 
 enum class ArchKind {
Index: llvm/include/llvm/Support/AArch64TargetParser.def
===================================================================
--- llvm/include/llvm/Support/AArch64TargetParser.def
+++ llvm/include/llvm/Support/AArch64TargetParser.def
@@ -79,6 +79,7 @@
 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
Index: llvm/include/llvm/IR/IntrinsicsAArch64.td
===================================================================
--- llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -701,3 +701,17 @@
 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], [], [IntrNoMem, IntrHasSideEffects]>;
+
+def int_aarch64_tcommit : GCCBuiltin<"__builtin_arm_tcommit">, Intrinsic<[], [], [IntrNoMem, IntrHasSideEffects] >;
+
+def int_aarch64_tcancel : Intrinsic<[], [llvm_i64_ty],
+                                    [ImmArg<0>, IntrNoMem, IntrHasSideEffects, IntrNoReturn, Throws]>;
+
+def int_aarch64_ttest   : GCCBuiltin<"__builtin_arm_ttest">,
+                          Intrinsic<[llvm_i64_ty], [], [IntrNoMem]>;
+}
Index: clang/test/CodeGen/aarch64-tme.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-tme.c
@@ -0,0 +1,37 @@
+// 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() #2
+// CHECK: declare void @llvm.aarch64.tcommit() #1
+// CHECK: declare void @llvm.aarch64.tcancel(i64 immarg) #3
+
+#ifdef __ARM_FEATURE_TME
+void arm_feature_tme_defined() {}
+#endif
+// CHECK: define void @arm_feature_tme_defined()
+
+// CHECK: attributes #1 = { nounwind }
+// CHECK: attributes #2 = { nounwind readnone }
+// CHECK: attributes #3 = { noreturn }
Index: clang/test/CodeGen/aarch64-tme-tcancel-range-error.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-tme-tcancel-range-error.c
@@ -0,0 +1,5 @@
+// RUN: not %clang_cc1 -triple aarch64-eabi -target-feature +tme -S -emit-llvm %s -o - 2>&1 | FileCheck %s
+void t_cancel() {
+  __builtin_arm_tcancel(0x12345u);
+}
+// CHECK: argument must be in range [0, 65535]
Index: clang/test/CodeGen/aarch64-tme-tcancel-const-error.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-tme-tcancel-const-error.c
@@ -0,0 +1,6 @@
+// RUN: not %clang_cc1 -triple aarch64-eabi -target-feature +tme -S -emit-llvm %s -o - 2>&1 | FileCheck %s
+void t_cancel(unsigned short u) {
+  __builtin_arm_tcancel(u);
+}
+
+// CHECK: error: argument to '__builtin_arm_tcancel' must be a constant integer
Index: clang/test/CodeGen/aarch64-tme-tcancel-arg.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-tme-tcancel-arg.cpp
@@ -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)
Index: clang/test/CodeGen/aarch64-tme-errors.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-tme-errors.c
@@ -0,0 +1,11 @@
+// RUN: not %clang_cc1 -triple aarch64-eabi -fsyntax-only %s -o - 2>&1 | FileCheck %s
+
+#include "arm_acle.h"
+
+void test_no_tme_funcs() {
+  __tstart();
+  __builtin_tstart();
+}
+
+// CHECK: implicit declaration of function '__tstart'
+// CHECK: use of unknown builtin '__builtin_tstart'
Index: clang/lib/Headers/arm_acle.h
===================================================================
--- clang/lib/Headers/arm_acle.h
+++ clang/lib/Headers/arm_acle.h
@@ -605,7 +605,7 @@
 #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)
@@ -615,6 +615,28 @@
 #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
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -7220,6 +7220,19 @@
     }
   }
 
+  /* Transactional Memory Extentions (TME) intrinsics. Check range of __tcancel
+     argument, other intrinsics are handled automatically. */
+  if (BuiltinID == AArch64::BI__builtin_arm_tcancel) {
+    llvm::APSInt Arg;
+    bool IsConst= E->getArg(0)->isIntegerConstantExpr(Arg, getContext());
+    assert(IsConst && "Constant arg isn't actually constant?");
+    (void)IsConst;
+    if (!(Arg <= 0xffffu))
+      CGM.Error(E->getArg(0)->getExprLoc(), "argument must be in range [0, 65535]");
+    auto ArgValue = llvm::ConstantInt::get(getLLVMContext(), Arg);
+    return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_tcancel), {ArgValue});
+  }
+
   if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
       BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
       BuiltinID == AArch64::BI__builtin_arm_rsrp ||
Index: clang/lib/Basic/Targets/AArch64.h
===================================================================
--- clang/lib/Basic/Targets/AArch64.h
+++ clang/lib/Basic/Targets/AArch64.h
@@ -28,13 +28,15 @@
   enum FPUModeEnum { FPUMode, NeonMode = (1 << 0), SveMode = (1 << 1) };
 
   unsigned FPU;
-  unsigned CRC;
-  unsigned Crypto;
-  unsigned Unaligned;
-  unsigned HasFullFP16;
-  unsigned HasDotProd;
-  unsigned HasFP16FML;
-  unsigned HasMTE;
+  bool HasCRC;
+  bool HasCrypto;
+  bool HasUnaligned;
+  bool HasFullFP16;
+  bool HasDotProd;
+  bool HasFP16FML;
+  bool HasMTE;
+  bool HasTME;
+
   llvm::AArch64::ArchKind ArchKind;
 
   static const Builtin::Info BuiltinInfo[];
Index: clang/lib/Basic/Targets/AArch64.cpp
===================================================================
--- clang/lib/Basic/Targets/AArch64.cpp
+++ clang/lib/Basic/Targets/AArch64.cpp
@@ -177,13 +177,13 @@
   if (FPU & SveMode)
     Builder.defineMacro("__ARM_FEATURE_SVE", "1");
 
-  if (CRC)
+  if (HasCRC)
     Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
 
-  if (Crypto)
+  if (HasCrypto)
     Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1");
 
-  if (Unaligned)
+  if (HasUnaligned)
     Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
 
   if ((FPU & NeonMode) && HasFullFP16)
@@ -197,6 +197,9 @@
   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");
 
@@ -232,13 +235,14 @@
 bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
                                              DiagnosticsEngine &Diags) {
   FPU = FPUMode;
-  CRC = 0;
-  Crypto = 0;
-  Unaligned = 1;
-  HasFullFP16 = 0;
-  HasDotProd = 0;
-  HasFP16FML = 0;
-  HasMTE = 0;
+  HasCRC = false;
+  HasCrypto = false;
+  HasUnaligned = true;
+  HasFullFP16 = false;
+  HasDotProd = false;
+  HasFP16FML = false;
+  HasMTE = false;
+  HasTME = false;
   ArchKind = llvm::AArch64::ArchKind::ARMV8A;
 
   for (const auto &Feature : Features) {
@@ -247,23 +251,25 @@
     if (Feature == "+sve")
       FPU |= SveMode;
     if (Feature == "+crc")
-      CRC = 1;
+      HasCRC = true;
     if (Feature == "+crypto")
-      Crypto = 1;
+      HasCrypto = true;
     if (Feature == "+strict-align")
-      Unaligned = 0;
+      HasUnaligned = false;
     if (Feature == "+v8.1a")
       ArchKind = llvm::AArch64::ArchKind::ARMV8_1A;
     if (Feature == "+v8.2a")
       ArchKind = llvm::AArch64::ArchKind::ARMV8_2A;
     if (Feature == "+fullfp16")
-      HasFullFP16 = 1;
+      HasFullFP16 = true;
     if (Feature == "+dotprod")
-      HasDotProd = 1;
+      HasDotProd = true;
     if (Feature == "+fp16fml")
-      HasFP16FML = 1;
+      HasFP16FML = true;
     if (Feature == "+mte")
-      HasMTE = 1;
+      HasMTE = true;
+    if (Feature == "+tme")
+      HasTME = true;
   }
 
   setDataLayout();
Index: clang/include/clang/Basic/BuiltinsAArch64.def
===================================================================
--- clang/include/clang/Basic/BuiltinsAArch64.def
+++ clang/include/clang/Basic/BuiltinsAArch64.def
@@ -89,6 +89,12 @@
 // 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, "")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D64410: [WIP] Intr... Momchil Velikov via Phabricator via cfe-commits

Reply via email to