From: Pierre Langlois <pierre.langlois@arm.com>
To: Yao Qi <qiyaoltc@gmail.com>,
"gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Cc: pierre.langlois@arm.com
Subject: Re: [PATCH 4/8] Implement target_emit_ops
Date: Fri, 18 Sep 2015 12:57:00 -0000 [thread overview]
Message-ID: <55FC0A35.4070807@arm.com> (raw)
In-Reply-To: <1442580184-22562-5-git-send-email-yao.qi@linaro.org>
Hi Yao,
Thank you for doing this! I've pointed out a couple of nits below.
On 18/09/15 13:43, Yao Qi wrote:
> From: Pierre Langlois <pierre.langlois@arm.com>
>
> This patch implements compiling agent expressions to native code for
> AArch64. This allows us to compile conditions set on fast tracepoints.
>
> The compiled function has the following prologue:
>
> High *------------------------------------------------------*
> | LR |
> | FP | <- FP
> | x1 (ULONGEST *value) |
> | x0 (unsigned char *regs) |
> Low *------------------------------------------------------*
>
> We save the function's argument on the stack as well as the return
> address and the frame pointer. We then set the current frame pointer to
> point to the previous one.
>
> The generated code for the expression will freely update the stack
> pointer so we use the frame pointer to refer to `*value' and `*regs'.
> `*value' needs to be accessed in the epilogue of the function, in order
> to set it to whatever is on top of the stack. `*regs' needs to be passed
> down to the `gdb_agent_get_reg' function with the `reg' operation.
gdb_agent_get_reg -> gdb_agent_get_raw_reg
>
> gdb/gdbserver/ChangeLog:
>
> * linux-aarch64-low-.c: Include ax.h and tracepoint.h.
> (enum aarch64_opcodes) <RET>, <SUBS>, <AND>, <ORR>, <ORN>,
> <EOR>, <LSLV>, <LSRV>, <ASRV>, <SBFM>, <UBFM>, <CSINC>, <MUL>,
> <NOP>: New.
> (enum aarch64_condition_codes): New enum.
> (w0): New static global.
> (fp): Likewise.
> (lr): Likewise.
> (struct aarch64_memory_operand) <type>: New
> MEMORY_OPERAND_POSTINDEX type.
> (postindex_memory_operand): New helper function.
> (emit_ret): New function.
> (emit_load_store_pair): New function, factored out of emit_stp
> with support for MEMORY_OPERAND_POSTINDEX.
> (emit_stp): Rewrite using emit_load_store_pair.
> (emit_ldp): New function.
> (emit_load_store): Likewise.
> (emit_ldr): Mention post-index instruction in comment.
> (emit_ldrh): New function.
> (emit_ldrb): New function.
> (emit_ldrsw): Mention post-index instruction in comment.
> (emit_str): Likewise.
> (emit_subs): New function.
> (emit_cmp): Likewise.
> (emit_and): Likewise.
> (emit_orr): Likewise.
> (emit_orn): Likewise.
> (emit_eor): Likewise.
> (emit_mvn): Likewise.
> (emit_lslv): Likewise.
> (emit_lsrv): Likewise.
> (emit_asrv): Likewise.
> (emit_mul): Likewise.
> (emit_sbfm): Likewise.
> (emit_sbfx): Likewise.
> (emit_ubfm): Likewise.
> (emit_ubfx): Likewise.
> (emit_csinc): Likewise.
> (emit_cset): Likewise.
> (emit_nop): Likewise.
> (emit_ops_insns): New helper function.
> (emit_pop): Likewise.
> (emit_push): Likewise.
> (aarch64_emit_prologue): New function.
> (aarch64_emit_epilogue): Likewise.
> (aarch64_emit_add): Likewise.
> (aarch64_emit_sub): Likewise.
> (aarch64_emit_mul): Likewise.
> (aarch64_emit_lsh): Likewise.
> (aarch64_emit_rsh_signed): Likewise.
> (aarch64_emit_rsh_unsigned): Likewise.
> (aarch64_emit_ext): Likewise.
> (aarch64_emit_log_not): Likewise.
> (aarch64_emit_bit_and): Likewise.
> (aarch64_emit_bit_or): Likewise.
> (aarch64_emit_bit_xor): Likewise.
> (aarch64_emit_bit_not): Likewise.
> (aarch64_emit_equal): Likewise.
> (aarch64_emit_less_signed): Likewise.
> (aarch64_emit_less_unsigned): Likewise.
> (aarch64_emit_ref): Likewise.
> (aarch64_emit_if_goto): Likewise.
> (aarch64_emit_goto): Likewise.
> (aarch64_write_goto_address): Likewise.
> (aarch64_emit_const): Likewise.
> (aarch64_emit_call): Likewise.
> (aarch64_emit_reg): Likewise.
> (aarch64_emit_pop): Likewise.
> (aarch64_emit_stack_flush): Likewise.
> (aarch64_emit_zero_ext): Likewise.
> (aarch64_emit_swap): Likewise.
> (aarch64_emit_stack_adjust): Likewise.
> (aarch64_emit_int_call_1): Likewise.
> (aarch64_emit_void_call_2): Likewise.
> (aarch64_emit_eq_goto): Likewise.
> (aarch64_emit_ne_goto): Likewise.
> (aarch64_emit_lt_goto): Likewise.
> (aarch64_emit_le_goto): Likewise.
> (aarch64_emit_gt_goto): Likewise.
> (aarch64_emit_ge_got): Likewise.
> (aarch64_emit_ops_impl): New static global variable.
> (aarch64_emit_ops): New target function, return
> &aarch64_emit_ops_impl.
> (struct linux_target_ops): Install it.
> ---
> gdb/gdbserver/linux-aarch64-low.c | 1227 ++++++++++++++++++++++++++++++++++++-
> 1 file changed, 1213 insertions(+), 14 deletions(-)
>
> diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
> index e2d738b..669a1e6 100644
> --- a/gdb/gdbserver/linux-aarch64-low.c
> +++ b/gdb/gdbserver/linux-aarch64-low.c
> @@ -26,6 +26,8 @@
> #include "arch/aarch64-insn.h"
> #include "linux-aarch32-low.h"
> #include "elf/common.h"
> +#include "ax.h"
> +#include "tracepoint.h"
>
> #include <signal.h>
> #include <sys/user.h>
> @@ -680,6 +682,8 @@ enum aarch64_opcodes
> TBNZ = 0x37000000 | B,
> /* BLR 1101 0110 0011 1111 0000 00rr rrr0 0000 */
> BLR = 0xd63f0000,
> + /* RET 1101 0110 0101 1111 0000 00rr rrr0 0000 */
> + RET = 0xd65f0000,
> /* STP s010 100o o0ii iiii irrr rrrr rrrr rrrr */
> /* LDP s010 100o o1ii iiii irrr rrrr rrrr rrrr */
> /* STP (SIMD&VFP) ss10 110o o0ii iiii irrr rrrr rrrr rrrr */
> @@ -709,6 +713,29 @@ enum aarch64_opcodes
> /* SUBS s11o ooo1 xxxx xxxx xxxx xxxx xxxx xxxx */
> ADD = 0x01000000,
> SUB = 0x40000000 | ADD,
> + SUBS = 0x20000000 | SUB,
> + /* AND s000 1010 xx0x xxxx xxxx xxxx xxxx xxxx */
> + /* ORR s010 1010 xx0x xxxx xxxx xxxx xxxx xxxx */
> + /* ORN s010 1010 xx1x xxxx xxxx xxxx xxxx xxxx */
> + /* EOR s100 1010 xx0x xxxx xxxx xxxx xxxx xxxx */
> + AND = 0x0a000000,
> + ORR = 0x20000000 | AND,
> + ORN = 0x00200000 | ORR,
> + EOR = 0x40000000 | AND,
> + /* LSLV s001 1010 110r rrrr 0010 00rr rrrr rrrr */
> + /* LSRV s001 1010 110r rrrr 0010 01rr rrrr rrrr */
> + /* ASRV s001 1010 110r rrrr 0010 10rr rrrr rrrr */
> + LSLV = 0x1ac02000,
> + LSRV = 0x00000400 | LSLV,
> + ASRV = 0x00000800 | LSLV,
> + /* SBFM s001 0011 0nii iiii iiii iirr rrrr rrrr */
> + SBFM = 0x13000000,
> + /* UBFM s101 0011 0nii iiii iiii iirr rrrr rrrr */
> + UBFM = 0x40000000 | SBFM,
> + /* CSINC s001 1010 100r rrrr cccc 01rr rrrr rrrr */
> + CSINC = 0x9a800400,
> + /* MUL s001 1011 000r rrrr 0111 11rr rrrr rrrr */
> + MUL = 0x1b007c00,
> /* MSR (register) 1101 0101 0001 oooo oooo oooo ooor rrrr */
> /* MRS 1101 0101 0011 oooo oooo oooo ooor rrrr */
> MSR = 0xd5100000,
> @@ -717,6 +744,20 @@ enum aarch64_opcodes
> HINT = 0xd503201f,
> SEVL = (5 << 5) | HINT,
> WFE = (2 << 5) | HINT,
> + NOP = (0 << 5) | HINT,
> +};
> +
> +/* List of condition codes that we need. */
> +
> +enum aarch64_condition_codes
> +{
> + EQ = 0x0,
> + NE = 0x1,
> + LO = 0x3,
> + GE = 0xa,
> + LT = 0xb,
> + GT = 0xc,
> + LE = 0xd,
> };
>
> /* Representation of a general purpose register of the form xN or wN.
> @@ -759,12 +800,15 @@ static const struct aarch64_register x3 = { 3, 1 };
> static const struct aarch64_register x4 = { 4, 1 };
>
> /* General purpose scratch registers (32 bit). */
> +static const struct aarch64_register w0 = { 0, 0 };
> static const struct aarch64_register w2 = { 2, 0 };
>
> /* Intra-procedure scratch registers. */
> static const struct aarch64_register ip0 = { 16, 1 };
>
> /* Special purpose registers. */
> +static const struct aarch64_register fp = { 29, 1 };
> +static const struct aarch64_register lr = { 30, 1 };
> static const struct aarch64_register sp = { 31, 1 };
> static const struct aarch64_register xzr = { 31, 1 };
>
> @@ -817,8 +861,9 @@ immediate_operand (uint32_t imm)
>
> The types correspond to the following variants:
>
> - MEMORY_OPERAND_OFFSET: LDR rt, [rn, #offset]
> - MEMORY_OPERAND_PREINDEX: LDR rt, [rn, #index]! */
> + MEMORY_OPERAND_OFFSET: LDR rt, [rn, #offset]
> + MEMORY_OPERAND_PREINDEX: LDR rt, [rn, #index]!
> + MEMORY_OPERAND_POSTINDEX: LDR rt, [rn], #index */
>
> struct aarch64_memory_operand
> {
> @@ -827,6 +872,7 @@ struct aarch64_memory_operand
> {
> MEMORY_OPERAND_OFFSET,
> MEMORY_OPERAND_PREINDEX,
> + MEMORY_OPERAND_POSTINDEX,
> } type;
> /* Index from the base register. */
> int32_t index;
> @@ -854,6 +900,17 @@ preindex_memory_operand (int32_t index)
> return (struct aarch64_memory_operand) { MEMORY_OPERAND_PREINDEX, index };
> }
>
> +/* Helper function to create a post-index memory operand.
> +
> + For example:
> + p += emit_ldr (p, x0, sp, postindex_memory_operand (16)); */
> +
> +static struct aarch64_memory_operand
> +postindex_memory_operand (int32_t index)
> +{
> + return (struct aarch64_memory_operand) { MEMORY_OPERAND_POSTINDEX, index };
> +}
> +
> /* System control registers. These special registers can be written and
> read with the MRS and MSR instructions.
>
> @@ -986,20 +1043,24 @@ emit_blr (uint32_t *buf, struct aarch64_register rn)
> return emit_insn (buf, BLR | ENCODE (rn.num, 5, 5));
> }
>
> -/* Write a STP instruction into *BUF.
> +/* Write a RET instruction into *BUF.
>
> - STP rt, rt2, [rn, #offset]
> - STP rt, rt2, [rn, #index]!
> + RET xn
>
> - RT and RT2 are the registers to store.
> - RN is the base address register.
> - OFFSET is the immediate to add to the base address. It is limited to a
> - -512 .. 504 range (7 bits << 3). */
> + RN is the register to branch to. */
>
> static int
> -emit_stp (uint32_t *buf, struct aarch64_register rt,
> - struct aarch64_register rt2, struct aarch64_register rn,
> - struct aarch64_memory_operand operand)
> +emit_ret (uint32_t *buf, struct aarch64_register rn)
> +{
> + return emit_insn (buf, RET | ENCODE (rn.num, 5, 5));
> +}
> +
> +static int
> +emit_load_store_pair (uint32_t *buf, enum aarch64_opcodes opcode,
> + struct aarch64_register rt,
> + struct aarch64_register rt2,
> + struct aarch64_register rn,
> + struct aarch64_memory_operand operand)
> {
> uint32_t opc;
> uint32_t pre_index;
> @@ -1018,6 +1079,12 @@ emit_stp (uint32_t *buf, struct aarch64_register rt,
> write_back = ENCODE (0, 1, 23);
> break;
> }
> + case MEMORY_OPERAND_POSTINDEX:
> + {
> + pre_index = ENCODE (0, 1, 24);
> + write_back = ENCODE (1, 1, 23);
> + break;
> + }
> case MEMORY_OPERAND_PREINDEX:
> {
> pre_index = ENCODE (1, 1, 24);
> @@ -1028,11 +1095,49 @@ emit_stp (uint32_t *buf, struct aarch64_register rt,
> return 0;
> }
>
> - return emit_insn (buf, STP | opc | pre_index | write_back
> + return emit_insn (buf, opcode | opc | pre_index | write_back
> | ENCODE (operand.index >> 3, 7, 15) | ENCODE (rt2.num, 5, 10)
> | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0));
> }
>
> +/* Write a STP instruction into *BUF.
> +
> + STP rt, rt2, [rn, #offset]
> + STP rt, rt2, [rn, #index]!
> + STP rt, rt2, [rn], #index
> +
> + RT and RT2 are the registers to store.
> + RN is the base address register.
> + OFFSET is the immediate to add to the base address. It is limited to a
> + -512 .. 504 range (7 bits << 3). */
> +
> +static int
> +emit_stp (uint32_t *buf, struct aarch64_register rt,
> + struct aarch64_register rt2, struct aarch64_register rn,
> + struct aarch64_memory_operand operand)
> +{
> + return emit_load_store_pair (buf, STP, rt, rt2, rn, operand);
> +}
> +
> +/* Write a LDP instruction into *BUF.
> +
> + LDP rt, rt2, [rn, #offset]
> + LDP rt, rt2, [rn, #index]!
> + LDP rt, rt2, [rn], #index
> +
> + RT and RT2 are the registers to store.
> + RN is the base address register.
> + OFFSET is the immediate to add to the base address. It is limited to a
> + -512 .. 504 range (7 bits << 3). */
> +
> +static int
> +emit_ldp (uint32_t *buf, struct aarch64_register rt,
> + struct aarch64_register rt2, struct aarch64_register rn,
> + struct aarch64_memory_operand operand)
> +{
> + return emit_load_store_pair (buf, LDP, rt, rt2, rn, operand);
> +}
> +
> /* Write a LDP (SIMD&VFP) instruction using Q registers into *BUF.
>
> LDP qt, qt2, [rn, #offset]
> @@ -1094,6 +1199,16 @@ emit_load_store (uint32_t *buf, uint32_t size, enum aarch64_opcodes opcode,
> | ENCODE (operand.index >> 3, 12, 10)
> | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0));
> }
> + case MEMORY_OPERAND_POSTINDEX:
> + {
> + uint32_t post_index = ENCODE (1, 2, 10);
> +
> + op = ENCODE (0, 1, 24);
> +
> + return emit_insn (buf, opcode | ENCODE (size, 2, 30) | op
> + | post_index | ENCODE (operand.index, 9, 12)
> + | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0));
> + }
> case MEMORY_OPERAND_PREINDEX:
> {
> uint32_t pre_index = ENCODE (3, 2, 10);
> @@ -1113,6 +1228,7 @@ emit_load_store (uint32_t *buf, uint32_t size, enum aarch64_opcodes opcode,
>
> LDR rt, [rn, #offset]
> LDR rt, [rn, #index]!
> + LDR rt, [rn], #index
>
> RT is the register to store.
> RN is the base address register.
> @@ -1126,10 +1242,49 @@ emit_ldr (uint32_t *buf, struct aarch64_register rt,
> return emit_load_store (buf, rt.is64 ? 3 : 2, LDR, rt, rn, operand);
> }
>
> +/* Write a LDRH instruction into *BUF.
> +
> + LDRH wt, [xn, #offset]
> + LDRH wt, [xn, #index]!
> + LDRH wt, [xn], #index
> +
> + RT is the register to store.
> + RN is the base address register.
> + OFFSET is the immediate to add to the base address. It is limited to
> + 0 .. 32760 range (12 bits << 3). */
> +
> +static int
> +emit_ldrh (uint32_t *buf, struct aarch64_register rt,
> + struct aarch64_register rn,
> + struct aarch64_memory_operand operand)
> +{
> + return emit_load_store (buf, 1, LDR, rt, rn, operand);
> +}
> +
> +/* Write a LDRB instruction into *BUF.
> +
> + LDRB wt, [xn, #offset]
> + LDRB wt, [xn, #index]!
> + LDRB wt, [xn], #index
> +
> + RT is the register to store.
> + RN is the base address register.
> + OFFSET is the immediate to add to the base address. It is limited to
> + 0 .. 32760 range (12 bits << 3). */
> +
> +static int
> +emit_ldrb (uint32_t *buf, struct aarch64_register rt,
> + struct aarch64_register rn,
> + struct aarch64_memory_operand operand)
> +{
> + return emit_load_store (buf, 0, LDR, rt, rn, operand);
> +}
> +
> /* Write a LDRSW instruction into *BUF. The register size is 64-bit.
>
> LDRSW xt, [rn, #offset]
> LDRSW xt, [rn, #index]!
> + LDRSW xt, [rn], #index
>
> RT is the register to store.
> RN is the base address register.
> @@ -1148,6 +1303,7 @@ emit_ldrsw (uint32_t *buf, struct aarch64_register rt,
>
> STR rt, [rn, #offset]
> STR rt, [rn, #index]!
> + STR rt, [rn], #index
>
> RT is the register to store.
> RN is the base address register.
> @@ -1390,6 +1546,165 @@ emit_mov_addr (uint32_t *buf, struct aarch64_register rd, CORE_ADDR addr)
> return p - buf;
> }
>
> +/* Write a SUBS instruction into *BUF.
> +
> + SUBS rd, rn, rm
> +
> + This instruction update the condition flags.
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_subs (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_operand operand)
> +{
> + return emit_data_processing (buf, SUBS, rd, rn, operand);
> +}
> +
> +/* Write a CMP instruction into *BUF.
> +
> + CMP rn, rm
> +
> + This instruction is an alias of SUBS xzr, rn, rm.
> +
> + RN and RM are the registers to compare. */
> +
> +static int
> +emit_cmp (uint32_t *buf, struct aarch64_register rn,
> + struct aarch64_operand operand)
> +{
> + return emit_subs (buf, xzr, rn, operand);
> +}
> +
> +/* Write a AND instruction into *BUF.
> +
> + AND rd, rn, rm
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_and (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm)
> +{
> + return emit_data_processing_reg (buf, AND, rd, rn, rm);
> +}
> +
> +/* Write a ORR instruction into *BUF.
> +
> + ORR rd, rn, rm
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_orr (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm)
> +{
> + return emit_data_processing_reg (buf, ORR, rd, rn, rm);
> +}
> +
> +/* Write a ORN instruction into *BUF.
> +
> + ORN rd, rn, rm
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_orn (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm)
> +{
> + return emit_data_processing_reg (buf, ORN, rd, rn, rm);
> +}
> +
> +/* Write a EOR instruction into *BUF.
> +
> + EOR rd, rn, rm
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_eor (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm)
> +{
> + return emit_data_processing_reg (buf, EOR, rd, rn, rm);
> +}
> +
> +/* Write a MVN instruction into *BUF.
> +
> + MVN rd, rm
> +
> + This is an alias for ORN rd, xzr, rm.
> +
> + RD is the destination register.
> + RM is the source register. */
> +
> +static int
> +emit_mvn (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rm)
> +{
> + return emit_orn (buf, rd, xzr, rm);
> +}
> +
> +/* Write a LSLV instruction into *BUF.
> +
> + LSLV rd, rn, rm
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_lslv (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm)
> +{
> + return emit_data_processing_reg (buf, LSLV, rd, rn, rm);
> +}
> +
> +/* Write a LSRV instruction into *BUF.
> +
> + LSRV rd, rn, rm
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_lsrv (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm)
> +{
> + return emit_data_processing_reg (buf, LSRV, rd, rn, rm);
> +}
> +
> +/* Write a ASRV instruction into *BUF.
> +
> + ASRV rd, rn, rm
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_asrv (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm)
> +{
> + return emit_data_processing_reg (buf, ASRV, rd, rn, rm);
> +}
> +
> +/* Write a MUL instruction into *BUF.
> +
> + MUL rd, rn, rm
> +
> + RD is the destination register.
> + RN and RM are the source registers. */
> +
> +static int
> +emit_mul (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm)
> +{
> + return emit_data_processing_reg (buf, MUL, rd, rn, rm);
> +}
> +
> /* Write a MRS instruction into *BUF. The register size is 64-bit.
>
> MRS xt, system_reg
> @@ -1440,6 +1755,150 @@ emit_wfe (uint32_t *buf)
> return emit_insn (buf, WFE);
> }
>
> +/* Write a SBFM instruction into *BUF.
> +
> + SBFM rd, rn, #immr, #imms
> +
> + This instruction moves the bits from #immr to #imms into the
> + destination, sign extending the result.
> +
> + RD is the destination register.
> + RN is the source register.
> + IMMR is the bit number to start at (least significant bit).
> + IMMS is the bit number to stop at (most significant bit). */
> +
> +static int
> +emit_sbfm (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, uint32_t immr, uint32_t imms)
> +{
> + uint32_t size = ENCODE (rd.is64, 1, 31);
> + uint32_t n = ENCODE (rd.is64, 1, 22);
> +
> + return emit_insn (buf, SBFM | size | n | ENCODE (immr, 6, 16)
> + | ENCODE (imms, 6, 10) | ENCODE (rn.num, 5, 5)
> + | ENCODE (rd.num, 5, 0));
> +}
> +
> +/* Write a SBFX instruction into *BUF.
> +
> + SBFX rd, rn, #lsb, #width
> +
> + This instruction moves #width bits from #lsb into the destination, sign
> + extending the result. This is an alias for:
> +
> + SBFM rd, rn, #lsb, #(lsb + width - 1)
> +
> + RD is the destination register.
> + RN is the source register.
> + LSB is the bit number to start at (least significant bit).
> + WIDTH is the number of bits to move. */
> +
> +static int
> +emit_sbfx (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, uint32_t lsb, uint32_t width)
> +{
> + return emit_sbfm (buf, rd, rn, lsb, lsb + width - 1);
> +}
> +
> +/* Write a UBFM instruction into *BUF.
> +
> + UBFM rd, rn, #immr, #imms
> +
> + This instruction moves the bits from #immr to #imms into the
> + destination, extending the result with zeros.
> +
> + RD is the destination register.
> + RN is the source register.
> + IMMR is the bit number to start at (least significant bit).
> + IMMS is the bit number to stop at (most significant bit). */
> +
> +static int
> +emit_ubfm (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, uint32_t immr, uint32_t imms)
> +{
> + uint32_t size = ENCODE (rd.is64, 1, 31);
> + uint32_t n = ENCODE (rd.is64, 1, 22);
> +
> + return emit_insn (buf, UBFM | size | n | ENCODE (immr, 6, 16)
> + | ENCODE (imms, 6, 10) | ENCODE (rn.num, 5, 5)
> + | ENCODE (rd.num, 5, 0));
> +}
> +
> +/* Write a UBFX instruction into *BUF.
> +
> + UBFX rd, rn, #lsb, #width
> +
> + This instruction moves #width bits from #lsb into the destination,
> + extending the result with zeros. This is an alias for:
> +
> + UBFM rd, rn, #lsb, #(lsb + width - 1)
> +
> + RD is the destination register.
> + RN is the source register.
> + LSB is the bit number to start at (least significant bit).
> + WIDTH is the number of bits to move. */
> +
> +static int
> +emit_ubfx (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, uint32_t lsb, uint32_t width)
> +{
> + return emit_ubfm (buf, rd, rn, lsb, lsb + width - 1);
> +}
> +
> +/* Write a CSINC instruction into *BUF.
> +
> + CSINC rd, rn, rm, cond
> +
> + This instruction conditionally increments rn or rm and places the result
> + in rd. rn is chosen is the condition is true.
> +
> + RD is the destination register.
> + RN and RM are the source registers.
> + COND is the encoded condition. */
> +
> +static int
> +emit_csinc (uint32_t *buf, struct aarch64_register rd,
> + struct aarch64_register rn, struct aarch64_register rm,
> + unsigned cond)
> +{
> + uint32_t size = ENCODE (rd.is64, 1, 31);
> +
> + return emit_insn (buf, CSINC | size | ENCODE (rm.num, 5, 16)
> + | ENCODE (cond, 4, 12) | ENCODE (rn.num, 5, 5)
> + | ENCODE (rd.num, 5, 0));
> +}
> +
> +/* Write a CSET instruction into *BUF.
> +
> + CSET rd, cond
> +
> + This instruction conditionally write 1 or 0 in the destination register.
> + 1 is written if the condition is true. This is an alias for:
> +
> + CSINC rd, xzr, xzr, !cond
> +
> + Note that the condition needs to be inverted.
> +
> + RD is the destination register.
> + RN and RM are the source registers.
> + COND is the encoded condition. */
> +
> +static int
> +emit_cset (uint32_t *buf, struct aarch64_register rd, unsigned cond)
> +{
> + /* The least significant bit of the condition needs toggling in order to
> + invert it. */
> + return emit_csinc (buf, rd, xzr, xzr, cond ^ 0x1);
> +}
> +
> +/* Write a NOP instruction into *BUF. */
> +
> +static int
> +emit_nop (uint32_t *buf)
> +{
> + return emit_insn (buf, NOP);
> +}
> +
> /* Write LEN instructions from BUF into the inferior memory at *TO.
>
> Note instructions are always little endian on AArch64, unlike data. */
> @@ -2024,6 +2483,746 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
> return 0;
> }
>
> +/* Helper function writing LEN instructions from START into
> + current_insn_ptr. */
> +
> +static void
> +emit_ops_insns (const uint32_t *start, int len)
> +{
> + CORE_ADDR buildaddr = current_insn_ptr;
> +
> + if (debug_threads)
> + debug_printf ("Adding %d instrucions at %s\n",
> + len, paddress (buildaddr));
> +
> + append_insns (&buildaddr, len, start);
> + current_insn_ptr = buildaddr;
> +}
> +
> +/* Pop a register from the stack. */
> +
> +static int
> +emit_pop (uint32_t *buf, struct aarch64_register rt)
> +{
> + return emit_ldr (buf, rt, sp, postindex_memory_operand (1 * 16));
> +}
> +
> +/* Push a register on the stack. */
> +
> +static int
> +emit_push (uint32_t *buf, struct aarch64_register rt)
> +{
> + return emit_str (buf, rt, sp, preindex_memory_operand (-1 * 16));
> +}
> +
> +/* Implementation of emit_ops method "emit_prologue". */
> +
> +static void
> +aarch64_emit_prologue (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + /* This function emit a prologue for the following function prototype:
> +
> + enum eval_result_type f (unsigned char *regs,
> + ULONGEST *value);
> +
> + The first argument is a buffer of raw registers. The second
> + argument is the result of
> + evaluating the expression, which will be set to whatever is on top of
> + the stack at the end.
> +
> + The stack set up by the prologue is as such:
> +
> + High *------------------------------------------------------*
> + | LR |
> + | FP | <- FP
> + | x1 (ULONGEST *value) |
> + | x0 (unsigned char *regs) |
> + Low *------------------------------------------------------*
> +
> + As we are implementing a stack machine, each opcode can expand the
> + stack so we never know how far we are from the data saved by this
> + prologue. In order to be able refer to value and regs later, we save
> + the current stack pointer in the frame pointer. This way, it is not
> + clobbered when calling C functions.
> +
> + Finally, throughtout every operation, we are using register x0 as the
> + top of the stack, and x1 as a scratch register. */
> +
> + p += emit_stp (p, x0, x1, sp, preindex_memory_operand (-2 * 16));
> + p += emit_str (p, lr, sp, offset_memory_operand (3 * 8));
> + p += emit_str (p, fp, sp, offset_memory_operand (2 * 8));
> +
> + p += emit_add (p, fp, sp, immediate_operand (2 * 8));
> +
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_epilogue". */
> +
> +static void
> +aarch64_emit_epilogue (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + /* Store the result of the expression (x0) in *value. */
> + p += emit_sub (p, x1, fp, immediate_operand (1 * 8));
> + p += emit_ldr (p, x1, x1, offset_memory_operand (0));
> + p += emit_str (p, x0, x1, offset_memory_operand (0));
> +
> + /* Restore the previous state. */
> + p += emit_add (p, sp, fp, immediate_operand (2 * 8));
> + p += emit_ldp (p, fp, lr, fp, offset_memory_operand (0));
> +
> + /* Return expr_eval_no_error. */
> + p += emit_mov (p, x0, immediate_operand (expr_eval_no_error));
> + p += emit_ret (p, lr);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_add". */
> +
> +static void
> +aarch64_emit_add (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_add (p, x0, x0, register_operand (x1));
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_sub". */
> +
> +static void
> +aarch64_emit_sub (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_sub (p, x0, x0, register_operand (x1));
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_mul". */
> +
> +static void
> +aarch64_emit_mul (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_mul (p, x0, x1, x0);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_lsh". */
> +
> +static void
> +aarch64_emit_lsh (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_lslv (p, x0, x1, x0);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_rsh_signed". */
> +
> +static void
> +aarch64_emit_rsh_signed (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_asrv (p, x0, x1, x0);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_rsh_unsigned". */
> +
> +static void
> +aarch64_emit_rsh_unsigned (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_lsrv (p, x0, x1, x0);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_ext". */
> +
> +static void
> +aarch64_emit_ext (int arg)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_sbfx (p, x0, x0, 0, arg);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_log_not". */
> +
> +static void
> +aarch64_emit_log_not (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + /* If the top of the stack is 0, replace it with 1. Else replace it with
> + 0. */
> +
> + p += emit_cmp (p, x0, immediate_operand (0));
> + p += emit_cset (p, x0, EQ);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_bit_and". */
> +
> +static void
> +aarch64_emit_bit_and (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_and (p, x0, x0, x1);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_bit_or". */
> +
> +static void
> +aarch64_emit_bit_or (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_orr (p, x0, x0, x1);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_bit_xor". */
> +
> +static void
> +aarch64_emit_bit_xor (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_eor (p, x0, x0, x1);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_bit_not". */
> +
> +static void
> +aarch64_emit_bit_not (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_mvn (p, x0, x0);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_equal". */
> +
> +static void
> +aarch64_emit_equal (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_cmp (p, x0, register_operand (x1));
> + p += emit_cset (p, x0, EQ);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_less_signed". */
> +
> +static void
> +aarch64_emit_less_signed (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_cmp (p, x1, register_operand (x0));
> + p += emit_cset (p, x0, LT);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_less_unsigned". */
> +
> +static void
> +aarch64_emit_less_unsigned (void)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_pop (p, x1);
> + p += emit_cmp (p, x1, register_operand (x0));
> + p += emit_cset (p, x0, LO);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_ref". */
> +
> +static void
> +aarch64_emit_ref (int size)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + switch (size)
> + {
> + case 1:
> + p += emit_ldrb (p, w0, x0, offset_memory_operand (0));
> + break;
> + case 2:
> + p += emit_ldrh (p, w0, x0, offset_memory_operand (0));
> + break;
> + case 4:
> + p += emit_ldr (p, w0, x0, offset_memory_operand (0));
> + break;
> + case 8:
> + p += emit_ldr (p, x0, x0, offset_memory_operand (0));
> + break;
> + default:
> + /* Unknown size, bail on compilation. */
> + emit_error = 1;
> + break;
> + }
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_if_goto". */
> +
> +static void
> +aarch64_emit_if_goto (int *offset_p, int *size_p)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + /* The Z flag is set or cleared here. */
> + p += emit_cmp (p, x0, immediate_operand (0));
> + /* This instruction must not change the Z flag. */
> + p += emit_pop (p, x0);
> + /* Branch over the next instruction if x0 == 0. */
> + p += emit_bcond (p, EQ, 8);
> +
> + /* The NOP instruction will be patched with an unconditional branch. */
> + if (offset_p)
> + *offset_p = (p - buf) * 4;
> + if (size_p)
> + *size_p = 4;
> + p += emit_nop (p);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_goto". */
> +
> +static void
> +aarch64_emit_goto (int *offset_p, int *size_p)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + /* The NOP instruction will be patched with an unconditional branch. */
> + if (offset_p)
> + *offset_p = 0;
> + if (size_p)
> + *size_p = 4;
> + p += emit_nop (p);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "write_goto_address". */
> +
> +void
> +aarch64_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
> +{
> + uint32_t insn;
> +
> + emit_b (&insn, 0, to - from);
> + append_insns (&from, 1, &insn);
> +}
> +
> +/* Implementation of emit_ops method "emit_const". */
> +
> +static void
> +aarch64_emit_const (LONGEST num)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_mov_addr (p, x0, num);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_call". */
> +
> +static void
> +aarch64_emit_call (CORE_ADDR fn)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + p += emit_mov_addr (p, ip0, fn);
> + p += emit_blr (p, ip0);
> +
> + emit_ops_insns (buf, p - buf);
> +}
> +
> +/* Implementation of emit_ops method "emit_reg". */
> +
> +static void
> +aarch64_emit_reg (int reg)
> +{
> + uint32_t buf[16];
> + uint32_t *p = buf;
> +
> + /* Set x0 to struct fast_tracepoint_ctx *ctx->regs. */
This comment should mention the saved raw registers instead of
fast_tracepoint_ctx.
/* Set x0 to unsigned char *regs. */
> + p += emit_sub (p, x0, fp, immediate_operand (2 * 8));
> + p += emit_ldr (p, x0, x0, offset_memory_operand (0));
> + p += emit_mov (p, x1, immediate_operand (reg));
> +
> + emit_ops_insns (buf, p - buf);
> +
> + aarch64_emit_call (get_raw_reg_func_addr ());
> +}
Thanks again!
Pierre
next prev parent reply other threads:[~2015-09-18 12:57 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-14 11:31 [PATCH 0/8] [AArch64] Support fast tracepoints Pierre Langlois
2015-09-14 11:31 ` [PATCH 3/8] [AArch64] Make aarch64_decode_adrp handle both ADR and ADRP instructions Pierre Langlois
2015-09-15 10:12 ` Yao Qi
2015-09-15 12:05 ` [PATCH 3/8 v2] " Pierre Langlois
2015-09-14 11:31 ` [PATCH 1/8] [AArch64] Use debug_printf instead of fprintf_unfiltered Pierre Langlois
2015-09-15 10:06 ` Yao Qi
2015-09-15 11:07 ` Pierre Langlois
2015-09-15 11:19 ` Yao Qi
2015-09-15 11:43 ` [PATCH 2/8 v2] " Pierre Langlois
2015-09-15 17:40 ` Pierre Langlois
2015-09-14 11:32 ` [PATCH 5/8] [GDBserver][AArch64] Implement target_emit_ops Pierre Langlois
2015-09-14 11:32 ` [PATCH 6/8] [testsuite][AArch64] Enable fast tracepoint tests Pierre Langlois
2015-09-15 10:18 ` Yao Qi
2015-09-14 11:32 ` [PATCH 7/8] [testsuite] Add a gdb.trace test for instruction relocation Pierre Langlois
2015-09-15 11:27 ` Yao Qi
2015-09-14 11:33 ` [PATCH 4/8] [GDBserver][AArch64] Add support for fast tracepoints Pierre Langlois
2015-09-15 13:01 ` Yao Qi
2015-09-14 11:38 ` [PATCH 8/8] [testsuite] Add a test case for fast tracepoints' locking mechanism Pierre Langlois
2015-09-14 11:38 ` [PATCH 2/8] [AArch64] Move instruction decoding into new arch/ directory Pierre Langlois
2015-09-15 10:10 ` Yao Qi
2015-09-15 12:02 ` [PATCH 2/8 v2] " Pierre Langlois
2015-09-14 16:45 ` [PATCH] Add NEWS entry for fast tracepoint support on aarch64-linux Pierre Langlois
2015-09-18 12:43 ` [PATCH 0/8 V2] [AArch64] Support fast tracepoints Yao Qi
2015-09-18 12:43 ` [PATCH 1/8] Move instruction decoding into new arch/ directory Yao Qi
2015-09-18 12:43 ` [PATCH 2/8] Make aarch64_decode_adrp handle both ADR and ADRP instructions Yao Qi
2015-09-18 12:43 ` [PATCH 7/8] Add a test case for fast tracepoints' locking mechanism Yao Qi
2015-09-18 12:43 ` [PATCH 4/8] Implement target_emit_ops Yao Qi
2015-09-18 12:57 ` Pierre Langlois [this message]
2016-02-05 20:09 ` Antoine Tremblay
2016-02-08 17:30 ` Yao Qi
2016-02-08 17:59 ` Antoine Tremblay
2015-09-18 12:43 ` [PATCH 8/8] Add NEWS entry for fast tracepoint support on aarch64-linux Yao Qi
2015-09-18 14:07 ` Eli Zaretskii
2015-09-18 12:43 ` [PATCH 5/8] Enable fast tracepoint tests Yao Qi
2015-09-18 12:44 ` [PATCH 6/8] Add a gdb.trace test for instruction relocation Yao Qi
2015-09-18 12:44 ` [PATCH 3/8] Add support for fast tracepoints Yao Qi
2015-09-21 14:06 ` [PATCH 0/8 V2] [AArch64] Support " Yao Qi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55FC0A35.4070807@arm.com \
--to=pierre.langlois@arm.com \
--cc=gdb-patches@sourceware.org \
--cc=qiyaoltc@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).