}
}
-/* Given a GIMPLE_CALL statement, return the type of the nth parameter
- passed if there is an nth parameter or NULL if there is no nth
- parameter. */
+/* Given a GIMPLE_CALL statement, return the FUNCTION_TYPE tree node
+ that represents the function prototype. */
static tree
-get_param_type (gimple call_stmt, int n)
+get_function_prototype (gimple call_stmt)
{
+ tree func;
+ tree func_type_pointer;
+ tree func_type;
+
aop_assert (gimple_code (call_stmt) == GIMPLE_CALL);
+ func = gimple_call_fn (call_stmt);
+
+ /* Get the function type. The func tree should have a pointer type,
+ pointing to the actual function type. */
+ func_type_pointer = TREE_TYPE (func);
+ aop_assert (TREE_CODE (func_type_pointer) == POINTER_TYPE);
+ func_type = TREE_TYPE (func_type_pointer);
+ aop_assert (TREE_CODE (func_type) == FUNCTION_TYPE);
+
+ return func_type;
+}
+
+/* Unfortunately, the type for a parameter is encoded in two different
+ places: the _formal_ parameter and the _actual_ parameter. These
+ two types should always be the same, but in some edge cases they
+ are not. In general, we give priority to the formal parameter type
+ when possible.
+
+ The formal parameter type is the type that the function expects to
+ be passed as encoded in the function declaration.
+
+ The actual parameter type is the type of the value passed at the
+ call site as encoded in the GIMPLE_CALL statement.
+
+ In particular, when passing a literal integer constant to a
+ function that expects a uint8 or uint16, GCC sometimes incorrectly
+ allows the actual parameter to have a signed type (whereas the
+ formal parameter has an unsigned type).
+
+ C vararg functions are not type safe, so there is no formal
+ parameter for any varargs argument. In the case of a vararg
+ argument, we must resort to the actual parameter type. */
+static tree
+get_formal_param_type (gimple call_stmt, int n)
+{
+ int i;
+ tree func_type;
+ tree type_list_node;
+ tree formal_type = NULL;
+
+ func_type = get_function_prototype (call_stmt);
+ type_list_node = TYPE_ARG_TYPES (func_type);
+ i = 0;
+ while (type_list_node != void_list_node && type_list_node != NULL)
+ {
+ if (i == n)
+ {
+ formal_type = TREE_VALUE (type_list_node);
+ break;
+ }
+
+ type_list_node = TREE_CHAIN (type_list_node);
+ i++;
+ }
+
+ return formal_type;
+}
+
+/* See comment for get_formal_param_type(). */
+static tree
+get_actual_param_type (gimple call_stmt, int n)
+{
if (n < gimple_call_num_args (call_stmt))
return TREE_TYPE (gimple_call_arg (call_stmt, n));
else
return NULL;
}
+/* Given a GIMPLE_CALL statement, return the type of the nth parameter
+ passed if there is an nth parameter or NULL if there is no nth
+ parameter. */
+static tree
+get_param_type (gimple call_stmt, int n)
+{
+ tree param_type;
+
+ aop_assert (gimple_code (call_stmt) == GIMPLE_CALL);
+
+ param_type = get_formal_param_type (call_stmt, n);
+ if (param_type == NULL)
+ param_type = get_actual_param_type (call_stmt, n);
+
+ return param_type;
+}
+
/* Return true if a call statement matches the pointcut's criteria for
name, return type, and argument types. */
static bool