From 4b9d806a71fc287c1ed786aadb6df2c42bc8b437 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 27 Mar 2017 17:06:13 -0400
Subject: [PATCH 10/46] gcc_jit_type_get_aligned

(This also implements the missing C++ binding
gccjit::type::get_const, needed by a test case)

DONE:
- feature macro in libgccjit.h
- a new ABI tag in libgccjit.map
- support for gcc_jit_context_dump_reproducer_to_file()
- testsuite
- test coverage for non-power-of-two
- test same layout as C frontend
- add new tests to the combined/thread test
- rename to gcc_jit_type_get_aligned
- including filenames
- verify no gcc_jit_type_set_alignment
- documentation for the C API
- documentation for the new ABI tag (see topics/compatibility.rst)
- C++ bindings
- testsuite
- C++ test coverage
- documentation for the C++ API
- FIXMEs and TODOs
- convert from unsigned int to size_t
- ChangeLog

TODO:
(regenerate .texi when committing)

gcc/jit/ChangeLog:
	* docs/cp/topics/types.rst (gccjit::type::get_const): Remove
	comment.
	(gccjit::type::get_aligned): Add.
	* docs/topics/compatibility.rst: Add LIBGCCJIT_ABI_7.
	* docs/topics/types.rst: Add gcc_jit_type_get_aligned.
	* jit-playback.c (gcc::jit::playback::type::get_aligned): New
	method.
	* jit-playback.h (gcc::jit::playback::type::get_aligned): New
	method.
	* jit-recording.c: Within namespace gcc::jit::recording...
	(type::get_aligned): New method.
	(memento_of_get_aligned::replay_into): New method.
	(memento_of_get_aligned::make_debug_string): New method.
	(memento_of_get_aligned::write_reproducer): New method.
	* jit-recording.h: Within namespace gcc::jit::recording...
	(type::get_aligned): New method.
	(type::accepts_writes_from): Strip off qualifications from
	this when comparing pointer equality.
	(decorated_type): New subclass of type, subsuming the
	commonality between memento_of_get_const and
	memento_of_get_volatile.
	(memento_of_get_const): Make a subclass of decorated_type,
	rather than type.
	(memento_of_get_volatile): Likewise.
	(memento_of_get_aligned): Likewise.
	* libgccjit++.h: Within namespace gccjit...
	(type::get_const): New method.
	(type::get_aligned): New method.
	* libgccjit.c (gcc_jit_type_get_aligned): New function.
	* libgccjit.h (gcc_jit_type_get_aligned): New decl.
	* libgccjit.map (LIBGCCJIT_ABI_7): New
	(gcc_jit_type_get_aligned): Add.

gcc/testsuite/ChangeLog:
	* jit.dg/all-non-failing-tests.h: Add test-alignment.c.
	* jit.dg/test-alignment.c: New test case.
	* jit.dg/test-alignment.cc: New test case.
	* jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c:
	New test case.
---
 gcc/jit/docs/cp/topics/types.rst                   |  12 +-
 gcc/jit/docs/topics/compatibility.rst              |   7 +
 gcc/jit/docs/topics/types.rst                      |  19 ++
 gcc/jit/jit-playback.c                             |  15 ++
 gcc/jit/jit-playback.h                             |   2 +
 gcc/jit/jit-recording.c                            |  52 +++++
 gcc/jit/jit-recording.h                            |  68 +++---
 gcc/jit/libgccjit++.h                              |  15 ++
 gcc/jit/libgccjit.c                                |  24 +++
 gcc/jit/libgccjit.h                                |  16 ++
 gcc/jit/libgccjit.map                              |   5 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h       |  10 +
 gcc/testsuite/jit.dg/test-alignment.c              | 232 +++++++++++++++++++++
 gcc/testsuite/jit.dg/test-alignment.cc             | 176 ++++++++++++++++
 ...ror-gcc_jit_type_get_aligned-non-power-of-two.c |  30 +++
 15 files changed, 657 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-alignment.c
 create mode 100644 gcc/testsuite/jit.dg/test-alignment.cc
 create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c

diff --git a/gcc/jit/docs/cp/topics/types.rst b/gcc/jit/docs/cp/topics/types.rst
index 453f1d3..e85a492 100644
--- a/gcc/jit/docs/cp/topics/types.rst
+++ b/gcc/jit/docs/cp/topics/types.rst
@@ -82,8 +82,6 @@ Pointers, `const`, and `volatile`
 
    Given type "T", get type "T*".
 
-.. FIXME: get_const doesn't seem to exist
-
 .. function::  gccjit::type gccjit::type::get_const ()
 
    Given type "T", get type "const T".
@@ -92,6 +90,16 @@ Pointers, `const`, and `volatile`
 
    Given type "T", get type "volatile T".
 
+.. function::  gccjit::type gccjit::type::get_aligned (size_t alignment_in_bytes)
+
+   Given type "T", get type:
+
+   .. code-block:: c
+
+      T __attribute__ ((aligned (ALIGNMENT_IN_BYTES)))
+
+   The alignment must be a power of two.
+
 .. function::  gccjit::type \
                gccjit::context::new_array_type (gccjit::type element_type, \
                                                 int num_elements, \
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 4aff425..5a13653 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -142,3 +142,10 @@ entrypoints:
 -------------------
 ``LIBGCCJIT_ABI_6`` covers the addition of
 :func:`gcc_jit_rvalue_set_bool_require_tail_call`
+
+.. _LIBGCCJIT_ABI_7:
+
+``LIBGCCJIT_ABI_7``
+-------------------
+``LIBGCCJIT_ABI_7`` covers the addition of
+:func:`gcc_jit_type_get_aligned`
diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
index 9a1b879..119f10e 100644
--- a/gcc/jit/docs/topics/types.rst
+++ b/gcc/jit/docs/topics/types.rst
@@ -117,6 +117,25 @@ Pointers, `const`, and `volatile`
 
    Given type "T", get type "T[N]" (for a constant N).
 
+.. function::  gcc_jit_type *\
+               gcc_jit_type_get_aligned (gcc_jit_type *type, \
+                                         size_t alignment_in_bytes)
+
+   Given type "T", get type:
+
+   .. code-block:: c
+
+      T __attribute__ ((aligned (ALIGNMENT_IN_BYTES)))
+
+   The alignment must be a power of two.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_7`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_aligned
+
 
 Structures and unions
 ---------------------
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index c0f10c9..76cc88f 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -1095,6 +1095,21 @@ new_dereference (tree ptr,
   return datum;
 }
 
+/* Construct a playback::type instance (wrapping a tree)
+   with the given alignment.  */
+
+playback::type *
+playback::type::
+get_aligned (size_t alignment_in_bytes) const
+{
+  tree t_new_type = build_variant_type_copy (m_inner);
+
+  SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
+  TYPE_USER_ALIGN (t_new_type) = 1;
+
+  return new type (t_new_type);
+}
+
 /* Construct a playback::lvalue instance (wrapping a tree) for a
    field access.  */
 
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 5c8555c..0a83390 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -391,6 +391,8 @@ public:
     return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE));
   }
 
+  type *get_aligned (size_t alignment_in_bytes) const;
+
 private:
   tree m_inner;
 };
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index e356c14..723ddb3 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1974,6 +1974,20 @@ recording::type::get_volatile ()
   return result;
 }
 
+/* Given a type, get an aligned version of the type.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_aligned.  */
+
+recording::type *
+recording::type::get_aligned (size_t alignment_in_bytes)
+{
+  recording::type *result
+    = new memento_of_get_aligned (this, alignment_in_bytes);
+  m_ctxt->record (result);
+  return result;
+}
+
 const char *
 recording::type::access_as_type (reproducer &r)
 {
@@ -2419,6 +2433,44 @@ recording::memento_of_get_volatile::write_reproducer (reproducer &r)
 	   r.get_identifier_as_type (m_other_type));
 }
 
+/* The implementation of class gcc::jit::recording::memento_of_get_aligned.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_aligned.  */
+
+void
+recording::memento_of_get_aligned::replay_into (replayer *)
+{
+  set_playback_obj
+    (m_other_type->playback_type ()->get_aligned (m_alignment_in_bytes));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_aligned.  */
+
+recording::string *
+recording::memento_of_get_aligned::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s  __attribute__((aligned(%zi)))",
+			      m_other_type->get_debug_string (),
+			      m_alignment_in_bytes);
+}
+
+/* Implementation of recording::memento::write_reproducer for volatile
+   types. */
+
+void
+recording::memento_of_get_aligned::write_reproducer (reproducer &r)
+{
+  const char *id = r.make_identifier (this, "type");
+  r.write ("  gcc_jit_type *%s =\n"
+	   "    gcc_jit_type_get_aligned (%s, %zi);\n",
+	   id,
+	   r.get_identifier_as_type (m_other_type),
+	   m_alignment_in_bytes);
+}
+
 /* The implementation of class gcc::jit::recording::array_type */
 
 /* Implementation of pure virtual hook recording::type::dereference for
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 8e5bd52..5faf35e 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -473,6 +473,7 @@ public:
   type *get_pointer ();
   type *get_const ();
   type *get_volatile ();
+  type *get_aligned (size_t alignment_in_bytes);
 
   /* Get the type obtained when dereferencing this type.
 
@@ -489,7 +490,7 @@ public:
   virtual bool accepts_writes_from (type *rtype)
   {
     gcc_assert (rtype);
-    return this == rtype->unqualified ();
+    return this->unqualified () == rtype->unqualified ();
   }
 
   /* Strip off "const" etc */
@@ -599,16 +600,35 @@ private:
   type *m_other_type;
 };
 
-/* Result of "gcc_jit_type_get_const".  */
-class memento_of_get_const : public type
+/* A decorated version of a type, for get_const, get_volatile and
+   get_aligned.  */
+
+class decorated_type : public type
 {
 public:
-  memento_of_get_const (type *other_type)
+  decorated_type (type *other_type)
   : type (other_type->m_ctxt),
     m_other_type (other_type) {}
 
   type *dereference () FINAL OVERRIDE { return m_other_type->dereference (); }
 
+  bool is_int () const FINAL OVERRIDE { return m_other_type->is_int (); }
+  bool is_float () const FINAL OVERRIDE { return m_other_type->is_float (); }
+  bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); }
+  type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); }
+  type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); }
+
+protected:
+  type *m_other_type;
+};
+
+/* Result of "gcc_jit_type_get_const".  */
+class memento_of_get_const : public decorated_type
+{
+public:
+  memento_of_get_const (type *other_type)
+  : decorated_type (other_type) {}
+
   bool accepts_writes_from (type */*rtype*/) FINAL OVERRIDE
   {
     /* Can't write to a "const".  */
@@ -618,40 +638,40 @@ public:
   /* Strip off the "const", giving the underlying type.  */
   type *unqualified () FINAL OVERRIDE { return m_other_type; }
 
-  bool is_int () const FINAL OVERRIDE { return m_other_type->is_int (); }
-  bool is_float () const FINAL OVERRIDE { return m_other_type->is_float (); }
-  bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); }
-  type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); }
-  type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); }
-
   void replay_into (replayer *) FINAL OVERRIDE;
 
 private:
   string * make_debug_string () FINAL OVERRIDE;
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
-
-private:
-  type *m_other_type;
 };
 
 /* Result of "gcc_jit_type_get_volatile".  */
-class memento_of_get_volatile : public type
+class memento_of_get_volatile : public decorated_type
 {
 public:
   memento_of_get_volatile (type *other_type)
-  : type (other_type->m_ctxt),
-    m_other_type (other_type) {}
-
-  type *dereference () FINAL OVERRIDE { return m_other_type->dereference (); }
+  : decorated_type (other_type) {}
 
   /* Strip off the "volatile", giving the underlying type.  */
   type *unqualified () FINAL OVERRIDE { return m_other_type; }
 
-  bool is_int () const FINAL OVERRIDE { return m_other_type->is_int (); }
-  bool is_float () const FINAL OVERRIDE { return m_other_type->is_float (); }
-  bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); }
-  type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); }
-  type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); }
+  void replay_into (replayer *) FINAL OVERRIDE;
+
+private:
+  string * make_debug_string () FINAL OVERRIDE;
+  void write_reproducer (reproducer &r) FINAL OVERRIDE;
+};
+
+/* Result of "gcc_jit_type_get_aligned".  */
+class memento_of_get_aligned : public decorated_type
+{
+public:
+  memento_of_get_aligned (type *other_type, size_t alignment_in_bytes)
+  : decorated_type (other_type),
+    m_alignment_in_bytes (alignment_in_bytes) {}
+
+  /* Strip off the alignment, giving the underlying type.  */
+  type *unqualified () FINAL OVERRIDE { return m_other_type; }
 
   void replay_into (replayer *) FINAL OVERRIDE;
 
@@ -660,7 +680,7 @@ private:
   void write_reproducer (reproducer &r) FINAL OVERRIDE;
 
 private:
-  type *m_other_type;
+  size_t m_alignment_in_bytes;
 };
 
 class array_type : public type
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 8dc2112..ea277f8 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -330,7 +330,9 @@ namespace gccjit
     gcc_jit_type *get_inner_type () const;
 
     type get_pointer ();
+    type get_const ();
     type get_volatile ();
+    type get_aligned (size_t alignment_in_bytes);
 
     // Shortcuts for getting values of numeric types:
     rvalue zero ();
@@ -1286,11 +1288,24 @@ type::get_pointer ()
 }
 
 inline type
+type::get_const ()
+{
+  return type (gcc_jit_type_get_const (get_inner_type ()));
+}
+
+inline type
 type::get_volatile ()
 {
   return type (gcc_jit_type_get_volatile (get_inner_type ()));
 }
 
+inline type
+type::get_aligned (size_t alignment_in_bytes)
+{
+  return type (gcc_jit_type_get_aligned (get_inner_type (),
+					 alignment_in_bytes));
+}
+
 inline rvalue
 type::zero ()
 {
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index b5e72f4..9b003e3 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -2970,3 +2970,27 @@ gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue *rvalue,
 
   call->set_require_tail_call (require_tail_call);
 }
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::type::get_aligned method, in
+   jit-recording.c.  */
+
+gcc_jit_type *
+gcc_jit_type_get_aligned (gcc_jit_type *type,
+			  size_t alignment_in_bytes)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  gcc::jit::recording::context *ctxt = type->m_ctxt;
+
+  JIT_LOG_FUNC (ctxt->get_logger ());
+
+  RETURN_NULL_IF_FAIL_PRINTF1
+    (pow2_or_zerop (alignment_in_bytes), ctxt, NULL,
+     "alignment not a power of two: %zi",
+     alignment_in_bytes);
+
+  return (gcc_jit_type *)type->get_aligned (alignment_in_bytes);
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 8965093..898ee98 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1387,6 +1387,22 @@ extern void
 gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue *call,
 					   int require_tail_call);
 
+#define LIBGCCJIT_HAVE_gcc_jit_type_get_aligned
+
+/* Given type "T", get type:
+
+     T __attribute__ ((aligned (ALIGNMENT_IN_BYTES)))
+
+   The alignment must be a power of two.
+
+   This API entrypoint was added in LIBGCCJIT_ABI_7; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_aligned
+*/
+extern gcc_jit_type *
+gcc_jit_type_get_aligned (gcc_jit_type *type,
+			  size_t alignment_in_bytes);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 80a273f..160f4cd 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -150,3 +150,8 @@ LIBGCCJIT_ABI_6 {
   global:
     gcc_jit_rvalue_set_bool_require_tail_call;
 } LIBGCCJIT_ABI_5;
+
+LIBGCCJIT_ABI_7 {
+  global:
+    gcc_jit_type_get_aligned;
+} LIBGCCJIT_ABI_6;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 3e2b3b9..58e0c30 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -22,6 +22,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-alignment.c */
+#define create_code create_code_alignment
+#define verify_code verify_code_alignment
+#include "test-alignment.c"
+#undef create_code
+#undef verify_code
+
 /* test-arith-overflow.c */
 #define create_code create_code_arith_overflow
 #define verify_code verify_code_arith_overflow
@@ -246,6 +253,9 @@ const struct testcase testcases[] = {
   {"accessing_union",
    create_code_accessing_union,
    verify_code_accessing_union},
+  {"alignment",
+   create_code_alignment,
+   verify_code_alignment},
   {"arith_overflow",
    create_code_arith_overflow,
    verify_code_arith_overflow},
diff --git a/gcc/testsuite/jit.dg/test-alignment.c b/gcc/testsuite/jit.dg/test-alignment.c
new file mode 100644
index 0000000..686d981
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-alignment.c
@@ -0,0 +1,232 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct s2
+{
+  char x __attribute__ ((aligned (2)));
+  char y __attribute__ ((aligned (2)));
+};
+
+struct s4
+{
+  char x __attribute__ ((aligned (4)));
+  char y __attribute__ ((aligned (4)));
+};
+
+struct s8
+{
+  char x __attribute__ ((aligned (8)));
+  char y __attribute__ ((aligned (8)));
+};
+
+struct s16
+{
+  char x __attribute__ ((aligned (16)));
+  char y __attribute__ ((aligned (16)));
+};
+
+struct s32
+{
+  char x __attribute__ ((aligned (32)));
+  char y __attribute__ ((aligned (32)));
+};
+
+struct s64
+{
+  char x __attribute__ ((aligned (64)));
+  char y __attribute__ ((aligned (64)));
+};
+
+struct s128
+{
+  char x __attribute__ ((aligned (128)));
+  char y __attribute__ ((aligned (128)));
+};
+
+static void
+create_aligned_code (gcc_jit_context *ctxt, const char *struct_name,
+		     unsigned int alignment, const char *reader_fn_name,
+		     const char *writer_fn_name)
+{
+  /* Let's try to inject the equivalent of:
+
+     char
+     READER_FN_NAME (const struct STRUCT_NAME *f)
+     {
+       return f->x * f->y;
+     }
+
+     char
+     WRITER_FN_NAME (struct STRUCT_NAME *g)
+     {
+       g->x = 5;
+       g->y = 7;
+       return READER_FN_NAME (g);
+     }
+  */
+  gcc_jit_type *char_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+  gcc_jit_type *aligned_char_type =
+    gcc_jit_type_get_aligned (char_type, alignment);
+  gcc_jit_field *x =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               aligned_char_type,
+                               "x");
+  gcc_jit_field *y =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               aligned_char_type,
+                               "y");
+  gcc_jit_field *fields[] = {x, y};
+  gcc_jit_type *struct_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt, NULL, struct_name, 2, fields));
+  gcc_jit_type *const_struct_type = gcc_jit_type_get_const (struct_type);
+  gcc_jit_type *const_ptr_type = gcc_jit_type_get_pointer (const_struct_type);
+
+  /* Build the reader fn.  */
+  gcc_jit_param *param_f =
+    gcc_jit_context_new_param (ctxt, NULL, const_ptr_type, "f");
+  gcc_jit_function *fn_test_reading =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  char_type,
+				  reader_fn_name,
+                                  1, &param_f,
+                                  0);
+
+  /* return f->x * f->y; */
+  gcc_jit_block *reading_block = gcc_jit_function_new_block (fn_test_reading, NULL);
+  gcc_jit_block_end_with_return (
+    reading_block,
+    NULL,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      char_type,
+      gcc_jit_lvalue_as_rvalue (
+	gcc_jit_rvalue_dereference_field (
+	  gcc_jit_param_as_rvalue (param_f),
+	  NULL,
+	  x)),
+      gcc_jit_lvalue_as_rvalue (
+	gcc_jit_rvalue_dereference_field (
+	gcc_jit_param_as_rvalue (param_f),
+	NULL,
+	y))));
+
+  /* Build the writer fn.  */
+  gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (struct_type);
+  gcc_jit_param *param_g =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "g");
+  gcc_jit_function *fn_test_writing =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  char_type,
+                                  writer_fn_name,
+                                  1, &param_g,
+                                  0);
+
+  /* g->x = 5; */
+  gcc_jit_block *writing_block = gcc_jit_function_new_block (fn_test_writing, NULL);
+  gcc_jit_block_add_assignment (
+    writing_block, NULL,
+    gcc_jit_rvalue_dereference_field (gcc_jit_param_as_rvalue (param_g),
+				      NULL, x),
+    gcc_jit_context_new_rvalue_from_int (ctxt, char_type, 5));
+
+  /* g->y = 7; */
+  gcc_jit_block_add_assignment (
+    writing_block, NULL,
+    gcc_jit_rvalue_dereference_field (gcc_jit_param_as_rvalue (param_g),
+				      NULL, y),
+    gcc_jit_context_new_rvalue_from_int (ctxt, char_type, 7));
+
+  /* return READER_FN_NAME (g); */
+  gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_g);
+  gcc_jit_block_end_with_return (
+    writing_block,
+    NULL,
+    gcc_jit_context_new_call (
+      ctxt, NULL,
+      fn_test_reading,
+      1, &arg));
+}
+
+/* Implement a verifier function for a given struct.  */
+
+#define IMPL_VERIFY_ALIGNED_CODE(TYPENAME) \
+  static void								\
+  verify_aligned_code_ ##TYPENAME (gcc_jit_context *ctxt,		\
+				   gcc_jit_result *result,		\
+				   const char *writer_fn_name)		\
+  {									\
+  typedef int (*fn_type) (struct TYPENAME *);				\
+  CHECK_NON_NULL (result);						\
+									\
+  struct TYPENAME tmp;							\
+  memset (&tmp, 0xac, sizeof (tmp));					\
+									\
+  fn_type test_writing =						\
+    (fn_type)gcc_jit_result_get_code (result, writer_fn_name);		\
+  CHECK_NON_NULL (test_writing);					\
+									\
+  /* Verify that the code correctly returns the product of the fields.  */ \
+  CHECK_VALUE (test_writing (&tmp), 35);				\
+									\
+  /* Verify the we can read the values of the fields, and thus that the \
+     struct layout agrees with that of the C frontend.  */		\
+  CHECK_VALUE (tmp.x, 5);						\
+  CHECK_VALUE (tmp.y, 7);						\
+  }
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  create_aligned_code (ctxt, "s2", 2, "test_aligned_reading_s2",
+		       "test_aligned_writing_s2");
+  create_aligned_code (ctxt, "s4", 4, "test_aligned_reading_s4",
+		       "test_aligned_writing_s4");
+  create_aligned_code (ctxt, "s8", 8, "test_aligned_reading_s8",
+		       "test_aligned_writing_s8");
+  create_aligned_code (ctxt, "s16", 16, "test_aligned_reading_s16",
+		       "test_aligned_writing_s16");
+  create_aligned_code (ctxt, "s32", 32, "test_aligned_reading_s32",
+		       "test_aligned_writing_s32");
+  create_aligned_code (ctxt, "s64", 64, "test_aligned_reading_s64",
+		       "test_aligned_writing_s64");
+  create_aligned_code (ctxt, "s128", 128, "test_aligned_reading_s128",
+		       "test_aligned_writing_s128");
+}
+
+IMPL_VERIFY_ALIGNED_CODE(s2)
+IMPL_VERIFY_ALIGNED_CODE(s4)
+IMPL_VERIFY_ALIGNED_CODE(s8)
+IMPL_VERIFY_ALIGNED_CODE(s16)
+IMPL_VERIFY_ALIGNED_CODE(s32)
+IMPL_VERIFY_ALIGNED_CODE(s64)
+IMPL_VERIFY_ALIGNED_CODE(s128)
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  verify_aligned_code_s2 (ctxt, result,
+			  "test_aligned_writing_s2");
+  verify_aligned_code_s4 (ctxt, result,
+			  "test_aligned_writing_s4");
+  verify_aligned_code_s8 (ctxt, result,
+			  "test_aligned_writing_s8");
+  verify_aligned_code_s16 (ctxt, result,
+			   "test_aligned_writing_s16");
+  verify_aligned_code_s32 (ctxt, result,
+			   "test_aligned_writing_s32");
+  verify_aligned_code_s64 (ctxt, result,
+			   "test_aligned_writing_s64");
+  verify_aligned_code_s128 (ctxt, result,
+			   "test_aligned_writing_s128");
+}
diff --git a/gcc/testsuite/jit.dg/test-alignment.cc b/gcc/testsuite/jit.dg/test-alignment.cc
new file mode 100644
index 0000000..3e99209
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-alignment.cc
@@ -0,0 +1,176 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit++.h"
+
+#include "harness.h"
+
+struct s2
+{
+  char x __attribute__ ((aligned (2)));
+  char y __attribute__ ((aligned (2)));
+};
+
+struct s4
+{
+  char x __attribute__ ((aligned (4)));
+  char y __attribute__ ((aligned (4)));
+};
+
+struct s8
+{
+  char x __attribute__ ((aligned (8)));
+  char y __attribute__ ((aligned (8)));
+};
+
+struct s16
+{
+  char x __attribute__ ((aligned (16)));
+  char y __attribute__ ((aligned (16)));
+};
+
+struct s32
+{
+  char x __attribute__ ((aligned (32)));
+  char y __attribute__ ((aligned (32)));
+};
+
+struct s64
+{
+  char x __attribute__ ((aligned (64)));
+  char y __attribute__ ((aligned (64)));
+};
+
+struct s128
+{
+  char x __attribute__ ((aligned (128)));
+  char y __attribute__ ((aligned (128)));
+};
+
+static void
+create_aligned_code (gcc_jit_context *c_ctxt, const char *struct_name,
+		     unsigned int alignment, const char *reader_fn_name,
+		     const char *writer_fn_name)
+{
+  /* Let's try to inject the equivalent of:
+
+     char
+     READER_FN_NAME (const struct STRUCT_NAME *f)
+     {
+       return f->x * f->y;
+     }
+
+     char
+     WRITER_FN_NAME (struct STRUCT_NAME *g)
+     {
+       g->x = 5;
+       g->y = 7;
+       return READER_FN_NAME (g);
+     }
+  */
+  gccjit::context ctxt (c_ctxt);
+  gccjit::type char_type = ctxt.get_type (GCC_JIT_TYPE_CHAR);
+  gccjit::type aligned_char_type = char_type.get_aligned (alignment);
+  gccjit::field x = ctxt.new_field (aligned_char_type, "x");
+  gccjit::field y = ctxt.new_field (aligned_char_type, "y");
+  std::vector<gccjit::field> fields = {x, y};
+  gccjit::type struct_type = ctxt.new_struct_type (struct_name, fields);
+  gccjit::type const_struct_type = struct_type.get_const ();
+  gccjit::type const_ptr_type = const_struct_type.get_pointer ();
+
+  /* Build the reader fn.  */
+  gccjit::param param_f = ctxt.new_param (const_ptr_type, "f");
+  std::vector<gccjit::param> params = {param_f};
+  gccjit::function fn_test_reading
+    = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+                         char_type,
+                         reader_fn_name,
+                         params,
+                         0);
+
+  /* return f->x * f->y; */
+  gccjit::block reading_block = fn_test_reading.new_block ();
+  reading_block.end_with_return (param_f.dereference_field (x)
+                                 * param_f.dereference_field (y));
+
+  /* Build the writer fn.  */
+  gccjit::type ptr_type = struct_type.get_pointer ();
+  gccjit::param param_g = ctxt.new_param (ptr_type, "g");
+  params = {param_g};
+  gccjit::function fn_test_writing
+    = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+                         char_type,
+                         writer_fn_name,
+                         params,
+                         0);
+
+  /* g->x = 5; */
+  gccjit::block writing_block = fn_test_writing.new_block ();
+  writing_block.add_assignment (param_g.dereference_field (x),
+                                ctxt.new_rvalue (char_type, 5));
+
+  /* g->y = 7; */
+  writing_block.add_assignment (param_g.dereference_field (y),
+                                ctxt.new_rvalue (char_type, 7));
+
+  /* return READER_FN_NAME (g); */
+  writing_block.end_with_return (ctxt.new_call (fn_test_reading,
+                                                param_g));
+}
+
+/* Implement a verifier function for a given struct.  */
+
+template <typename T>
+static void
+verify_aligned_code (gcc_jit_context *ctxt,
+                     gcc_jit_result *result,
+                     const char *writer_fn_name)
+{
+  typedef int (*fn_type) (T *);
+  CHECK_NON_NULL (result);
+
+  T tmp;
+  memset (&tmp, 0xac, sizeof (tmp));
+  fn_type test_writing =
+    (fn_type)gcc_jit_result_get_code (result, writer_fn_name);
+  CHECK_NON_NULL (test_writing);
+
+  /* Verify that the code correctly returns the product of the fields.  */
+  CHECK_VALUE (test_writing (&tmp), 35);
+
+  /* Verify the we can read the values of the fields, and thus that the
+     struct layout agrees with that of the C++ frontend.  */
+  CHECK_VALUE (tmp.x, 5);
+  CHECK_VALUE (tmp.y, 7);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  create_aligned_code (ctxt, "s2", 2, "test_aligned_reading_s2",
+		       "test_aligned_writing_s2");
+  create_aligned_code (ctxt, "s4", 4, "test_aligned_reading_s4",
+		       "test_aligned_writing_s4");
+  create_aligned_code (ctxt, "s8", 8, "test_aligned_reading_s8",
+		       "test_aligned_writing_s8");
+  create_aligned_code (ctxt, "s16", 16, "test_aligned_reading_s16",
+		       "test_aligned_writing_s16");
+  create_aligned_code (ctxt, "s32", 32, "test_aligned_reading_s32",
+		       "test_aligned_writing_s32");
+  create_aligned_code (ctxt, "s64", 64, "test_aligned_reading_s64",
+		       "test_aligned_writing_s64");
+  create_aligned_code (ctxt, "s128", 128, "test_aligned_reading_s128",
+		       "test_aligned_writing_s128");
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  verify_aligned_code<s2> (ctxt, result, "test_aligned_writing_s2");
+  verify_aligned_code<s4> (ctxt, result, "test_aligned_writing_s4");
+  verify_aligned_code<s8> (ctxt, result, "test_aligned_writing_s8");
+  verify_aligned_code<s16> (ctxt, result, "test_aligned_writing_s16");
+  verify_aligned_code<s32> (ctxt, result, "test_aligned_writing_s32");
+  verify_aligned_code<s64> (ctxt, result, "test_aligned_writing_s64");
+  verify_aligned_code<s128> (ctxt, result, "test_aligned_writing_s128");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c b/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c
new file mode 100644
index 0000000..8f3233b
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c
@@ -0,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Trigger an API error by passing a bad alignment.  */
+  (void)gcc_jit_type_get_aligned (int_type, 7);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      ("gcc_jit_type_get_aligned:"
+		       " alignment not a power of two: 7"));
+}
+
-- 
1.8.5.3

