OSDN Git Service

Include gvarargs.h.
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Mar 1993 13:09:36 +0000 (13:09 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Mar 1993 13:09:36 +0000 (13:09 +0000)
Add prototypes to forward declarations and declare static functions.
(prepare_call_address, emit_call_1): Now static.
(emit_library_call, emit_library_call_value): Move to here.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@3848 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/calls.c

index a4b8747..2b024d4 100644 (file)
@@ -22,6 +22,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tree.h"
 #include "flags.h"
 #include "expr.h"
+#include "gvarargs.h"
 #include "insn-flags.h"
 
 /* Decide whether a function's arguments should be processed
@@ -117,8 +118,12 @@ static int highest_outgoing_arg_in_use;
 int stack_arg_under_construction;
 #endif
 
-static void store_one_arg ();
-extern enum machine_mode mode_for_size ();
+static int calls_function      PROTO((tree, int));
+static rtx prepare_call_address        PROTO((rtx, tree, rtx *));
+static void emit_call_1                PROTO((rtx, tree, int, int, rtx, rtx, int,
+                                      rtx, int));
+static void store_one_arg      PROTO ((struct arg_data *, rtx, int, int,
+                                       tree, int));
 \f
 /* If WHICH is 1, return 1 if EXP contains a call to the built-in function
    `alloca'.
@@ -213,7 +218,7 @@ calls_function (exp, which)
    to which a USE of the static chain
    register should be added, if required.  */
 
-rtx
+static rtx
 prepare_call_address (funexp, fndecl, use_insns)
      rtx funexp;
      tree fndecl;
@@ -293,7 +298,7 @@ prepare_call_address (funexp, fndecl, use_insns)
 
    IS_CONST is true if this is a `const' call.  */
 
-void
+static void
 emit_call_1 (funexp, funtype, stack_size, struct_value_size, next_arg_reg,
             valreg, old_inhibit_defer_pop, use_insns, is_const)
      rtx funexp;
@@ -1931,6 +1936,604 @@ expand_call (exp, target, ignore)
   return target;
 }
 \f
+/* Output a library call to function FUN (a SYMBOL_REF rtx)
+   (emitting the queue unless NO_QUEUE is nonzero),
+   for a value of mode OUTMODE,
+   with NARGS different arguments, passed as alternating rtx values
+   and machine_modes to convert them to.
+   The rtx values should have been passed through protect_from_queue already.
+
+   NO_QUEUE will be true if and only if the library call is a `const' call
+   which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent
+   to the variable is_const in expand_call.
+
+   NO_QUEUE must be true for const calls, because if it isn't, then
+   any pending increment will be emitted between REG_LIBCALL/REG_RETVAL notes,
+   and will be lost if the libcall sequence is optimized away.
+
+   NO_QUEUE must be false for non-const calls, because if it isn't, the
+   call insn will have its CONST_CALL_P bit set, and it will be incorrectly
+   optimized.  For instance, the instruction scheduler may incorrectly
+   move memory references across the non-const call.  */
+
+void
+emit_library_call (va_alist)
+     va_dcl
+{
+  va_list p;
+  /* Total size in bytes of all the stack-parms scanned so far.  */
+  struct args_size args_size;
+  /* Size of arguments before any adjustments (such as rounding).  */
+  struct args_size original_args_size;
+  register int argnum;
+  enum machine_mode outmode;
+  int nargs;
+  rtx fun;
+  rtx orgfun;
+  int inc;
+  int count;
+  rtx argblock = 0;
+  CUMULATIVE_ARGS args_so_far;
+  struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
+              struct args_size offset; struct args_size size; };
+  struct arg *argvec;
+  int old_inhibit_defer_pop = inhibit_defer_pop;
+  int no_queue = 0;
+  rtx use_insns;
+
+  va_start (p);
+  orgfun = fun = va_arg (p, rtx);
+  no_queue = va_arg (p, int);
+  outmode = va_arg (p, enum machine_mode);
+  nargs = va_arg (p, int);
+
+  /* Copy all the libcall-arguments out of the varargs data
+     and into a vector ARGVEC.
+
+     Compute how to pass each argument.  We only support a very small subset
+     of the full argument passing conventions to limit complexity here since
+     library functions shouldn't have many args.  */
+
+  argvec = (struct arg *) alloca (nargs * sizeof (struct arg));
+
+  INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun);
+
+  args_size.constant = 0;
+  args_size.var = 0;
+
+  for (count = 0; count < nargs; count++)
+    {
+      rtx val = va_arg (p, rtx);
+      enum machine_mode mode = va_arg (p, enum machine_mode);
+
+      /* We cannot convert the arg value to the mode the library wants here;
+        must do it earlier where we know the signedness of the arg.  */
+      if (mode == BLKmode
+         || (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode))
+       abort ();
+
+      /* On some machines, there's no way to pass a float to a library fcn.
+        Pass it as a double instead.  */
+#ifdef LIBGCC_NEEDS_DOUBLE
+      if (LIBGCC_NEEDS_DOUBLE && mode == SFmode)
+       val = convert_to_mode (DFmode, val, 0), mode = DFmode;
+#endif
+
+      /* There's no need to call protect_from_queue, because
+        either emit_move_insn or emit_push_insn will do that.  */
+
+      /* Make sure it is a reasonable operand for a move or push insn.  */
+      if (GET_CODE (val) != REG && GET_CODE (val) != MEM
+         && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val)))
+       val = force_operand (val, NULL_RTX);
+
+      argvec[count].value = val;
+      argvec[count].mode = mode;
+
+#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
+      if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1))
+       abort ();
+#endif
+
+      argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
+      if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST)
+       abort ();
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+      argvec[count].partial
+       = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, NULL_TREE, 1);
+#else
+      argvec[count].partial = 0;
+#endif
+
+      locate_and_pad_parm (mode, NULL_TREE,
+                          argvec[count].reg && argvec[count].partial == 0,
+                          NULL_TREE, &args_size, &argvec[count].offset,
+                          &argvec[count].size);
+
+      if (argvec[count].size.var)
+       abort ();
+
+#ifndef REG_PARM_STACK_SPACE
+      if (argvec[count].partial)
+       argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
+#endif
+
+      if (argvec[count].reg == 0 || argvec[count].partial != 0
+#ifdef REG_PARM_STACK_SPACE
+         || 1
+#endif
+         )
+       args_size.constant += argvec[count].size.constant;
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+      /* If this arg is actually passed on the stack, it might be
+        clobbering something we already put there (this library call might
+        be inside the evaluation of an argument to a function whose call
+        requires the stack).  This will only occur when the library call
+        has sufficient args to run out of argument registers.  Abort in
+        this case; if this ever occurs, code must be added to save and
+        restore the arg slot.  */
+
+      if (argvec[count].reg == 0 || argvec[count].partial != 0)
+       abort ();
+#endif
+
+      FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1);
+    }
+  va_end (p);
+
+  /* If this machine requires an external definition for library
+     functions, write one out.  */
+  assemble_external_libcall (fun);
+
+  original_args_size = args_size;
+#ifdef STACK_BOUNDARY
+  args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
+                        / STACK_BYTES) * STACK_BYTES);
+#endif
+
+#ifdef REG_PARM_STACK_SPACE
+  args_size.constant = MAX (args_size.constant,
+                           REG_PARM_STACK_SPACE (NULL_TREE));
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+  args_size.constant -= REG_PARM_STACK_SPACE (NULL_TREE);
+#endif
+#endif
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+  if (args_size.constant > current_function_outgoing_args_size)
+    current_function_outgoing_args_size = args_size.constant;
+  args_size.constant = 0;
+#endif
+
+#ifndef PUSH_ROUNDING
+  argblock = push_block (GEN_INT (args_size.constant), 0, 0);
+#endif
+
+#ifdef PUSH_ARGS_REVERSED
+#ifdef STACK_BOUNDARY
+  /* If we push args individually in reverse order, perform stack alignment
+     before the first push (the last arg).  */
+  if (argblock == 0)
+    anti_adjust_stack (GEN_INT (args_size.constant
+                               - original_args_size.constant));
+#endif
+#endif
+
+#ifdef PUSH_ARGS_REVERSED
+  inc = -1;
+  argnum = nargs - 1;
+#else
+  inc = 1;
+  argnum = 0;
+#endif
+
+  /* Push the args that need to be pushed.  */
+
+  for (count = 0; count < nargs; count++, argnum += inc)
+    {
+      register enum machine_mode mode = argvec[argnum].mode;
+      register rtx val = argvec[argnum].value;
+      rtx reg = argvec[argnum].reg;
+      int partial = argvec[argnum].partial;
+
+      if (! (reg != 0 && partial == 0))
+       emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
+                       argblock, GEN_INT (argvec[count].offset.constant));
+      NO_DEFER_POP;
+    }
+
+#ifndef PUSH_ARGS_REVERSED
+#ifdef STACK_BOUNDARY
+  /* If we pushed args in forward order, perform stack alignment
+     after pushing the last arg.  */
+  if (argblock == 0)
+    anti_adjust_stack (GEN_INT (args_size.constant
+                               - original_args_size.constant));
+#endif
+#endif
+
+#ifdef PUSH_ARGS_REVERSED
+  argnum = nargs - 1;
+#else
+  argnum = 0;
+#endif
+
+  /* Now load any reg parms into their regs.  */
+
+  for (count = 0; count < nargs; count++, argnum += inc)
+    {
+      register enum machine_mode mode = argvec[argnum].mode;
+      register rtx val = argvec[argnum].value;
+      rtx reg = argvec[argnum].reg;
+      int partial = argvec[argnum].partial;
+
+      if (reg != 0 && partial == 0)
+       emit_move_insn (reg, val);
+      NO_DEFER_POP;
+    }
+
+  /* For version 1.37, try deleting this entirely.  */
+  if (! no_queue)
+    emit_queue ();
+
+  /* Any regs containing parms remain in use through the call.  */
+  start_sequence ();
+  for (count = 0; count < nargs; count++)
+    if (argvec[count].reg != 0)
+      emit_insn (gen_rtx (USE, VOIDmode, argvec[count].reg));
+
+  use_insns = get_insns ();
+  end_sequence ();
+
+  fun = prepare_call_address (fun, NULL_TREE, &use_insns);
+
+  /* Don't allow popping to be deferred, since then
+     cse'ing of library calls could delete a call and leave the pop.  */
+  NO_DEFER_POP;
+
+  /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
+     will set inhibit_defer_pop to that value.  */
+
+  emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size.constant, 0,
+              FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
+              outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
+              old_inhibit_defer_pop + 1, use_insns, no_queue);
+
+  /* Now restore inhibit_defer_pop to its actual original value.  */
+  OK_DEFER_POP;
+}
+\f
+/* Like emit_library_call except that an extra argument, VALUE,
+   comes second and says where to store the result.
+   (If VALUE is zero, the result comes in the function value register.)  */
+
+void
+emit_library_call_value (va_alist)
+     va_dcl
+{
+  va_list p;
+  /* Total size in bytes of all the stack-parms scanned so far.  */
+  struct args_size args_size;
+  /* Size of arguments before any adjustments (such as rounding).  */
+  struct args_size original_args_size;
+  register int argnum;
+  enum machine_mode outmode;
+  int nargs;
+  rtx fun;
+  rtx orgfun;
+  int inc;
+  int count;
+  rtx argblock = 0;
+  CUMULATIVE_ARGS args_so_far;
+  struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
+              struct args_size offset; struct args_size size; };
+  struct arg *argvec;
+  int old_inhibit_defer_pop = inhibit_defer_pop;
+  int no_queue = 0;
+  rtx use_insns;
+  rtx value;
+  rtx mem_value = 0;
+
+  va_start (p);
+  orgfun = fun = va_arg (p, rtx);
+  value = va_arg (p, rtx);
+  no_queue = va_arg (p, int);
+  outmode = va_arg (p, enum machine_mode);
+  nargs = va_arg (p, int);
+
+  /* If this kind of value comes back in memory,
+     decide where in memory it should come back.  */
+  if (RETURN_IN_MEMORY (type_for_mode (outmode, 0)))
+    {
+      if (GET_CODE (value) == MEM)
+       mem_value = value;
+      else
+       mem_value = assign_stack_temp (outmode, GET_MODE_SIZE (outmode), 0);
+    }
+
+  /* ??? Unfinished: must pass the memory address as an argument.  */
+
+  /* Copy all the libcall-arguments out of the varargs data
+     and into a vector ARGVEC.
+
+     Compute how to pass each argument.  We only support a very small subset
+     of the full argument passing conventions to limit complexity here since
+     library functions shouldn't have many args.  */
+
+  argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg));
+
+  INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun);
+
+  args_size.constant = 0;
+  args_size.var = 0;
+
+  count = 0;
+
+  /* If there's a structure value address to be passed,
+     either pass it in the special place, or pass it as an extra argument.  */
+  if (mem_value)
+    {
+      rtx addr = XEXP (mem_value, 0);
+
+      if (! struct_value_rtx)
+       {
+         nargs++;
+
+         /* Make sure it is a reasonable operand for a move or push insn.  */
+         if (GET_CODE (addr) != REG && GET_CODE (addr) != MEM
+             && ! (CONSTANT_P (addr) && LEGITIMATE_CONSTANT_P (addr)))
+           addr = force_operand (addr, NULL_RTX);
+
+         argvec[count].value = addr;
+         argvec[count].mode = outmode;
+         argvec[count].partial = 0;
+
+         argvec[count].reg = FUNCTION_ARG (args_so_far, outmode, NULL_TREE, 1);
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+         if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, outmode, NULL_TREE, 1))
+           abort ();
+#endif
+
+         locate_and_pad_parm (outmode, NULL_TREE,
+                              argvec[count].reg && argvec[count].partial == 0,
+                              NULL_TREE, &args_size, &argvec[count].offset,
+                              &argvec[count].size);
+
+
+         if (argvec[count].reg == 0 || argvec[count].partial != 0
+#ifdef REG_PARM_STACK_SPACE
+             || 1
+#endif
+             )
+           args_size.constant += argvec[count].size.constant;
+
+         FUNCTION_ARG_ADVANCE (args_so_far, outmode, (tree)0, 1);
+       }
+    }
+
+  for (; count < nargs; count++)
+    {
+      rtx val = va_arg (p, rtx);
+      enum machine_mode mode = va_arg (p, enum machine_mode);
+
+      /* We cannot convert the arg value to the mode the library wants here;
+        must do it earlier where we know the signedness of the arg.  */
+      if (mode == BLKmode
+         || (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode))
+       abort ();
+
+      /* On some machines, there's no way to pass a float to a library fcn.
+        Pass it as a double instead.  */
+#ifdef LIBGCC_NEEDS_DOUBLE
+      if (LIBGCC_NEEDS_DOUBLE && mode == SFmode)
+       val = convert_to_mode (DFmode, val, 0), mode = DFmode;
+#endif
+
+      /* There's no need to call protect_from_queue, because
+        either emit_move_insn or emit_push_insn will do that.  */
+
+      /* Make sure it is a reasonable operand for a move or push insn.  */
+      if (GET_CODE (val) != REG && GET_CODE (val) != MEM
+         && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val)))
+       val = force_operand (val, NULL_RTX);
+
+      argvec[count].value = val;
+      argvec[count].mode = mode;
+
+#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
+      if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1))
+       abort ();
+#endif
+
+      argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
+      if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST)
+       abort ();
+#ifdef FUNCTION_ARG_PARTIAL_NREGS
+      argvec[count].partial
+       = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, NULL_TREE, 1);
+#else
+      argvec[count].partial = 0;
+#endif
+
+      locate_and_pad_parm (mode, NULL_TREE,
+                          argvec[count].reg && argvec[count].partial == 0,
+                          NULL_TREE, &args_size, &argvec[count].offset,
+                          &argvec[count].size);
+
+      if (argvec[count].size.var)
+       abort ();
+
+#ifndef REG_PARM_STACK_SPACE
+      if (argvec[count].partial)
+       argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
+#endif
+
+      if (argvec[count].reg == 0 || argvec[count].partial != 0
+#ifdef REG_PARM_STACK_SPACE
+         || 1
+#endif
+         )
+       args_size.constant += argvec[count].size.constant;
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+      /* If this arg is actually passed on the stack, it might be
+        clobbering something we already put there (this library call might
+        be inside the evaluation of an argument to a function whose call
+        requires the stack).  This will only occur when the library call
+        has sufficient args to run out of argument registers.  Abort in
+        this case; if this ever occurs, code must be added to save and
+        restore the arg slot.  */
+
+      if (argvec[count].reg == 0 || argvec[count].partial != 0)
+       abort ();
+#endif
+
+      FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1);
+    }
+  va_end (p);
+
+  /* If this machine requires an external definition for library
+     functions, write one out.  */
+  assemble_external_libcall (fun);
+
+  original_args_size = args_size;
+#ifdef STACK_BOUNDARY
+  args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
+                        / STACK_BYTES) * STACK_BYTES);
+#endif
+
+#ifdef REG_PARM_STACK_SPACE
+  args_size.constant = MAX (args_size.constant,
+                           REG_PARM_STACK_SPACE (NULL_TREE));
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+  args_size.constant -= REG_PARM_STACK_SPACE (NULL_TREE);
+#endif
+#endif
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+  if (args_size.constant > current_function_outgoing_args_size)
+    current_function_outgoing_args_size = args_size.constant;
+  args_size.constant = 0;
+#endif
+
+#ifndef PUSH_ROUNDING
+  argblock = push_block (GEN_INT (args_size.constant), 0, 0);
+#endif
+
+#ifdef PUSH_ARGS_REVERSED
+#ifdef STACK_BOUNDARY
+  /* If we push args individually in reverse order, perform stack alignment
+     before the first push (the last arg).  */
+  if (argblock == 0)
+    anti_adjust_stack (GEN_INT (args_size.constant
+                               - original_args_size.constant));
+#endif
+#endif
+
+#ifdef PUSH_ARGS_REVERSED
+  inc = -1;
+  argnum = nargs - 1;
+#else
+  inc = 1;
+  argnum = 0;
+#endif
+
+  /* Push the args that need to be pushed.  */
+
+  for (count = 0; count < nargs; count++, argnum += inc)
+    {
+      register enum machine_mode mode = argvec[argnum].mode;
+      register rtx val = argvec[argnum].value;
+      rtx reg = argvec[argnum].reg;
+      int partial = argvec[argnum].partial;
+
+      if (! (reg != 0 && partial == 0))
+       emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
+                       argblock, GEN_INT (argvec[count].offset.constant));
+      NO_DEFER_POP;
+    }
+
+#ifndef PUSH_ARGS_REVERSED
+#ifdef STACK_BOUNDARY
+  /* If we pushed args in forward order, perform stack alignment
+     after pushing the last arg.  */
+  if (argblock == 0)
+    anti_adjust_stack (GEN_INT (args_size.constant
+                               - original_args_size.constant));
+#endif
+#endif
+
+#ifdef PUSH_ARGS_REVERSED
+  argnum = nargs - 1;
+#else
+  argnum = 0;
+#endif
+
+  /* Now load any reg parms into their regs.  */
+
+  if (mem_value != 0 && struct_value_rtx != 0)
+    emit_move_insn (struct_value_rtx, XEXP (mem_value, 0));
+
+  for (count = 0; count < nargs; count++, argnum += inc)
+    {
+      register enum machine_mode mode = argvec[argnum].mode;
+      register rtx val = argvec[argnum].value;
+      rtx reg = argvec[argnum].reg;
+      int partial = argvec[argnum].partial;
+
+      if (reg != 0 && partial == 0)
+       emit_move_insn (reg, val);
+      NO_DEFER_POP;
+    }
+
+#if 0
+  /* For version 1.37, try deleting this entirely.  */
+  if (! no_queue)
+    emit_queue ();
+#endif
+
+  /* Any regs containing parms remain in use through the call.  */
+  start_sequence ();
+  for (count = 0; count < nargs; count++)
+    if (argvec[count].reg != 0)
+      emit_insn (gen_rtx (USE, VOIDmode, argvec[count].reg));
+
+  use_insns = get_insns ();
+  end_sequence ();
+
+  fun = prepare_call_address (fun, NULL_TREE, &use_insns);
+
+  /* Don't allow popping to be deferred, since then
+     cse'ing of library calls could delete a call and leave the pop.  */
+  NO_DEFER_POP;
+
+  /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
+     will set inhibit_defer_pop to that value.  */
+
+  emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size.constant, 0,
+              FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
+              outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
+              old_inhibit_defer_pop + 1, use_insns, no_queue);
+
+  /* Now restore inhibit_defer_pop to its actual original value.  */
+  OK_DEFER_POP;
+
+  /* Copy the value to the right place.  */
+  if (outmode != VOIDmode)
+    {
+      if (mem_value)
+       {
+         if (value == 0)
+           value = hard_libcall_value (outmode);
+         if (value != mem_value)
+           emit_move_insn (value, mem_value);
+       }
+      else if (value != 0)
+       emit_move_insn (value, hard_libcall_value (outmode));
+    }
+}
+\f
 #if 0
 /* Return an rtx which represents a suitable home on the stack
    given TYPE, the type of the argument looking for a home.