]> gcc.gnu.org Git - gcc.git/commitdiff
builtins.def (BUILT_IN_VA_ARG_PACK): New built-in.
authorJakub Jelinek <jakub@gcc.gnu.org>
Wed, 5 Sep 2007 20:45:27 +0000 (22:45 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 5 Sep 2007 20:45:27 +0000 (22:45 +0200)
* builtins.def (BUILT_IN_VA_ARG_PACK): New built-in.
* tree.h (CALL_EXPR_VA_ARG_PACK): Define.
* tree-inline.h (copy_body_data): Add call_expr field.
* tree-inline.c (expand_call_inline): Initialize call_expr.
(copy_bb): Append anonymous inline fn arguments to arguments
when inlining a CALL_EXPR_VA_ARG_PACK call.
* builtins.c (expand_builtin): Issue an error if
BUILT_IN_VA_ARG_PACK is seen during expand.
(fold_call_expr, fold_builtin_call_array): Don't fold
CALL_EXPR_VA_ARG_PACK CALL_EXPRs or calls with
__builtin_va_arg_pack () call as last argument.
* gimplify.c (gimplify_call_expr): If last argument to a vararg
function is __builtin_va_arg_pack (), decrease number of call
arguments and instead set CALL_EXPR_VA_ARG_PACK on the CALL_EXPR.
* expr.c (expand_expr_real_1): Issue an error if
CALL_EXPR_VA_ARG_PACK CALL_EXPR is seen during expand.
* tree-pretty-print.c (dump_generic_node): Handle printing
CALL_EXPR_VA_ARG_PACK bit on CALL_EXPRs.
* doc/extend.texi (__builtin_va_arg_pack): Document.

* gcc.c-torture/execute/va-arg-pack-1.c: New test.
* gcc.dg/va-arg-pack-1.c: New test.

From-SVN: r128150

13 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/builtins.def
gcc/doc/extend.texi
gcc/expr.c
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/va-arg-pack-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/va-arg-pack-1.c [new file with mode: 0644]
gcc/tree-inline.c
gcc/tree-inline.h
gcc/tree-pretty-print.c
gcc/tree.h

index 6f0ea1852267612d56389b2cd22caa5bef4b9e62..ea2f73f8ed389f9afe50cbecea0800c95604fc33 100644 (file)
@@ -1,3 +1,25 @@
+2007-09-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * builtins.def (BUILT_IN_VA_ARG_PACK): New built-in.
+       * tree.h (CALL_EXPR_VA_ARG_PACK): Define.
+       * tree-inline.h (copy_body_data): Add call_expr field.
+       * tree-inline.c (expand_call_inline): Initialize call_expr.
+       (copy_bb): Append anonymous inline fn arguments to arguments
+       when inlining a CALL_EXPR_VA_ARG_PACK call.
+       * builtins.c (expand_builtin): Issue an error if
+       BUILT_IN_VA_ARG_PACK is seen during expand.
+       (fold_call_expr, fold_builtin_call_array): Don't fold
+       CALL_EXPR_VA_ARG_PACK CALL_EXPRs or calls with
+       __builtin_va_arg_pack () call as last argument.
+       * gimplify.c (gimplify_call_expr): If last argument to a vararg
+       function is __builtin_va_arg_pack (), decrease number of call
+       arguments and instead set CALL_EXPR_VA_ARG_PACK on the CALL_EXPR.
+       * expr.c (expand_expr_real_1): Issue an error if
+       CALL_EXPR_VA_ARG_PACK CALL_EXPR is seen during expand.
+       * tree-pretty-print.c (dump_generic_node): Handle printing
+       CALL_EXPR_VA_ARG_PACK bit on CALL_EXPRs.
+       * doc/extend.texi (__builtin_va_arg_pack): Document.
+
 2007-09-05  Adam Nemet  <anemet@caviumnetworks.com>
 
        PR tree-optimization/21513
        (was_mips16_p): New.
        (mips_set_mips16_mode): New, split out from override_options.
        (mips_set_current_function): New.
-       (override_options):  Add sorry for unsupported mips16/pic
+       (override_options): Add sorry for unsupported mips16/pic
        combination.  Remove error for mips16/dsp combination.  Save
        base option settings.  
        (mips_file_start): Move mips16 mode setting output from here....
 
        * config/mips/mips.c (mips_legitimize_tls_address): Call sorry
        if we encounter TLS address in MIPS16 mode.
-       (mips_legitimize_const_move):  Check cannot_force_const_mem for
+       (mips_legitimize_const_move): Check cannot_force_const_mem for
        the (const (plus symbol offset)) case; this forces invalid TLS
        address in MIPS16 mode to be caught by the above call to sorry.
        (override_options): Don't reset targetm.have_tls in MIPS16 mode,
        * function.h: Here.
        (set_cfun): Declare.
        * tree-inline.c (cfun_stack, push_cfun, pop_cfun): Moved to...
-       * function.c:  Here.
+       * function.c: Here.
        (push_function_context_to): Use allocate_struct_function
        to create null context, not init_dummy_function_start.  Use set_cfun.
        (pop_function_context_from): Use set_cfun.
 
 2007-09-05  Kenneth Zadeck <zadeck@naturalbridge.com>
 
-       * regrename.c (rerename_optimize):  Use deferred rescanning and
+       * regrename.c (rerename_optimize): Use deferred rescanning and
        insert explicit calls to rescan insns when changed.
        
 2007-09-05  Jan Hubicka  <jh@suse.cz>
 
        * toplev.c (init_alignments): New, split out from...
        (process_options): ...here.
-       (backend_init_target):  New, split out from...
+       (backend_init_target): New, split out from...
        (backend_init): ...here.
-       (lang_dependent_init_target):  New, split out from...
+       (lang_dependent_init_target): New, split out from...
        (lang_dependent_init): ...here.
        (target_reinit): New.
        * toplev.h (target_reinit): Declare.
 
 2007-08-11  David Daney  <ddaney@avtrex.com>
 
-       * config/mips/mips.c (mips_sched_reorder):  Mark cycle parameter
+       * config/mips/mips.c (mips_sched_reorder): Mark cycle parameter
        as ATTRIBUTE_UNUSED.
 
 2007-08-11  David Edelsohn  <edelsohn@gnu.org>
 
 2007-08-09  Sandra Loosemore  <sandra@codesourcery.com>
 
-       * config/mips/mips.opt (mhard-float, msoft-float):  Make these
+       * config/mips/mips.opt (mhard-float, msoft-float): Make these
        control TARGET_HARD_FLOAT_ABI and TARGET_SOFT_FLOAT_ABI, rather
        than TARGET_HARD_FLOAT and TARGET_SOFT_FLOAT.  
        * config/mips/mips.h (mips16_hard_float): Delete.
-       (TARGET_HARD_FLOAT_ABI, TARGET_SOFT_FLOAT_ABI):  Delete these
+       (TARGET_HARD_FLOAT_ABI, TARGET_SOFT_FLOAT_ABI): Delete these
        definitions, and replace with....
        (TARGET_HARD_FLOAT, TARGET_SOFT_FLOAT): Define.
        * config/mips/mips.c (mips16_hard_float): Delete.  Replace
        all references with (TARGET_MIPS16 && TARGET_HARD_FLOAT_ABI).
        (MIPS_MARCH_CONTROLS_SOFT_FLOAT): Update comments.
-       (override_options):  Replace MASK_SOFT_FLOAT references with
+       (override_options): Replace MASK_SOFT_FLOAT references with
        MASK_SOFT_FLOAT_ABI.  Delete twiddling with MASK_SOFT_FLOAT
        and mips16_hard_float when TARGET_MIPS16.
        
        tri-state integer.
        * optabs.c (expand_ffs, expand_ctz): New functions to compute
        ffs and ctz using clz.
-       (expand_unop):  Call them.
+       (expand_unop): Call them.
        * config/rs6000/rs6000.h (CLZ_DEFINED_VALUE_AT_ZERO): Fix its
        result value.
        (CTZ_DEFINED_VALUE_AT_ZERO): Likewise.
 
 2007-08-01  Sandra Loosemore  <sandra@codesourcery.com>
 
-       * reload.c (find_reloads_address_part):  Pass correct MEMREFLOC
+       * reload.c (find_reloads_address_part): Pass correct MEMREFLOC
        argument to find_reloads_address.
 
 2007-08-01  Daniel Jacobowitz  <dan@codesourcery.com>
 
 2007-07-31  Sandra Loosemore  <sandra@codesourcery.com>
 
-       * config/mips/mips.h (ISA_HAS_SYNCI):  Add !TARGET_MIPS16 test.
+       * config/mips/mips.h (ISA_HAS_SYNCI): Add !TARGET_MIPS16 test.
 
 2007-07-31  Revital Eres  <eres@il.ibm.com>
 
 
 2007-07-18  Caroline Tice  <ctice@apple.com>
        
-       * var-tracking.c (find_src_status):  Check for  COND_EXEC insns
+       * var-tracking.c (find_src_status): Check for  COND_EXEC insns
        and handle them correctly; check that src is not NULL before
        trying to use it.
        (find_src_set_src): Likewise.
 2007-07-16  Sandra Loosemore  <sandra@codesourcery.com>
            Nigel Stephens  <nigel@mips.com>
 
-       * config/mips/mips.md:  Include 20kc.md.
+       * config/mips/mips.md: Include 20kc.md.
        * config/mips/20kc.md: New file.
        * config/mips/mips.c (mips_rtx_cost_data): Fill in 20Kc costs.
        (mips_adjust_cost): Tweak for 20Kc.
        * df-problems.c (df_ru_alloc, df_rd_alloc, df_lr_alloc,
        df_live_alloc, df_urec_alloc, df_note_alloc): set optional_p.
        (problem_RU, problem_RD, problem_LR, problem_UREC, problem_CHAIN,
-       problem_NOTE):  Initialize free_blocks_on_set_blocks.
+       problem_NOTE): Initialize free_blocks_on_set_blocks.
        (df_lr_bb_local_compute): Recompute luids if df_live problem is
        not active.
        (df_live_set_all_dirty, df_note_alloc): New function.
        * tree-ssa.c (tree_ssa_useless_type_conversion_1):
        Convert the MIN/MAX of the inner type to the outer
        type before comparing them.
-       * tree-ssa-loop-prefetch.c (idx_analyze_ref):  Handle
+       * tree-ssa-loop-prefetch.c (idx_analyze_ref): Handle
        POINTER_PLUS_EXPR instead of PLUS_EXPR.
        (issue_prefetch_ref): Create a POINTER_PLUS_EXPR instead
        of PLUS_EXPR for pointers.
        * config/mn10300/mn10300.md: Include.
        * config/mn10300/mn10300.c(mn10300_secondary_reload_class):
        Fix up for removed macro.
-       * config/mn10300/predicates.md (call_address_operand):  Ditto.
+       * config/mn10300/predicates.md (call_address_operand): Ditto.
        * config/mn10300/mn10300.h (REG_CLASS_FROM_LETTER): Delete.
        (CONST_OK_FOR_I): Ditto.
        (CONST_OK_FOR_J): Ditto.
        * doc/extend.texi (Function Attributes): Document MIPS "near" and
        "far" attributes.
 
-       * testsuite/gcc.target/mips/near-far-1.c:  New test case.
-       * testsuite/gcc.target/mips/near-far-2.c:  New test case.
-       * testsuite/gcc.target/mips/near-far-3.c:  New test case.
-       * testsuite/gcc.target/mips/near-far-4.c:  New test case.
+       * testsuite/gcc.target/mips/near-far-1.c: New test case.
+       * testsuite/gcc.target/mips/near-far-2.c: New test case.
+       * testsuite/gcc.target/mips/near-far-3.c: New test case.
+       * testsuite/gcc.target/mips/near-far-4.c: New test case.
 
 2007-05-25  Eric Christopher  <echristo@apple.com>
 
        stmt_dominates_stmt_p, get_lsm_tmp_name): Declare.
        * Makefile.in (tree-predcom.o): Add.
        (tree-affine.o): Add TREE_GIMPLE_H dependency.
-       * passes.c (init_optimization_passes):  Add dceloop after
+       * passes.c (init_optimization_passes): Add dceloop after
        copy propagation in loop optimizer.  Add predictive commoning
        to loop optimizer passes.
 
 
 2007-05-14  Dave Korn  <dave.korn@artimi.com>
 
-       * genautomata.c (gen_regexp_el):  Allocate correct size for regexp.
+       * genautomata.c (gen_regexp_el): Allocate correct size for regexp.
 
 2007-05-14  Rafael Avila de Espindola  <espindola@google.com>
 
 
 2007-04-26  Steve Ellcey  <sje@cup.hp.com>
 
-       * config/ia64/ia64.md (ip_value):  Fix itanium_class attribute.
+       * config/ia64/ia64.md (ip_value): Fix itanium_class attribute.
 
 2007-04-26  Richard Guenther  <rguenther@suse.de>
 
        (create_phi_node): Use set_phi_nodes.
        * omp-low.c (expand_omp_parallel): Use bb_stmt_list.
        * tree-if-conv.c (process_phi_nodes): Use set_phi_nodes.
-       (combine_blocks):  Use bb_stmt_list and set_bb_stmt_list.
+       (combine_blocks): Use bb_stmt_list and set_bb_stmt_list.
        * tree-flow-inline.h (phi_nodes, set_phi_nodes,
        (bsi_start, bsi_last): Use bb_stmt_list.
        (phi_nodes_ptr, bb_stmt_list, set_bb_stmt_list): New functions.
        * tree-ssa-loop-ivopts.c (ivopts_global_cost_for_size): Use
        estimate_reg_pressure_cost.  Add number of ivs.
        (determine_set_costs): Dump target_reg_cost.
-       * loop-invariant.c (gain_for_invariant):  Use
+       * loop-invariant.c (gain_for_invariant): Use
        estimate_reg_pressure_cost.  Removed n_inv_uses argument.
        (best_gain_for_invariant, find_invariants_to_move): Remove
        n_inv_uses.
 2007-04-07  Bruce Korb  <bkorb@gnu.org>
 
        * c.opt: Add -Wformat-contains-nul.
-       * c-format.c (set_Wformat):  Set warn_format_contains_nul to the
+       * c-format.c (set_Wformat): Set warn_format_contains_nul to the
          -Wformat setting.
        (check_format_info_main): Check OPT_Wformat_contains_nul before emitting
        the NUL byte warning.
        argument "reliable".
        (infer_loop_bounds_from_ref, infer_loop_bounds_from_array):
        Add argument "reliable".  Propagate it through calls.
-       (infer_loop_bounds_from_undefined):  Derive number of iterations
+       (infer_loop_bounds_from_undefined): Derive number of iterations
        estimates from references in blocks that do not dominate loop latch.
        (gcov_type_to_double_int): New function.
        (estimate_numbers_of_iterations_loop): Use gcov_type_to_double_int
        (dsp_32only_bdesc): New description table for 32-bit only DSP REV 1
        and 2 builtins.
        (bdesc_map): Add one field of unsupported_target_flags.
-       (bdesc_arrays):  Update entries to have extra fields.  Add
+       (bdesc_arrays): Update entries to have extra fields.  Add
        dsp_32only_bdesc.
        (mips_init_builtins): Initialize new function types.
        Check unsupported_target_fileds to filter out builtins.
 
 2007-03-01  Zdenek Dvorak  <dvorakz@suse.cz>
 
-       * tree-ssa-loop-prefetch.c (determine_unroll_factor):  Bound the
+       * tree-ssa-loop-prefetch.c (determine_unroll_factor): Bound the
        unroll factor by the estimated number of iterations.
        (loop_prefetch_arrays): Do not prefetch in loops that iterate less
        than prefetch latency.
 2007-02-23  Steve Ellcey  <sje@cup.hp.com>
 
        PR debug/29614
-       * varpool.c (varpool_assemble_pending_decls):  Set
+       * varpool.c (varpool_assemble_pending_decls): Set
        varpool_last_needed_node to null.
 
 2007-02-23  DJ Delorie  <dj@redhat.com>
        * config/spu/spu-protos.h (spu_init_expanders): Declare.
        * config/spu/spu.c (spu_expand_prologue): Set REGNO_POINTER_ALIGN for
        HARD_FRAME_POINTER_REGNUM.
-       (spu_legitimate_address):  Use regno_aligned_for_reload.
-       (regno_aligned_for_load):  HARD_FRAME_POINTER_REGNUM is only 16 byte
+       (spu_legitimate_address): Use regno_aligned_for_reload.
+       (regno_aligned_for_load): HARD_FRAME_POINTER_REGNUM is only 16 byte
        aligned when frame_pointer_needed is true.
        (spu_init_expanders): New.  Set alignment of HARD_FRAME_POINTER_REGNUM
        to 8 bits.
        rotqmbi_<mode>, rotqmby_<mode>, ashr<mode>3, rotma_<mode>,
        rotl<mode>3, rotlti3, rotqbybi_ti, rotqby_ti, rotqbi_ti): Use
        spu_nonmem_operand instead of spu_shift_operands.  Use new modifiers.
-       (lshr<mode>3_reg):  Fix rtl description.
+       (lshr<mode>3_reg): Fix rtl description.
 
        Make sure mulhisi immediate operands are valid.
        * config/spu/predicates.md (imm_K_operand): Add.
        * config/spu/spu.c (print_operand): Handle HIGH correctly.
        (spu_split_immediate): Split CONST_VECTORs with -mlarge-mem.
        (immediate_load_p): Allow symbols that use 2 instructions to create.
-       (classify_immediate, spu_builtin_splats):  Don't accept a CONST_VECTOR
+       (classify_immediate, spu_builtin_splats): Don't accept a CONST_VECTOR
        with symbols when flag_pic is set.
        (const_vector_immediate_p): New.
        (logical_immediate_p, iohl_immediate_p, arith_immediate_p): Don't
        * config/spu/spu_internals.h: Ditto.
 
        Fix incorrect operand modifiers.
-       * config/spu/spu-builtins.md (spu_mpy, spu_mpyu):  Remove use of %H.
-       * config/spu/spu.md (xor<mode>3):  Change %S to %J.
+       * config/spu/spu-builtins.md (spu_mpy, spu_mpyu): Remove use of %H.
+       * config/spu/spu.md (xor<mode>3): Change %S to %J.
 
        Optimize one case of zero_extend of a vec_select.
-       * config/spu/spu.md (_vec_extractv8hi_ze):  Add.
+       * config/spu/spu.md (_vec_extractv8hi_ze): Add.
 
        Accept any immediate for hbr.
-       * config/spu/spu.md (hbr):  Change s constraints to i.
+       * config/spu/spu.md (hbr): Change s constraints to i.
 
 2007-02-21  Paul Brook  <paul@codesourcery.com>
 
 2007-02-18  Roger Sayle  <roger@eyesopen.com>
 
        PR rtl-optimization/28173
-       * simplify-rtx.c (simplify_binary_operation_1) <IOR>:  Optimize
+       * simplify-rtx.c (simplify_binary_operation_1) <IOR>: Optimize
        (X & C1) | C2 as C2 when (C1 & C2) == C1 and X has no side-effects.
        Optimize (X & C1) | C2 as X | C2 when (C1 | C2) == ~0.
        Canonicalize (X & C1) | C2 as (X & (C1 & ~C2)) | C2.
        of an arglist.  Change return type to bool.  Use new CALL_EXPR
        accessors.
 
-       (fold_builtin_strstr):  Pass call arguments individually instead
+       (fold_builtin_strstr): Pass call arguments individually instead
        of as an arglist, fixing callers appropriately.  Use new CALL_EXPR
        accessors and constructors.  Return NULL_TREE instead of 0.
        (fold_builtin_strchr): Likewise.
        (fold_ternary): Remove CALL_EXPR case, since they are no longer
        ternary expressions.
        (fold): Add logic for tcc_vl_exp.
-       (fold_checksum_tree):  Make it know about tcc_vl_exp.  Use
+       (fold_checksum_tree): Make it know about tcc_vl_exp.  Use
        TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.
        (fold_build3_stat): Add assertion to flag broken interface for
        constructing CALL_EXPRs.
        * tree-vrp.c (stmt_interesting_for_vrp): Use new CALL_EXPR accessors.
        (vrp_visit_stmt): Likewise.
 
-       * tree-ssa-loop-im.c (outermost_invariant_loop_expr):  Make it
+       * tree-ssa-loop-im.c (outermost_invariant_loop_expr): Make it
        know about tcc_vl_exp.  Use TREE_OPERAND_LENGTH instead of
        TREE_CODE_LENGTH.
        (force_move_till_expr): Likewise.
        (estimate_num_insns_1): Use new CALL_EXPR accessors.
        (expand_call_inline): Tidy up call to initialize_inlined_parameters.
 
-       * tree-vect-transform.c (vect_create_epilog_for_reduction):  Use
+       * tree-vect-transform.c (vect_create_epilog_for_reduction): Use
        TREE_OPERAND_LENGTH instead of TREE_CODE_LENGTH.
        (vectorizable_reduction): Likewise.
        (vectorizable_call): Use new CALL_EXPR iterators.
        (arm_expand_unop_builtin): Likewise.
        (arm_expand_builtin): Use new CALL_EXPR accessors.
 
-       * config/mips/mips.c (mips_expand_builtin):  Use new CALL_EXPR
+       * config/mips/mips.c (mips_expand_builtin): Use new CALL_EXPR
        accessors.
 
        * config/bfin/bfin.c (bfin_expand_binop_builtin): Pass entire
        * tree-data-ref.c (tree_fold_divides_p): Don't use tree_fold_gcd to
        test whether one constant integer is a multiple of another.  Instead
        call int_const_binop with TRUNC_MOD_EXPR and test for a zero result.
-       * fold-const.c (multiple_of_p):  We've determined both TOP and
+       * fold-const.c (multiple_of_p): We've determined both TOP and
        BOTTOM are integer constants so we can call int_const_binop directly
        instead of the more generic const_binop.
 
 
        PR other/30182
        * config/pa/pa.c (pa_init_builtins): Set asm names for finite routines.
-       * config/ia64/ia64.c (ia64_init_builtins):  Ditto.
+       * config/ia64/ia64.c (ia64_init_builtins): Ditto.
 
 2007-01-25  Richard Guenther  <rguenther@suse.de>
 
        * longlong.h (count_leading_zeros, COUNT_LEADING_ZEROS_0): Add
        ColdFire alternatives.
        * config/m68k/m68k.h (CLZ_DEFINED_VALUE_AT_ZERO): New macro.
-       * config/m68k/m68k.md (clzsi2):  Define for ColdFire
+       * config/m68k/m68k.md (clzsi2): Define for ColdFire
        architectures that support ff1 instruction.
 
 2007-01-19  Richard Sandiford  <richard@codesourcery.com>
 
 2007-01-02  Steve Ellcey  <sje@cup.hp.com>
 
-       * sbitmap.c (HOST_BITS_PER_LONG_LONG):  Change to
+       * sbitmap.c (HOST_BITS_PER_LONG_LONG): Change to
        HOST_BITS_PER_LONGLONG
 
 2007-01-02  Manuel Lopez-Ibanez <manu@gcc.gnu.org>
index 166792c4a40e3707c1a4b8b0e217c0ace4b06e14..566e1cc2e1b883038440f559e506b67a85af44e4 100644 (file)
@@ -6270,6 +6270,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_ARGS_INFO:
       return expand_builtin_args_info (exp);
 
+    case BUILT_IN_VA_ARG_PACK:
+      /* All valid uses of __builtin_va_arg_pack () are removed during
+        inlining.  */
+      error ("invalid use of %<__builtin_va_arg_pack ()%>");
+      return const0_rtx;
+
       /* Return the address of the first anonymous stack arg.  */
     case BUILT_IN_NEXT_ARG:
       if (fold_builtin_next_arg (exp, false))
@@ -10472,14 +10478,32 @@ fold_call_expr (tree exp, bool ignore)
   tree fndecl = get_callee_fndecl (exp);
   if (fndecl
       && TREE_CODE (fndecl) == FUNCTION_DECL
-      && DECL_BUILT_IN (fndecl))
-    {
+      && DECL_BUILT_IN (fndecl)
+      /* If CALL_EXPR_VA_ARG_PACK is set, the arguments aren't finalized
+        yet.  Defer folding until we see all the arguments
+        (after inlining).  */
+      && !CALL_EXPR_VA_ARG_PACK (exp))
+    {
+      int nargs = call_expr_nargs (exp);
+
+      /* Before gimplification CALL_EXPR_VA_ARG_PACK is not set, but
+        instead last argument is __builtin_va_arg_pack ().  Defer folding
+        even in that case, until arguments are finalized.  */
+      if (nargs && TREE_CODE (CALL_EXPR_ARG (exp, nargs - 1)) == CALL_EXPR)
+       {
+         tree fndecl2 = get_callee_fndecl (CALL_EXPR_ARG (exp, nargs - 1));
+         if (fndecl2
+             && TREE_CODE (fndecl2) == FUNCTION_DECL
+             && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
+             && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
+           return NULL_TREE;
+       }
+
       /* FIXME: Don't use a list in this interface.  */
       if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
          return targetm.fold_builtin (fndecl, CALL_EXPR_ARGS (exp), ignore);
       else
        {
-         int nargs = call_expr_nargs (exp);
          if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
            {
              tree *args = CALL_EXPR_ARGP (exp);
@@ -10565,6 +10589,17 @@ fold_builtin_call_array (tree type,
     if (TREE_CODE (fndecl) == FUNCTION_DECL
         && DECL_BUILT_IN (fndecl))
       {
+       /* If last argument is __builtin_va_arg_pack (), arguments to this
+          function are not finalized yet.  Defer folding until they are.  */
+       if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR)
+         {
+           tree fndecl2 = get_callee_fndecl (argarray[n - 1]);
+           if (fndecl2
+               && TREE_CODE (fndecl2) == FUNCTION_DECL
+               && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
+               && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
+             return build_call_array (type, fn, n, argarray);
+         }
         if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
           {
             tree arglist = NULL_TREE;
index 8bedfbf30e93f3a251602cd015a4f7647b3e45bc..01ba3b365877015a2c70ecbc65841c7564a8ed50 100644 (file)
@@ -701,6 +701,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_UPDATE_SETJMP_BUF, "update_setjmp_buf", BT_FN_V
 DEF_GCC_BUILTIN        (BUILT_IN_VA_COPY, "va_copy", BT_FN_VOID_VALIST_REF_VALIST_ARG, ATTR_NULL)
 DEF_GCC_BUILTIN        (BUILT_IN_VA_END, "va_end", BT_FN_VOID_VALIST_REF, ATTR_NULL)
 DEF_GCC_BUILTIN        (BUILT_IN_VA_START, "va_start", BT_FN_VOID_VALIST_REF_VAR, ATTR_NULL)
+DEF_GCC_BUILTIN        (BUILT_IN_VA_ARG_PACK, "va_arg_pack", BT_FN_INT, ATTR_PURE_NOTHROW_LIST)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN__EXIT, "_exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LIST)
 DEF_C99_BUILTIN        (BUILT_IN__EXIT2, "_Exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LIST)
 
index 0012740476b924b22404f75118112352f88742cd..9f306a44e484007d78958dfee6aee30e59d4738e 100644 (file)
@@ -556,6 +556,32 @@ the containing function.  You should specify, for @var{result}, a value
 returned by @code{__builtin_apply}.
 @end deftypefn
 
+@deftypefn {Built-in Function} __builtin_va_arg_pack ()
+This built-in function represents all anonymous arguments of an inline
+function.  It can be used only in inline functions which will be always
+inlined, never compiled as a separate function, such as those using
+@code{__attribute__ ((__always_inline__))} or
+@code{__attribute__ ((__gnu_inline__))} extern inline functions.
+It must be only passed as last argument to some other function
+with variable arguments.  This is useful for writing small wrapper
+inlines for variable argument functions, when using preprocessor
+macros is undesirable.  For example:
+@smallexample
+extern int myprintf (FILE *f, const char *format, ...);
+extern inline __attribute__ ((__gnu_inline__)) int
+myprintf (FILE *f, const char *format, ...)
+@{
+  int r = fprintf (f, "myprintf: ");
+  if (r < 0)
+    return r;
+  int s = fprintf (f, format, __builtin_va_arg_pack ());
+  if (s < 0)
+    return s;
+  return r + s;
+@}
+@end smallexample
+@end deftypefn
+
 @node Typeof
 @section Referring to a Type with @code{typeof}
 @findex typeof
index 13f447cc8b6aaa27901d29714cef8c304aa0944c..054f4f13add7875b1cd66f3dbefc85558475146d 100644 (file)
@@ -7935,6 +7935,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier);
 
     case CALL_EXPR:
+      /* All valid uses of __builtin_va_arg_pack () are removed during
+        inlining.  */
+      if (CALL_EXPR_VA_ARG_PACK (exp))
+       error ("invalid use of %<__builtin_va_arg_pack ()%>");
       /* Check for a built-in function.  */
       if (TREE_CODE (CALL_EXPR_FN (exp)) == ADDR_EXPR
          && (TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (exp), 0))
index 5c376ac5060129b15481faa0f56d81b17a62e92c..ee8ef09a10302269f97c69931424835657468a3e 100644 (file)
@@ -2170,8 +2170,50 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
            }
        }
     }
-  else if (nargs != 0)
-    CALL_CANNOT_INLINE_P (*expr_p) = 1;
+  else
+    {
+      if (nargs != 0)
+       CALL_CANNOT_INLINE_P (*expr_p) = 1;
+      i = 0;
+      p = NULL_TREE;
+    }
+
+  /* If the last argument is __builtin_va_arg_pack () and it is not
+     passed as a named argument, decrease the number of CALL_EXPR
+     arguments and set instead the CALL_EXPR_VA_ARG_PACK flag.  */
+  if (!p
+      && i < nargs
+      && TREE_CODE (CALL_EXPR_ARG (*expr_p, nargs - 1)) == CALL_EXPR)
+    {
+      tree last_arg = CALL_EXPR_ARG (*expr_p, nargs - 1);
+      tree last_arg_fndecl = get_callee_fndecl (last_arg);
+
+      if (last_arg_fndecl
+         && TREE_CODE (last_arg_fndecl) == FUNCTION_DECL
+         && DECL_BUILT_IN_CLASS (last_arg_fndecl) == BUILT_IN_NORMAL
+         && DECL_FUNCTION_CODE (last_arg_fndecl) == BUILT_IN_VA_ARG_PACK)
+       {
+         tree call = *expr_p;
+
+         --nargs;
+         *expr_p = build_call_array (TREE_TYPE (call), CALL_EXPR_FN (call),
+                                     nargs, CALL_EXPR_ARGP (call));
+         /* Copy all CALL_EXPR flags, locus and block, except
+            CALL_EXPR_VA_ARG_PACK flag.  */
+         CALL_EXPR_STATIC_CHAIN (*expr_p) = CALL_EXPR_STATIC_CHAIN (call);
+         CALL_EXPR_TAILCALL (*expr_p) = CALL_EXPR_TAILCALL (call);
+         CALL_EXPR_RETURN_SLOT_OPT (*expr_p)
+           = CALL_EXPR_RETURN_SLOT_OPT (call);
+         CALL_FROM_THUNK_P (*expr_p) = CALL_FROM_THUNK_P (call);
+         CALL_CANNOT_INLINE_P (*expr_p)
+           = CALL_CANNOT_INLINE_P (call);
+         TREE_NOTHROW (*expr_p) = TREE_NOTHROW (call);
+         SET_EXPR_LOCUS (*expr_p, EXPR_LOCUS (call));
+         TREE_BLOCK (*expr_p) = TREE_BLOCK (call);
+         /* Set CALL_EXPR_VA_ARG_PACK.  */
+         CALL_EXPR_VA_ARG_PACK (*expr_p) = 1;
+       }
+    }
 
   /* Finally, gimplify the function arguments.  */
   for (i = (PUSH_ARGS_REVERSED ? nargs - 1 : 0);
index aeaad7277a5233b2ccb894662b2a976349c00159..7a2a20bd149acd6e6b21402b3a8f97e07eaf34c6 100644 (file)
@@ -1,3 +1,8 @@
+2007-09-05  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.c-torture/execute/va-arg-pack-1.c: New test.
+       * gcc.dg/va-arg-pack-1.c: New test.
+
 2007-09-05  Adam Nemet  <anemet@caviumnetworks.com>
 
        * gcc.dg/tree-ssa/builtin-expect-1.c: New test.
diff --git a/gcc/testsuite/gcc.c-torture/execute/va-arg-pack-1.c b/gcc/testsuite/gcc.c-torture/execute/va-arg-pack-1.c
new file mode 100644 (file)
index 0000000..baefe87
--- /dev/null
@@ -0,0 +1,143 @@
+/* __builtin_va_arg_pack () builtin tests.  */
+
+#include <stdarg.h>
+
+extern void abort (void);
+
+int v1 = 8;
+long int v2 = 3;
+void *v3 = (void *) &v2;
+struct A { char c[16]; } v4 = { "foo" };
+long double v5 = 40;
+char seen[20];
+int cnt;
+
+__attribute__ ((noinline)) int
+foo1 (int x, int y, ...)
+{
+  int i;
+  long int l;
+  void *v;
+  struct A a;
+  long double ld;
+  va_list ap;
+
+  va_start (ap, y);
+  if (x < 0 || x >= 20 || seen[x])
+    abort ();
+  seen[x] = ++cnt;
+  if (y != 6)
+    abort ();
+  i = va_arg (ap, int);
+  if (i != 5)
+    abort ();
+  switch (x)
+    {
+    case 0:
+      i = va_arg (ap, int);
+      if (i != 9 || v1 != 9)
+       abort ();
+      a = va_arg (ap, struct A);
+      if (__builtin_memcmp (a.c, v4.c, sizeof (a.c)) != 0)
+       abort ();
+      v = (void *) va_arg (ap, struct A *);
+      if (v != (void *) &v4)
+       abort ();
+      l = va_arg (ap, long int);
+      if (l != 3 || v2 != 4)
+       abort ();
+      break;
+    case 1:
+      ld = va_arg (ap, long double);
+      if (ld != 41 || v5 != ld)
+       abort ();
+      i = va_arg (ap, int);
+      if (i != 8)
+       abort ();
+      v = va_arg (ap, void *);
+      if (v != &v2)
+       abort ();
+      break;
+    case 2:
+      break;
+    default:
+      abort ();
+    }
+  va_end (ap);
+  return x;
+}
+
+__attribute__ ((noinline)) int
+foo2 (int x, int y, ...)
+{
+  long long int ll;
+  void *v;
+  struct A a, b;
+  long double ld;
+  va_list ap;
+
+  va_start (ap, y);
+  if (x < 0 || x >= 20 || seen[x])
+    abort ();
+  seen[x] = ++cnt | 64;
+  if (y != 10)
+    abort ();
+  switch (x)
+    {
+    case 11:
+      break;
+    case 12:
+      ld = va_arg (ap, long double);
+      if (ld != 41 || v5 != 40)
+       abort ();
+      a = va_arg (ap, struct A);
+      if (__builtin_memcmp (a.c, v4.c, sizeof (a.c)) != 0)
+       abort ();
+      b = va_arg (ap, struct A);
+      if (__builtin_memcmp (b.c, v4.c, sizeof (b.c)) != 0)
+       abort ();
+      v = va_arg (ap, void *);
+      if (v != &v2)
+       abort ();
+      ll = va_arg (ap, long long int);
+      if (ll != 16LL)
+       abort ();
+      break;
+    case 2:
+      break;
+    default:
+      abort ();
+    }
+  va_end (ap);
+  return x + 8;
+}
+
+__attribute__ ((noinline)) int
+foo3 (void)
+{
+  return 6;
+}
+
+extern inline __attribute__ ((always_inline, gnu_inline)) int
+bar (int x, ...)
+{
+  if (x < 10)
+    return foo1 (x, foo3 (), 5, __builtin_va_arg_pack ());
+  return foo2 (x, foo3 () + 4, __builtin_va_arg_pack ());
+}
+
+int
+main (void)
+{
+  if (bar (0, ++v1, v4, &v4, v2++) != 0)
+    abort ();
+  if (bar (1, ++v5, 8, v3) != 1)
+    abort ();
+  if (bar (2) != 2)
+    abort ();
+  if (bar (v1 + 2) != 19)
+    abort ();
+  if (bar (v1 + 3, v5--, v4, v4, v3, 16LL) != 20)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/va-arg-pack-1.c b/gcc/testsuite/gcc.dg/va-arg-pack-1.c
new file mode 100644 (file)
index 0000000..09ae979
--- /dev/null
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int bar (int, const char *, int, ...);
+int baz (int, const char *, long int);
+
+int
+f1 (int x, ...)
+{
+  return bar (5, "", 6, __builtin_va_arg_pack ());     /* { dg-error "invalid use of" } */
+}
+
+extern inline __attribute__((always_inline)) int
+f2 (int y, ...)
+{
+  return bar (y, "", __builtin_va_arg_pack ());                /* { dg-error "invalid use of" } */
+}
+
+extern inline __attribute__((always_inline)) int
+f3 (int y, ...)
+{
+  return bar (y, "", 5, __builtin_va_arg_pack ());
+}
+
+extern inline __attribute__((always_inline)) int
+f4 (int y, ...)
+{
+  return bar (y, "", 4, __builtin_va_arg_pack (), 6);  /* { dg-error "invalid use of" } */
+}
+
+extern inline __attribute__((always_inline)) int
+f5 (int y, ...)
+{
+  return baz (y, "", __builtin_va_arg_pack ());                /* { dg-error "invalid use of" } */
+}
+
+extern inline __attribute__((always_inline)) int
+f6 (int y, ...)
+{
+  return __builtin_va_arg_pack ();                     /* { dg-error "invalid use of" } */
+}
+
+int
+test (void)
+{
+  int a = f2 (5, "a", 6);
+  a += f3 (6, "ab", 17LL);
+  a += f4 (7, 1, 2, 3);
+  a += f5 (8, 7L);
+  a += f6 (9);
+  return a;
+}
index b655b79ac01d2b8168fc1cde398a9d6c4ddd826d..d49c3c8c49055b855090e48c09840fbbb92d634c 100644 (file)
@@ -815,9 +815,59 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, int count_scal
             into multiple statements, we need to process all of them.  */
          while (!bsi_end_p (copy_bsi))
            {
-             stmt = bsi_stmt (copy_bsi);
+             tree *stmtp = bsi_stmt_ptr (copy_bsi);
+             tree stmt = *stmtp;
              call = get_call_expr_in (stmt);
 
+             if (call && CALL_EXPR_VA_ARG_PACK (call) && id->call_expr)
+               {
+                 /* __builtin_va_arg_pack () should be replaced by
+                    all arguments corresponding to ... in the caller.  */
+                 tree p, *argarray, new_call, *call_ptr;
+                 int nargs = call_expr_nargs (id->call_expr);
+
+                 for (p = DECL_ARGUMENTS (id->src_fn); p; p = TREE_CHAIN (p))
+                   nargs--;
+
+                 argarray = (tree *) alloca ((nargs + call_expr_nargs (call))
+                                             * sizeof (tree));
+
+                 memcpy (argarray, CALL_EXPR_ARGP (call),
+                         call_expr_nargs (call) * sizeof (*argarray));
+                 memcpy (argarray + call_expr_nargs (call),
+                         CALL_EXPR_ARGP (id->call_expr)
+                         + (call_expr_nargs (id->call_expr) - nargs),
+                         nargs * sizeof (*argarray));
+
+                 new_call = build_call_array (TREE_TYPE (call),
+                                              CALL_EXPR_FN (call),
+                                              nargs + call_expr_nargs (call),
+                                              argarray);
+                 /* Copy all CALL_EXPR flags, locus and block, except
+                    CALL_EXPR_VA_ARG_PACK flag.  */
+                 CALL_EXPR_STATIC_CHAIN (new_call)
+                   = CALL_EXPR_STATIC_CHAIN (call);
+                 CALL_EXPR_TAILCALL (new_call) = CALL_EXPR_TAILCALL (call);
+                 CALL_EXPR_RETURN_SLOT_OPT (new_call)
+                   = CALL_EXPR_RETURN_SLOT_OPT (call);
+                 CALL_FROM_THUNK_P (new_call) = CALL_FROM_THUNK_P (call);
+                 CALL_CANNOT_INLINE_P (new_call)
+                   = CALL_CANNOT_INLINE_P (call);
+                 TREE_NOTHROW (new_call) = TREE_NOTHROW (call);
+                 SET_EXPR_LOCUS (new_call, EXPR_LOCUS (call));
+                 TREE_BLOCK (new_call) = TREE_BLOCK (call);
+
+                 call_ptr = stmtp;
+                 if (TREE_CODE (*call_ptr) == GIMPLE_MODIFY_STMT)
+                   call_ptr = &GIMPLE_STMT_OPERAND (*call_ptr, 1);
+                 if (TREE_CODE (*call_ptr) == WITH_SIZE_EXPR)
+                   call_ptr = &TREE_OPERAND (*call_ptr, 0);
+                 gcc_assert (*call_ptr == call);
+                 *call_ptr = new_call;
+                 stmt = *stmtp;
+                 update_stmt (stmt);
+               }
+
              /* Statements produced by inlining can be unfolded, especially
                 when we constant propagated some operands.  We can't fold
                 them right now for two reasons:
@@ -2518,6 +2568,7 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
   id->src_fn = fn;
   id->src_node = cg_edge->callee;
   id->src_cfun = DECL_STRUCT_FUNCTION (fn);
+  id->call_expr = t;
 
   initialize_inlined_parameters (id, t, fn, bb);
 
index 574b1d70040f80c1b922066b9bb1b208be234377..1fa360ad3459ff1b82ad491a8812db5a7e3eab56 100644 (file)
@@ -56,6 +56,10 @@ typedef struct copy_body_data
   /* Current BLOCK.  */
   tree block;
 
+  /* CALL_EXPR if va arg parameter packs should be expanded or NULL
+     is not.  */
+  tree call_expr;
+
   /* Exception region the inlined call lie in.  */
   int eh_region;
   /* Take region number in the function being copied, add this value and
index 8da7ade6a110cdf403d4c7fb7f1ffbece26b80b3..bc7ebf4ea79b84d63bb60ccb43a16ba6dc458b65 100644 (file)
@@ -1228,6 +1228,15 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
              }
          }
       }
+      if (CALL_EXPR_VA_ARG_PACK (node))
+       {
+         if (call_expr_nargs (node) > 0)
+           {
+             pp_character (buffer, ',');
+             pp_space (buffer);
+           }
+         pp_string (buffer, "__builtin_va_arg_pack ()");
+       }
       pp_character (buffer, ')');
 
       op1 = CALL_EXPR_STATIC_CHAIN (node);
index 5fda4d4b3a18a173dd56233ed7f045199afde07a..c274fb6ec245382f660c4d7c7383b01dc40b5912 100644 (file)
@@ -464,6 +464,8 @@ struct gimple_stmt GTY(())
            VAR_DECL or FUNCTION_DECL or IDENTIFIER_NODE
        ASM_VOLATILE_P in
            ASM_EXPR
+       CALL_EXPR_VA_ARG_PACK in
+         CALL_EXPR
        TYPE_CACHED_VALUES_P in
           ..._TYPE
        SAVE_EXPR_RESOLVED_P in
@@ -1222,6 +1224,11 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 #define SAVE_EXPR_RESOLVED_P(NODE) \
   (TREE_CHECK (NODE, SAVE_EXPR)->base.public_flag)
 
+/* Set on a CALL_EXPR if this stdarg call should be passed the argument
+   pack.  */
+#define CALL_EXPR_VA_ARG_PACK(NODE) \
+  (CALL_EXPR_CHECK(NODE)->base.public_flag)
+
 /* In any expression, decl, or constant, nonzero means it has side effects or
    reevaluation of the whole expression could produce a different value.
    This is set if any subexpression is a function call, a side effect or a
This page took 0.184394 seconds and 5 git commands to generate.