diff mbox series

[committed] d: Add @simd and @simd_clones attributes to compiler and library

Message ID 20220628171144.187681-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Add @simd and @simd_clones attributes to compiler and library | expand

Commit Message

Iain Buclaw June 28, 2022, 5:11 p.m. UTC
Hi,

This patch adds a `@simd' attribute to the D front-end, which is
equivalent to `__attribute__((simd))', and `@simd_clones' is a
convenience alias to allow specifying whether the compiler should
generated masked or non-masked simd clones.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and
committed to mainline.

Regards,
Iain.

---
gcc/d/ChangeLog:

	* d-attribs.cc (handle_omp_declare_simd_attribute): New function.
	(d_handle_simd_attribute): New function.
	(d_langhook_common_attribute_table): Add 'omp declare simd' attribute.
	(d_langhook_attribute_table): Add simd attribute.

libphobos/ChangeLog:

	* libdruntime/gcc/attributes.d (simd): Define.

gcc/testsuite/ChangeLog:

	* gdc.dg/attr_simd1.d: New test.
	* gdc.dg/attr_simd2.d: New test.
---
 gcc/d/d-attribs.cc                     | 65 ++++++++++++++++++++++++++
 gcc/testsuite/gdc.dg/attr_simd1.d      | 40 ++++++++++++++++
 gcc/testsuite/gdc.dg/attr_simd2.d      | 16 +++++++
 libphobos/libdruntime/gcc/attributes.d | 40 ++++++++++++++++
 4 files changed, 161 insertions(+)
 create mode 100644 gcc/testsuite/gdc.dg/attr_simd1.d
 create mode 100644 gcc/testsuite/gdc.dg/attr_simd2.d
diff mbox series

Patch

diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index 1dd806f7144..04f7f1686a2 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -58,6 +58,7 @@  static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
 static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
 static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
 static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
+static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *);
 
 /* D attribute handlers for user defined attributes.  */
 static tree d_handle_noinline_attribute (tree *, tree, tree, int, bool *);
@@ -80,6 +81,7 @@  static tree d_handle_restrict_attribute (tree *, tree, tree, int, bool *);
 static tree d_handle_used_attribute (tree *, tree, tree, int, bool *);
 static tree d_handle_visibility_attribute (tree *, tree, tree, int, bool *);
 static tree d_handle_no_sanitize_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_simd_attribute (tree *, tree, tree, int, bool *);
 
 /* Helper to define attribute exclusions.  */
 #define ATTR_EXCL(name, function, type, variable)	\
@@ -186,6 +188,8 @@  const attribute_spec d_langhook_common_attribute_table[] =
 	     handle_type_generic_attribute, NULL),
   ATTR_SPEC ("fn spec", 1, 1, false, true, true, false,
 	     handle_fnspec_attribute, NULL),
+  ATTR_SPEC ("omp declare simd", 0, -1, true,  false, false, false,
+	     handle_omp_declare_simd_attribute, NULL),
   ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
 };
 
@@ -228,6 +232,8 @@  const attribute_spec d_langhook_attribute_table[] =
 	     d_handle_register_attribute, NULL),
   ATTR_SPEC ("restrict", 0, 0, true, false, false, false,
 	     d_handle_restrict_attribute, NULL),
+  ATTR_SPEC ("simd", 0, 1, true,  false, false, false,
+	     d_handle_simd_attribute, NULL),
   ATTR_SPEC ("used", 0, 0, true, false, false, false,
 	     d_handle_used_attribute, NULL),
   ATTR_SPEC ("visibility", 1, 1, false, false, false, false,
@@ -664,6 +670,16 @@  handle_fnspec_attribute (tree *, tree, tree args, int, bool *)
   return NULL_TREE;
 }
 
+/* Handle an "omp declare simd" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_omp_declare_simd_attribute (tree *node, tree, tree, int, bool *)
+{
+  gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+  return NULL_TREE;
+}
+
 /* Language specific attribute handlers.
    These functions take the arguments:
    (tree *node, tree name, tree args, int flags, bool *no_add_attrs)  */
@@ -1474,6 +1490,55 @@  d_handle_restrict_attribute (tree *node, tree name, tree, int,
   return NULL_TREE;
 }
 
+/* Handle a "simd" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+d_handle_simd_attribute (tree *node, tree name, tree args, int,
+			 bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  tree omp_attr = get_identifier ("omp declare simd");
+  tree omp_flags = NULL_TREE;
+  if (args)
+    {
+      tree id = TREE_VALUE (args);
+
+      if (TREE_CODE (id) != STRING_CST)
+	{
+	  error ("%qE attribute argument not a string constant", name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+
+      if (strcmp (TREE_STRING_POINTER (id), "notinbranch") == 0)
+	omp_flags = build_omp_clause (DECL_SOURCE_LOCATION (*node),
+				      OMP_CLAUSE_NOTINBRANCH);
+      else if (strcmp (TREE_STRING_POINTER (id), "inbranch") == 0)
+	omp_flags = build_omp_clause (DECL_SOURCE_LOCATION (*node),
+				      OMP_CLAUSE_INBRANCH);
+      else
+	{
+	  error ("only %<inbranch%> and %<notinbranch%> flags are "
+		 "allowed for %<simd%> attribute");
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  DECL_ATTRIBUTES (*node) =
+    tree_cons (omp_attr, build_tree_list (NULL_TREE, omp_flags),
+	       DECL_ATTRIBUTES (*node));
+
+  return NULL_TREE;
+}
+
 /* Handle a "used" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/testsuite/gdc.dg/attr_simd1.d b/gcc/testsuite/gdc.dg/attr_simd1.d
new file mode 100644
index 00000000000..8e83d80b3e0
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/attr_simd1.d
@@ -0,0 +1,40 @@ 
+// { dg-do compile }
+// { dg-options "-fdump-tree-optimized" }
+
+import gcc.attributes;
+
+extern(C) @simd int simd_attr() { return 0; }
+
+// { dg-final { scan-tree-dump "simd_attr\[ \\t\]simdclone|vector" "optimized" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4_simd_attr:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbM4_simd_attr:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4_simd_attr:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4_simd_attr:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8_simd_attr:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8_simd_attr:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16_simd_attr:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16_simd_attr:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+extern(C) @simd_clones("notinbranch") int simd_notinbranch() { return 0; }
+
+// { dg-final { scan-tree-dump "simd_notinbranch\[ \\t\]simdclone|vector" "optimized" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4_simd_notinbranch:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4_simd_notinbranch:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8_simd_notinbranch:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16_simd_notinbranch:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGVbM4_simd_notinbranch:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGVcM4_simd_notinbranch:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGVdM8_simd_notinbranch:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGVeM16_simd_notinbranch:" { target { i?86-*-* x86_64-*-* } } } }
+
+extern(C) @simd_clones("inbranch") int simd_inbranch() { return 0; }
+
+// { dg-final { scan-tree-dump "simd_inbranch\[ \\t\]simdclone|vector" "optimized" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGVbN4_simd_inbranch:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGVcN4_simd_inbranch:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGVdN8_simd_inbranch:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGVeN16_simd_inbranch:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbM4_simd_inbranch:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4_simd_inbranch:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8_simd_inbranch:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16_simd_inbranch:" 1 { target { i?86-*-* x86_64-*-* } } } }
diff --git a/gcc/testsuite/gdc.dg/attr_simd2.d b/gcc/testsuite/gdc.dg/attr_simd2.d
new file mode 100644
index 00000000000..49cb6421fab
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/attr_simd2.d
@@ -0,0 +1,16 @@ 
+// { dg-do compile }
+// { dg-options "-fdump-tree-optimized" }
+
+import gcc.attributes;
+
+@attribute("simd")
+int simd_ignored; // { dg-warning ".simd. attribute ignored" }
+
+@attribute("simd", 123)
+int simd_string() { return 0; } // { dg-error ".simd. attribute argument not a string constant" }
+
+@attribute("simd", "invalid")
+int simd_invalid() { return 0; } // { dg-error "only .inbranch. and .notinbranch. flags are allowed for .simd. attribute" }
+
+@attribute("simd", "notinbranch", "inbranch")
+int simd_wrong_args() { return 0; } // { dg-error "wrong number of arguments specified for .simd. attribute" }
diff --git a/libphobos/libdruntime/gcc/attributes.d b/libphobos/libdruntime/gcc/attributes.d
index 40a18bfa947..9d7f2e1d861 100644
--- a/libphobos/libdruntime/gcc/attributes.d
+++ b/libphobos/libdruntime/gcc/attributes.d
@@ -371,6 +371,46 @@  auto section(A...)(A arguments)
     assert(false, "section attribute argument not a string constant");
 }
 
+/**
+ * The `@simd` attribute enables creation of one or more function versions that
+ * can process multiple arguments using SIMD instructions from a single
+ * invocation. Specifying this attribute allows compiler to assume that such
+ * versions are available at link time (provided in the same or another module).
+ * Generated versions are target-dependent and described in the corresponding
+ * Vector ABI document. For x86_64 target this document can be found here.
+ * https://sourceware.org/glibc/wiki/libmvec?action=AttachFile&do=view&target=VectorABI.txt
+ * 
+ * The `@simd_clones` attribute is the same as `@simd`, but also includes a
+ * `mask` argument.  Valid masks values are `notinbranch` or `inbranch`, and
+ * instructs the compiler to generate non-masked or masked clones
+ * correspondingly.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @simd double sqrt(double x);
+ * @simd("notinbranch") double atan2(double y, double x);
+ * ---
+ */
+enum simd = attribute("simd");
+
+auto simd_clones(string mask)
+{
+    if (mask == "notinbranch" || mask == "inbranch")
+        return attribute("simd", mask);
+    else
+    {
+        assert(false, "unrecognized parameter `" ~ mask
+               ~ "` for `gcc.attribute.simd_clones`");
+    }
+}
+
+auto simd_clones(A...)(A arguments)
+{
+    assert(false, "simd_clones attribute argument not a string constant");
+}
+
 /**
  * The `@symver` attribute creates a symbol version on ELF targets.  The syntax
  * of the string parameter is `name@nodename`.  The `name` part of the parameter