From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by sourceware.org (Postfix) with ESMTP id B0B493858D35 for ; Wed, 28 Jun 2023 10:08:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B0B493858D35 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=loongson.cn Received: from loongson.cn (unknown [113.200.148.30]) by gateway (Coremail) with SMTP id _____8CxZ8WmBpxkMXADAA--.5576S3; Wed, 28 Jun 2023 18:08:39 +0800 (CST) Received: from localhost.localdomain (unknown [113.200.148.30]) by localhost.localdomain (Coremail) with SMTP id AQAAf8DxJ8ymBpxkdiQOAA--.13181S2; Wed, 28 Jun 2023 18:08:38 +0800 (CST) From: Hui Li To: gdb-patches@sourceware.org Cc: Tiezhu Yang Subject: [PATCH] gdb: LoongArch: Handle special floating-point member struct in dummy call Date: Wed, 28 Jun 2023 18:08:27 +0800 Message-Id: <20230628100827.1822-1-lihui@loongson.cn> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CM-TRANSID:AQAAf8DxJ8ymBpxkdiQOAA--.13181S2 X-CM-SenderInfo: 5olk3xo6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBj93XoW3tw17WFy5WFy5Ar47Ww4xKrX_yoWkZF48pF yfAF1xKF48Jr97u3srGa90yw1fK34xuFWDCasxXa4I9r1Dt3s8ua1rCryYgFWYkr1vgr1a yFs8Kry7CFyUJFXCm3ZEXasCq-sJn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUkFb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_JFI_Gr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr0_Cr1l84ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AK xVW8Jr0_Cr1UM2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6xACxx 1l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1j6r18McIj6I8E87Iv 67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41l42xK82IYc2 Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s02 6x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1Y6r17MIIYrxkI7VAKI48JMIIF0x vE2Ix0cI8IcVAFwI0_Jr0_JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26r1j6r4UMIIF0xvE 42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6x kF7I0E14v26r1j6r4UYxBIdaVFxhVjvjDU0xZFpf9x07UE-erUUUUU= X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00,GIT_PATCH_0,KAM_DMARC_STATUS,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: This commit solves some special problems when a struct containing floating-point members as function argument or return value for a dummy call. LoongArch GCC have some special processing for struct containing floating-point members. This is also the main reason for a large number of test failures about C++ empty structures as function arguments or return values. Mainly includes the following cases: 1.struct contains one floating-point member and at least one floating-point argument register is available. 2.struct contains two floating-point member and at least two floating-point argument register is available. 3.struct containing one floating-point member and one integral member and at least one floating-point argument register and at least one integer argument register is available These cases will preferentially use the argument register for argument passing, even if the structure length is greater than 2*regsize. Execute the following test on LoongArch64: loongson@bogon:~$ cat test.c #include struct test { long a; double b __attribute__((aligned(16))); }; struct test val = { 88, 99.99 }; int check_arg_struct (struct test arg) { printf("arg.a = %ld\n", arg.a); printf("arg.b = %f\n", arg.b); printf("sizeof(val) = %d\n", sizeof(val)); return 1; } int main() { check_arg_struct (val); return 0; } loongson@bogon:~$ gcc -g test.c -o test loongson@bogon:~$ ./test arg.a = 88 arg.b = 99.990000 sizeof(val) = 32 before this patch loongson@bogon:~$ gdb test ... (gdb) start ... Temporary breakpoint 1, main () at test.c:19 19 check_arg_struct (val); (gdb) p check_arg_struct (val) arg.a = 140737488286128 arg.b = -nan sizeof(val) = 32 $1 = 1 ... make check-gdb TESTS="gdb.base/infcall-nested-structs-c++.exp" === gdb Summary === # of expected passes 5533 # of unexpected failures 367 ------------------------ after this patch loongson@bogon:~$ gdb test ... (gdb) start ... Temporary breakpoint 1, main () at test.c:19 19 check_arg_struct (val); (gdb) p check_arg_struct (val) arg.a = 88 arg.b = 99.990000 sizeof(val) = 32 $1 = 1 ... make check-gdb TESTS="gdb.base/infcall-nested-structs-c++.exp" === gdb Summary === # of expected passes 5900 Signed-off-by: Hui Li --- gdb/loongarch-tdep.c | 209 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 182 insertions(+), 27 deletions(-) diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c index 62c6f9b220e..11ac4f8732c 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -516,7 +516,8 @@ static void compute_struct_member (struct type *type, unsigned int *fixed_point_members, unsigned int *floating_point_members, - bool *first_member_is_fixed_point) + bool *first_member_is_fixed_point, + bool *has_long_double) { for (int i = 0; i < type->num_fields (); i++) { @@ -526,6 +527,10 @@ compute_struct_member (struct type *type, struct type *field_type = check_typedef (type->field (i).type ()); + if ((field_type->code () == TYPE_CODE_FLT && field_type->length () == 16) + || (field_type->code () == TYPE_CODE_COMPLEX && field_type->length () == 32)) + *has_long_double = true; + if (field_type->code () == TYPE_CODE_INT || field_type->code () == TYPE_CODE_BOOL || field_type->code () == TYPE_CODE_CHAR @@ -544,12 +549,77 @@ compute_struct_member (struct type *type, compute_struct_member (field_type, fixed_point_members, floating_point_members, - first_member_is_fixed_point); + first_member_is_fixed_point, + has_long_double); else if (field_type->code () == TYPE_CODE_COMPLEX) (*floating_point_members) += 2; } } +/* Compute the lengths and offsets of struct member. */ + +static void +struct_member_info (struct type *type, + unsigned int *m_offsets, + unsigned int *m_lens, + unsigned int offset, + unsigned int *m_fields) +{ + unsigned int count = type->num_fields (); + unsigned int i; + + for (i = 0; i < count; ++i) + { + if (type->field (i).loc_kind () != FIELD_LOC_KIND_BITPOS) + continue; + + struct type *field_type = check_typedef (type->field (i).type ()); + int field_offset = offset + type->field (i).loc_bitpos () / TARGET_CHAR_BIT; + + switch (field_type->code ()) + { + case TYPE_CODE_STRUCT: + struct_member_info (field_type, m_offsets, m_lens, field_offset, m_fields); + break; + + case TYPE_CODE_COMPLEX: + if (*m_fields == 0) + { + /* _Complex float */ + if (field_type->length () == 8) + { + m_offsets[0] = field_offset; + m_offsets[1] = field_offset + 4; + m_lens[0] = m_lens[1] = 4; + *m_fields = 2; + } + /* _Complex double */ + else if (field_type->length () == 16) + { + m_offsets[0] = field_offset; + m_offsets[1] = field_offset + 8; + m_lens[0] = m_lens[1] = 8; + *m_fields = 2; + } + } + break; + + default: + if (*m_fields < 2) + { + m_offsets[*m_fields] = field_offset; + m_lens[*m_fields] = field_type->length (); + } + (*m_fields)++; + break; + } + + /* only has special handling for structures with 1 or 2 fields. */ + if (*m_fields > 2) + return; + } +} + /* Implement the push_dummy_call gdbarch method. */ static CORE_ADDR @@ -566,15 +636,13 @@ loongarch_push_dummy_call (struct gdbarch *gdbarch, int regsize = register_size (gdbarch, 0); unsigned int gar = LOONGARCH_ARG_REGNUM; unsigned int far = LOONGARCH_ARG_REGNUM; - unsigned int fixed_point_members; - unsigned int floating_point_members; - bool first_member_is_fixed_point; gdb_byte buf[1024] = { 0 }; gdb_byte *addr = buf; if (return_method != return_method_normal) pass_in_gar (regcache, gar--, (gdb_byte *) &struct_addr); + for (int i = 0; i < nargs; i++) { struct value *arg = args[i]; @@ -695,15 +763,56 @@ loongarch_push_dummy_call (struct gdbarch *gdbarch, break; case TYPE_CODE_STRUCT: { - fixed_point_members = 0; - floating_point_members = 0; - first_member_is_fixed_point = false; + unsigned int fixed_point_members = 0; + unsigned int floating_point_members = 0; + bool first_member_is_fixed_point = false; + bool has_long_double = false; + unsigned int total_members = 0; + unsigned int m_offsets[2] = { 0, 0 }; + unsigned int m_lens[2] = { 0, 0 }; + unsigned int m_fields = 0; compute_struct_member (type, &fixed_point_members, &floating_point_members, - &first_member_is_fixed_point); - - if (len > 0 && len <= regsize) + &first_member_is_fixed_point, + &has_long_double); + total_members = fixed_point_members + floating_point_members; + struct_member_info (type, m_offsets, m_lens, 0, &m_fields); + /* struct has one floating_point_member and at least one FAR; + struct has two floating_point_member and at least two FAR; + struct has one floating_point_member and fixed_point_member + and least one FAR and one GAR. */ + if (total_members <= 2 && floating_point_members > 0 + && has_long_double == false + && ((total_members == 1 && far >= 1) + || (floating_point_members == 2 && far >= 2) + || (fixed_point_members == 1 && floating_point_members == 1 + && far >= 1 && gar >=1))) + { + if (floating_point_members == 2) + { + pass_in_far (regcache, far--, val + m_offsets[0]); + pass_in_far (regcache, far--, val + m_offsets[1]); + } + else if (floating_point_members == 1 && fixed_point_members == 1) + { + if (first_member_is_fixed_point == false) + { + pass_in_far (regcache, far--, val + m_offsets[0]); + pass_in_gar (regcache, gar--, val + m_offsets[1]); + } + else + { + pass_in_gar (regcache, gar--, val + m_offsets[0]); + pass_in_far (regcache, far--, val + m_offsets[1]); + } + } + else if (floating_point_members == 1 && total_members == 1) + { + pass_in_far (regcache, far--, val + m_offsets[0]); + } + } + else if (len > 0 && len <= regsize) { /* The structure has only fixed-point members. */ if (fixed_point_members > 0 && floating_point_members == 0) @@ -1157,17 +1266,19 @@ loongarch_return_value (struct gdbarch *gdbarch, struct value *function, int regsize = register_size (gdbarch, 0); enum type_code code = type->code (); size_t len = type->length (); - unsigned int fixed_point_members; - unsigned int floating_point_members; - bool first_member_is_fixed_point; + unsigned int fixed_point_members = 0; + unsigned int floating_point_members = 0; + bool first_member_is_fixed_point = false; + bool has_long_double = false; + unsigned int total_members = 0; + unsigned int m_offsets[2] = { 0, 0 }; + unsigned int m_lens[2] = { 0, 0 }; + unsigned int m_fields = 0; int a0 = LOONGARCH_A0_REGNUM; int a1 = LOONGARCH_A0_REGNUM + 1; int f0 = LOONGARCH_FIRST_FP_REGNUM; int f1 = LOONGARCH_FIRST_FP_REGNUM + 1; - if (len > 2 * regsize) - return RETURN_VALUE_STRUCT_CONVENTION; - switch (code) { case TYPE_CODE_INT: @@ -1217,15 +1328,52 @@ loongarch_return_value (struct gdbarch *gdbarch, struct value *function, break; case TYPE_CODE_STRUCT: { - fixed_point_members = 0; - floating_point_members = 0; - first_member_is_fixed_point = false; compute_struct_member (type, &fixed_point_members, &floating_point_members, - &first_member_is_fixed_point); + &first_member_is_fixed_point, + &has_long_double); - if (len > 0 && len <= regsize) + total_members = fixed_point_members + floating_point_members; + struct_member_info (type, m_offsets, m_lens, 0, &m_fields); + + /* struct has one floating_point_member; + struct has two floating_point_member; + struct has one floating_point_member and fixed_point_member. */ + if (total_members <= 2 && floating_point_members > 0 + && has_long_double == false) + { + if (floating_point_members == 2) + { + loongarch_xfer_reg (regcache, f0, m_lens[0], readbuf, + writebuf, m_offsets[0]); + loongarch_xfer_reg (regcache, f1, m_lens[1], readbuf, + writebuf, m_offsets[1]); + } + else if (floating_point_members == 1 && fixed_point_members == 1) + { + if (first_member_is_fixed_point == false) + { + loongarch_xfer_reg (regcache, f0, m_lens[0], readbuf, + writebuf, m_offsets[0]); + loongarch_xfer_reg (regcache, a0, m_lens[1], readbuf, + writebuf, m_offsets[1]); + } + else + { + loongarch_xfer_reg (regcache, a0, m_lens[0], readbuf, + writebuf, m_offsets[0]); + loongarch_xfer_reg (regcache, f0, m_lens[1], readbuf, + writebuf, m_offsets[1]); + } + } + else if (floating_point_members == 1 && total_members == 1) + { + loongarch_xfer_reg (regcache, f0, m_lens[0], readbuf, + writebuf, m_offsets[0]); + } + } + else if (len > 0 && len <= regsize) { /* The structure has only fixed-point members. */ if (fixed_point_members > 0 && floating_point_members == 0) @@ -1338,6 +1486,8 @@ loongarch_return_value (struct gdbarch *gdbarch, struct value *function, } } } + else if (len > 2 * regsize) + return RETURN_VALUE_STRUCT_CONVENTION; } break; case TYPE_CODE_UNION: @@ -1352,13 +1502,18 @@ loongarch_return_value (struct gdbarch *gdbarch, struct value *function, loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); } + else if (len > 2 * regsize) + return RETURN_VALUE_STRUCT_CONVENTION; break; case TYPE_CODE_COMPLEX: - { - /* The return value is passed in f0 and f1. */ - loongarch_xfer_reg (regcache, f0, len / 2, readbuf, writebuf, 0); - loongarch_xfer_reg (regcache, f1, len / 2, readbuf, writebuf, len / 2); - } + if (len > 2 * regsize) + return RETURN_VALUE_STRUCT_CONVENTION; + else + { + /* The return value is passed in f0 and f1. */ + loongarch_xfer_reg (regcache, f0, len / 2, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, f1, len / 2, readbuf, writebuf, len / 2); + } break; default: break; -- 2.38.1