[PATCH] [PowerPC] Add Hardware Transaction Memory builtins support

Adhemerval Zanella azanella at linux.vnet.ibm.com
Fri Feb 20 05:22:14 PST 2015


This patch adds Hardware Transaction Memory (HTM) support supported by
ISA 2.07 (POWER8).  The intrinsic support is based on GCC one [1], but
currently only the 'PowerPC HTM Low Level Built-in Function' are
implemented.

Along with builtins a new driver switch is added to enable/disable HTM
instruction support (-mhtm) and a header with common definitions (mostly
to parse the TFHAR register value).  The HTM switch also sets a
preprocessor builtin __HTM__.

The HTM usage requires a recently newer kernel with PPC HTM enabled.
Tested on powerpc64 and powerpc64le.

This is send along a llvm patch to enabled the builtins and option
switch.

[1] https://gcc.gnu.org/onlinedocs/gcc/PowerPC-Hardware-Transactional-Memory-Built-in-Functions.html
---
 include/clang/Basic/BuiltinsPPC.def |  31 +++++++++
 include/clang/Driver/Options.td     |   2 +
 lib/Basic/Targets.cpp               |  11 +++-
 lib/CodeGen/CGBuiltin.cpp           |  86 ++++++++++++++++++++++++
 lib/Headers/htmintrin.h             | 127 ++++++++++++++++++++++++++++++++++++
 test/CodeGen/builtins-ppc-htm.c     |  62 ++++++++++++++++++
 6 files changed, 318 insertions(+), 1 deletion(-)
 create mode 100644 lib/Headers/htmintrin.h
 create mode 100644 test/CodeGen/builtins-ppc-htm.c

diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def
index e42af42..cfaceb5 100644
--- a/include/clang/Basic/BuiltinsPPC.def
+++ b/include/clang/Basic/BuiltinsPPC.def
@@ -223,6 +223,37 @@ BUILTIN(__builtin_vsx_xsmindp, "ddd", "")
 BUILTIN(__builtin_vsx_xvdivdp, "V2dV2dV2d", "")
 BUILTIN(__builtin_vsx_xvdivsp, "V4fV4fV4f", "")
 
+// HTM builtins
+BUILTIN(__builtin_tbegin, "UiUIi", "")
+BUILTIN(__builtin_tend, "UiUIi", "")
+
+BUILTIN(__builtin_tabort, "UiUi", "")
+BUILTIN(__builtin_tabortdc, "UiUiUiUi", "")
+BUILTIN(__builtin_tabortdci, "UiUiUii", "")
+BUILTIN(__builtin_tabortwc, "UiUiUiUi", "")
+BUILTIN(__builtin_tabortwci, "UiUiUii", "")
+
+BUILTIN(__builtin_tcheck, "UiUi", "")
+BUILTIN(__builtin_treclaim, "UiUi", "")
+BUILTIN(__builtin_trechkpt, "Ui", "")
+BUILTIN(__builtin_tsr, "UiUi", "")
+
+BUILTIN(__builtin_tendall, "Ui", "")
+BUILTIN(__builtin_tresume, "Ui", "")
+BUILTIN(__builtin_tsuspend, "Ui", "")
+
+BUILTIN(__builtin_get_texasr, "LUi", "c")
+BUILTIN(__builtin_get_texasru, "LUi", "c")
+BUILTIN(__builtin_get_tfhar, "LUi", "c")
+BUILTIN(__builtin_get_tfiar, "LUi", "c")
+
+BUILTIN(__builtin_set_texasr, "vLUi", "c")
+BUILTIN(__builtin_set_texasru, "vLUi", "c")
+BUILTIN(__builtin_set_tfhar, "vLUi", "c")
+BUILTIN(__builtin_set_tfiar, "vLUi", "c")
+
+BUILTIN(__builtin_ttest, "LUi", "")
+
 // FIXME: Obviously incomplete.
 
 #undef BUILTIN
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 80f68ef..30553aa 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -1230,6 +1230,8 @@ def mpower8_vector : Flag<["-"], "mpower8-vector">,
     Group<m_ppc_Features_Group>;
 def mno_power8_vector : Flag<["-"], "mno-power8-vector">,
     Group<m_ppc_Features_Group>;
+def mhtm : Flag<["-"], "mhtm">, Group<m_ppc_Features_Group>;
+def mno_htm : Flag<["-"], "mno-htm">, Group<m_ppc_Features_Group>;
 def mfprnd : Flag<["-"], "mfprnd">, Group<m_ppc_Features_Group>;
 def mno_fprnd : Flag<["-"], "mno-fprnd">, Group<m_ppc_Features_Group>;
 def mcmpb : Flag<["-"], "mcmpb">, Group<m_ppc_Features_Group>;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index f9da2bf..6c8183b 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -704,13 +704,14 @@ class PPCTargetInfo : public TargetInfo {
   // Target cpu features.
   bool HasVSX;
   bool HasP8Vector;
+  bool HasHTM;
 
 protected:
   std::string ABI;
 
 public:
   PPCTargetInfo(const llvm::Triple &Triple)
-    : TargetInfo(Triple), HasVSX(false), HasP8Vector(false) {
+    : TargetInfo(Triple), HasVSX(false), HasP8Vector(false), HasHTM(false) {
     BigEndian = (Triple.getArch() != llvm::Triple::ppc64le);
     LongDoubleWidth = LongDoubleAlign = 128;
     LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble;
@@ -971,6 +972,11 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
       continue;
     }
 
+    if (Feature == "htm") {
+      HasHTM = true;
+      continue;
+    }
+
     // TODO: Finish this list and add an assert that we've handled them
     // all.
   }
@@ -1123,6 +1129,8 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
     Builder.defineMacro("__VSX__");
   if (HasP8Vector)
     Builder.defineMacro("__POWER8_VECTOR__");
+  if (HasHTM)
+    Builder.defineMacro("__HTM__");
 
   // FIXME: The following are not yet generated here by Clang, but are
   //        generated by GCC:
@@ -1168,6 +1176,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
     .Case("powerpc", true)
     .Case("vsx", HasVSX)
     .Case("power8-vector", HasP8Vector)
+    .Case("htm", HasHTM)
     .Default(false);
 }
 
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 859ad3e..b622d59 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -6347,6 +6347,92 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
     llvm::Function *F = CGM.getIntrinsic(ID);
     return Builder.CreateCall(F, Ops, "");
   }
+
+  // HTM builtins
+  case PPC::BI__builtin_tbegin:
+  case PPC::BI__builtin_tend:
+  case PPC::BI__builtin_tcheck:
+  case PPC::BI__builtin_tsr: {
+    unsigned int MaxValue;
+    // The HTM instructions only accepts one argument and with limited range.
+    ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
+    assert(CI);
+    switch (BuiltinID) {
+    case PPC::BI__builtin_tbegin:
+      ID = Intrinsic::ppc_tbegin;
+      MaxValue = 1;
+      break;
+    case PPC::BI__builtin_tend:
+      ID = Intrinsic::ppc_tend;
+      MaxValue = 1;
+      break;
+    case PPC::BI__builtin_tsr:
+      ID = Intrinsic::ppc_tsr;
+      MaxValue = 7;
+      break;
+    case PPC::BI__builtin_tcheck:
+      ID = Intrinsic::ppc_tcheck;
+      MaxValue = 7;
+      break;
+    }
+    if (CI->getZExtValue() > MaxValue) {
+      CGM.ErrorUnsupported(E->getArg(0), "argument out of range (should be 0 or 1)");
+      return llvm::UndefValue::get(Ops[0]->getType());
+    }
+
+    llvm::Function *F = CGM.getIntrinsic(ID);
+    return Builder.CreateCall(F, Ops, "");
+  }
+  case PPC::BI__builtin_tabortdc:
+  case PPC::BI__builtin_tabortwc: {
+    // For wd and dc variant of tabort first argument must be a 5-bits constant
+    // integer
+    ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
+    assert(CI);
+    if (CI->getZExtValue() > 31) {
+      CGM.ErrorUnsupported(E->getArg(0), "argument out of range (should be 0-31)");
+      return llvm::UndefValue::get(Ops[0]->getType());
+    }
+    switch (BuiltinID) {
+    case PPC::BI__builtin_tabortdc:
+      ID = Intrinsic::ppc_tabortdc;
+      break;
+    case PPC::BI__builtin_tabortwc:
+      ID = Intrinsic::ppc_tabortwc;
+      break;
+    }
+    llvm::Function *F = CGM.getIntrinsic(ID);
+    return Builder.CreateCall(F, Ops, "");
+  }
+  case PPC::BI__builtin_tabortdci:
+  case PPC::BI__builtin_tabortwci: {
+    // For wd and dc variant of tabort first and third argument must be a
+    // 5-bits constant integer
+    ConstantInt *CI = dyn_cast<ConstantInt>(Ops[0]);
+    assert(CI);
+    if (CI->getZExtValue() > 31) {
+      CGM.ErrorUnsupported(E->getArg(0), "argument out of range (should be 0-31)");
+      return llvm::UndefValue::get(Ops[0]->getType());
+    }
+    CI = dyn_cast<ConstantInt>(Ops[2]);
+    assert(CI);
+    if (CI->getZExtValue() > 31) {
+      CGM.ErrorUnsupported(E->getArg(2), "argument out of range (should be 0-31)");
+      return llvm::UndefValue::get(Ops[2]->getType());
+    }
+    switch (BuiltinID) {
+    default: llvm_unreachable("Unsupported htm intrinsic!");
+    case PPC::BI__builtin_tabortdci:
+      ID = Intrinsic::ppc_tabortdci;
+      break;
+    case PPC::BI__builtin_tabortwci:
+      ID = Intrinsic::ppc_tabortwci;
+      break;
+    }
+    llvm::Function *F = CGM.getIntrinsic(ID);
+    return Builder.CreateCall(F, Ops, "");
+  }
+
   }
 }
 
diff --git a/lib/Headers/htmintrin.h b/lib/Headers/htmintrin.h
new file mode 100644
index 0000000..9f6b166
--- /dev/null
+++ b/lib/Headers/htmintrin.h
@@ -0,0 +1,127 @@
+/*===---- htmintrin.h - Standard header for PowerPC HTM ---------------===*\
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+\*===----------------------------------------------------------------------===*/
+
+#ifndef __HTMINTRIN_H
+#define __HTMINTRIN_H
+
+#ifndef __HTM__
+#error "HTM instruction set not enabled"
+#endif
+
+#include <stdint.h>
+
+typedef uint64_t texasr_t;
+typedef uint32_t texasru_t;
+typedef uint32_t texasrl_t;
+typedef uintptr_t tfiar_t;
+typedef uintptr_t tfhar_t;
+
+#define _HTM_STATE(CR0) ((CR0 >> 1) & 0x3)
+#define _HTM_NONTRANSACTIONAL 0x0
+#define _HTM_SUSPENDED        0x1
+#define _HTM_TRANSACTIONAL    0x2
+
+#define _TEXASR_EXTRACT_BITS(TEXASR,BITNUM,SIZE) \
+  (((TEXASR) >> (63-(BITNUM))) & ((1<<(SIZE))-1))
+#define _TEXASRU_EXTRACT_BITS(TEXASR,BITNUM,SIZE) \
+  (((TEXASR) >> (31-(BITNUM))) & ((1<<(SIZE))-1))
+
+#define _TEXASR_FAILURE_CODE(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 7, 8)
+#define _TEXASRU_FAILURE_CODE(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 7, 8)
+
+#define _TEXASR_FAILURE_PERSISTENT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 7, 1)
+#define _TEXASRU_FAILURE_PERSISTENT(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 7, 1)
+
+#define _TEXASR_DISALLOWED(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 8, 1)
+#define _TEXASRU_DISALLOWED(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 8, 1)
+
+#define _TEXASR_NESTING_OVERFLOW(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 9, 1)
+#define _TEXASRU_NESTING_OVERFLOW(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 9, 1)
+
+#define _TEXASR_FOOTPRINT_OVERFLOW(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 10, 1)
+#define _TEXASRU_FOOTPRINT_OVERFLOW(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 10, 1)
+
+#define _TEXASR_SELF_INDUCED_CONFLICT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 11, 1)
+#define _TEXASRU_SELF_INDUCED_CONFLICT(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 11, 1)
+
+#define _TEXASR_NON_TRANSACTIONAL_CONFLICT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 12, 1)
+#define _TEXASRU_NON_TRANSACTIONAL_CONFLICT(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 12, 1)
+
+#define _TEXASR_TRANSACTION_CONFLICT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 13, 1)
+#define _TEXASRU_TRANSACTION_CONFLICT(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 13, 1)
+
+#define _TEXASR_TRANSLATION_INVALIDATION_CONFLICT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 14, 1)
+#define _TEXASRU_TRANSLATION_INVALIDATION_CONFLICT(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 14, 1)
+
+#define _TEXASR_IMPLEMENTAION_SPECIFIC(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 15, 1)
+#define _TEXASRU_IMPLEMENTAION_SPECIFIC(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 15, 1)
+
+#define _TEXASR_INSTRUCTION_FETCH_CONFLICT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 16, 1)
+#define _TEXASRU_INSTRUCTION_FETCH_CONFLICT(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 16, 1)
+
+#define _TEXASR_ABORT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 31, 1)
+#define _TEXASRU_ABORT(TEXASRU) \
+  _TEXASRU_EXTRACT_BITS(TEXASRU, 31, 1)
+
+
+#define _TEXASR_SUSPENDED(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 32, 1)
+
+#define _TEXASR_PRIVILEGE(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 35, 2)
+
+#define _TEXASR_FAILURE_SUMMARY(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 36, 1)
+
+#define _TEXASR_TFIAR_EXACT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 37, 1)
+
+#define _TEXASR_ROT(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 38, 1)
+
+#define _TEXASR_TRANSACTION_LEVEL(TEXASR) \
+  _TEXASR_EXTRACT_BITS(TEXASR, 63, 12)
+
+#endif /* __HTMINTRIN_H */
diff --git a/test/CodeGen/builtins-ppc-htm.c b/test/CodeGen/builtins-ppc-htm.c
new file mode 100644
index 0000000..663c814
--- /dev/null
+++ b/test/CodeGen/builtins-ppc-htm.c
@@ -0,0 +1,62 @@
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -faltivec -target-feature +htm -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+void test1(long int *r, int code, long int *a, long int *b) {
+// CHECK-LABEL: define void @test1
+
+  r[0] = __builtin_tbegin (0);
+// CHECK: @llvm.ppc.tbegin
+  r[1] = __builtin_tbegin (1);
+// CHECK: @llvm.ppc.tbegin
+  r[2] = __builtin_tend (0);
+// CHECK: @llvm.ppc.tend
+  r[3] = __builtin_tendall ();
+// CHECK: @llvm.ppc.tendall
+
+  r[4] = __builtin_tabort (code);
+// CHECK: @llvm.ppc.tabort
+  r[5] = __builtin_tabort (0x1);
+// CHECK: @llvm.ppc.tabort
+  r[6] = __builtin_tabortdc (0xf, a[0], b[0]);
+// CHECK: @llvm.ppc.tabortdc
+  r[7] = __builtin_tabortdci (0xf, a[1], 0x1);
+// CHECK: @llvm.ppc.tabortdc
+  r[8] = __builtin_tabortwc (0xf, a[2], b[2]);
+// CHECK: @llvm.ppc.tabortwc
+  r[9] = __builtin_tabortwci (0xf, a[3], 0x1);
+// CHECK: @llvm.ppc.tabortwc
+
+  r[10] = __builtin_tcheck (0x1);
+// CHECK: @llvm.ppc.tcheck
+  r[11] = __builtin_trechkpt ();
+// CHECK: @llvm.ppc.trechkpt
+  r[12] = __builtin_treclaim (0);
+// CHECK: @llvm.ppc.treclaim
+  r[13] = __builtin_tresume ();
+// CHECK: @llvm.ppc.tresume
+  r[14] = __builtin_tsuspend ();
+// CHECK: @llvm.ppc.tsuspend
+  r[15] = __builtin_tsr (0);
+// CHECK: @llvm.ppc.tsr
+
+  r[16] = __builtin_ttest ();
+// CHECK: @llvm.ppc.ttest
+
+  r[17] = __builtin_get_texasr ();
+// CHECK: @llvm.ppc.get.texasr
+  r[18] = __builtin_get_texasru ();
+// CHECK: @llvm.ppc.get.texasru
+  r[19] = __builtin_get_tfhar ();
+// CHECK: @llvm.ppc.get.tfhar
+  r[20] = __builtin_get_tfiar ();
+// CHECK: @llvm.ppc.get.tfiar
+
+  __builtin_set_texasr (a[21]);
+// CHECK: @llvm.ppc.set.texasr
+  __builtin_set_texasru (a[22]);
+// CHECK: @llvm.ppc.set.texasru
+  __builtin_set_tfhar (a[23]);
+// CHECK: @llvm.ppc.set.tfhar
+  __builtin_set_tfiar (a[24]);
+// CHECK: @llvm.ppc.set.tfiar
+}




More information about the cfe-commits mailing list