Qing Zhao <[email protected]> writes:
>>> diff --git a/gcc/flag-types.h b/gcc/flag-types.h
>>> index 852ea76..0f7e503 100644
>>> --- a/gcc/flag-types.h
>>> +++ b/gcc/flag-types.h
>>> @@ -285,6 +285,15 @@ enum sanitize_code {
>>> | SANITIZE_BOUNDS_STRICT
>>> };
>>>
>>> +enum zero_call_used_regs_code {
>>> + UNSET = 0,
>>> + SKIP = 1UL << 0,
>>> + ONLY_USED = 1UL << 1,
>>> + ONLY_GPR = 1UL << 2,
>>> + ONLY_ARG = 1UL << 3,
>>> + ALL = 1UL << 4
>>> +};
>>
>> I'd suggested these names on the assumption that we'd be using
>> a C++ enum class, so that the enum would be referenced as
>> name::ALL, name::SKIP, etc. But I guess using a C++ enum class
>> doesn't work well with bitfields after all.
>>
>> These names are too generic without the name:: scoping though.
>> Perhaps we should put them in a namespace:
>>
>> namespace zero_regs_flags {
>> const unsigned int UNSET = 0;
>> …etc…
>> }
>>
>> (call-used probably doesn't need to be part of the flag names,
>> since the concept is more general than that and call-usedness
>> is really a filter that's being applied on top. Although I guess
>> the same is true of “zero”. ;-))
>>
>> I don't think we should have ALL as a separate flag: ALL is the absence
>> of ONLY_*. Maybe we should have an ENABLED flag that all non-skip
>> combinations use?
>>
>> If it makes things easier, I think it would be good to have e.g.:
>>
>> unsigned int USED_GPR = ENABLED | ONLY_USED | ONLY_GPR;
>>
>> inside the namespace, to reduce the verbosity in the option table.
>
> Then, the final namespace will look like:
>
> namespace zero_regs_flags {
> const unsigned int UNSET = 0;
> const unsigned int SKIP = 1UL << 0;
> const unsigned int ONLY_USED = 1UL << 1;
> const unsigned int ONLY_GPR = 1UL << 2;
> const unsigned int ONLY_ARG = 1UL << 3;
> const unsigned int ENABLED = 1UL << 4;
> const unsigned int USED_GPR_ARG = ONLY_USED | ONLY_GPR | ONLY_ARG;
“ENABLED |” here
> const unsigned int USED_GPR = ENABLED | ONLY_USED | ONLY_GPR;
> const unsigned int USED_ARG = ENABLED | ONLY_USED | ONLY_ARG;
> const unsigned int USED = ENABLED | ONLY_USED;
> const unsigned int ALL_GRP_ARG = ENABLED | ONLY_GPR | ONLY_ARG;
GPR
> const unsigned int ALL_GPR = ENABLED | ONLY_GPR;
> const unsigned int ALL_ARG = ENABLED | ONLY_ARG;
> const unsigned int ALL = ENABLED;
> }
>
> ??
Yeah, looks right modulo the above.
>>> + and 3. it is not live at the return of the routine;
>>> + and 4. it is general registor if gpr_only is true;
>>> + and 5. it is used in the routine if used_only is true;
>>> + and 6. it is a register that passes parameter if arg_only is true;
>>> + */
>>
>> Under GCC formatting, the “and” lines need to be indented under “For each”.
>> Maybe indent the “1.” line a bit more if you think it looks nicer with the
>> numbers lined up (it probably does).
>>
>> Similarly, the last bit of text should end with “. */”, rather than
>> with the “;\n */” above.
>>
>> (Sorry that the rules are so picky about this.)
>
> /* For each of the hard registers, check to see whether we should zero it
> if:
> 1. it is a call-used-registers;
> and 2. it is not a fixed-registers;
> and 3. it is not live at the return of the routine;
> and 4. it is general registor if gpr_only is true;
> and 5. it is used in the routine if used_only is true;
> and 6. it is a register that passes parameter if arg_only is true. */
>
> How about this?
The 1. line looks overindented now :-) Was expecting it to line up
with "2.".
Otherwise looks good.
>>> + HARD_REG_SET zeroed_hardregs;
>>> + start_sequence ();
>>> + zeroed_hardregs = targetm.calls.zero_call_used_regs
>>> (need_zeroed_hardregs);
>>> + rtx_insn *seq = get_insns ();
>>> + end_sequence ();
>>> + if (seq)
>>> + {
>>> + /* Emit the memory blockage and register clobber asm volatile before
>>> + the whole sequence. */
>>> + start_sequence ();
>>> + expand_asm_reg_clobber_mem_blockage (zeroed_hardregs);
>>> + rtx_insn *seq_barrier = get_insns ();
>>> + end_sequence ();
>>> +
>>> + emit_insn_before (seq_barrier, ret);
>>> + emit_insn_before (seq, ret);
>>> +
>>> + /* Update the data flow information. */
>>> + crtl->must_be_zero_on_return |= zeroed_hardregs;
>>> + df_set_bb_dirty (EXIT_BLOCK_PTR_FOR_FN (cfun));
>>> + }
>>> +}
>>> +
>>> +
>>> /* Return a sequence to be used as the epilogue for the current function,
>>> or NULL. */
>>>
>>> @@ -6486,7 +6584,120 @@ make_pass_thread_prologue_and_epilogue
>>> (gcc::context *ctxt)
>>> {
>>> return new pass_thread_prologue_and_epilogue (ctxt);
>>> }
>>> -
>>>
>>> +
>>> +static unsigned int
>>> +rest_of_zero_call_used_regs (void)
>>
>> This needs a function comment. Maybe:
>>
>> /* Iterate over the function's return instructions and insert any
>> register zeroing required by the -fzero-call-used-regs command-line
>> option or the "zero_call_used_regs" function attribute. */
>>
>> Also, we might as well make it:
>>
>> pass_zero_call_used_regs::execute
>>
>> rather than a separate function. The “rest_of_…” stuff is mostly legacy.
>
> You mean to delete the “rest_of_zero_call_used_regs” function, and move its
> body to
> Pass_zero_call_used_regs::execute?
Yes.
>>> +
>>> + crtl->zero_call_used_regs = zero_regs_type;
>>> +
>>> + /* No need to zero call-used-regs when no user request is present. */
>>> + return zero_regs_type > SKIP;
>>
>> Think testing for skip using & SKIP or ==/!= SKIP is more obvious.
>
> Testing with & SKIP or ==/!= SKIP will not work if the flag is UNSET.
But can that happen? I would have expected the command line to be
!= UNDEF at this stage.
If that's not true, then & ENABLED would also work.
>> The i386 tests are Uros's domain, but I think it would be good to have
>> generic tests for all the variants. E.g.:
>>
>> (1) one test per -fzero-call-used-regs option (including skip)
>> (2) one test that tries all valid attribute values (including skip),
>> compiled without -fzero-call-used-regs
>> (3) one test that #includes (2) but is compiled with an arbitrarily-chosen
>> -fzero-call-used-regs (say =all).
>> (4) one test that tries invalid uses of the attribute, e.g.:
>> - one use of the attribute on a variable
>> - one use of the attribute on a function, but with an obviously-wrong
>> value
>> - one use of the attribute on a function, but with -gpr and -arg the
>> wrong way around
>
> You mean to add the above new testing cases to gcc/testsuite/c-c++-common
> For all targets?
Yes.
> Then, we cannot test for the assembly matching, we can only testing for
> “dg-do run” right?
Right. This is in addition to target-specific tests rather than a
replacement for them.
Thanks,
Richard