On 10/01/2022 16:20, Jakub Jelinek wrote:
On Sat, Dec 18, 2021 at 06:05:09PM +0530, Siddhesh Poyarekar wrote:
@@ -1440,6 +1441,53 @@ cond_expr_object_size (struct object_size_info *osi, 
tree var, gimple *stmt)
    return reexamine;
  }
+/* Find size of an object passed as a parameter to the function. */
+
+static void
+parm_object_size (struct object_size_info *osi, tree var)
+{
+  int object_size_type = osi->object_size_type;
+  tree parm = SSA_NAME_VAR (var);
+
+  if (!(object_size_type & OST_DYNAMIC) || !POINTER_TYPE_P (TREE_TYPE (parm)))
+    expr_object_size (osi, var, parm);

This looks very suspicious.  Didn't you mean { expr_object_size (...); return; 
} here?
Because the code below e.g. certainly assumes OST_DYNAMIC and that TREE_TYPE 
(parm)
is a pointer type (otherwise TREE_TYPE (TREE_TYPE (...) wouldn't work.

Indeed, fixed.


+
+  /* Look for access attribute.  */
+  rdwr_map rdwr_idx;
+
+  tree fndecl = cfun->decl;
+  const attr_access *access = get_parm_access (rdwr_idx, parm, fndecl);
+  tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm)));
+  tree sz = NULL_TREE;
+
+  if (access && access->sizarg != UINT_MAX)

Perhaps && typesize here?  It makes no sense to e.g. create ssa default def
when you aren't going to use it in any way.

The typesize is only for scaling; the result of get_or_create_ssa_default_def should get returned unscaled if it is non-NULL and typesize is NULL; the latter happens when the type is void *:

          sz = get_or_create_ssa_default_def (cfun, arg);
          if (sz != NULL_TREE)
            {
              sz = fold_convert (sizetype, sz);
              if (typesize)
                sz = size_binop (MULT_EXPR, sz, typesize);
            }
        }


+    {
+      tree fnargs = DECL_ARGUMENTS (fndecl);
+      tree arg = NULL_TREE;
+      unsigned argpos = 0;
+
+      /* Walk through the parameters to pick the size parameter and safely
+        scale it by the type size.  */
+      for (arg = fnargs; argpos != access->sizarg && arg;
+          arg = TREE_CHAIN (arg), ++argpos);

Instead of a loop with empty body wouldn't it be better to
do the work in that for loop?
I.e. take argpos != access->sizarg && from the condition,
replace arg != NULL_TREE with that argpos == access->sizarg
and add a break;?

Fixed.


+
+      if (arg != NULL_TREE && INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+       {
+         sz = get_or_create_ssa_default_def (cfun, arg);

Also, I must say I'm little bit worried about this
get_or_create_ssa_default_def call.  If the SSA_NAME doesn't exist,
so you create it and then attempt to use it but in the end don't
because e.g. some PHI's another argument was unknown etc., will
that SSA_NAME be released through release_ssa_name?
I think GIMPLE is fairly unhappy if there are SSA_NAMEs created and not
released that don't appear in the IL anywhere.

AFAICT, set_ss_default_def ends up creating a definition for the new SSA_NAME it creates, so it does end up in the IR and in case of object size computation failure, it just ends up being a dead store. I've added a test to verify this:

size_t
__attribute__ ((access (__read_write__, 1, 3)))
__attribute__ ((noinline))
test_parmsz_unknown (void *obj, void *unknown, size_t sz, int cond)
{
  return __builtin_dynamic_object_size (cond ? obj : unknown, 0);
}

which works as expected and returns -1.

Thanks,
Siddhesh

Reply via email to