GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>.
Java and all Java-based marks are trademarks or registered trademarks
of Sun Microsystems, Inc. in the United States and other countries.
static int
type_assertion_eq (const void * k1_p, const void * k2_p)
{
- type_assertion k1 = *(type_assertion *)k1_p;
- type_assertion k2 = *(type_assertion *)k2_p;
+ const type_assertion k1 = *(const type_assertion *)k1_p;
+ const type_assertion k2 = *(const type_assertion *)k2_p;
return (k1.assertion_code == k2.assertion_code
&& k1.op1 == k2.op1
&& k1.op2 == k2.op2);
{
tree call;
- call = build3 (CALL_EXPR,
- void_type_node,
- build_address_of (throw_node),
- build_tree_list (NULL_TREE, node),
- NULL_TREE);
+ call = build_call_nary (void_type_node,
+ build_address_of (throw_node),
+ 1, node);
TREE_SIDE_EFFECTS (call) = 1;
java_add_stmt (call);
java_stack_pop (stack_pointer);
static tree
build_java_throw_out_of_bounds_exception (tree index)
{
- tree node = build3 (CALL_EXPR, int_type_node,
- build_address_of (soft_badarrayindex_node),
- build_tree_list (NULL_TREE, index), NULL_TREE);
+ tree node = build_call_nary (int_type_node,
+ build_address_of (soft_badarrayindex_node),
+ 1, index);
TREE_SIDE_EFFECTS (node) = 1; /* Allows expansion within ANDIF */
return (node);
}
expr = build3 (COND_EXPR, TREE_TYPE (expr),
build2 (EQ_EXPR, boolean_type_node,
expr, null_pointer_node),
- build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_nullpointer_node),
- NULL_TREE, NULL_TREE),
+ build_call_nary (void_type_node,
+ build_address_of (soft_nullpointer_node),
+ 0),
expr);
}
/* Multiply the index by the size of an element to obtain a byte
offset. Convert the result to a pointer to the element type. */
- index = fold_convert (TREE_TYPE (node),
- build2 (MULT_EXPR, sizetype,
- fold_convert (sizetype, index),
- size_exp));
+ index = build2 (MULT_EXPR, sizetype,
+ fold_convert (sizetype, index),
+ size_exp);
/* Sum the byte offset and the address of the data field. */
- node = fold_build2 (PLUS_EXPR, TREE_TYPE (node), node, index);
+ node = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (node), node, index);
/* Finally, return
}
/* Build an invocation of _Jv_CheckArrayStore */
- check = build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_checkarraystore_node),
- tree_cons (NULL_TREE, array,
- build_tree_list (NULL_TREE, object)),
- NULL_TREE);
+ check = build_call_nary (void_type_node,
+ build_address_of (soft_checkarraystore_node),
+ 2, array, object);
TREE_SIDE_EFFECTS (check) = 1;
return check;
some work. */
type_arg = build_class_ref (prim_type);
- return build3 (CALL_EXPR, promote_type (type),
- build_address_of (soft_newarray_node),
- tree_cons (NULL_TREE,
- type_arg,
- build_tree_list (NULL_TREE, length)),
- NULL_TREE);
+ return build_call_nary (promote_type (type),
+ build_address_of (soft_newarray_node),
+ 2, type_arg, length);
}
/* Generates anewarray from a given CLASS_TYPE. Gets from the stack the size
host_integerp (length, 0)
? tree_low_cst (length, 0) : -1);
- return build3 (CALL_EXPR, promote_type (type),
- build_address_of (soft_anewarray_node),
- tree_cons (NULL_TREE, length,
- tree_cons (NULL_TREE, build_class_ref (class_type),
- build_tree_list (NULL_TREE,
- null_pointer_node))),
- NULL_TREE);
+ return build_call_nary (promote_type (type),
+ build_address_of (soft_anewarray_node),
+ 3,
+ length,
+ build_class_ref (class_type),
+ null_pointer_node);
}
/* Return a node the evaluates 'new TYPE[LENGTH]'. */
for( i = 0; i < ndim; i++ )
args = tree_cons (NULL_TREE, pop_value (int_type_node), args);
- push_value (build3 (CALL_EXPR,
- promote_type (class_type),
- build_address_of (soft_multianewarray_node),
- tree_cons (NULL_TREE, build_class_ref (class_type),
- tree_cons (NULL_TREE,
- build_int_cst (NULL_TREE, ndim),
- args)),
- NULL_TREE));
+ args = tree_cons (NULL_TREE,
+ build_class_ref (class_type),
+ tree_cons (NULL_TREE,
+ build_int_cst (NULL_TREE, ndim),
+ args));
+
+ push_value (build_call_list (promote_type (class_type),
+ build_address_of (soft_multianewarray_node),
+ args));
}
/* ARRAY[INDEX] <- RHS. build_java_check_indexed_type makes sure that
static tree
build_java_monitor (tree call, tree object)
{
- return build3 (CALL_EXPR,
- void_type_node,
- build_address_of (call),
- build_tree_list (NULL_TREE, object),
- NULL_TREE);
+ return build_call_nary (void_type_node,
+ build_address_of (call),
+ 1, object);
}
/* Emit code for one of the PUSHC instructions. */
retval = build1(NOP_EXPR, TREE_TYPE(res), retval);
TREE_SIDE_EFFECTS (retval) = 1;
- java_add_stmt (build1 (RETURN_EXPR, TREE_TYPE (retval), retval));
+ java_add_stmt (build1 (RETURN_EXPR, void_type_node, retval));
}
}
? alloc_object_node
: alloc_no_finalizer_node);
- return build3 (CALL_EXPR, promote_type (type),
- build_address_of (alloc_node),
- build_tree_list (NULL_TREE, build_class_ref (type)),
- NULL_TREE);
+ return build_call_nary (promote_type (type),
+ build_address_of (alloc_node),
+ 1, build_class_ref (type));
}
static void
if (! CLASS_LOADED_P (type))
load_class (type, 1);
safe_layout_class (type);
- push_value (build3 (CALL_EXPR, promote_type (type),
- build_address_of (alloc_node),
- build_tree_list (NULL_TREE, build_class_ref (type)),
- NULL_TREE));
+ push_value (build_call_nary (promote_type (type),
+ build_address_of (alloc_node),
+ 1, build_class_ref (type)));
}
/* This returns an expression which will extract the class of an
}
else
{
- expr = build3 (CALL_EXPR, itype,
- build_address_of (soft_instanceof_node),
- tree_cons (NULL_TREE, value,
- build_tree_list (NULL_TREE,
- build_class_ref (type))),
- NULL_TREE);
+ expr = build_call_nary (itype,
+ build_address_of (soft_instanceof_node),
+ 2, value, build_class_ref (type));
}
TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (value);
return expr;
expand_java_CHECKCAST (tree type)
{
tree value = pop_value (ptr_type_node);
- value = build3 (CALL_EXPR, promote_type (type),
- build_address_of (soft_checkcast_node),
- tree_cons (NULL_TREE, build_class_ref (type),
- build_tree_list (NULL_TREE, value)),
- NULL_TREE);
+ value = build_call_nary (promote_type (type),
+ build_address_of (soft_checkcast_node),
+ 2, build_class_ref (type), value);
push_value (value);
}
}
gcc_assert (call);
- call = build3 (CALL_EXPR, type,
- build_address_of (call),
- tree_cons (NULL_TREE, arg1,
- build_tree_list (NULL_TREE, arg2)),
- NULL_TREE);
-
+ call = build_call_nary (type, build_address_of (call), 2, arg1, arg2);
return call;
}
{
case URSHIFT_EXPR:
{
- tree u_type = java_unsigned_type (type);
+ tree u_type = unsigned_type_for (type);
arg1 = convert (u_type, arg1);
arg1 = build_java_binop (RSHIFT_EXPR, u_type, arg1, arg2);
return convert (type, arg1);
arg1 = convert (double_type_node, arg1);
arg2 = convert (double_type_node, arg2);
}
- call = build3 (CALL_EXPR, double_type_node,
- build_address_of (soft_fmod_node),
- tree_cons (NULL_TREE, arg1,
- build_tree_list (NULL_TREE, arg2)),
- NULL_TREE);
+ call = build_call_nary (double_type_node,
+ build_address_of (soft_fmod_node),
+ 2, arg1, arg2);
if (type != double_type_node)
call = convert (type, call);
return call;
= build3 (COND_EXPR, TREE_TYPE (field_offset),
build2 (EQ_EXPR, boolean_type_node,
field_offset, integer_zero_node),
- build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_nosuchfield_node),
- build_tree_list (NULL_TREE, otable_index),
- NULL_TREE),
+ build_call_nary (void_type_node,
+ build_address_of (soft_nosuchfield_node),
+ 1, otable_index),
field_offset);
field_offset = fold (convert (sizetype, field_offset));
self_value = java_check_reference (self_value, check);
address
- = fold_build2 (PLUS_EXPR,
- build_pointer_type (TREE_TYPE (field_decl)),
+ = fold_build2 (POINTER_PLUS_EXPR,
+ TREE_TYPE (self_value),
self_value, field_offset);
+ address = fold_convert (build_pointer_type (TREE_TYPE (field_decl)),
+ address);
return fold_build1 (INDIRECT_REF, TREE_TYPE (field_decl), address);
}
{
/* The type of the address of a label is return_address_type_node. */
tree decl = create_label_decl (name);
- LABEL_PC (decl) = pc;
return pushdecl (decl);
}
}
return decl;
}
-/* This maps a bytecode offset (PC) to various flags. */
+/* This maps a bytecode offset (PC) to various flags. */
char *instruction_bits;
+/* This is a vector of type states for the current method. It is
+ indexed by PC. Each element is a tree vector holding the type
+ state at that PC. We only note type states at basic block
+ boundaries. */
+VEC(tree, gc) *type_states;
+
static void
note_label (int current_pc ATTRIBUTE_UNUSED, int target_pc)
{
if (always_initialize_class_p)
{
- init = build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_initclass_node),
- build_tree_list (NULL_TREE, build_class_ref (clas)),
- NULL_TREE);
+ init = build_call_nary (void_type_node,
+ build_address_of (soft_initclass_node),
+ 1, build_class_ref (clas));
TREE_SIDE_EFFECTS (init) = 1;
}
else
*init_test_decl = decl;
}
- init = build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_initclass_node),
- build_tree_list (NULL_TREE, build_class_ref (clas)),
- NULL_TREE);
+ init = build_call_nary (void_type_node,
+ build_address_of (soft_initclass_node),
+ 1, build_class_ref (clas));
TREE_SIDE_EFFECTS (init) = 1;
init = build3 (COND_EXPR, void_type_node,
build2 (EQ_EXPR, boolean_type_node,
rewrite_arglist_getcaller (tree arglist)
{
tree retaddr
- = (build_function_call_expr
- (built_in_decls[BUILT_IN_RETURN_ADDRESS],
- build_tree_list (NULL_TREE, integer_zero_node)));
+ = build_call_expr (built_in_decls[BUILT_IN_RETURN_ADDRESS],
+ 1, integer_zero_node);
DECL_INLINE (current_function_decl) = 0;
{NULL, NULL, NULL, NULL, 0, NULL}};
+/* True if this method is special, i.e. it's a private method that
+ should be exported from a DSO. */
+
+bool
+special_method_p (tree candidate_method)
+{
+ tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (candidate_method)));
+ tree method = DECL_NAME (candidate_method);
+ rewrite_rule *p;
+
+ for (p = rules; p->classname; p++)
+ {
+ if (get_identifier (p->classname) == context
+ && get_identifier (p->method) == method)
+ return true;
+ }
+ return false;
+}
+
/* Scan the rules list for replacements for *METHOD_P and replace the
args accordingly. If the rewrite results in an access to a private
method, update SPECIAL.*/
method_index++;
}
method_index *= int_size_in_bytes (method_type_node);
- ref = fold_build2 (PLUS_EXPR, method_ptr_type_node,
- ref, build_int_cst (NULL_TREE, method_index));
+ ref = fold_build2 (POINTER_PLUS_EXPR, method_ptr_type_node,
+ ref, size_int (method_index));
ref = build1 (INDIRECT_REF, method_type_node, ref);
func = build3 (COMPONENT_REF, nativecode_ptr_type_node,
ref, lookup_field (&method_type_node, ncode_ident),
size_int (TARGET_VTABLE_USES_DESCRIPTORS));
}
- func = fold_build2 (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable,
- convert (nativecode_ptr_ptr_type_node, method_index));
+ func = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dtable), dtable,
+ convert (sizetype, method_index));
if (TARGET_VTABLE_USES_DESCRIPTORS)
func = build1 (NOP_EXPR, nativecode_ptr_type_node, func);
else
- func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
+ {
+ func = fold_convert (nativecode_ptr_ptr_type_node, func);
+ func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
+ }
return func;
}
tree
build_invokeinterface (tree dtable, tree method)
{
- tree lookup_arg;
tree interface;
tree idx;
interface = build_class_ref (interface);
}
- lookup_arg = tree_cons (NULL_TREE, dtable,
- tree_cons (NULL_TREE, interface,
- build_tree_list (NULL_TREE, idx)));
-
- return build3 (CALL_EXPR, ptr_type_node,
- build_address_of (soft_lookupinterfacemethod_node),
- lookup_arg, NULL_TREE);
+ return build_call_nary (ptr_type_node,
+ build_address_of (soft_lookupinterfacemethod_node),
+ 3, dtable, interface, idx);
}
/* Expand one of the invoke_* opcodes.
else
func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
- call = build3 (CALL_EXPR, TREE_TYPE (method_type),
- func, arg_list, NULL_TREE);
+ call = build_call_list (TREE_TYPE (method_type), func, arg_list);
TREE_SIDE_EFFECTS (call) = 1;
call = check_for_builtin (method, call);
tree
build_jni_stub (tree method)
{
- tree jnifunc, call, args, body, lookup_arg, method_sig, arg_types;
+ tree jnifunc, call, args, body, method_sig, arg_types;
+ tree jniarg0, jniarg1, jniarg2, jniarg3;
tree jni_func_type, tem;
tree env_var, res_var = NULL_TREE, block;
tree method_args, res_type;
/* Compute the local `env' by calling _Jv_GetJNIEnvNewFrame. */
body = build2 (MODIFY_EXPR, ptr_type_node, env_var,
- build3 (CALL_EXPR, ptr_type_node,
- build_address_of (soft_getjnienvnewframe_node),
- build_tree_list (NULL_TREE, klass),
- NULL_TREE));
+ build_call_nary (ptr_type_node,
+ build_address_of (soft_getjnienvnewframe_node),
+ 1, klass));
CAN_COMPLETE_NORMALLY (body) = 1;
/* All the arguments to this method become arguments to the
/* We call _Jv_LookupJNIMethod to find the actual underlying
function pointer. _Jv_LookupJNIMethod will throw the appropriate
exception if this function is not found at runtime. */
- tem = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, args_size));
method_sig = build_java_signature (TREE_TYPE (method));
- lookup_arg = tree_cons (NULL_TREE,
- build_utf8_ref (unmangle_classname
- (IDENTIFIER_POINTER (method_sig),
- IDENTIFIER_LENGTH (method_sig))),
- tem);
- tem = DECL_NAME (method);
- lookup_arg
- = tree_cons (NULL_TREE, klass,
- tree_cons (NULL_TREE, build_utf8_ref (tem), lookup_arg));
-
+ jniarg0 = klass;
+ jniarg1 = build_utf8_ref (DECL_NAME (method));
+ jniarg2 = build_utf8_ref (unmangle_classname
+ (IDENTIFIER_POINTER (method_sig),
+ IDENTIFIER_LENGTH (method_sig)));
+ jniarg3 = build_int_cst (NULL_TREE, args_size);
+
tem = build_function_type (TREE_TYPE (TREE_TYPE (method)), arg_types);
#ifdef MODIFY_JNI_METHOD_CALL
jni_func_type = build_pointer_type (tem);
jnifunc = build3 (COND_EXPR, ptr_type_node,
- meth_var, meth_var,
+ build2 (NE_EXPR, boolean_type_node,
+ meth_var, build_int_cst (TREE_TYPE (meth_var), 0)),
+ meth_var,
build2 (MODIFY_EXPR, ptr_type_node, meth_var,
- build3 (CALL_EXPR, ptr_type_node,
- build_address_of
- (soft_lookupjnimethod_node),
- lookup_arg, NULL_TREE)));
+ build_call_nary (ptr_type_node,
+ build_address_of
+ (soft_lookupjnimethod_node),
+ 4,
+ jniarg0, jniarg1,
+ jniarg2, jniarg3)));
/* Now we make the actual JNI call via the resulting function
pointer. */
- call = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (method)),
- build1 (NOP_EXPR, jni_func_type, jnifunc),
- args, NULL_TREE);
+ call = build_call_list (TREE_TYPE (TREE_TYPE (method)),
+ build1 (NOP_EXPR, jni_func_type, jnifunc),
+ args);
/* If the JNI call returned a result, capture it here. If we had to
unwrap JNI object results, we would do that here. */
/* If the call returns an object, it may return a JNI weak
reference, in which case we must unwrap it. */
if (! JPRIMITIVE_TYPE_P (TREE_TYPE (TREE_TYPE (method))))
- call = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (method)),
- build_address_of (soft_unwrapjni_node),
- build_tree_list (NULL_TREE, call),
- NULL_TREE);
+ call = build_call_nary (TREE_TYPE (TREE_TYPE (method)),
+ build_address_of (soft_unwrapjni_node),
+ 1, call);
call = build2 (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (method)),
res_var, call);
}
TREE_SIDE_EFFECTS (body) = 1;
/* Now free the environment we allocated. */
- call = build3 (CALL_EXPR, ptr_type_node,
- build_address_of (soft_jnipopsystemframe_node),
- build_tree_list (NULL_TREE, env_var),
- NULL_TREE);
+ call = build_call_nary (ptr_type_node,
+ build_address_of (soft_jnipopsystemframe_node),
+ 1, env_var);
TREE_SIDE_EFFECTS (call) = 1;
CAN_COMPLETE_NORMALLY (call) = 1;
body = build2 (COMPOUND_EXPR, void_type_node, body, call);
}
body = build2 (COMPOUND_EXPR, void_type_node, body,
- build1 (RETURN_EXPR, res_type, res_var));
+ build1 (RETURN_EXPR, void_type_node, res_var));
TREE_SIDE_EFFECTS (body) = 1;
/* Prepend class initialization for static methods reachable from
&& (! METHOD_PRIVATE (method)
|| INNER_CLASS_P (DECL_CONTEXT (method))))
{
- tree init = build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_initclass_node),
- build_tree_list (NULL_TREE,
- klass),
- NULL_TREE);
+ tree init = build_call_expr (soft_initclass_node, 1,
+ klass);
body = build2 (COMPOUND_EXPR, void_type_node, init, body);
TREE_SIDE_EFFECTS (body) = 1;
}
field_ref, new_value);
if (TREE_THIS_VOLATILE (field_decl))
- java_add_stmt
- (build3
- (CALL_EXPR, void_type_node,
- build_address_of (built_in_decls[BUILT_IN_SYNCHRONIZE]),
- NULL_TREE, NULL_TREE));
+ java_add_stmt
+ (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
java_add_stmt (modify_expr);
}
if (TREE_THIS_VOLATILE (field_decl))
java_add_stmt
- (build3
- (CALL_EXPR, void_type_node,
- build_address_of (built_in_decls[BUILT_IN_SYNCHRONIZE]),
- NULL_TREE, NULL_TREE));
+ (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
push_value (temp);
}
TREE_THIS_VOLATILE (field_ref) = TREE_THIS_VOLATILE (field_decl);
}
-void
-load_type_state (tree label)
+static void
+load_type_state (int pc)
{
int i;
- tree vec = LABEL_TYPE_STATE (label);
+ tree vec = VEC_index (tree, type_states, pc);
int cur_length = TREE_VEC_LENGTH (vec);
stack_pointer = cur_length - DECL_MAX_LOCALS(current_function_decl);
for (i = 0; i < cur_length; i++)
byte_ops = jcf->read_ptr;
instruction_bits = xrealloc (instruction_bits, length + 1);
memset (instruction_bits, 0, length + 1);
+ type_states = VEC_alloc (tree, gc, length + 1);
+ VEC_safe_grow_cleared (tree, gc, type_states, length + 1);
/* This pass figures out which PC can be the targets of jumps. */
for (PC = 0; PC < length;)
flush_quick_stack ();
if ((instruction_bits [PC] & BCODE_TARGET) != 0)
java_add_stmt (build1 (LABEL_EXPR, void_type_node, label));
- if (LABEL_VERIFIED (label) || PC == 0)
- load_type_state (label);
+ if ((instruction_bits[PC] & BCODE_VERIFIED) != 0)
+ load_type_state (PC);
}
if (! (instruction_bits [PC] & BCODE_VERIFIED))
&& TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR
&& TREE_CODE (TREE_OPERAND (node, 1)) == SAVE_EXPR))
{
- tree arg, cmp;
+ tree call, cmp;
+ int i, nargs;
- arg = node;
-
- /* Position arg properly, account for wrapped around ctors. */
+ /* Account for wrapped around ctors. */
if (TREE_CODE (node) == COMPOUND_EXPR)
- arg = TREE_OPERAND (node, 0);
-
- arg = TREE_OPERAND (arg, 1);
-
- /* An empty argument list is ok, just ignore it. */
- if (!arg)
- return node;
+ call = TREE_OPERAND (node, 0);
+ else
+ call = node;
- /* Not having a list of arguments here is an error. */
- gcc_assert (TREE_CODE (arg) == TREE_LIST);
+ nargs = call_expr_nargs (call);
/* This reverses the evaluation order. This is a desired effect. */
- for (cmp = NULL_TREE; arg; arg = TREE_CHAIN (arg))
+ for (i = 0, cmp = NULL_TREE; i < nargs; i++)
{
+ tree arg = CALL_EXPR_ARG (call, i);
/* Promote types smaller than integer. This is required by
some ABIs. */
- tree type = TREE_TYPE (TREE_VALUE (arg));
+ tree type = TREE_TYPE (arg);
tree saved;
if (targetm.calls.promote_prototypes (type)
&& INTEGRAL_TYPE_P (type)
&& INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
TYPE_SIZE (integer_type_node)))
- TREE_VALUE (arg) = fold_convert (integer_type_node, TREE_VALUE (arg));
+ arg = fold_convert (integer_type_node, arg);
- saved = save_expr (force_evaluation_order (TREE_VALUE (arg)));
+ saved = save_expr (force_evaluation_order (arg));
cmp = (cmp == NULL_TREE ? saved :
build2 (COMPOUND_EXPR, void_type_node, cmp, saved));
- TREE_VALUE (arg) = saved;
+
+ CALL_EXPR_ARG (call, i) = saved;
}
if (cmp && TREE_CODE (cmp) == COMPOUND_EXPR)