public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: Alignment not supported?
  2017-01-01  0:00 ` Florian Weimer
@ 2017-01-01  0:00   ` 정인배(Inbae Jeong)
  2017-01-01  0:00     ` David Malcolm
                       ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: 정인배(Inbae Jeong) @ 2017-01-01  0:00 UTC (permalink / raw)
  To: Florian Weimer; +Cc: jit

Sorry for being too short. It's JIT mailing list so I thought everyone
would expect it to be related to gccjit.

I'm writing a small JITed interpreter and trying to call an external C
function (actually it is an external "C" C++ function) of which one of
the parameters is a struct containing an aligned member variable.

To make a struct type with gccjit, it will be somewhat like this:

struct my_arg {
    int a;
    alignas(32) int b;
};

1: gcc_jit_type *int_type  = gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_INT)
2: gcc_jit_field *field_a    = gcc_jit_context_new_field(ctxt, NULL,
int_type, "a");
3: gcc_jit_field *field_b    = gcc_jit_context_new_field(ctxt, NULL,
int_type, "b"); // How do I specify the alignment?
4: gcc_jit_field *fields[2] = {field_a, field_b};
5: gcc_jit_struct *my_arg   = gcc_jit_context_new_struct_type(ctxt,
NULL, "my_arg", 2, fields);


Maybe the alignment should be specified in line 3 or a new int type
has to be made with alignment specification, if supported. However I
don't see anything about alignment in the gccjit manual.




2017-03-25 22:41 GMT+09:00 Florian Weimer <fw@deneb.enyo.de>:
> * 정인배:
>
>> I need to align a type for calling an external function.
>>
>> How do I set the alignment for a type like the struct below?
>>
>> struct my_arg {
>> int a;
>> alignas(32) int b;
>> };
>>
>> I don't see any option for giving the alignment requirement to b.
>
> This should work:
>
> struct my_arg {
>   int a;
>   int b __attribute__ ((aligned (32)));
> };

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00               ` David Malcolm
@ 2017-01-01  0:00                 ` Florian Weimer
  0 siblings, 0 replies; 16+ messages in thread
From: Florian Weimer @ 2017-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: 정인배(Inbae Jeong), jit

* David Malcolm:

>> It's also more type-safe and self-documenting.  Although “int”
>> probably isn't exactly the right type here.
>
> "unsigned int" ?

I think the appropriate type used to be “unsigned HOST_WIDE_INT”
inside GCC at one point.  I don't know what the equivalent on the
libgccjit interface is.  If libgccjit does not support
cross-compilation, size_t should be okay.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00         ` David Malcolm
  2017-01-01  0:00           ` Florian Weimer
@ 2017-01-01  0:00           ` David Malcolm
  2017-01-01  0:00             ` Florian Weimer
  1 sibling, 1 reply; 16+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: Florian Weimer; +Cc: 정인배(Inbae Jeong), jit

On Mon, 2017-03-27 at 12:00 -0400, David Malcolm wrote:
> On Mon, 2017-03-27 at 16:48 +0200, Florian Weimer wrote:
> > * David Malcolm:
> > 
> > > My first thought was that we could add a way to expose attributes
> > > on types from the API, something like:
> > > 
> > > extern gcc_jit_type *
> > > gcc_jit_type_add_attribute (gcc_jit_type *type,
> > >                             const char *attribute_name,
> > >                             /* some extra params */ );
> > > 
> > > but it's not clear to me what those extra params should look like
> > > here.
> > > 
> > > It could be variadic, but variadic functions make for an error
> > > -prone
> > > API that's easy to crash, and they're a pain to deal with in
> > > language bindings.
> > 
> > Right, please don't do that. :)
> > 
> > > Maybe:
> > > 
> > > extern gcc_jit_type *
> > > gcc_jit_type_add_attribute_int (gcc_jit_type *type,
> > >                                 const char *attribute_name,
> > >                                 int attr_param);
> > > 
> > > (perhaps adding other suffixes for other type signatures; this is
> > > a
> > > C API, so there we can't use overloads; the C++ bindings could
> > > use
> > them, though).
> > I would suggest to model the interface after
> > gcc_jit_context_new_call
> > (but still keep it separate because even though attributes with
> > arguments are syntactically pretty much like function calls in the
> > C
> > front end, semantically, they are not). 
> 
> If I understand you right, this would give something like:
> 
> extern gcc_jit_type *
> gcc_jit_type_add_attribute (gcc_jit_type *type
>                             const char *attribute_name,
>                             int numargs, gcc_jit_rvalue **args);
> 
> Is every attribute arg an rvalue though?  Can some of them be types?
> 
> If so, maybe we should use gcc_jit_object instead:
> 
> extern gcc_jit_type *
> gcc_jit_type_add_attribute (gcc_jit_type *type
>                             const char *attribute_name,
>                             int numargs, gcc_jit_object **args);
> 
> so that for the motivating example:
> 
> struct my_arg {
>   int a;
>   int b __attribute__ ((aligned (32)));
> };
> 
> we'd have:
> 
> 1: gcc_jit_type *int_type  = gcc_jit_context_get_type(ctxt,
> GCC_JIT_TYPE_INT)
> 2: gcc_jit_field *field_a    = gcc_jit_context_new_field(ctxt, NULL,
> int_type, "a");
> 
> 
> gcc_jit_object *alignment
>   = gcc_jit_rvalue_as_object
>       (gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 32));
> 
> gcc_jit_type *aligned_int_type
>    = gcc_jit_type_attribute (int_type,
>                              "aligned",
>                              1, &alignment);
> 
> 3a: gcc_jit_field *field_b    = gcc_jit_context_new_field(ctxt, NULL,
> aligned_int_type, "b");
> 
> 
> 
> 
> 4: gcc_jit_field *fields[2] = {field_a, field_b};
> 5: gcc_jit_struct *my_arg   = gcc_jit_context_new_struct_type(ctxt,
> NULL, "my_arg", 2, fields);
> 
> 
> 
> > I'm not sure where the argument list checking for attributes
> > happens
> > (at least it's not part of the C parser).  It would be preferable
> > if
> > there were at least some consistency checks when using the JIT
> > interface, instead of silently generating broken code.
> 
> (nods)
> 
> It strikes me that a lot of the attributes are frontend-specific; see
> for example gcc/c-family/c-attribs.c
> (Also, LTO is often the place to look for things that are frontend
> -specific but perhaps shouldn't be, or, at least, can need
> duplicating
> in libgccjit; I see some attribute handlers there in gcc/lto/lto
> -lang.c)
> 
> Am poking at this, to see exactly what happens in C frontend for this
> case.
> 

The attribute in question is this entry in c-attribs.c
c_common_attribute_table[25]:

  { "aligned",                0, 1, false, false, false,
			      handle_aligned_attribute, false },

which calls: handle_aligned_attribute, which effectively implements the
attribute.

Hence all of this pre-existing logic for setting the alignment of a
type is implemented with the c-family front-end code, which isn't
available from libgccjit.

We could still invent attributes for the JIT, and aim for compatibility
with the C family (maybe refactoring things).

Alternatively, it might make more sense to go with this earlier API
idea:

extern gcc_jit_type *
gcc_jit_type_set_alignment (gcc_jit_type *type,
                            int alignment);

or similar ("make_aligned" ?  "add_alignment" ?)

I think I prefer the latter approach, as it makes it explicit in client
code linkage metadata what functionality it's using, whereas with the
attribute-based approach it's hard to tell what attributes a particular
client binary might make use of (similar to how I switched to new
entrypoints for new options; see gcc_jit_context_set_bool_allow_unreach
able_blocks() and
https://gcc.gnu.org/onlinedocs/jit/topics/compatibility.html#libgccjit-
abi-2 )


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00 Alignment not supported? 정인배(Inbae Jeong)
@ 2017-01-01  0:00 ` Florian Weimer
  2017-01-01  0:00   ` 정인배(Inbae Jeong)
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-01-01  0:00 UTC (permalink / raw)
  To: 정인배(Inbae Jeong); +Cc: jit

* 정인배:

> I need to align a type for calling an external function.
>
> How do I set the alignment for a type like the struct below?
>
> struct my_arg {
> int a;
> alignas(32) int b;
> };
>
> I don't see any option for giving the alignment requirement to b.

This should work:

struct my_arg {
  int a;
  int b __attribute__ ((aligned (32)));
};

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00             ` Florian Weimer
@ 2017-01-01  0:00               ` David Malcolm
  2017-01-01  0:00                 ` Florian Weimer
  0 siblings, 1 reply; 16+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: Florian Weimer; +Cc: 정인배(Inbae Jeong), jit

On Mon, 2017-03-27 at 19:22 +0200, Florian Weimer wrote:
> * David Malcolm:
> 
> > Hence all of this pre-existing logic for setting the alignment of a
> > type is implemented with the c-family front-end code, which isn't
> > available from libgccjit.
> 
> Ah, I assumed it was a c-family target.
> 
> > Alternatively, it might make more sense to go with this earlier API
> > idea:
> > 
> > extern gcc_jit_type *
> > gcc_jit_type_set_alignment (gcc_jit_type *type,
> >                             int alignment);
> > 
> > or similar ("make_aligned" ?  "add_alignment" ?)
> > 
> > I think I prefer the latter approach, as it makes it explicit in
> > client
> > code linkage metadata what functionality it's using,
> 
> It's also more type-safe and self-documenting.  Although “int”
> probably isn't exactly the right type here.

"unsigned int" ?


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Alignment not supported?
@ 2017-01-01  0:00 정인배(Inbae Jeong)
  2017-01-01  0:00 ` Florian Weimer
  0 siblings, 1 reply; 16+ messages in thread
From: 정인배(Inbae Jeong) @ 2017-01-01  0:00 UTC (permalink / raw)
  To: jit

I need to align a type for calling an external function.

How do I set the alignment for a type like the struct below?

struct my_arg {
int a;
alignas(32) int b;
};

I don't see any option for giving the alignment requirement to b.

Currently I make a large enough character array and manually
serialize/deserialize as if gcc would do with alignof and sizeof
operator (and with non-standard endianness macros), and it seems it's
working, but i really hope there is support for alignment. The code
gets uglier when the struct contains another struct in it so that i
don't think i can manage it if the struct changes.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH] Add gcc_jit_type_get_aligned
  2017-01-01  0:00       ` Florian Weimer
@ 2017-01-01  0:00         ` David Malcolm
  2017-01-01  0:00           ` David Malcolm
  0 siblings, 1 reply; 16+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: Florian Weimer
  Cc: 정인배(Inbae Jeong), jit, gcc-patches, David Malcolm

On Thu, 2017-03-30 at 22:28 +0200, Florian Weimer wrote:
> * David Malcolm:
> 
> > Here's a work-in-progress implementation of the idea, adding this
> > entrypoint to the API:
> > 
> >   extern gcc_jit_type *
> >   gcc_jit_type_get_aligned (gcc_jit_type *type,
> >                             unsigned int alignment_in_bytes);
> 
> Should be size_t, not unsigned int.  A 2**31 alignment isn't as
> ridiculous as it might seem.  x86-64 already has a 2**30 alignment
> requirement in some contexts.

Thanks; fixed in this version.

Here's a completed version of the patch.

It also implements the missing C++ binding
gccjit::type::get_const, needed by a test case.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.
Takes jit.sum from 8609 to 9349 PASS results.

Release managers: is it acceptable to commit this to trunk in
stage 4?  It purely touches jit-related code/testcases, but I
appreciate it's very late to be adding features.

Otherwise I'll commit it in the next stage 1.

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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Work-in-progress: gcc_jit_type_get_aligned
  2017-01-01  0:00     ` [PATCH] Work-in-progress: gcc_jit_type_get_aligned David Malcolm
@ 2017-01-01  0:00       ` Florian Weimer
  2017-01-01  0:00         ` [PATCH] Add gcc_jit_type_get_aligned David Malcolm
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: 정인배(Inbae Jeong), jit

* David Malcolm:

> Here's a work-in-progress implementation of the idea, adding this
> entrypoint to the API:
>
>   extern gcc_jit_type *
>   gcc_jit_type_get_aligned (gcc_jit_type *type,
>                             unsigned int alignment_in_bytes);

Should be size_t, not unsigned int.  A 2**31 alignment isn't as
ridiculous as it might seem.  x86-64 already has a 2**30 alignment
requirement in some contexts.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH] Work-in-progress: gcc_jit_type_get_aligned
  2017-01-01  0:00   ` 정인배(Inbae Jeong)
  2017-01-01  0:00     ` David Malcolm
  2017-01-01  0:00     ` Florian Weimer
@ 2017-01-01  0:00     ` David Malcolm
  2017-01-01  0:00       ` Florian Weimer
  2 siblings, 1 reply; 16+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: 정인배(Inbae Jeong), Florian Weimer; +Cc: jit, David Malcolm

On Sat, 2017-03-25 at 23:05 +0900, 정인배(Inbae Jeong) wrote:
> Sorry for being too short. It's JIT mailing list so I thought
> everyone
> would expect it to be related to gccjit.
> 
> I'm writing a small JITed interpreter and trying to call an external
> C
> function (actually it is an external "C" C++ function) of which one
> of
> the parameters is a struct containing an aligned member variable.
> 
> To make a struct type with gccjit, it will be somewhat like this:
> 
> struct my_arg {
>     int a;
>     alignas(32) int b;
> };
> 
> 1: gcc_jit_type *int_type  = gcc_jit_context_get_type(ctxt,
> GCC_JIT_TYPE_INT)
> 2: gcc_jit_field *field_a    = gcc_jit_context_new_field(ctxt, NULL,
> int_type, "a");
> 3: gcc_jit_field *field_b    = gcc_jit_context_new_field(ctxt, NULL,
> int_type, "b"); // How do I specify the alignment?
> 4: gcc_jit_field *fields[2] = {field_a, field_b};
> 5: gcc_jit_struct *my_arg   = gcc_jit_context_new_struct_type(ctxt,
> NULL, "my_arg", 2, fields);
> 
> 
> Maybe the alignment should be specified in line 3 or a new int type
> has to be made with alignment specification, if supported. However I
> don't see anything about alignment in the gccjit manual.
> 
> 
> 
> 
> 2017-03-25 22:41 GMT+09:00 Florian Weimer <fw@deneb.enyo.de>:
> > * 정인배:
> > 
> > > I need to align a type for calling an external function.
> > > 
> > > How do I set the alignment for a type like the struct below?
> > > 
> > > struct my_arg {
> > > int a;
> > > alignas(32) int b;
> > > };
> > > 
> > > I don't see any option for giving the alignment requirement to b.
> > 
> > This should work:
> > 
> > struct my_arg {
> >   int a;
> >   int b __attribute__ ((aligned (32)));
> > };

Here's a work-in-progress implementation of the idea, adding this
entrypoint to the API:

  extern gcc_jit_type *
  gcc_jit_type_get_aligned (gcc_jit_type *type,
                            unsigned int alignment_in_bytes);

With the above, you should be able to do:

  gcc_jit_type *aligned_int_type
     = gcc_jit_type_get_aligned (int_type, 32);

equivalent to __attribute__ ((aligned (32))).

Does this solve the problem for you?


Notes to myself on the status of the patch follow:

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

TODO:
  - FIXMEs and TODOs
  - C++ bindings
  - testsuite
    - C++ test coverage
  - documentation for the C++ API
  - documentation for the new ABI tag (see topics/compatibility.rst)
  - ChangeLog
---
 gcc/jit/docs/topics/types.rst                      |   9 +
 gcc/jit/jit-playback.c                             |  14 ++
 gcc/jit/jit-playback.h                             |   2 +
 gcc/jit/jit-recording.c                            |  52 +++++
 gcc/jit/jit-recording.h                            |  68 +++---
 gcc/jit/libgccjit.c                                |  24 +++
 gcc/jit/libgccjit.h                                |  12 ++
 gcc/jit/libgccjit.map                              |   5 +
 gcc/testsuite/jit.dg/all-non-failing-tests.h       |  10 +
 gcc/testsuite/jit.dg/test-alignment.c              | 232 +++++++++++++++++++++
 ...ror-gcc_jit_type_get_aligned-non-power-of-two.c |  30 +++
 11 files changed, 434 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-alignment.c
 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/topics/types.rst b/gcc/jit/docs/topics/types.rst
index 9a1b879..38b8b3b 100644
--- a/gcc/jit/docs/topics/types.rst
+++ b/gcc/jit/docs/topics/types.rst
@@ -117,6 +117,15 @@ 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, \
+                                         unsigned int alignment_in_bytes)
+
+   Given type "T", get type:
+
+   .. code-block:: c
+
+      T __attribute__ ((aligned (ALIGNMENT_IN_BYTES)))
 
 Structures and unions
 ---------------------
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index cf9f36d..6b12468 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -1095,6 +1095,20 @@ new_dereference (tree ptr,
   return datum;
 }
 
+/* FIXME.  */
+
+playback::type *
+playback::type::
+get_aligned (unsigned int 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..8cc8fb7 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 (unsigned int alignment_in_bytes) const;
+
 private:
   tree m_inner;
 };
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 9a515ab..db739e1 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1975,6 +1975,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 (unsigned int 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)
 {
@@ -2420,6 +2434,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(%i)))",
+			      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, %i);\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 4acaae6..e9e947d 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 (unsigned int 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, unsigned int 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;
+  unsigned int m_alignment_in_bytes;
 };
 
 class array_type : public type
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 4bd56bd..ab32469 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -2971,3 +2971,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,
+			  unsigned int alignment_in_bytes)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  gcc::jit::recording::context *ctxt = type->m_ctxt;
+
+  LOG_FUNC (ctxt->get_logger ());
+
+  RETURN_NULL_IF_FAIL_PRINTF1
+    (pow2_or_zerop (alignment_in_bytes), ctxt, NULL,
+     "alignment not a power of two: %i",
+     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..524a32b 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1387,6 +1387,18 @@ 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
+
+/* FIXME
+
+   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,
+			  unsigned int 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-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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00         ` David Malcolm
@ 2017-01-01  0:00           ` Florian Weimer
  2017-01-01  0:00           ` David Malcolm
  1 sibling, 0 replies; 16+ messages in thread
From: Florian Weimer @ 2017-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: 정인배(Inbae Jeong), jit

* David Malcolm:

>> I would suggest to model the interface after gcc_jit_context_new_call
>> (but still keep it separate because even though attributes with
>> arguments are syntactically pretty much like function calls in the C
>> front end, semantically, they are not). 
>
> If I understand you right, this would give something like:
>
> extern gcc_jit_type *
> gcc_jit_type_add_attribute (gcc_jit_type *type
>                             const char *attribute_name,
>                             int numargs, gcc_jit_rvalue **args);

Right.

> Is every attribute arg an rvalue though?  Can some of them be types?

Not sure about that, but the “mode” attribute appears to be special in
this regard.  There could be others.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00   ` 정인배(Inbae Jeong)
  2017-01-01  0:00     ` David Malcolm
@ 2017-01-01  0:00     ` Florian Weimer
  2017-01-01  0:00     ` [PATCH] Work-in-progress: gcc_jit_type_get_aligned David Malcolm
  2 siblings, 0 replies; 16+ messages in thread
From: Florian Weimer @ 2017-01-01  0:00 UTC (permalink / raw)
  To: 정인배(Inbae Jeong); +Cc: jit

* 정인배:

> Sorry for being too short. It's JIT mailing list so I thought everyone
> would expect it to be related to gccjit.

Oh, sorry, I was being dense.

> Maybe the alignment should be specified in line 3 or a new int type
> has to be made with alignment specification, if supported. However I
> don't see anything about alignment in the gccjit manual.

I reviewed the gcc/jit sources, and there does not seem to be a way to
set attributes (such as alignment) on types or field members.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00     ` David Malcolm
@ 2017-01-01  0:00       ` Florian Weimer
  2017-01-01  0:00         ` David Malcolm
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: 정인배(Inbae Jeong), jit

* David Malcolm:

> My first thought was that we could add a way to expose attributes on types from the API, something like:
>
> extern gcc_jit_type *
> gcc_jit_type_add_attribute (gcc_jit_type *type,
>                             const char *attribute_name,
>                             /* some extra params */ );
>
> but it's not clear to me what those extra params should look like here.
>
> It could be variadic, but variadic functions make for an error-prone
> API that's easy to crash, and they're a pain to deal with in
> language bindings.

Right, please don't do that. :)

> Maybe:
>
> extern gcc_jit_type *
> gcc_jit_type_add_attribute_int (gcc_jit_type *type,
>                                 const char *attribute_name,
>                                 int attr_param);
>
> (perhaps adding other suffixes for other type signatures; this is a
> C API, so there we can't use overloads; the C++ bindings could use
> them, though).

I would suggest to model the interface after gcc_jit_context_new_call
(but still keep it separate because even though attributes with
arguments are syntactically pretty much like function calls in the C
front end, semantically, they are not).

I'm not sure where the argument list checking for attributes happens
(at least it's not part of the C parser).  It would be preferable if
there were at least some consistency checks when using the JIT
interface, instead of silently generating broken code.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00   ` 정인배(Inbae Jeong)
@ 2017-01-01  0:00     ` David Malcolm
  2017-01-01  0:00       ` Florian Weimer
  2017-01-01  0:00     ` Florian Weimer
  2017-01-01  0:00     ` [PATCH] Work-in-progress: gcc_jit_type_get_aligned David Malcolm
  2 siblings, 1 reply; 16+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: 정인배(Inbae Jeong), Florian Weimer; +Cc: jit

On Sat, 2017-03-25 at 23:05 +0900, 정인배(Inbae Jeong) wrote:
> Sorry for being too short. It's JIT mailing list so I thought
> everyone
> would expect it to be related to gccjit.
> 
> I'm writing a small JITed interpreter and trying to call an external
> C
> function (actually it is an external "C" C++ function) of which one
> of
> the parameters is a struct containing an aligned member variable.
> 
> To make a struct type with gccjit, it will be somewhat like this:
> 
> struct my_arg {
>     int a;
>     alignas(32) int b;
> };
> 
> 1: gcc_jit_type *int_type  = gcc_jit_context_get_type(ctxt,
> GCC_JIT_TYPE_INT)
> 2: gcc_jit_field *field_a    = gcc_jit_context_new_field(ctxt, NULL,
> int_type, "a");
> 3: gcc_jit_field *field_b    = gcc_jit_context_new_field(ctxt, NULL,
> int_type, "b"); // How do I specify the alignment?
> 4: gcc_jit_field *fields[2] = {field_a, field_b};
> 5: gcc_jit_struct *my_arg   = gcc_jit_context_new_struct_type(ctxt,
> NULL, "my_arg", 2, fields);
> 
> 
> Maybe the alignment should be specified in line 3 or a new int type
> has to be made with alignment specification, if supported. However I
> don't see anything about alignment in the gccjit manual.

I don't think that there's currently a way to do this from libgccjit.

My first thought was that we could add a way to expose attributes on types from the API, something like:

extern gcc_jit_type *
gcc_jit_type_add_attribute (gcc_jit_type *type,
                            const char *attribute_name,
                            /* some extra params */ );

but it's not clear to me what those extra params should look like here.

It could be variadic, but variadic functions make for an error-prone API that's easy to crash, and they're a pain to deal with in language bindings.

Maybe:

extern gcc_jit_type *
gcc_jit_type_add_attribute_int (gcc_jit_type *type,
                                const char *attribute_name,
                                int attr_param);

(perhaps adding other suffixes for other type signatures; this is a C API, so there we can't use overloads; the C++ bindings could use them, though).

Alternatively, we could have a special-case entrypoint:

extern gcc_jit_type *
gcc_jit_type_set_alignment (gcc_jit_type *type,
                            int alignment);

and hide the fact that it's an attribute internally.

I'm not yet sure which approach I prefer (and maybe I need to poke at this from the implementation side to see what's implementable).

What other attributes might people want to use?  Thoughts?

Dave

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00       ` Florian Weimer
@ 2017-01-01  0:00         ` David Malcolm
  2017-01-01  0:00           ` Florian Weimer
  2017-01-01  0:00           ` David Malcolm
  0 siblings, 2 replies; 16+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: Florian Weimer; +Cc: 정인배(Inbae Jeong), jit

On Mon, 2017-03-27 at 16:48 +0200, Florian Weimer wrote:
> * David Malcolm:
> 
> > My first thought was that we could add a way to expose attributes
> > on types from the API, something like:
> > 
> > extern gcc_jit_type *
> > gcc_jit_type_add_attribute (gcc_jit_type *type,
> >                             const char *attribute_name,
> >                             /* some extra params */ );
> > 
> > but it's not clear to me what those extra params should look like
> > here.
> > 
> > It could be variadic, but variadic functions make for an error
> > -prone
> > API that's easy to crash, and they're a pain to deal with in
> > language bindings.
> 
> Right, please don't do that. :)
> 
> > Maybe:
> > 
> > extern gcc_jit_type *
> > gcc_jit_type_add_attribute_int (gcc_jit_type *type,
> >                                 const char *attribute_name,
> >                                 int attr_param);
> > 
> > (perhaps adding other suffixes for other type signatures; this is a
> > C API, so there we can't use overloads; the C++ bindings could use
> them, though).
> I would suggest to model the interface after gcc_jit_context_new_call
> (but still keep it separate because even though attributes with
> arguments are syntactically pretty much like function calls in the C
> front end, semantically, they are not). 

If I understand you right, this would give something like:

extern gcc_jit_type *
gcc_jit_type_add_attribute (gcc_jit_type *type
                            const char *attribute_name,
                            int numargs, gcc_jit_rvalue **args);

Is every attribute arg an rvalue though?  Can some of them be types?

If so, maybe we should use gcc_jit_object instead:

extern gcc_jit_type *
gcc_jit_type_add_attribute (gcc_jit_type *type
                            const char *attribute_name,
                            int numargs, gcc_jit_object **args);

so that for the motivating example:

struct my_arg {
  int a;
  int b __attribute__ ((aligned (32)));
};

we'd have:

1: gcc_jit_type *int_type  = gcc_jit_context_get_type(ctxt,
GCC_JIT_TYPE_INT)
2: gcc_jit_field *field_a    = gcc_jit_context_new_field(ctxt, NULL,
int_type, "a");


gcc_jit_object *alignment
  = gcc_jit_rvalue_as_object
      (gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 32));

gcc_jit_type *aligned_int_type
   = gcc_jit_type_attribute (int_type,
                             "aligned",
                             1, &alignment);

3a: gcc_jit_field *field_b    = gcc_jit_context_new_field(ctxt, NULL,
aligned_int_type, "b");




4: gcc_jit_field *fields[2] = {field_a, field_b};
5: gcc_jit_struct *my_arg   = gcc_jit_context_new_struct_type(ctxt,
NULL, "my_arg", 2, fields);



> I'm not sure where the argument list checking for attributes happens
> (at least it's not part of the C parser).  It would be preferable if
> there were at least some consistency checks when using the JIT
> interface, instead of silently generating broken code.

(nods)

It strikes me that a lot of the attributes are frontend-specific; see
for example gcc/c-family/c-attribs.c
(Also, LTO is often the place to look for things that are frontend
-specific but perhaps shouldn't be, or, at least, can need duplicating
in libgccjit; I see some attribute handlers there in gcc/lto/lto
-lang.c)

Am poking at this, to see exactly what happens in C frontend for this
case.

Dave

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Alignment not supported?
  2017-01-01  0:00           ` David Malcolm
@ 2017-01-01  0:00             ` Florian Weimer
  2017-01-01  0:00               ` David Malcolm
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2017-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: 정인배(Inbae Jeong), jit

* David Malcolm:

> Hence all of this pre-existing logic for setting the alignment of a
> type is implemented with the c-family front-end code, which isn't
> available from libgccjit.

Ah, I assumed it was a c-family target.

> Alternatively, it might make more sense to go with this earlier API
> idea:
>
> extern gcc_jit_type *
> gcc_jit_type_set_alignment (gcc_jit_type *type,
>                             int alignment);
>
> or similar ("make_aligned" ?  "add_alignment" ?)
>
> I think I prefer the latter approach, as it makes it explicit in client
> code linkage metadata what functionality it's using,

It's also more type-safe and self-documenting.  Although “int”
probably isn't exactly the right type here.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] Add gcc_jit_type_get_aligned
  2017-01-01  0:00         ` [PATCH] Add gcc_jit_type_get_aligned David Malcolm
@ 2017-01-01  0:00           ` David Malcolm
  0 siblings, 0 replies; 16+ messages in thread
From: David Malcolm @ 2017-01-01  0:00 UTC (permalink / raw)
  To: Florian Weimer; +Cc: 정인배(Inbae Jeong), jit, gcc-patches

On Fri, 2017-03-31 at 17:13 -0400, David Malcolm wrote:
> On Thu, 2017-03-30 at 22:28 +0200, Florian Weimer wrote:
> > * David Malcolm:
> > 
> > > Here's a work-in-progress implementation of the idea, adding this
> > > entrypoint to the API:
> > > 
> > >   extern gcc_jit_type *
> > >   gcc_jit_type_get_aligned (gcc_jit_type *type,
> > >                             unsigned int alignment_in_bytes);
> > 
> > Should be size_t, not unsigned int.  A 2**31 alignment isn't as
> > ridiculous as it might seem.  x86-64 already has a 2**30 alignment
> > requirement in some contexts.
> 
> Thanks; fixed in this version.
> 
> Here's a completed version of the patch.
> 
> It also implements the missing C++ binding
> gccjit::type::get_const, needed by a test case.
> 
> Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.
> Takes jit.sum from 8609 to 9349 PASS results.
> 
> Release managers: is it acceptable to commit this to trunk in
> stage 4?  It purely touches jit-related code/testcases, but I
> appreciate it's very late to be adding features.
> 
> Otherwise I'll commit it in the next stage 1.

I've committed this to trunk (for gcc 8) as r247111.

[...snip...]

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2017-04-24 20:34 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-01  0:00 Alignment not supported? 정인배(Inbae Jeong)
2017-01-01  0:00 ` Florian Weimer
2017-01-01  0:00   ` 정인배(Inbae Jeong)
2017-01-01  0:00     ` David Malcolm
2017-01-01  0:00       ` Florian Weimer
2017-01-01  0:00         ` David Malcolm
2017-01-01  0:00           ` Florian Weimer
2017-01-01  0:00           ` David Malcolm
2017-01-01  0:00             ` Florian Weimer
2017-01-01  0:00               ` David Malcolm
2017-01-01  0:00                 ` Florian Weimer
2017-01-01  0:00     ` Florian Weimer
2017-01-01  0:00     ` [PATCH] Work-in-progress: gcc_jit_type_get_aligned David Malcolm
2017-01-01  0:00       ` Florian Weimer
2017-01-01  0:00         ` [PATCH] Add gcc_jit_type_get_aligned David Malcolm
2017-01-01  0:00           ` David Malcolm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).