From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7873) id 163C8385829A; Tue, 26 Jul 2022 14:19:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 163C8385829A Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Tiezhu Yang To: gdb-cvs@sourceware.org Subject: [binutils-gdb] gdb: LoongArch: Handle the function return value X-Act-Checkin: binutils-gdb X-Git-Author: Tiezhu Yang X-Git-Refname: refs/heads/master X-Git-Oldrev: 4a75d7c5384a2c1cbaa0f341d844713d9ae475d6 X-Git-Newrev: ecbff28a4457d0ebe11023fa9671d62251e7463d Message-Id: <20220726141940.163C8385829A@sourceware.org> Date: Tue, 26 Jul 2022 14:19:40 +0000 (GMT) X-BeenThere: gdb-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Jul 2022 14:19:40 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Decbff28a4457= d0ebe11023fa9671d62251e7463d commit ecbff28a4457d0ebe11023fa9671d62251e7463d Author: Tiezhu Yang Date: Mon Jul 25 20:42:59 2022 +0800 gdb: LoongArch: Handle the function return value =20 According to LoongArch ELF ABI specification [1], handle the function return value of various types. =20 [1] https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-AB= I-EN.html#_return_values =20 Signed-off-by: Tiezhu Yang Diff: --- 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; } =20 +/* 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. */ =20 static enum return_value_convention @@ -1081,24 +1094,216 @@ loongarch_return_value (struct gdbarch *gdbarch, s= truct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { - int len =3D TYPE_LENGTH (type); - int regnum =3D -1; + int regsize =3D register_size (gdbarch, 0); + enum type_code code =3D type->code (); + size_t len =3D TYPE_LENGTH (type); + unsigned int fixed_point_members; + unsigned int floating_point_members; + bool first_member_is_fixed_point; + int a0 =3D LOONGARCH_A0_REGNUM; + int a1 =3D LOONGARCH_A0_REGNUM + 1; + int f0 =3D LOONGARCH_FIRST_FP_REGNUM; + int f1 =3D LOONGARCH_FIRST_FP_REGNUM + 1; =20 - /* 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 =3D 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 =3D extract_unsigned_integer (writebuf, len, BFD_ENDIAN_LI= TTLE); + store_unsigned_integer (buf, regsize, BFD_ENDIAN_LITTLE, data); + } + else + { + LONGEST data =3D extract_signed_integer (writebuf, len, BFD_ENDIAN_LITTL= E); + 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 =3D=3D 2 * regsize) + { + loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, reg= size); + } + /* 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 =3D 0; + floating_point_members =3D 0; + first_member_is_fixed_point =3D false; + compute_struct_member (type, + &fixed_point_members, + &floating_point_members, + &first_member_is_fixed_point); + + if (len > 0 && len <=3D regsize) + { + /* The structure has only fixed-point members. */ + if (fixed_point_members > 0 && floating_point_members =3D=3D 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 =3D=3D 0 && floating_point_members > 0) + { + /* The structure has one floating-point member. + The return value is passed in f0. */ + if (floating_point_members =3D=3D 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 =3D=3D 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 =3D=3D 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 =3D=3D 1 && fixed_point_members =3D=3D 1) + { + /* The return value is passed in f0 and a0 if the first member is fl= oating-point. */ + if (first_member_is_fixed_point =3D=3D false) + { + loongarch_xfer_reg (regcache, f0, regsize / 2, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a0, regsize / 2, readbuf, writebuf, regsi= ze / 2); + } + /* The return value is passed in a0 and f0 if the first member is fi= xed-point. */ + else + { + loongarch_xfer_reg (regcache, a0, regsize / 2, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, f0, regsize / 2, readbuf, writebuf, regsi= ze / 2); + } + } + } + } + else if (len > regsize && len <=3D 2 * regsize) + { + /* The structure has only fixed-point members. */ + if (fixed_point_members > 0 && floating_point_members =3D=3D 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, regs= ize); + } + /* The structure has only floating-point members. */ + else if (fixed_point_members =3D=3D 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 =3D=3D 16 && floating_point_members =3D=3D 1) + || (len =3D=3D 16 && floating_point_members =3D=3D 3) + || (len =3D=3D 12 && floating_point_members =3D=3D 3) + || (len =3D=3D 16 && floating_point_members =3D=3D 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 =3D=3D 16 && floating_point_members =3D=3D 2) + || (len =3D=3D 12 && floating_point_members =3D=3D 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 membe= r. */ + if (floating_point_members =3D=3D 1 && fixed_point_members =3D=3D 1) + { + /* The return value is passed in f0 and a0 if the first member is fl= oating-point. */ + if (first_member_is_fixed_point =3D=3D false) + { + loongarch_xfer_reg (regcache, f0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, a0, len - regsize, readbuf, writebuf, reg= size); + } + /* The return value is passed in a0 and f0 if the first member is fi= xed-point. */ + else + { + loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); + loongarch_xfer_reg (regcache, f0, len - regsize, readbuf, writebuf, reg= size); + } + } + 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 <=3D regsize) + { + /* The return value is passed in a0. */ + loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0); + } + else if (len > regsize && len <=3D 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, reg= size); + } + 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; } =20 - /* Extract the return value from the register where it was stored. */ - if (readbuf !=3D nullptr) - regcache->raw_read_part (regnum, 0, len, readbuf); - if (writebuf !=3D nullptr) - regcache->raw_write_part (regnum, 0, len, writebuf); - return RETURN_VALUE_REGISTER_CONVENTION; }