if (*last_used_bit != offset)
{
+ /* We never clear padding bits in any other registers than the
+ first 4 GPRs. */
+ gcc_assert (*regno < 4);
if (offset < *last_used_bit)
{
/* This field's offset is before the 'last_used_bit', that
last_used_bit_t = (starting_bit + field_size) % 32;
}
- for (i = *regno; i < regno_t; i++)
+ /* We only clear padding bits in the first 4 GPRs. No need to check
+ regno_t, since there is no way where this field would have been
+ put into part GPR part FP reg. */
+ if (*regno < 4)
{
- /* For all but the last register used by this field only keep the
- padding bits that were padding bits in this field. */
- padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
- }
+ for (i = *regno; i < regno_t; i++)
+ {
+ /* For all but the last register used by this field only keep
+ the padding bits that were padding bits in this field. */
+ padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+ }
- /* For the last register, keep all padding bits that were padding
- bits in this field and any padding bits that are still valid
- as padding bits but fall outside of this field's size. */
- mask = (((uint32_t) -1) - ((uint32_t) 1 << last_used_bit_t)) + 1;
- padding_bits_to_clear_res[regno_t]
- &= padding_bits_to_clear_t[regno_t] | mask;
+ /* For the last register, keep all padding bits that were padding
+ bits in this field and any padding bits that are still valid
+ as padding bits but fall outside of this field's size. */
+ mask = (((uint32_t) -1) - ((uint32_t) 1 << last_used_bit_t)) + 1;
+ padding_bits_to_clear_res[regno_t]
+ &= padding_bits_to_clear_t[regno_t] | mask;
+ }
/* Update the maximum size of the fields in terms of registers used
('max_reg') and the 'last_used_bit' in said register. */
field = TREE_CHAIN (field);
}
- /* Update the current padding_bits_to_clear using the intersection of the
- padding bits of all the fields. */
- for (i=*regno; i < max_reg; i++)
- padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+ /* We only clear padding bits in the first 4 GPRs. No need to check
+ regno_t, since there is no way where this field would have been
+ put into part GPR part FP reg. */
+ if (*regno < 4)
+ {
+ /* Update the current padding_bits_to_clear using the intersection of the
+ padding bits of all the fields. */
+ for (i=*regno; i < max_reg; i++)
+ padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
- /* Do not keep trailing padding bits, we do not know yet whether this
- is the end of the argument. */
- mask = ((uint32_t) 1 << max_bit) - 1;
- padding_bits_to_clear[max_reg]
- |= padding_bits_to_clear_res[max_reg] & mask;
+ /* Do not keep trailing padding bits, we do not know yet whether this
+ is the end of the argument. */
+ mask = ((uint32_t) 1 << max_bit) - 1;
+ padding_bits_to_clear[max_reg]
+ |= padding_bits_to_clear_res[max_reg] & mask;
+ }
for (int i = *regno; i < max_reg; ++i)
not_to_clear_reg_mask |= HOST_WIDE_INT_1U << i;
/* If the 'last_used_bit' is not zero, that means we are still using a
part of the last 'regno'. In such cases we must clear the trailing
bits. Otherwise we are not using regno and we should mark it as to
- clear. */
- if (last_used_bit != 0)
+ clear. We only clear padding bits for scalar values that are passed
+ in registers, so regno is never 4 or higher. */
+ if (regno < 4 && last_used_bit != 0)
padding_bits_to_clear[regno]
|= ((uint32_t)-1) - ((uint32_t) 1 << last_used_bit) + 1;
else
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "../../../union-4.x"
+
+/*
+** fn:
+** ...
+** lsrs r4, r4, #1
+** lsls r4, r4, #1
+** movw ip, #7939
+** and r0, r0, ip
+** mov r2, r4
+** mov r3, r4
+** vmov.f64 d0, #1.0e\+0
+** vmov.f64 d1, #1.0e\+0
+** vmov.f64 d2, #1.0e\+0
+** vmov.f64 d3, #1.0e\+0
+** vmov.f64 d4, #1.0e\+0
+** vmov.f64 d5, #1.0e\+0
+** vmov.f64 d6, #1.0e\+0
+** vmov.f64 d7, #1.0e\+0
+** bl __gnu_cmse_nonsecure_call
+** ...
+*/
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+union u_t_0 {
+ float f;
+};
+union u_t_1 {
+ double d;
+};
+
+typedef void (__attribute__ ((cmse_nonsecure_call)) fn_t_0)(union u_t_0);
+typedef void (__attribute__ ((cmse_nonsecure_call)) fn_t_1)(union u_t_1);
+
+void fn_caller_0 (fn_t_0 *f_ptr) {
+ union u_t_0 x = {0.0f};
+ f_ptr (x);
+}
+
+/*
+** fn_caller_0:
+** ...
+** lsrs r4, r4, #1
+** lsls r4, r4, #1
+** mov r0, r4
+** mov r1, r4
+** mov r2, r4
+** mov r3, r4
+** vmov.f32 s1, #1.0e\+0
+** vmov.f64 d1, #1.0e\+0
+** vmov.f64 d2, #1.0e\+0
+** vmov.f64 d3, #1.0e\+0
+** vmov.f64 d4, #1.0e\+0
+** vmov.f64 d5, #1.0e\+0
+** vmov.f64 d6, #1.0e\+0
+** vmov.f64 d7, #1.0e\+0
+** bl __gnu_cmse_nonsecure_call
+** ...
+*/
+
+void fn_caller_1 (fn_t_1 *f_ptr) {
+ union u_t_1 x = {0.0};
+ f_ptr (x);
+}
+
+/*
+** fn_caller_1:
+** ...
+** lsrs r4, r4, #1
+** lsls r4, r4, #1
+** mov r0, r4
+** mov r1, r4
+** mov r2, r4
+** mov r3, r4
+** vmov.f64 d1, #1.0e\+0
+** vmov.f64 d2, #1.0e\+0
+** vmov.f64 d3, #1.0e\+0
+** vmov.f64 d4, #1.0e\+0
+** vmov.f64 d5, #1.0e\+0
+** vmov.f64 d6, #1.0e\+0
+** vmov.f64 d7, #1.0e\+0
+** bl __gnu_cmse_nonsecure_call
+** ...
+*/