From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by sourceware.org (Postfix) with ESMTP id C8F563858C83 for ; Tue, 26 Jul 2022 14:23:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C8F563858C83 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 localhost.localdomain (unknown [111.18.133.251]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9AxOeDB+N9iJu85AA--.18215S3; Tue, 26 Jul 2022 22:22:59 +0800 (CST) From: Tiezhu Yang To: gdb-patches@sourceware.org Subject: [COMMITTED PATCH 2/2] gdb: LoongArch: Handle the function return value Date: Tue, 26 Jul 2022 22:22:53 +0800 Message-Id: <20220726142253.4822-2-yangtiezhu@loongson.cn> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20220726142253.4822-1-yangtiezhu@loongson.cn> References: <20220726142253.4822-1-yangtiezhu@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CM-TRANSID: AQAAf9AxOeDB+N9iJu85AA--.18215S3 X-Coremail-Antispam: 1UD129KBjvJXoW3Jr4kWr43GFW7Wr1fCr15Jwb_yoWfAFW7pF yakFyxtF48Krn7urnrG3Z8Zwn7Ca4xXFya9a43G34I9r1UG3WDuF95Crya9Fsakw1UWrWY gF4DKa9xZF18JFJanT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUvEb7Iv0xC_Kw4lb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I2 0VC2zVCF04k26cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI 8067AKxVWUGwA2048vs2IY020Ec7CjxVAFwI0_Jr4l8cAvFVAK0II2c7xJM28CjxkF64kE wVA0rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVWUCVW8JwA2z4x0Y4vE2Ix0cI8IcVCY1x 0267AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x02 67AKxVW0oVCq3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I 80ewAv7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCj c4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4 AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE 17CEb7AF67AKxVWUJVWUXwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1j6r1xMI IF0xvE2Ix0cI8IcVCY1x0267AKxVWUJVW8JwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4l IxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVWUJVW8JbIYCTnIWI evJa73UjIFyTuYvjxUgQeoUUUUU X-CM-SenderInfo: p1dqw3xlh2x3gn0dqz5rrqw2lrqou0/ X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Jul 2022 14:23:05 -0000 According to LoongArch ELF ABI specification [1], handle the function return value of various types. [1] https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_return_values Signed-off-by: Tiezhu Yang --- gdb/loongarch-tdep.c | 233 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 219 insertions(+), 14 deletions(-) diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c index 3fb7774d8af..85a1dd70ebd 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -1074,6 +1074,19 @@ loongarch_push_dummy_call (struct gdbarch *gdbarch, return sp; } +/* Partial transfer of a cooked register. */ + +static void +loongarch_xfer_reg (struct regcache *regcache, + int regnum, int len, gdb_byte *readbuf, + const gdb_byte *writebuf, size_t offset) +{ + if (readbuf) + regcache->cooked_read_part (regnum, 0, len, readbuf + offset); + if (writebuf) + regcache->cooked_write_part (regnum, 0, len, writebuf + offset); +} + /* Implement the return_value gdbarch method. */ static enum return_value_convention @@ -1081,24 +1094,216 @@ loongarch_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { - int len = TYPE_LENGTH (type); - int regnum = -1; + int regsize = register_size (gdbarch, 0); + enum type_code code = type->code (); + size_t len = TYPE_LENGTH (type); + unsigned int fixed_point_members; + unsigned int floating_point_members; + bool first_member_is_fixed_point; + int a0 = LOONGARCH_A0_REGNUM; + int a1 = LOONGARCH_A0_REGNUM + 1; + int f0 = LOONGARCH_FIRST_FP_REGNUM; + int f1 = LOONGARCH_FIRST_FP_REGNUM + 1; - /* See if our value is returned through a register. If it is, then - store the associated register number in REGNUM. */ - switch (type->code ()) + if (len > 2 * regsize) + return RETURN_VALUE_STRUCT_CONVENTION; + + switch (code) { - case TYPE_CODE_INT: - regnum = LOONGARCH_A0_REGNUM; - break; + case TYPE_CODE_INT: + case TYPE_CODE_BOOL: + case TYPE_CODE_CHAR: + case TYPE_CODE_RANGE: + case TYPE_CODE_ENUM: + case TYPE_CODE_PTR: + { + /* integer or pointer type. + The return value is passed in a0, + the unsigned integer scalars are zero-extended to GRLEN bits, + and the signed integer scalars are sign-extended. */ + if (writebuf) + { + gdb_byte buf[regsize]; + if (type->is_unsigned ()) + { + ULONGEST data = extract_unsigned_integer (writebuf, len, BFD_ENDIAN_LITTLE); + store_unsigned_integer (buf, regsize, BFD_ENDIAN_LITTLE, data); + } + else + { + LONGEST data = extract_signed_integer (writebuf, len, BFD_ENDIAN_LITTLE); + store_signed_integer (buf, regsize, BFD_ENDIAN_LITTLE, data); + } + loongarch_xfer_reg (regcache, a0, regsize, nullptr, buf, 0); + } + else + loongarch_xfer_reg (regcache, a0, len, readbuf, nullptr, 0); + } + break; + case TYPE_CODE_FLT: + /* long double type. + The return value is passed in a0 and a1. */ + if (len == 2 * regsize) + { + loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); + } + /* float or double type. + The return value is passed in f0. */ + else + { + loongarch_xfer_reg (regcache, f0, len, readbuf, writebuf, 0); + } + 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); + + if (len > 0 && len <= regsize) + { + /* The structure has only fixed-point members. */ + if (fixed_point_members > 0 && floating_point_members == 0) + { + /* The return value is passed in a0. */ + loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0); + } + /* The structure has only floating-point members. */ + else if (fixed_point_members == 0 && floating_point_members > 0) + { + /* The structure has one floating-point member. + The return value is passed in f0. */ + if (floating_point_members == 1) + { + loongarch_xfer_reg (regcache, f0, len, readbuf, writebuf, 0); + } + /* The structure has two floating-point members. + The return value is passed in f0 and f1. */ + else if (floating_point_members == 2) + { + loongarch_xfer_reg (regcache, f0, len / 2, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, f1, len / 2, readbuf, writebuf, len / 2); + } + } + /* The structure has both fixed-point and floating-point members. */ + else if (fixed_point_members > 0 && floating_point_members > 0) + { + /* The structure has one float member and multiple fixed-point members. + The return value is passed in a0. */ + if (floating_point_members == 1 && fixed_point_members > 1) + { + loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0); + } + /* The structure has one float member and one fixed-point member. */ + else if (floating_point_members == 1 && fixed_point_members == 1) + { + /* The return value is passed in f0 and a0 if the first member is floating-point. */ + if (first_member_is_fixed_point == false) + { + loongarch_xfer_reg (regcache, f0, regsize / 2, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a0, regsize / 2, readbuf, writebuf, regsize / 2); + } + /* The return value is passed in a0 and f0 if the first member is fixed-point. */ + else + { + loongarch_xfer_reg (regcache, a0, regsize / 2, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, f0, regsize / 2, readbuf, writebuf, regsize / 2); + } + } + } + } + else if (len > regsize && len <= 2 * regsize) + { + /* The structure has only fixed-point members. */ + if (fixed_point_members > 0 && floating_point_members == 0) + { + /* The return value is passed in a0 and a1. */ + loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); + } + /* The structure has only floating-point members. */ + else if (fixed_point_members == 0 && floating_point_members > 0) + { + /* The structure has one long double member + or one double member and two adjacent float members + or 3-4 float members. + The return value is passed in a0 and a1. */ + if ((len == 16 && floating_point_members == 1) + || (len == 16 && floating_point_members == 3) + || (len == 12 && floating_point_members == 3) + || (len == 16 && floating_point_members == 4)) + { + loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); + } + /* The structure has two double members + or one double member and one float member. + The return value is passed in f0 and f1. */ + else if ((len == 16 && floating_point_members == 2) + || (len == 12 && floating_point_members == 2)) + { + loongarch_xfer_reg (regcache, f0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, f1, len - regsize, readbuf, writebuf, regsize); + } + } + /* The structure has both fixed-point and floating-point members. */ + else if (fixed_point_members > 0 && floating_point_members > 0) + { + /* The structure has one floating-point member and one fixed-point member. */ + if (floating_point_members == 1 && fixed_point_members == 1) + { + /* The return value is passed in f0 and a0 if the first member is floating-point. */ + if (first_member_is_fixed_point == false) + { + loongarch_xfer_reg (regcache, f0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a0, len - regsize, readbuf, writebuf, regsize); + } + /* The return value is passed in a0 and f0 if the first member is fixed-point. */ + else + { + loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, f0, len - regsize, readbuf, writebuf, regsize); + } + } + else + { + /* The return value is passed in a0 and a1. */ + loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); + } + } + } + } + break; + case TYPE_CODE_UNION: + if (len > 0 && len <= regsize) + { + /* The return value is passed in a0. */ + loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0); + } + else if (len > regsize && len <= 2 * regsize) + { + /* The return value is passed in a0 and a1. */ + loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); + } + 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); + } + break; + default: + break; } - /* Extract the return value from the register where it was stored. */ - if (readbuf != nullptr) - regcache->raw_read_part (regnum, 0, len, readbuf); - if (writebuf != nullptr) - regcache->raw_write_part (regnum, 0, len, writebuf); - return RETURN_VALUE_REGISTER_CONVENTION; } -- 2.27.0