Avoid memcpys in regcache read_part/write_part for full registers.

Additionally, tidy up the functions: Remove asserts, use gdb_byte,
update comments.

gdb/
	* regcache.c (readable_regcache::read_part): Avoid memcpy when
	possible.
	(regcache::write_part): Likewise.
	(readable_regcache::cooked_read_part): Update comment.
	(readable_regcache::cooked_write_part): Likewise.
	* regcache.h: (readable_regcache::read_part): Likewise.
	(regcache::write_part): Likewise.
This commit is contained in:
Alan Hayward 2018-06-20 09:31:37 +01:00
parent d388f64333
commit 33bab475a6
3 changed files with 77 additions and 51 deletions

View File

@ -1,3 +1,13 @@
2018-06-21 Alan Hayward <alan.hayward@arm.com>
* regcache.c (readable_regcache::read_part): Avoid memcpy when
possible.
(regcache::write_part): Likewise.
(readable_regcache::cooked_read_part): Update comment.
(readable_regcache::cooked_write_part): Likewise.
* regcache.h: (readable_regcache::read_part): Likewise.
(regcache::write_part): Likewise.
2018-06-21 Richard Bunt <richard.bunt@arm.com> 2018-06-21 Richard Bunt <richard.bunt@arm.com>
Dirk Schubert <dirk.schubert@arm.com> Dirk Schubert <dirk.schubert@arm.com>

View File

@ -775,77 +775,85 @@ regcache::cooked_write (int regnum, const gdb_byte *buf)
regnum, buf); regnum, buf);
} }
/* Perform a partial register transfer using a read, modify, write /* See regcache.h. */
operation. */
enum register_status enum register_status
readable_regcache::read_part (int regnum, int offset, int len, void *in, readable_regcache::read_part (int regnum, int offset, int len,
bool is_raw) gdb_byte *out, bool is_raw)
{ {
struct gdbarch *gdbarch = arch (); int reg_size = register_size (arch (), regnum);
gdb_byte *reg = (gdb_byte *) alloca (register_size (gdbarch, regnum));
gdb_assert (out != NULL);
gdb_assert (offset >= 0 && len >= 0 && offset + len <= reg_size);
if (offset == 0 && len == 0)
{
/* Nothing to do. */
return REG_VALID;
}
if (offset == 0 && len == reg_size)
{
/* Read the full register. */
return (is_raw) ? raw_read (regnum, out) : cooked_read (regnum, out);
}
gdb_assert (in != NULL);
gdb_assert (offset >= 0 && offset <= m_descr->sizeof_register[regnum]);
gdb_assert (len >= 0 && offset + len <= m_descr->sizeof_register[regnum]);
/* Something to do? */
if (offset + len == 0)
return REG_VALID;
/* Read (when needed) ... */
enum register_status status; enum register_status status;
gdb_byte *reg = (gdb_byte *) alloca (reg_size);
if (is_raw) /* Read full register to buffer. */
status = raw_read (regnum, reg); status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg);
else
status = cooked_read (regnum, reg);
if (status != REG_VALID) if (status != REG_VALID)
return status; return status;
/* ... modify ... */ /* Copy out. */
memcpy (in, reg + offset, len); memcpy (out, reg + offset, len);
return REG_VALID; return REG_VALID;
} }
/* See regcache.h. */
enum register_status enum register_status
regcache::write_part (int regnum, int offset, int len, regcache::write_part (int regnum, int offset, int len,
const void *out, bool is_raw) const gdb_byte *in, bool is_raw)
{ {
struct gdbarch *gdbarch = arch (); int reg_size = register_size (arch (), regnum);
gdb_byte *reg = (gdb_byte *) alloca (register_size (gdbarch, regnum));
gdb_assert (out != NULL); gdb_assert (in != NULL);
gdb_assert (offset >= 0 && offset <= m_descr->sizeof_register[regnum]); gdb_assert (offset >= 0 && len >= 0 && offset + len <= reg_size);
gdb_assert (len >= 0 && offset + len <= m_descr->sizeof_register[regnum]);
/* Something to do? */ if (offset == 0 && len == 0)
if (offset + len == 0)
return REG_VALID;
/* Read (when needed) ... */
if (offset > 0
|| offset + len < m_descr->sizeof_register[regnum])
{ {
enum register_status status; /* Nothing to do. */
return REG_VALID;
if (is_raw)
status = raw_read (regnum, reg);
else
status = cooked_read (regnum, reg);
if (status != REG_VALID)
return status;
} }
memcpy (reg + offset, out, len); if (offset == 0 && len == reg_size)
/* ... write (when needed). */ {
if (is_raw) /* Write the full register. */
raw_write (regnum, reg); (is_raw) ? raw_write (regnum, in) : cooked_write (regnum, in);
else return REG_VALID;
cooked_write (regnum, reg); }
enum register_status status;
gdb_byte *reg = (gdb_byte *) alloca (reg_size);
/* Read existing register to buffer. */
status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg);
if (status != REG_VALID)
return status;
/* Update buffer, then write back to regcache. */
memcpy (reg + offset, in, len);
is_raw ? raw_write (regnum, reg) : cooked_write (regnum, reg);
return REG_VALID; return REG_VALID;
} }
/* See regcache.h. */
enum register_status enum register_status
readable_regcache::raw_read_part (int regnum, int offset, int len, gdb_byte *buf) readable_regcache::raw_read_part (int regnum, int offset, int len,
gdb_byte *buf)
{ {
assert_regnum (regnum); assert_regnum (regnum);
return read_part (regnum, offset, len, buf, true); return read_part (regnum, offset, len, buf, true);
@ -861,6 +869,8 @@ regcache::raw_write_part (int regnum, int offset, int len,
write_part (regnum, offset, len, buf, true); write_part (regnum, offset, len, buf, true);
} }
/* See regcache.h. */
enum register_status enum register_status
readable_regcache::cooked_read_part (int regnum, int offset, int len, readable_regcache::cooked_read_part (int regnum, int offset, int len,
gdb_byte *buf) gdb_byte *buf)
@ -869,6 +879,8 @@ readable_regcache::cooked_read_part (int regnum, int offset, int len,
return read_part (regnum, offset, len, buf, false); return read_part (regnum, offset, len, buf, false);
} }
/* See regcache.h. */
void void
regcache::cooked_write_part (int regnum, int offset, int len, regcache::cooked_write_part (int regnum, int offset, int len,
const gdb_byte *buf) const gdb_byte *buf)

View File

@ -253,8 +253,11 @@ public:
struct value *cooked_read_value (int regnum); struct value *cooked_read_value (int regnum);
protected: protected:
enum register_status read_part (int regnum, int offset, int len, void *in,
bool is_raw); /* Perform a partial register transfer using a read, modify, write
operation. Will fail if register is currently invalid. */
enum register_status read_part (int regnum, int offset, int len,
gdb_byte *out, bool is_raw);
}; };
/* Buffer of registers, can be read and written. */ /* Buffer of registers, can be read and written. */
@ -355,9 +358,10 @@ private:
int regnum, const void *in_buf, int regnum, const void *in_buf,
void *out_buf, size_t size) const; void *out_buf, size_t size) const;
/* Perform a partial register transfer using a read, modify, write
operation. */
enum register_status write_part (int regnum, int offset, int len, enum register_status write_part (int regnum, int offset, int len,
const void *out, bool is_raw); const gdb_byte *in, bool is_raw);
/* The address space of this register cache (for registers where it /* The address space of this register cache (for registers where it
makes sense, like PC or SP). */ makes sense, like PC or SP). */