diff mbox

[jit] Various changes to expression-handling (API changes)

Message ID 1382144724-6322-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Oct. 19, 2013, 1:05 a.m. UTC
I've committed the following to dmalcolm/jit:

Add unary ops.
Add more binary ops.
Add more comparison modes.
Convert field access API from:

  extern gcc_jit_lvalue *
  gcc_jit_context_new_field_access (gcc_jit_context *ctxt,
				    gcc_jit_location *loc,
				    gcc_jit_rvalue *ptr_or_struct,
				    const char *fieldname);
to:

  /* Accessing a field of an lvalue of struct type, analogous to:
      (EXPR).field = ...;
     in C.  */
  extern gcc_jit_lvalue *
  gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
			       gcc_jit_location *loc,
			       const char *fieldname);

  /* Accessing a field of an rvalue of struct type, analogous to:
      (EXPR).field
   in C.  */
  extern gcc_jit_rvalue *
  gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
			       gcc_jit_location *loc,
			       const char *fieldname);

  /* Accessing a field of an rvalue of pointer type, analogous to:
      (EXPR)->field
     in C, itself equivalent to (*EXPR).FIELD  */
  extern gcc_jit_lvalue *
  gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
				    gcc_jit_location *loc,
				    const char *fieldname);

  /* Dereferencing a pointer; analogous to:
       *(EXPR)
  */
  extern gcc_jit_lvalue *
  gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
			      gcc_jit_location *loc);

gcc/jit/
	* internal-api.c (gcc::jit::context::new_param): Add context
	argument to ctor for rvalue and its subclasses.
	(gcc::jit::context::new_global): Likewise.
	(gcc::jit::context::new_rvalue_from_int): Likewise.
	(gcc::jit::context::new_rvalue_from_double): Likewise.
	(gcc::jit::context::new_rvalue_from_ptr): Likewise.
	(gcc::jit::context::new_string_literal): Likewise.
	(gcc::jit::context::new_call): Likewise.
	(gcc::jit::context::new_array_lookup): Likewise.
	(gcc::jit::function::new_local): Likewise.
	(gcc::jit::context::new_binary_op): Likewise; add new
	operations.
	(gcc::jit::context::new_comparison): Likewise; add new
	comparisons.
	(gcc::jit::context::as_truth_value): New.
	(gcc::jit::context::new_unary_op): New.
	(gcc::jit::context::new_field_access): Convert to a helper
	method for use by the access_fields methods.
	(gcc::jit::context::new_dereference): New.
	(gcc::jit::lvalue::access_field): New.
	(gcc::jit::rvalue::access_field): New.
	(gcc::jit::rvalue::dereference_field): New.
	(gcc::jit::rvalue::dereference): New.
	* internal-api.h (gcc::jit::context::new_unary_op): New.
	(gcc::jit::context::new_field_access): Work
	(gcc::jit::context::new_dereference): New.
	(gcc::jit::context::as_truth_value): New.
	(gcc::jit::rvalue): Add a context field.
	(gcc::jit::rvalue::access_field): New.
	(gcc::jit::rvalue::dereference_field): New.
	(gcc::jit::rvalue::dereference): New.
	(gcc::jit::lvalue::lvalue): Add context to ctor.
	(gcc::jit::lvalue::access_field): New.
	(gcc::jit::param::param): Add context to ctor.
	* libgccjit.c (gcc_jit_context_new_unary_op): New.
	(gcc_jit_context_new_field_access): Remove.
	(gcc_jit_lvalue_access_field): New.
	(gcc_jit_rvalue_access_field): New.
	(gcc_jit_rvalue_dereference_field): New.
	(gcc_jit_rvalue_dereference): New.
	*libgccjit.h (enum gcc_jit_unary_op): New.
	(gcc_jit_context_new_unary_op): New.
	(enum gcc_jit_binary_op): Document values, and add...
	(GCC_JIT_BINARY_OP_DIVIDE): New.
	(GCC_JIT_BINARY_OP_MODULO): New.
	(GCC_JIT_BINARY_OP_BITWISE_AND): New.
	(GCC_JIT_BINARY_OP_BITWISE_XOR): New.
	(GCC_JIT_BINARY_OP_BITWISE_OR): New.
	(GCC_JIT_BINARY_OP_LOGICAL_AND): New.
	(GCC_JIT_BINARY_OP_LOGICAL_OR): New.
	(enum gcc_jit_comparison): Document values, and add...
	(GCC_JIT_COMPARISON_EQ): New.
	(GCC_JIT_COMPARISON_NE): New.
	(GCC_JIT_COMPARISON_LE): New.
	(GCC_JIT_COMPARISON_GT): New.
	(GCC_JIT_COMPARISON_GE): New.
	(gcc_jit_context_new_field_access): Remove.
	(gcc_jit_lvalue_access_field): New.
	(gcc_jit_rvalue_access_field): New.
	(gcc_jit_rvalue_dereference_field): New.
	(gcc_jit_rvalue_dereference): New.
	* libgccjit.map (gcc_jit_context_new_field_access): Remove.
	(gcc_jit_lvalue_access_field): New.
	(gcc_jit_rvalue_access_field): New.
	(gcc_jit_rvalue_dereference_field): New.
	(gcc_jit_rvalue_dereference): New.
	* TODO.rst: Update

gcc/testsuite/
	* jit.dg/test-expressions.c: New.
	* jit.dg/test-combination.c: Add usage of test-expressions.c
	* jit.dg/test-accessing-struct.c (code_making_callback): Update
	for changes to field-access API.
	* jit.dg/test-types.c (code_making_callback): Likewise.
---
 gcc/jit/ChangeLog.jit                        |  70 ++++
 gcc/jit/TODO.rst                             |  24 +-
 gcc/jit/internal-api.c                       | 224 ++++++++++--
 gcc/jit/internal-api.h                       |  54 ++-
 gcc/jit/libgccjit.c                          |  58 ++-
 gcc/jit/libgccjit.h                          | 125 ++++++-
 gcc/jit/libgccjit.map                        |   6 +-
 gcc/testsuite/ChangeLog.jit                  |   8 +
 gcc/testsuite/jit.dg/test-accessing-struct.c |  20 +-
 gcc/testsuite/jit.dg/test-combination.c      |   9 +
 gcc/testsuite/jit.dg/test-expressions.c      | 518 +++++++++++++++++++++++++++
 gcc/testsuite/jit.dg/test-types.c            |   4 +-
 12 files changed, 1043 insertions(+), 77 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-expressions.c
diff mbox

Patch

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index bcbb93b..7c574e8 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,75 @@ 
 2013-10-18  David Malcolm  <dmalcolm@redhat.com>
 
+	* internal-api.c (gcc::jit::context::new_param): Add context
+	argument to ctor for rvalue and its subclasses.
+	(gcc::jit::context::new_global): Likewise.
+	(gcc::jit::context::new_rvalue_from_int): Likewise.
+	(gcc::jit::context::new_rvalue_from_double): Likewise.
+	(gcc::jit::context::new_rvalue_from_ptr): Likewise.
+	(gcc::jit::context::new_string_literal): Likewise.
+	(gcc::jit::context::new_call): Likewise.
+	(gcc::jit::context::new_array_lookup): Likewise.
+	(gcc::jit::function::new_local): Likewise.
+	(gcc::jit::context::new_binary_op): Likewise; add new
+	operations.
+	(gcc::jit::context::new_comparison): Likewise; add new
+	comparisons.
+	(gcc::jit::context::as_truth_value): New.
+	(gcc::jit::context::new_unary_op): New.
+	(gcc::jit::context::new_field_access): Convert to a helper
+	method for use by the access_fields methods.
+	(gcc::jit::context::new_dereference): New.
+	(gcc::jit::lvalue::access_field): New.
+	(gcc::jit::rvalue::access_field): New.
+	(gcc::jit::rvalue::dereference_field): New.
+	(gcc::jit::rvalue::dereference): New.
+	* internal-api.h (gcc::jit::context::new_unary_op): New.
+	(gcc::jit::context::new_field_access): Work
+	(gcc::jit::context::new_dereference): New.
+	(gcc::jit::context::as_truth_value): New.
+	(gcc::jit::rvalue): Add a context field.
+	(gcc::jit::rvalue::access_field): New.
+	(gcc::jit::rvalue::dereference_field): New.
+	(gcc::jit::rvalue::dereference): New.
+	(gcc::jit::lvalue::lvalue): Add context to ctor.
+	(gcc::jit::lvalue::access_field): New.
+	(gcc::jit::param::param): Add context to ctor.
+	* libgccjit.c (gcc_jit_context_new_unary_op): New.
+	(gcc_jit_context_new_field_access): Remove.
+	(gcc_jit_lvalue_access_field): New.
+	(gcc_jit_rvalue_access_field): New.
+	(gcc_jit_rvalue_dereference_field): New.
+	(gcc_jit_rvalue_dereference): New.
+	*libgccjit.h (enum gcc_jit_unary_op): New.
+	(gcc_jit_context_new_unary_op): New.
+	(enum gcc_jit_binary_op): Document values, and add...
+	(GCC_JIT_BINARY_OP_DIVIDE): New.
+	(GCC_JIT_BINARY_OP_MODULO): New.
+	(GCC_JIT_BINARY_OP_BITWISE_AND): New.
+	(GCC_JIT_BINARY_OP_BITWISE_XOR): New.
+	(GCC_JIT_BINARY_OP_BITWISE_OR): New.
+	(GCC_JIT_BINARY_OP_LOGICAL_AND): New.
+	(GCC_JIT_BINARY_OP_LOGICAL_OR): New.
+	(enum gcc_jit_comparison): Document values, and add...
+	(GCC_JIT_COMPARISON_EQ): New.
+	(GCC_JIT_COMPARISON_NE): New.
+	(GCC_JIT_COMPARISON_LE): New.
+	(GCC_JIT_COMPARISON_GT): New.
+	(GCC_JIT_COMPARISON_GE): New.
+	(gcc_jit_context_new_field_access): Remove.
+	(gcc_jit_lvalue_access_field): New.
+	(gcc_jit_rvalue_access_field): New.
+	(gcc_jit_rvalue_dereference_field): New.
+	(gcc_jit_rvalue_dereference): New.
+	* libgccjit.map (gcc_jit_context_new_field_access): Remove.
+	(gcc_jit_lvalue_access_field): New.
+	(gcc_jit_rvalue_access_field): New.
+	(gcc_jit_rvalue_dereference_field): New.
+	(gcc_jit_rvalue_dereference): New.
+	* TODO.rst: Update
+
+2013-10-18  David Malcolm  <dmalcolm@redhat.com>
+
 	* internal-api.c (gcc::jit::context::get_type): Improve error
 	message, and report the bogus value.
 	(gcc::jit::context::new_binary_op): Likewise.
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
index ffe4c37..41cc4ad 100644
--- a/gcc/jit/TODO.rst
+++ b/gcc/jit/TODO.rst
@@ -24,19 +24,6 @@  Initial Release
 * how do you encode "x[5]=y;"?  should gcc_jit_context_new_array_lookup()
   return an lvalue rather than an rvalue?
 
-* separate out "x->field" from "x.field":
-    (x.field) = ...;   : (lvalue, str) -> lvalue
-    ... = (x.field);   : (rvalue, str) -> rvalue
-    (x->field) = ...;  : (lvalue, str) -> lvalue
-    ... = (x->field);  : (rvalue, str) -> rvalue
-
-* explicit dereferencing::
-
-    extern gcc_jit_lvalue *
-    gcc_jit_rvalue_dereference (gcc_jit_rvalue *);
-
-  for e.g. *ptr = 42;
-
 * explicit casts::
 
     extern gcc_jit_rvalue *
@@ -110,6 +97,10 @@  Initial Release
 
 * valgrind; fix memory leaks
 
+* do we need alternative forms of division (floor vs rounding)?
+
+* are we missing any ops?
+
 
 Future milestones
 =================
@@ -121,4 +112,11 @@  Future milestones
 
 * measure code coverage in testing of libgccjit.so
 
+* "switch" and "case" ?
+
+* do we need unary plus?
+* shift operators?
+* sizeof (should this be an API hook?)  do we even need it? presumably
+  client code can just do the sizeof() in its own code.
+
 etc etc
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index c5376a3..81178e1 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -210,7 +210,7 @@  new_param (location *loc,
   if (loc)
     set_tree_location (inner, loc);
 
-  return new param (inner);
+  return new param (this, inner);
 }
 
 gcc::jit::function *
@@ -298,7 +298,7 @@  new_global (location *loc,
   if (loc)
     set_tree_location (inner, loc);
 
-  return new lvalue (inner);
+  return new lvalue (this, inner);
 }
 
 gcc::jit::rvalue *
@@ -311,14 +311,14 @@  new_rvalue_from_int (type *type,
   if (INTEGRAL_TYPE_P (inner_type))
     {
       tree inner = build_int_cst (inner_type, value);
-      return new rvalue (inner);
+      return new rvalue (this, inner);
     }
   else
     {
       REAL_VALUE_TYPE real_value;
       real_from_integer (&real_value, VOIDmode, value, 0, 0);
       tree inner = build_real (inner_type, real_value);
-      return new rvalue (inner);
+      return new rvalue (this, inner);
     }
 }
 
@@ -347,7 +347,7 @@  new_rvalue_from_double (type *type,
   as_long_ints[1] = u.as_uint32s[1];
   real_from_target (&real_value, as_long_ints, DFmode);
   tree inner = build_real (inner_type, real_value);
-  return new rvalue (inner);
+  return new rvalue (this, inner);
 }
 
 gcc::jit::rvalue *
@@ -358,7 +358,7 @@  new_rvalue_from_ptr (type *type,
   tree inner_type = type->as_tree ();
   /* FIXME: how to ensure we have a wide enough type?  */
   tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
-  return new rvalue (inner);
+  return new rvalue (this, inner);
 }
 
 gcc::jit::rvalue *
@@ -374,7 +374,72 @@  new_string_literal (const char *value)
      by taking address of start of string.  */
   tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
 
-  return new rvalue (t_addr);
+  return new rvalue (this, t_addr);
+}
+
+tree
+gcc::jit::context::
+as_truth_value (tree expr, location *loc)
+{
+  /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
+  tree typed_zero = fold_build1 (CONVERT_EXPR,
+				 TREE_TYPE (expr),
+				 integer_zero_node);
+  if (loc)
+    set_tree_location (typed_zero, loc);
+
+  expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
+  if (loc)
+    set_tree_location (expr, loc);
+
+  return expr;
+}
+
+gcc::jit::rvalue *
+gcc::jit::context::
+new_unary_op (location *loc,
+	      enum gcc_jit_unary_op op,
+	      type *result_type,
+	      rvalue *a)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (result_type);
+  gcc_assert (a);
+
+  tree node = a->as_tree ();
+  tree inner_result = NULL;
+
+  switch (op)
+    {
+    default:
+      add_error ("unrecognized (enum gcc_jit_unary_op) value: %i", op);
+      return NULL;
+
+    case GCC_JIT_UNARY_OP_MINUS:
+      inner_op = NEGATE_EXPR;
+      break;
+
+    case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
+      inner_op = BIT_NOT_EXPR;
+      break;
+
+    case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
+      node = as_truth_value (node, loc);
+      inner_result = invert_truthvalue (node);
+      if (loc)
+	set_tree_location (inner_result, loc);
+      return new rvalue (this, inner_result);
+    }
+
+  inner_result = build1 (inner_op,
+			 result_type->as_tree (),
+			 node);
+  if (loc)
+    set_tree_location (inner_result, loc);
+
+  return new rvalue (this, inner_result);
 }
 
 gcc::jit::rvalue *
@@ -391,6 +456,9 @@  new_binary_op (location *loc,
   gcc_assert (a);
   gcc_assert (b);
 
+  tree node_a = a->as_tree ();
+  tree node_b = b->as_tree ();
+
   switch (op)
     {
     default:
@@ -408,16 +476,49 @@  new_binary_op (location *loc,
     case GCC_JIT_BINARY_OP_MULT:
       inner_op = MULT_EXPR;
       break;
+
+    case GCC_JIT_BINARY_OP_DIVIDE:
+      inner_op = TRUNC_DIV_EXPR;
+      break;
+      /* do we want separate floor divide vs frac divide? */
+
+    case GCC_JIT_BINARY_OP_MODULO:
+      inner_op = TRUNC_MOD_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_AND:
+      inner_op = BIT_AND_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_XOR:
+      inner_op = BIT_XOR_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_OR:
+      inner_op = BIT_IOR_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_LOGICAL_AND:
+      node_a = as_truth_value (node_a, loc);
+      node_b = as_truth_value (node_b, loc);
+      inner_op = TRUTH_ANDIF_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_LOGICAL_OR:
+      node_a = as_truth_value (node_a, loc);
+      node_b = as_truth_value (node_b, loc);
+      inner_op = TRUTH_ORIF_EXPR;
+      break;
     }
 
   tree inner_expr = build2 (inner_op,
 			    result_type->as_tree (),
-			    a->as_tree (),
-			    b->as_tree ());
+			    node_a,
+			    node_b);
   if (loc)
     set_tree_location (inner_expr, loc);
 
-  return new rvalue (inner_expr);
+  return new rvalue (this, inner_expr);
 }
 
 gcc::jit::rvalue *
@@ -438,9 +539,21 @@  new_comparison (location *loc,
       add_error ("unrecognized (enum gcc_jit_comparison) value: %i", op);
       return NULL;
 
+    case GCC_JIT_COMPARISON_EQ:
+      inner_op = EQ_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_NE:
+      inner_op = NE_EXPR;
+      break;
     case GCC_JIT_COMPARISON_LT:
       inner_op = LT_EXPR;
       break;
+    case GCC_JIT_COMPARISON_LE:
+      inner_op = LE_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_GT:
+      inner_op = GT_EXPR;
+      break;
     case GCC_JIT_COMPARISON_GE:
       inner_op = GE_EXPR;
       break;
@@ -452,7 +565,7 @@  new_comparison (location *loc,
 			    b->as_tree ());
   if (loc)
     set_tree_location (inner_expr, loc);
-  return new rvalue (inner_expr);
+  return new rvalue (this, inner_expr);
 }
 
 gcc::jit::rvalue *
@@ -483,7 +596,8 @@  new_call (location *loc,
   if (loc)
     set_tree_location (fn, loc);
 
-  return new rvalue (build_call_vec (func->get_return_type_as_tree (),
+  return new rvalue (this,
+		     build_call_vec (func->get_return_type_as_tree (),
 				     fn, tree_args));
 
   /* see c-typeck.c: build_function_call
@@ -521,7 +635,7 @@  new_array_lookup (location *loc,
 			      NULL_TREE, NULL_TREE);
       if (loc)
         set_tree_location (t_result, loc);
-      return new rvalue (t_result);
+      return new rvalue (this, t_result);
     }
   else
     {
@@ -542,7 +656,7 @@  new_array_lookup (location *loc,
           set_tree_location (t_indirection, loc);
         }
 
-      return new rvalue (t_indirection);
+      return new rvalue (this, t_indirection);
     }
 }
 
@@ -555,40 +669,92 @@  get_field (tree type, tree component)
   return NULL;
 }
 
-gcc::jit::lvalue *
+tree
 gcc::jit::context::
 new_field_access (location *loc,
-		  rvalue *ptr_or_struct,
+		  tree datum,
 		  const char *fieldname)
 {
-  gcc_assert (ptr_or_struct);
+  gcc_assert (datum);
   gcc_assert (fieldname);
 
   /* Compare with c/ctypeck.c:lookup_field, build_indirect_ref, and
      build_component_ref. */
-  tree datum = ptr_or_struct->as_tree ();
   tree type = TREE_TYPE (datum);
-
-  if (TREE_CODE (type) == POINTER_TYPE)
-    {
-      datum = build1 (INDIRECT_REF, type, datum);
-      if (loc)
-        set_tree_location (datum, loc);
-      type = TREE_TYPE (type);
-    }
+  gcc_assert (TREE_CODE (type) != POINTER_TYPE);
 
   tree component = get_identifier (fieldname);
   tree field = get_field (type, component);
   if (!field)
     {
-      // FIXME: field not found
+      add_error ("field not found: \"%s\"", fieldname);
       return NULL;
     }
   tree ref = build3 (COMPONENT_REF, TREE_TYPE (field), datum,
 		     field, NULL_TREE);
   if (loc)
     set_tree_location (ref, loc);
-  return new lvalue (ref);
+  return ref;
+}
+
+tree
+gcc::jit::context::
+new_dereference (tree ptr,
+		 location *loc)
+{
+  gcc_assert (ptr);
+
+  tree type = TREE_TYPE (TREE_TYPE(ptr));
+  tree datum = build1 (INDIRECT_REF, type, ptr);
+  if (loc)
+    set_tree_location (datum, loc);
+  return datum;
+}
+
+gcc::jit::lvalue *
+gcc::jit::lvalue::
+access_field (location *loc,
+	      const char *fieldname)
+{
+  tree datum = as_tree ();
+  tree ref = get_context ()->new_field_access (loc, datum, fieldname);
+  if (!ref)
+    return NULL;
+  return new lvalue (get_context (), ref);
+}
+
+gcc::jit::rvalue *
+gcc::jit::rvalue::
+access_field (gcc::jit::location *loc,
+	      const char *fieldname)
+{
+  tree datum = as_tree ();
+  tree ref = get_context ()->new_field_access (loc, datum, fieldname);
+  if (!ref)
+    return NULL;
+  return new rvalue (get_context (), ref);
+}
+
+gcc::jit::lvalue *
+gcc::jit::rvalue::
+dereference_field (gcc::jit::location *loc,
+		   const char *fieldname)
+{
+  tree ptr = as_tree ();
+  tree datum = get_context ()->new_dereference (ptr, loc);
+  tree ref = get_context ()->new_field_access (loc, datum, fieldname);
+  if (!ref)
+    return NULL;
+  return new lvalue (get_context (), ref);
+}
+
+gcc::jit::lvalue *
+gcc::jit::rvalue::
+dereference (gcc::jit::location *loc)
+{
+  tree ptr = as_tree ();
+  tree datum = get_context ()->new_dereference (ptr, loc);
+  return new lvalue (get_context (), datum);
 }
 
 void *
@@ -643,7 +809,7 @@  new_local (location *loc,
 			   type->as_tree ());
   if (loc)
     set_tree_location (inner, loc);
-  return new lvalue (inner);
+  return new lvalue (m_ctxt, inner);
 }
 
 gcc::jit::label *
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index 6665e65..e31dbc8 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -97,6 +97,12 @@  public:
   new_string_literal (const char *value);
 
   rvalue *
+  new_unary_op (location *loc,
+		enum gcc_jit_unary_op op,
+		type *result_type,
+		rvalue *a);
+
+  rvalue *
   new_binary_op (location *loc,
 		 enum gcc_jit_binary_op op,
 		 type *result_type,
@@ -117,11 +123,6 @@  public:
 		    rvalue *ptr,
 		    rvalue *index);
 
-  lvalue *
-  new_field_access (location *loc,
-		    rvalue *ptr_or_struct,
-		    const char *fieldname);
-
   void
   set_str_option (enum gcc_jit_str_option opt,
 		  const char *value);
@@ -160,6 +161,17 @@  public:
   void
   set_tree_location (tree t, location *loc);
 
+  tree
+  new_field_access (location *loc,
+		    tree datum,
+		    const char *fieldname);
+
+  tree
+  new_dereference (tree ptr, location *loc);
+
+  tree
+  as_truth_value (tree expr, location *loc);
+
 private:
   source_file *
   get_source_file (const char *filename);
@@ -365,8 +377,9 @@  public: // for now
 class rvalue : public wrapper
 {
 public:
-  rvalue (tree inner)
-    : m_inner(inner)
+  rvalue (context *ctxt, tree inner)
+    : m_ctxt (ctxt),
+      m_inner (inner)
   {}
 
   rvalue *
@@ -374,29 +387,48 @@  public:
 
   tree as_tree () const { return m_inner; }
 
+  context *get_context () const { return m_ctxt; }
+
   type *
   get_type () { return new type (TREE_TYPE (m_inner)); }
 
+  rvalue *
+  access_field (location *loc,
+		const char *fieldname);
+
+  lvalue *
+  dereference_field (location *loc,
+		     const char *fieldname);
+
+  lvalue *
+  dereference (location *loc);
+
 private:
+  context *m_ctxt;
   tree m_inner;
 };
 
 class lvalue : public rvalue
 {
 public:
-  lvalue (tree inner)
-    : rvalue(inner)
+  lvalue (context *ctxt, tree inner)
+    : rvalue(ctxt, inner)
   {}
 
   lvalue *
   as_lvalue () { return this; }
+
+  lvalue *
+  access_field (location *loc,
+		const char *fieldname);
+
 };
 
 class param : public lvalue
 {
 public:
-  param (tree inner)
-    : lvalue(inner)
+  param (context *ctxt, tree inner)
+    : lvalue(ctxt, inner)
   {}
 };
 
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 05afd8e..023c213 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -413,6 +413,21 @@  gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
 }
 
 gcc_jit_rvalue *
+gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
+			      gcc_jit_location *loc,
+			      enum gcc_jit_unary_op op,
+			      gcc_jit_type *result_type,
+			      gcc_jit_rvalue *rvalue)
+{
+  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
+  /* op is checked by the inner function.  */
+  RETURN_NULL_IF_FAIL (result_type, ctxt, "NULL result_type");
+  RETURN_NULL_IF_FAIL (rvalue, ctxt, "NULL rvalue");
+
+  return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue);
+}
+
+gcc_jit_rvalue *
 gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
 			       gcc_jit_location *loc,
 			       enum gcc_jit_binary_op op,
@@ -472,17 +487,46 @@  gcc_jit_context_new_array_lookup (gcc_jit_context *ctxt,
   return (gcc_jit_rvalue *)ctxt->new_array_lookup (loc, ptr, index);
 }
 
-extern gcc_jit_lvalue *
-gcc_jit_context_new_field_access (gcc_jit_context *ctxt,
+gcc_jit_lvalue *
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
+			     gcc_jit_location *loc,
+			     const char *fieldname)
+{
+  RETURN_NULL_IF_FAIL (struct_, NULL, "NULL struct");
+  RETURN_NULL_IF_FAIL (fieldname, NULL, "NULL fieldname");
+
+  return (gcc_jit_lvalue *)struct_->access_field (loc, fieldname);
+}
+
+gcc_jit_rvalue *
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
+			     gcc_jit_location *loc,
+			     const char *fieldname)
+{
+  RETURN_NULL_IF_FAIL (struct_, NULL, "NULL struct");
+  RETURN_NULL_IF_FAIL (fieldname, NULL, "NULL fieldname");
+
+  return (gcc_jit_rvalue *)struct_->access_field (loc, fieldname);
+}
+
+gcc_jit_lvalue *
+gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
 				  gcc_jit_location *loc,
-				  gcc_jit_rvalue *ptr_or_struct,
 				  const char *fieldname)
 {
-  RETURN_NULL_IF_NOT_CALLBACK_CTXT (ctxt);
-  RETURN_NULL_IF_FAIL (ptr_or_struct, ctxt, "NULL ptr_or_struct");
-  RETURN_NULL_IF_FAIL (fieldname, ctxt, "NULL fieldname");
+  RETURN_NULL_IF_FAIL (ptr, NULL, "NULL ptr");
+  RETURN_NULL_IF_FAIL (fieldname, NULL, "NULL fieldname");
+
+  return (gcc_jit_lvalue *)ptr->dereference_field (loc, fieldname);
+}
+
+gcc_jit_lvalue *
+gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
+			    gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (rvalue, NULL, "NULL rvalue");
 
-  return (gcc_jit_lvalue *)ctxt->new_field_access (loc, ptr_or_struct, fieldname);
+  return (gcc_jit_lvalue *)rvalue->dereference (loc);
 }
 
 gcc_jit_lvalue *
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 78d3904..2187ede 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -438,12 +438,85 @@  extern gcc_jit_rvalue *
 gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
 				    const char *value);
 
+enum gcc_jit_unary_op
+{
+  /* Negate an arithmetic value; analogous to:
+       -(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_MINUS,
+
+  /* Bitwise negation of an integer value (one's complement); analogous
+     to:
+       ~(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+
+  /* Logical negation of an arithmetic or pointer value; analogous to:
+       !(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
+			      gcc_jit_location *loc,
+			      enum gcc_jit_unary_op op,
+			      gcc_jit_type *result_type,
+			      gcc_jit_rvalue *rvalue);
 
 enum gcc_jit_binary_op
 {
+  /* Addition of arithmetic values; analogous to:
+       (EXPR_A) + (EXPR_B)
+     in C.
+     For pointer addition, use gcc_jit_context_new_array_lookup.  */
   GCC_JIT_BINARY_OP_PLUS,
+
+  /* Subtraction of arithmetic values; analogous to:
+       (EXPR_A) - (EXPR_B)
+     in C.  */
   GCC_JIT_BINARY_OP_MINUS,
-  GCC_JIT_BINARY_OP_MULT
+
+  /* Multiplication of a pair of arithmetic values; analogous to:
+       (EXPR_A) * (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_MULT,
+
+  /* Quotient of division of arithmetic values; analogous to:
+       (EXPR_A) / (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_DIVIDE,
+  /* do we want separate floor divide vs frac divide? */
+
+  /* Remainder of division of arithmetic values; analogous to:
+       (EXPR_A) / (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_MODULO,
+
+  /* Bitwise AND; analogous to:
+       (EXPR_A) & (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_AND,
+
+  /* Bitwise exclusive OR; analogous to:
+       (EXPR_A) ^ (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_XOR,
+
+  /* Bitwise inclusive OR; analogous to:
+       (EXPR_A) | (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_OR,
+
+  /* Logical AND; analogous to:
+       (EXPR_A) && (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_LOGICAL_AND,
+
+  /* Logical OR; analogous to:
+       (EXPR_A) || (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_LOGICAL_OR
 };
 
 extern gcc_jit_rvalue *
@@ -453,9 +526,27 @@  gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
 			       gcc_jit_type *result_type,
 			       gcc_jit_rvalue *a, gcc_jit_rvalue *b);
 
+/* (Comparisons are treated as separate from "binary_op" to save
+   you having to specify the result_type).  */
+
 enum gcc_jit_comparison
 {
+  /* (EXPR_A) == (EXPR_B).  */
+  GCC_JIT_COMPARISON_EQ,
+
+  /* (EXPR_A) != (EXPR_B).  */
+  GCC_JIT_COMPARISON_NE,
+
+  /* (EXPR_A) < (EXPR_B).  */
   GCC_JIT_COMPARISON_LT,
+
+  /* (EXPR_A) <=(EXPR_B).  */
+  GCC_JIT_COMPARISON_LE,
+
+  /* (EXPR_A) > (EXPR_B).  */
+  GCC_JIT_COMPARISON_GT,
+
+  /* (EXPR_A) >= (EXPR_B).  */
   GCC_JIT_COMPARISON_GE
 };
 
@@ -477,13 +568,39 @@  gcc_jit_context_new_array_lookup (gcc_jit_context *ctxt,
 				  gcc_jit_rvalue *ptr,
 				  gcc_jit_rvalue *index);
 
-/* Field access, either s.field or s->field.  */
+/* Field access is provided separately for both lvalues and rvalues.  */
+
+/* Accessing a field of an lvalue of struct type, analogous to:
+      (EXPR).field = ...;
+   in C.  */
 extern gcc_jit_lvalue *
-gcc_jit_context_new_field_access (gcc_jit_context *ctxt,
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
+			     gcc_jit_location *loc,
+			     const char *fieldname);
+
+/* Accessing a field of an rvalue of struct type, analogous to:
+      (EXPR).field
+   in C.  */
+extern gcc_jit_rvalue *
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
+			     gcc_jit_location *loc,
+			     const char *fieldname);
+
+/* Accessing a field of an rvalue of pointer type, analogous to:
+      (EXPR)->field
+   in C, itself equivalent to (*EXPR).FIELD  */
+extern gcc_jit_lvalue *
+gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
 				  gcc_jit_location *loc,
-				  gcc_jit_rvalue *ptr_or_struct,
 				  const char *fieldname);
 
+/* Dereferencing a pointer; analogous to:
+     *(EXPR)
+*/
+extern gcc_jit_lvalue *
+gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
+			    gcc_jit_location *loc);
+
 extern gcc_jit_lvalue *
 gcc_jit_function_new_local (gcc_jit_function *func,
 			    gcc_jit_location *loc,
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index beaf0de..7700788 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -10,7 +10,6 @@ 
     gcc_jit_context_new_call;
     gcc_jit_context_new_comparison;
     gcc_jit_context_new_field;
-    gcc_jit_context_new_field_access;
     gcc_jit_context_new_function;
     gcc_jit_context_new_global;
     gcc_jit_context_new_location;
@@ -20,6 +19,7 @@ 
     gcc_jit_context_new_rvalue_from_ptr;
     gcc_jit_context_new_string_literal;
     gcc_jit_context_new_struct_type;
+    gcc_jit_context_new_unary_op;
     gcc_jit_context_one;
     gcc_jit_context_release;
     gcc_jit_context_set_bool_option;
@@ -40,10 +40,14 @@ 
     gcc_jit_function_place_forward_label;
     gcc_jit_loop_end;
     gcc_jit_lvalue_as_rvalue;
+    gcc_jit_lvalue_access_field;
     gcc_jit_param_as_lvalue;
     gcc_jit_param_as_rvalue;
     gcc_jit_result_get_code;
     gcc_jit_result_release;
+    gcc_jit_rvalue_access_field;
+    gcc_jit_rvalue_dereference;
+    gcc_jit_rvalue_dereference_field;
     gcc_jit_type_get_const;
     gcc_jit_type_get_pointer;
 
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index b23c8fc..987353d 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,5 +1,13 @@ 
 2013-10-18  David Malcolm  <dmalcolm@redhat.com>
 
+	* jit.dg/test-expressions.c: New.
+	* jit.dg/test-combination.c: Add usage of test-expressions.c
+	* jit.dg/test-accessing-struct.c (code_making_callback): Update
+	for changes to field-access API.
+	* jit.dg/test-types.c (code_making_callback): Likewise.
+
+2013-10-18  David Malcolm  <dmalcolm@redhat.com>
+
 	* jit.dg/test-null-passed-to-api.c: New.
 
 2013-10-17  David Malcolm  <dmalcolm@redhat.com>
diff --git a/gcc/testsuite/jit.dg/test-accessing-struct.c b/gcc/testsuite/jit.dg/test-accessing-struct.c
index 46f112a..4e197c5 100644
--- a/gcc/testsuite/jit.dg/test-accessing-struct.c
+++ b/gcc/testsuite/jit.dg/test-accessing-struct.c
@@ -64,23 +64,23 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
       GCC_JIT_BINARY_OP_MULT,
       int_type,
       gcc_jit_lvalue_as_rvalue (
-        gcc_jit_context_new_field_access (
-          ctxt, NULL,
-          gcc_jit_param_as_rvalue (param_f),
-          "x")),
+	gcc_jit_rvalue_dereference_field (
+	  gcc_jit_param_as_rvalue (param_f),
+	  NULL,
+	  "x")),
       gcc_jit_lvalue_as_rvalue (
-        gcc_jit_context_new_field_access (
-          ctxt, NULL,
-          gcc_jit_param_as_rvalue (param_f),
-          "y")));
+	gcc_jit_rvalue_dereference_field (
+	gcc_jit_param_as_rvalue (param_f),
+	NULL,
+	"y")));
 
   /* f->z = ... */
   gcc_jit_function_add_assignment (
     test_fn,
     NULL,
-    gcc_jit_context_new_field_access (
-      ctxt, NULL,
+    gcc_jit_rvalue_dereference_field (
       gcc_jit_param_as_rvalue (param_f),
+      NULL,
       "z"),
     sum);
 
diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c
index 2bf7124..3338d94 100644
--- a/gcc/testsuite/jit.dg/test-combination.c
+++ b/gcc/testsuite/jit.dg/test-combination.c
@@ -28,6 +28,13 @@ 
 #undef code_making_callback
 #undef verify_code
 
+/* test-expressions.c */
+#define code_making_callback code_making_callback_expressions
+#define verify_code verify_code_expressions
+#include "test-expressions.c"
+#undef code_making_callback
+#undef verify_code
+
 /* test-factorial.c */
 #define code_making_callback code_making_callback_factorial
 #define verify_code verify_code_factorial
@@ -95,6 +102,7 @@  code_making_callback (gcc_jit_context *ctxt, void * user_data)
   errors += code_making_callback_accessing_struct (ctxt, user_data);
   errors += code_making_callback_calling_external_function (ctxt, user_data);
   errors += code_making_callback_dot_product (ctxt, user_data);
+  errors += code_making_callback_expressions (ctxt, user_data);
   errors += code_making_callback_factorial (ctxt, user_data);
   errors += code_making_callback_fibonacci (ctxt, user_data);
   errors += code_making_callback_hello_world (ctxt, user_data);
@@ -112,6 +120,7 @@  verify_code (gcc_jit_result *result)
   verify_code_accessing_struct (result);
   verify_code_calling_external_function (result);
   verify_code_dot_product (result);
+  verify_code_expressions (result);
   verify_code_factorial (result);
   verify_code_fibonacci (result);
   verify_code_hello_world (result);
diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c
new file mode 100644
index 0000000..91103f8
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-expressions.c
@@ -0,0 +1,518 @@ 
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/**********************************************************************
+ Unary ops
+ **********************************************************************/
+
+static void
+make_test_of_unary_op (gcc_jit_context *ctxt,
+		       gcc_jit_type *type,
+		       enum gcc_jit_unary_op op,
+		       const char *funcname)
+{
+  /* Make a test function of the form:
+       T test_unary_op (T a)
+       {
+	  return OP a;
+       }
+  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, type, "a");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  type,
+				  funcname,
+				  1, &param_a,
+				  0);
+  gcc_jit_function_add_return (
+    test_fn,
+    NULL,
+    gcc_jit_context_new_unary_op (
+      ctxt,
+      NULL,
+      op,
+      type,
+      gcc_jit_param_as_rvalue (param_a)));
+}
+
+
+static void
+make_tests_of_unary_ops (gcc_jit_context *ctxt)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  make_test_of_unary_op (ctxt,
+			 int_type,
+			 GCC_JIT_UNARY_OP_MINUS,
+			 "test_UNARY_OP_MINUS_on_int");
+  make_test_of_unary_op (ctxt,
+			 int_type,
+			 GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+			 "test_UNARY_OP_BITWISE_NEGATE_on_int");
+  make_test_of_unary_op (ctxt,
+			 int_type,
+			 GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
+			 "test_UNARY_OP_LOGICAL_NEGATE_on_int");
+}
+
+static void
+verify_unary_ops (gcc_jit_result *result)
+{
+  typedef int (*test_fn) (int);
+
+  test_fn test_UNARY_OP_MINUS_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_UNARY_OP_MINUS_on_int");
+  CHECK_NON_NULL (test_UNARY_OP_MINUS_on_int);
+  CHECK_VALUE (test_UNARY_OP_MINUS_on_int (0), 0);
+  CHECK_VALUE (test_UNARY_OP_MINUS_on_int (42), -42);
+  CHECK_VALUE (test_UNARY_OP_MINUS_on_int (-5), 5);
+
+  test_fn test_UNARY_OP_BITWISE_NEGATE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_UNARY_OP_BITWISE_NEGATE_on_int");
+  CHECK_NON_NULL (test_UNARY_OP_BITWISE_NEGATE_on_int);
+  CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (0), ~0);
+  CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (42), ~42);
+  CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (-5), ~-5);
+
+  test_fn test_UNARY_OP_LOGICAL_NEGATE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_UNARY_OP_LOGICAL_NEGATE_on_int");
+  CHECK_NON_NULL (test_UNARY_OP_LOGICAL_NEGATE_on_int);
+  CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (0), 1);
+  CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (42), 0);
+  CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (-5), 0);
+
+}
+
+/**********************************************************************
+ Binary ops
+ **********************************************************************/
+
+static void
+make_test_of_binary_op (gcc_jit_context *ctxt,
+			gcc_jit_type *type,
+			enum gcc_jit_binary_op op,
+			const char *funcname)
+{
+  /* Make a test function of the form:
+       T test_binary_op (T a, T b)
+       {
+	  return a OP b;
+       }
+  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, type, "b");
+  gcc_jit_param *params[] = {param_a, param_b};
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  type,
+				  funcname,
+				  2, params,
+				  0);
+  gcc_jit_function_add_return (
+    test_fn,
+    NULL,
+    gcc_jit_context_new_binary_op (
+      ctxt,
+      NULL,
+      op,
+      type,
+      gcc_jit_param_as_rvalue (param_a),
+      gcc_jit_param_as_rvalue (param_b)));
+}
+
+
+static void
+make_tests_of_binary_ops (gcc_jit_context *ctxt)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Test binary ops.  */
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_PLUS,
+			  "test_BINARY_OP_PLUS_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_MINUS,
+			  "test_BINARY_OP_MINUS_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_MULT,
+			  "test_BINARY_OP_MULT_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_DIVIDE,
+			  "test_BINARY_OP_DIVIDE_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_MODULO,
+			  "test_BINARY_OP_MODULO_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_BITWISE_AND,
+			  "test_BINARY_OP_BITWISE_AND_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_BITWISE_XOR,
+			  "test_BINARY_OP_BITWISE_XOR_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_BITWISE_OR,
+			  "test_BINARY_OP_BITWISE_OR_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_LOGICAL_AND,
+			  "test_BINARY_OP_LOGICAL_AND_on_int");
+  make_test_of_binary_op (ctxt,
+			  int_type,
+			  GCC_JIT_BINARY_OP_LOGICAL_OR,
+			  "test_BINARY_OP_LOGICAL_OR_on_int");
+}
+
+static void
+verify_binary_ops (gcc_jit_result *result)
+{
+  typedef int (*test_fn) (int, int);
+
+  test_fn test_BINARY_OP_PLUS_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_PLUS_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_PLUS_on_int);
+  CHECK_VALUE (test_BINARY_OP_PLUS_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_PLUS_on_int (1, 2), 3);
+  CHECK_VALUE (test_BINARY_OP_PLUS_on_int (100, -1), 99);
+  CHECK_VALUE (test_BINARY_OP_PLUS_on_int (-1, -4), -5);
+
+  test_fn test_BINARY_OP_MINUS_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_MINUS_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_MINUS_on_int);
+  CHECK_VALUE (test_BINARY_OP_MINUS_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_MINUS_on_int (1, 2), -1);
+  CHECK_VALUE (test_BINARY_OP_MINUS_on_int (100, -1), 101);
+  CHECK_VALUE (test_BINARY_OP_MINUS_on_int (-1, -4), 3);
+
+  test_fn test_BINARY_OP_MULT_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_MULT_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_MULT_on_int);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (1, 2), 2);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (100, -1), -100);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (-1, -4), 4);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (7, 10), 70);
+
+  test_fn test_BINARY_OP_DIVIDE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_DIVIDE_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_DIVIDE_on_int);
+  CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (7, 2), 3);
+  CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (100, -1), (100 / -1));
+  CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (-1, -4), (-1 / -4));
+  CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (60, 5), 12);
+
+  test_fn test_BINARY_OP_MODULO_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_MODULO_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_MODULO_on_int);
+  CHECK_VALUE (test_BINARY_OP_MODULO_on_int (7, 2), 1);
+  CHECK_VALUE (test_BINARY_OP_MODULO_on_int (100, -1), (100 % -1));
+  CHECK_VALUE (test_BINARY_OP_MODULO_on_int (-1, -4), (-1 % -4));
+  CHECK_VALUE (test_BINARY_OP_MODULO_on_int (60, 5), 0);
+
+  test_fn test_BINARY_OP_BITWISE_AND_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_BITWISE_AND_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_BITWISE_AND_on_int);
+  CHECK_VALUE (test_BINARY_OP_BITWISE_AND_on_int (0xf0f0, 0x7777), 0x7070);
+
+  test_fn test_BINARY_OP_BITWISE_XOR_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_BITWISE_XOR_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_BITWISE_XOR_on_int);
+  CHECK_VALUE (test_BINARY_OP_BITWISE_XOR_on_int (0xf0f0, 0x7777), 0x8787);
+
+  test_fn test_BINARY_OP_BITWISE_OR_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_BITWISE_OR_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_BITWISE_OR_on_int);
+  CHECK_VALUE (test_BINARY_OP_BITWISE_OR_on_int (0xf0f0, 0x7777), 0xf7f7);
+
+  test_fn test_BINARY_OP_LOGICAL_AND_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_LOGICAL_AND_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_LOGICAL_AND_on_int);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (42, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (0, -13), 0);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (1997, 1998), 1);
+
+  test_fn test_BINARY_OP_LOGICAL_OR_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_BINARY_OP_LOGICAL_OR_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_LOGICAL_OR_on_int);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (42, 0), 1);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (0, -13), 1);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (1997, 1998), 1);
+}
+
+/**********************************************************************
+ Comparisons
+ **********************************************************************/
+
+static void
+make_test_of_comparison (gcc_jit_context *ctxt,
+			 gcc_jit_type *type,
+			 enum gcc_jit_comparison op,
+			 const char *funcname)
+{
+  /* Make a test function of the form:
+       T test_comparison_op (T a, T b)
+       {
+	  return a OP b;
+       }
+  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, type, "b");
+  gcc_jit_param *params[] = {param_a, param_b};
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  type,
+				  funcname,
+				  2, params,
+				  0);
+  gcc_jit_function_add_return (
+    test_fn,
+    NULL,
+    gcc_jit_context_new_comparison (
+      ctxt,
+      NULL,
+      op,
+      gcc_jit_param_as_rvalue (param_a),
+      gcc_jit_param_as_rvalue (param_b)));
+}
+
+static void
+make_tests_of_comparisons (gcc_jit_context *ctxt)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  make_test_of_comparison (ctxt,
+			   int_type,
+			   GCC_JIT_COMPARISON_EQ,
+			   "test_COMPARISON_EQ_on_int");
+  make_test_of_comparison (ctxt,
+			   int_type,
+			   GCC_JIT_COMPARISON_NE,
+			   "test_COMPARISON_NE_on_int");
+  make_test_of_comparison (ctxt,
+			   int_type,
+			   GCC_JIT_COMPARISON_LT,
+			   "test_COMPARISON_LT_on_int");
+  make_test_of_comparison (ctxt,
+			   int_type,
+			   GCC_JIT_COMPARISON_LE,
+			   "test_COMPARISON_LE_on_int");
+  make_test_of_comparison (ctxt,
+			   int_type,
+			   GCC_JIT_COMPARISON_GT,
+			   "test_COMPARISON_GT_on_int");
+  make_test_of_comparison (ctxt,
+			   int_type,
+			   GCC_JIT_COMPARISON_GE,
+			   "test_COMPARISON_GE_on_int");
+}
+
+static void
+verify_comparisons (gcc_jit_result *result)
+{
+  typedef int (*test_fn) (int, int);
+
+  test_fn test_COMPARISON_EQ_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_COMPARISON_EQ_on_int");
+  CHECK_NON_NULL (test_COMPARISON_EQ_on_int);
+  CHECK_VALUE (test_COMPARISON_EQ_on_int (0, 0), 1);
+  CHECK_VALUE (test_COMPARISON_EQ_on_int (1, 2), 0);
+
+  test_fn test_COMPARISON_NE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_COMPARISON_NE_on_int");
+  CHECK_NON_NULL (test_COMPARISON_NE_on_int);
+  CHECK_VALUE (test_COMPARISON_NE_on_int (0, 0), 0);
+  CHECK_VALUE (test_COMPARISON_NE_on_int (1, 2), 1);
+
+  test_fn test_COMPARISON_LT_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_COMPARISON_LT_on_int");
+  CHECK_NON_NULL (test_COMPARISON_LT_on_int);
+  CHECK_VALUE (test_COMPARISON_LT_on_int (0, 0), 0);
+  CHECK_VALUE (test_COMPARISON_LT_on_int (1, 2), 1);
+  CHECK_VALUE (test_COMPARISON_LT_on_int (2, 1), 0);
+  CHECK_VALUE (test_COMPARISON_LT_on_int (-2, 1), 1);
+
+  test_fn test_COMPARISON_LE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_COMPARISON_LE_on_int");
+  CHECK_NON_NULL (test_COMPARISON_LE_on_int);
+  CHECK_VALUE (test_COMPARISON_LE_on_int (0, 0), 1);
+  CHECK_VALUE (test_COMPARISON_LE_on_int (1, 2), 1);
+  CHECK_VALUE (test_COMPARISON_LE_on_int (2, 1), 0);
+
+  test_fn test_COMPARISON_GT_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_COMPARISON_GT_on_int");
+  CHECK_NON_NULL (test_COMPARISON_GT_on_int);
+  CHECK_VALUE (test_COMPARISON_GT_on_int (0, 0), 0);
+  CHECK_VALUE (test_COMPARISON_GT_on_int (1, 2), 0);
+  CHECK_VALUE (test_COMPARISON_GT_on_int (2, 1), 1);
+
+  test_fn test_COMPARISON_GE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+				      "test_COMPARISON_GE_on_int");
+  CHECK_NON_NULL (test_COMPARISON_GE_on_int);
+  CHECK_VALUE (test_COMPARISON_GE_on_int (0, 0), 1);
+  CHECK_VALUE (test_COMPARISON_GE_on_int (1, 2), 0);
+  CHECK_VALUE (test_COMPARISON_GE_on_int (2, 1), 1);
+}
+
+/**********************************************************************
+ Dereferences
+ **********************************************************************/
+
+static void
+make_tests_of_dereferences (gcc_jit_context *ctxt)
+{
+  /*
+       int test_dereference_read (int *ptr)
+       {
+	 return *ptr;
+       }
+       void test_dereference_write (int *ptr, int i)
+       {
+	 *ptr = i;
+       }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *int_ptr_type =
+    gcc_jit_type_get_pointer (int_type);
+  {
+    gcc_jit_param *param_ptr =
+      gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ptr");
+    gcc_jit_function *test_dereference_read =
+      gcc_jit_context_new_function (ctxt, NULL,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    int_type,
+				    "test_dereference_read",
+				    1, &param_ptr,
+				    0);
+    gcc_jit_function_add_return (
+      test_dereference_read,
+      NULL,
+      gcc_jit_lvalue_as_rvalue (
+	gcc_jit_rvalue_dereference (
+	  gcc_jit_param_as_rvalue (param_ptr),
+	  NULL)));
+  }
+
+  {
+    gcc_jit_param *param_ptr =
+      gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ptr");
+    gcc_jit_param *param_i =
+      gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+    gcc_jit_param *params[] = {param_ptr, param_i};
+    gcc_jit_function *test_dereference_write =
+      gcc_jit_context_new_function (ctxt, NULL,
+				    GCC_JIT_FUNCTION_EXPORTED,
+				    void_type,
+				    "test_dereference_write",
+				    2, params,
+				    0);
+    gcc_jit_function_add_assignment (
+      test_dereference_write,
+      NULL,
+      gcc_jit_rvalue_dereference (
+	gcc_jit_param_as_rvalue (param_ptr),
+	NULL),
+      gcc_jit_param_as_rvalue (param_i));
+  }
+}
+
+static void
+verify_dereferences (gcc_jit_result *result)
+{
+  int a = 42;
+  int b = -99;
+
+  {
+    typedef int (*test_read) (int *);
+    test_read test_dereference_read =
+      (test_read)gcc_jit_result_get_code (result,
+					  "test_dereference_read");
+    CHECK_NON_NULL (test_dereference_read);
+    CHECK_VALUE (test_dereference_read (&a), 42);
+    CHECK_VALUE (test_dereference_read (&b), -99);
+  }
+
+ {
+    typedef void (*test_write) (int *, int);
+    test_write test_dereference_write =
+      (test_write)gcc_jit_result_get_code (result,
+					  "test_dereference_write");
+    CHECK_NON_NULL (test_dereference_write);
+    test_dereference_write (&a, -55);
+    CHECK_VALUE (a, -55);
+
+    test_dereference_write (&b, 404);
+    CHECK_VALUE (b, 404);
+  }
+}
+
+/**********************************************************************
+ Code for harness
+ **********************************************************************/
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  make_tests_of_unary_ops (ctxt);
+  make_tests_of_binary_ops (ctxt);
+  make_tests_of_comparisons (ctxt);
+  make_tests_of_dereferences (ctxt);
+
+  return 0;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  verify_unary_ops (result);
+  verify_binary_ops (result);
+  verify_comparisons (result);
+  verify_dereferences (result);
+}
diff --git a/gcc/testsuite/jit.dg/test-types.c b/gcc/testsuite/jit.dg/test-types.c
index 4c30547..819c40a 100644
--- a/gcc/testsuite/jit.dg/test-types.c
+++ b/gcc/testsuite/jit.dg/test-types.c
@@ -128,9 +128,9 @@  code_making_callback (gcc_jit_context *ctxt, void *user_data)
 #define ASSIGN(FIELDNAME, EXPR) \
   gcc_jit_function_add_assignment (		\
     test_fn, NULL,				\
-    gcc_jit_context_new_field_access (		\
-      ctxt, NULL,				\
+    gcc_jit_rvalue_dereference_field (		\
       gcc_jit_param_as_rvalue (param_z),	\
+      NULL,					\
       (FIELDNAME)),				\
     (EXPR));