From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 41476 invoked by alias); 18 Sep 2015 12:57:36 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 41323 invoked by uid 89); 18 Sep 2015 12:57:35 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.1 required=5.0 tests=AWL,BAYES_00,KAM_ASCII_DIVIDERS,SPF_PASS autolearn=no version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Received: from eu-smtp-delivery-143.mimecast.com (HELO eu-smtp-delivery-143.mimecast.com) (207.82.80.143) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 18 Sep 2015 12:57:30 +0000 Received: from cam-owa2.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-12-8-BeqxL1RTqzUXFhRZY0WQ-1; Fri, 18 Sep 2015 13:57:25 +0100 Received: from [10.1.201.157] ([10.1.2.79]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 18 Sep 2015 13:57:24 +0100 Message-ID: <55FC0A35.4070807@arm.com> Date: Fri, 18 Sep 2015 12:57:00 -0000 From: Pierre Langlois User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.8.0 MIME-Version: 1.0 To: Yao Qi , "gdb-patches@sourceware.org" CC: pierre.langlois@arm.com Subject: Re: [PATCH 4/8] Implement target_emit_ops References: <1442230282-20751-1-git-send-email-pierre.langlois@arm.com> <1442580184-22562-1-git-send-email-yao.qi@linaro.org> <1442580184-22562-5-git-send-email-yao.qi@linaro.org> In-Reply-To: <1442580184-22562-5-git-send-email-yao.qi@linaro.org> X-MC-Unique: 8-BeqxL1RTqzUXFhRZY0WQ-1 Content-Type: text/plain; charset=WINDOWS-1252 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes X-SW-Source: 2015-09/txt/msg00469.txt.bz2 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 >=20 > This patch implements compiling agent expressions to native code for > AArch64. This allows us to compile conditions set on fast tracepoints. >=20 > The compiled function has the following prologue: >=20 > High *------------------------------------------------------* > | LR | > | FP | <- FP > | x1 (ULONGEST *value) | > | x0 (unsigned char *regs) | > Low *------------------------------------------------------* >=20 > 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. >=20 > 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 >=20 > gdb/gdbserver/ChangeLog: >=20 > * linux-aarch64-low-.c: Include ax.h and tracepoint.h. > (enum aarch64_opcodes) , , , , , > , , , , , , , , > : New. > (enum aarch64_condition_codes): New enum. > (w0): New static global. > (fp): Likewise. > (lr): Likewise. > (struct aarch64_memory_operand) : 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(-) >=20 > diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarc= h64-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" >=20 > #include > #include > @@ -680,6 +682,8 @@ enum aarch64_opcodes > TBNZ =3D 0x37000000 | B, > /* BLR 1101 0110 0011 1111 0000 00rr rrr0 0000 */ > BLR =3D 0xd63f0000, > + /* RET 1101 0110 0101 1111 0000 00rr rrr0 0000 */ > + RET =3D 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 =3D 0x01000000, > SUB =3D 0x40000000 | ADD, > + SUBS =3D 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 =3D 0x0a000000, > + ORR =3D 0x20000000 | AND, > + ORN =3D 0x00200000 | ORR, > + EOR =3D 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 =3D 0x1ac02000, > + LSRV =3D 0x00000400 | LSLV, > + ASRV =3D 0x00000800 | LSLV, > + /* SBFM s001 0011 0nii iiii iiii iirr rrrr rrrr */ > + SBFM =3D 0x13000000, > + /* UBFM s101 0011 0nii iiii iiii iirr rrrr rrrr */ > + UBFM =3D 0x40000000 | SBFM, > + /* CSINC s001 1010 100r rrrr cccc 01rr rrrr rrrr */ > + CSINC =3D 0x9a800400, > + /* MUL s001 1011 000r rrrr 0111 11rr rrrr rrrr */ > + MUL =3D 0x1b007c00, > /* MSR (register) 1101 0101 0001 oooo oooo oooo ooor rrrr */ > /* MRS 1101 0101 0011 oooo oooo oooo ooor rrrr */ > MSR =3D 0xd5100000, > @@ -717,6 +744,20 @@ enum aarch64_opcodes > HINT =3D 0xd503201f, > SEVL =3D (5 << 5) | HINT, > WFE =3D (2 << 5) | HINT, > + NOP =3D (0 << 5) | HINT, > +}; > + > +/* List of condition codes that we need. */ > + > +enum aarch64_condition_codes > +{ > + EQ =3D 0x0, > + NE =3D 0x1, > + LO =3D 0x3, > + GE =3D 0xa, > + LT =3D 0xb, > + GT =3D 0xc, > + LE =3D 0xd, > }; >=20 > /* Representation of a general purpose register of the form xN or wN. > @@ -759,12 +800,15 @@ static const struct aarch64_register x3 =3D { 3, 1 = }; > static const struct aarch64_register x4 =3D { 4, 1 }; >=20 > /* General purpose scratch registers (32 bit). */ > +static const struct aarch64_register w0 =3D { 0, 0 }; > static const struct aarch64_register w2 =3D { 2, 0 }; >=20 > /* Intra-procedure scratch registers. */ > static const struct aarch64_register ip0 =3D { 16, 1 }; >=20 > /* Special purpose registers. */ > +static const struct aarch64_register fp =3D { 29, 1 }; > +static const struct aarch64_register lr =3D { 30, 1 }; > static const struct aarch64_register sp =3D { 31, 1 }; > static const struct aarch64_register xzr =3D { 31, 1 }; >=20 > @@ -817,8 +861,9 @@ immediate_operand (uint32_t imm) >=20 > The types correspond to the following variants: >=20 > - 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 */ >=20 > 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, inde= x }; > } >=20 > +/* Helper function to create a post-index memory operand. > + > + For example: > + p +=3D 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, ind= ex }; > +} > + > /* System control registers. These special registers can be written and > read with the MRS and MSR instructions. >=20 > @@ -986,20 +1043,24 @@ emit_blr (uint32_t *buf, struct aarch64_register r= n) > return emit_insn (buf, BLR | ENCODE (rn.num, 5, 5)); > } >=20 > -/* Write a STP instruction into *BUF. > +/* Write a RET instruction into *BUF. >=20 > - STP rt, rt2, [rn, #offset] > - STP rt, rt2, [rn, #index]! > + RET xn >=20 > - 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. */ >=20 > 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 r= t, > write_back =3D ENCODE (0, 1, 23); > break; > } > + case MEMORY_OPERAND_POSTINDEX: > + { > + pre_index =3D ENCODE (0, 1, 24); > + write_back =3D ENCODE (1, 1, 23); > + break; > + } > case MEMORY_OPERAND_PREINDEX: > { > pre_index =3D ENCODE (1, 1, 24); > @@ -1028,11 +1095,49 @@ emit_stp (uint32_t *buf, struct aarch64_register = rt, > return 0; > } >=20 > - 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.nu= m, 5, 10) > | ENCODE (rn.num, 5, 5) | ENCODE (rt.num, 5, 0)); > } >=20 > +/* 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. >=20 > LDP qt, qt2, [rn, #offset] > @@ -1094,6 +1199,16 @@ emit_load_store (uint32_t *buf, uint32_t size, enu= m 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 =3D ENCODE (1, 2, 10); > + > + op =3D 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 =3D ENCODE (3, 2, 10); > @@ -1113,6 +1228,7 @@ emit_load_store (uint32_t *buf, uint32_t size, enum= aarch64_opcodes opcode, >=20 > LDR rt, [rn, #offset] > LDR rt, [rn, #index]! > + LDR rt, [rn], #index >=20 > 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); > } >=20 > +/* 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. >=20 > LDRSW xt, [rn, #offset] > LDRSW xt, [rn, #index]! > + LDRSW xt, [rn], #index >=20 > 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, >=20 > STR rt, [rn, #offset] > STR rt, [rn, #index]! > + STR rt, [rn], #index >=20 > RT is the register to store. > RN is the base address register. > @@ -1390,6 +1546,165 @@ emit_mov_addr (uint32_t *buf, struct aarch64_regi= ster rd, CORE_ADDR addr) > return p - buf; > } >=20 > +/* 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. >=20 > MRS xt, system_reg > @@ -1440,6 +1755,150 @@ emit_wfe (uint32_t *buf) > return emit_insn (buf, WFE); > } >=20 > +/* 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 =3D ENCODE (rd.is64, 1, 31); > + uint32_t n =3D 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, si= gn > + 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 =3D ENCODE (rd.is64, 1, 31); > + uint32_t n =3D 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 res= ult > + 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 =3D 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 regist= er. > + 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. >=20 > Note instructions are always little endian on AArch64, unlike data. = */ > @@ -2024,6 +2483,746 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_AD= DR tpoint, > return 0; > } >=20 > +/* 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 =3D 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 =3D 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 =3D 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 sa= ve > + 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 t= he > + top of the stack, and x1 as a scratch register. */ > + > + p +=3D emit_stp (p, x0, x1, sp, preindex_memory_operand (-2 * 16)); > + p +=3D emit_str (p, lr, sp, offset_memory_operand (3 * 8)); > + p +=3D emit_str (p, fp, sp, offset_memory_operand (2 * 8)); > + > + p +=3D 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 =3D buf; > + > + /* Store the result of the expression (x0) in *value. */ > + p +=3D emit_sub (p, x1, fp, immediate_operand (1 * 8)); > + p +=3D emit_ldr (p, x1, x1, offset_memory_operand (0)); > + p +=3D emit_str (p, x0, x1, offset_memory_operand (0)); > + > + /* Restore the previous state. */ > + p +=3D emit_add (p, sp, fp, immediate_operand (2 * 8)); > + p +=3D emit_ldp (p, fp, lr, fp, offset_memory_operand (0)); > + > + /* Return expr_eval_no_error. */ > + p +=3D emit_mov (p, x0, immediate_operand (expr_eval_no_error)); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D 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 =3D buf; > + > + /* If the top of the stack is 0, replace it with 1. Else replace it w= ith > + 0. */ > + > + p +=3D emit_cmp (p, x0, immediate_operand (0)); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D 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 =3D buf; > + > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D emit_cmp (p, x0, register_operand (x1)); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D emit_cmp (p, x1, register_operand (x0)); > + p +=3D 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 =3D buf; > + > + p +=3D emit_pop (p, x1); > + p +=3D emit_cmp (p, x1, register_operand (x0)); > + p +=3D 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 =3D buf; > + > + switch (size) > + { > + case 1: > + p +=3D emit_ldrb (p, w0, x0, offset_memory_operand (0)); > + break; > + case 2: > + p +=3D emit_ldrh (p, w0, x0, offset_memory_operand (0)); > + break; > + case 4: > + p +=3D emit_ldr (p, w0, x0, offset_memory_operand (0)); > + break; > + case 8: > + p +=3D emit_ldr (p, x0, x0, offset_memory_operand (0)); > + break; > + default: > + /* Unknown size, bail on compilation. */ > + emit_error =3D 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 =3D buf; > + > + /* The Z flag is set or cleared here. */ > + p +=3D emit_cmp (p, x0, immediate_operand (0)); > + /* This instruction must not change the Z flag. */ > + p +=3D emit_pop (p, x0); > + /* Branch over the next instruction if x0 =3D=3D 0. */ > + p +=3D emit_bcond (p, EQ, 8); > + > + /* The NOP instruction will be patched with an unconditional branch. = */ > + if (offset_p) > + *offset_p =3D (p - buf) * 4; > + if (size_p) > + *size_p =3D 4; > + p +=3D 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 =3D buf; > + > + /* The NOP instruction will be patched with an unconditional branch. = */ > + if (offset_p) > + *offset_p =3D 0; > + if (size_p) > + *size_p =3D 4; > + p +=3D 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 =3D buf; > + > + p +=3D 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 =3D buf; > + > + p +=3D emit_mov_addr (p, ip0, fn); > + p +=3D 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 =3D 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 +=3D emit_sub (p, x0, fp, immediate_operand (2 * 8)); > + p +=3D emit_ldr (p, x0, x0, offset_memory_operand (0)); > + p +=3D emit_mov (p, x1, immediate_operand (reg)); > + > + emit_ops_insns (buf, p - buf); > + > + aarch64_emit_call (get_raw_reg_func_addr ()); > +} Thanks again! Pierre