xref: /linux/tools/perf/util/annotate-arch/annotate-powerpc.c (revision 0e26ba5a87744ee8957cc1f341e403c0fd758398)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
207b972ffSIan Rogers #include <string.h>
3696e2457SJiri Olsa #include <linux/compiler.h>
407b972ffSIan Rogers #include <linux/kernel.h>
507b972ffSIan Rogers #include "../annotate-data.h"
607b972ffSIan Rogers #include "../debug.h"
707b972ffSIan Rogers #include "../disasm.h"
807b972ffSIan Rogers 
907b972ffSIan Rogers #define PPC_OP(op)	(((op) >> 26) & 0x3F)
1007b972ffSIan Rogers #define PPC_21_30(R)	(((R) >> 1) & 0x3ff)
1107b972ffSIan Rogers #define PPC_22_30(R)	(((R) >> 1) & 0x1ff)
1207b972ffSIan Rogers 
1307b972ffSIan Rogers #define MINUS_EXT_XO_FORM	234
1407b972ffSIan Rogers #define SUB_EXT_XO_FORM		232
1507b972ffSIan Rogers #define	ADD_ZERO_EXT_XO_FORM	202
1607b972ffSIan Rogers #define	SUB_ZERO_EXT_XO_FORM	200
1707b972ffSIan Rogers 
arithmetic__scnprintf(const struct ins * ins,char * bf,size_t size,struct ins_operands * ops,int max_ins_name)1807b972ffSIan Rogers static int arithmetic__scnprintf(const struct ins *ins, char *bf, size_t size,
1907b972ffSIan Rogers 		struct ins_operands *ops, int max_ins_name)
2007b972ffSIan Rogers {
2107b972ffSIan Rogers 	return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
2207b972ffSIan Rogers 			ops->raw);
2307b972ffSIan Rogers }
2407b972ffSIan Rogers 
2507b972ffSIan Rogers /*
2607b972ffSIan Rogers  * Sets the fields: multi_regs and "mem_ref".
2707b972ffSIan Rogers  * "mem_ref" is set for ops->source which is later used to
2807b972ffSIan Rogers  * fill the objdump->memory_ref-char field. This ops is currently
2907b972ffSIan Rogers  * used by powerpc and since binary instruction code is used to
3007b972ffSIan Rogers  * extract opcode, regs and offset, no other parsing is needed here.
3107b972ffSIan Rogers  *
3207b972ffSIan Rogers  * Dont set multi regs for 4 cases since it has only one operand
3307b972ffSIan Rogers  * for source:
3407b972ffSIan Rogers  * - Add to Minus One Extended XO-form ( Ex: addme, addmeo )
3507b972ffSIan Rogers  * - Subtract From Minus One Extended XO-form ( Ex: subfme )
3607b972ffSIan Rogers  * - Add to Zero Extended XO-form ( Ex: addze, addzeo )
3707b972ffSIan Rogers  * - Subtract From Zero Extended XO-form ( Ex: subfze )
3807b972ffSIan Rogers  */
arithmetic__parse(const struct arch * arch __maybe_unused,struct ins_operands * ops,struct map_symbol * ms __maybe_unused,struct disasm_line * dl)3907b972ffSIan Rogers static int arithmetic__parse(const struct arch *arch __maybe_unused, struct ins_operands *ops,
4007b972ffSIan Rogers 		struct map_symbol *ms __maybe_unused, struct disasm_line *dl)
4107b972ffSIan Rogers {
4207b972ffSIan Rogers 	int opcode = PPC_OP(dl->raw.raw_insn);
4307b972ffSIan Rogers 
4407b972ffSIan Rogers 	ops->source.mem_ref = false;
4507b972ffSIan Rogers 	if (opcode == 31) {
4607b972ffSIan Rogers 		if ((opcode != MINUS_EXT_XO_FORM) && (opcode != SUB_EXT_XO_FORM) &&
4707b972ffSIan Rogers 		    (opcode != ADD_ZERO_EXT_XO_FORM) && (opcode != SUB_ZERO_EXT_XO_FORM))
4807b972ffSIan Rogers 			ops->source.multi_regs = true;
4907b972ffSIan Rogers 	}
5007b972ffSIan Rogers 
5107b972ffSIan Rogers 	ops->target.mem_ref = false;
5207b972ffSIan Rogers 	ops->target.multi_regs = false;
5307b972ffSIan Rogers 
5407b972ffSIan Rogers 	return 0;
5507b972ffSIan Rogers }
5607b972ffSIan Rogers 
5707b972ffSIan Rogers static const struct ins_ops arithmetic_ops = {
5807b972ffSIan Rogers 	.parse     = arithmetic__parse,
5907b972ffSIan Rogers 	.scnprintf = arithmetic__scnprintf,
6007b972ffSIan Rogers };
6107b972ffSIan Rogers 
load_store__scnprintf(const struct ins * ins,char * bf,size_t size,struct ins_operands * ops,int max_ins_name)6207b972ffSIan Rogers static int load_store__scnprintf(const struct ins *ins, char *bf, size_t size,
6307b972ffSIan Rogers 		struct ins_operands *ops, int max_ins_name)
6407b972ffSIan Rogers {
6507b972ffSIan Rogers 	return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
6607b972ffSIan Rogers 			ops->raw);
6707b972ffSIan Rogers }
6807b972ffSIan Rogers 
6907b972ffSIan Rogers /*
7007b972ffSIan Rogers  * Sets the fields: multi_regs and "mem_ref".
7107b972ffSIan Rogers  * "mem_ref" is set for ops->source which is later used to
7207b972ffSIan Rogers  * fill the objdump->memory_ref-char field. This ops is currently
7307b972ffSIan Rogers  * used by powerpc and since binary instruction code is used to
7407b972ffSIan Rogers  * extract opcode, regs and offset, no other parsing is needed here
7507b972ffSIan Rogers  */
load_store__parse(const struct arch * arch __maybe_unused,struct ins_operands * ops,struct map_symbol * ms __maybe_unused,struct disasm_line * dl __maybe_unused)7607b972ffSIan Rogers static int load_store__parse(const struct arch *arch __maybe_unused, struct ins_operands *ops,
7707b972ffSIan Rogers 		struct map_symbol *ms __maybe_unused, struct disasm_line *dl __maybe_unused)
7807b972ffSIan Rogers {
7907b972ffSIan Rogers 	ops->source.mem_ref = true;
8007b972ffSIan Rogers 	ops->source.multi_regs = false;
8107b972ffSIan Rogers 	/* opcode 31 is of X form */
8207b972ffSIan Rogers 	if (PPC_OP(dl->raw.raw_insn) == 31)
8307b972ffSIan Rogers 		ops->source.multi_regs = true;
8407b972ffSIan Rogers 
8507b972ffSIan Rogers 	ops->target.mem_ref = false;
8607b972ffSIan Rogers 	ops->target.multi_regs = false;
8707b972ffSIan Rogers 
8807b972ffSIan Rogers 	return 0;
8907b972ffSIan Rogers }
9007b972ffSIan Rogers 
9107b972ffSIan Rogers static const struct ins_ops load_store_ops = {
9207b972ffSIan Rogers 	.parse     = load_store__parse,
9307b972ffSIan Rogers 	.scnprintf = load_store__scnprintf,
9407b972ffSIan Rogers };
95696e2457SJiri Olsa 
powerpc__associate_instruction_ops(struct arch * arch,const char * name)961e3b91d6SIan Rogers static const struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name)
97dbdebdc5SRavi Bangoria {
98dbdebdc5SRavi Bangoria 	int i;
991e3b91d6SIan Rogers 	const struct ins_ops *ops;
100dbdebdc5SRavi Bangoria 
101dbdebdc5SRavi Bangoria 	/*
102dbdebdc5SRavi Bangoria 	 * - Interested only if instruction starts with 'b'.
103dbdebdc5SRavi Bangoria 	 * - Few start with 'b', but aren't branch instructions.
104dbdebdc5SRavi Bangoria 	 */
105dbdebdc5SRavi Bangoria 	if (name[0] != 'b'             ||
106dbdebdc5SRavi Bangoria 	    !strncmp(name, "bcd", 3)   ||
107dbdebdc5SRavi Bangoria 	    !strncmp(name, "brinc", 5) ||
108dbdebdc5SRavi Bangoria 	    !strncmp(name, "bper", 4))
109dbdebdc5SRavi Bangoria 		return NULL;
110dbdebdc5SRavi Bangoria 
111dbdebdc5SRavi Bangoria 	ops = &jump_ops;
112dbdebdc5SRavi Bangoria 
113dbdebdc5SRavi Bangoria 	i = strlen(name) - 1;
114dbdebdc5SRavi Bangoria 	if (i < 0)
115dbdebdc5SRavi Bangoria 		return NULL;
116dbdebdc5SRavi Bangoria 
117dbdebdc5SRavi Bangoria 	/* ignore optional hints at the end of the instructions */
118dbdebdc5SRavi Bangoria 	if (name[i] == '+' || name[i] == '-')
119dbdebdc5SRavi Bangoria 		i--;
120dbdebdc5SRavi Bangoria 
121dbdebdc5SRavi Bangoria 	if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) {
122dbdebdc5SRavi Bangoria 		/*
123dbdebdc5SRavi Bangoria 		 * if the instruction ends up with 'l' or 'la', then
124dbdebdc5SRavi Bangoria 		 * those are considered 'calls' since they update LR.
125dbdebdc5SRavi Bangoria 		 * ... except for 'bnl' which is branch if not less than
126dbdebdc5SRavi Bangoria 		 * and the absolute form of the same.
127dbdebdc5SRavi Bangoria 		 */
128dbdebdc5SRavi Bangoria 		if (strcmp(name, "bnl") && strcmp(name, "bnl+") &&
129dbdebdc5SRavi Bangoria 		    strcmp(name, "bnl-") && strcmp(name, "bnla") &&
130dbdebdc5SRavi Bangoria 		    strcmp(name, "bnla+") && strcmp(name, "bnla-"))
131dbdebdc5SRavi Bangoria 			ops = &call_ops;
132dbdebdc5SRavi Bangoria 	}
133dbdebdc5SRavi Bangoria 	if (name[i] == 'r' && name[i-1] == 'l')
134dbdebdc5SRavi Bangoria 		/*
135dbdebdc5SRavi Bangoria 		 * instructions ending with 'lr' are considered to be
136dbdebdc5SRavi Bangoria 		 * return instructions
137dbdebdc5SRavi Bangoria 		 */
138dbdebdc5SRavi Bangoria 		ops = &ret_ops;
139dbdebdc5SRavi Bangoria 
140dbdebdc5SRavi Bangoria 	arch__associate_ins_ops(arch, name, ops);
141dbdebdc5SRavi Bangoria 	return ops;
142dbdebdc5SRavi Bangoria }
143dbdebdc5SRavi Bangoria 
144ace7d681SAthira Rajeev struct insn_offset {
145ace7d681SAthira Rajeev 	const char	*name;
146ace7d681SAthira Rajeev 	int		value;
147ace7d681SAthira Rajeev };
148ace7d681SAthira Rajeev 
149ace7d681SAthira Rajeev /*
150ace7d681SAthira Rajeev  * There are memory instructions with opcode 31 which are
151ace7d681SAthira Rajeev  * of X Form, Example:
152ace7d681SAthira Rajeev  * ldx RT,RA,RB
153ace7d681SAthira Rajeev  * ______________________________________
154ace7d681SAthira Rajeev  * | 31 |  RT  |  RA |  RB |   21     |/|
155ace7d681SAthira Rajeev  * --------------------------------------
156ace7d681SAthira Rajeev  * 0    6     11    16    21         30 31
157ace7d681SAthira Rajeev  *
158ace7d681SAthira Rajeev  * But all instructions with opcode 31 are not memory.
159ace7d681SAthira Rajeev  * Example: add RT,RA,RB
160ace7d681SAthira Rajeev  *
161ace7d681SAthira Rajeev  * Use bits 21 to 30 to check memory insns with 31 as opcode.
162ace7d681SAthira Rajeev  * In ins_array below, for ldx instruction:
163ace7d681SAthira Rajeev  * name => OP_31_XOP_LDX
164ace7d681SAthira Rajeev  * value => 21
165ace7d681SAthira Rajeev  */
166ace7d681SAthira Rajeev 
167ace7d681SAthira Rajeev static struct insn_offset ins_array[] = {
168ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LXSIWZX",  .value = 12, },
169ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LWARX",	.value = 20, },
170ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LDX",	.value = 21, },
171ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LWZX",	.value = 23, },
172ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LDUX",	.value = 53, },
173ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LWZUX",	.value = 55, },
174ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LXSIWAX",  .value = 76, },
175ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LDARX",    .value = 84, },
176ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LBZX",	.value = 87, },
177ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LVX",      .value = 103, },
178ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LBZUX",    .value = 119, },
179ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STXSIWX",  .value = 140, },
180ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STDX",	.value = 149, },
181ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STWX",	.value = 151, },
182ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STDUX",	.value = 181, },
183ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STWUX",	.value = 183, },
184ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STBX",	.value = 215, },
185ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STVX",     .value = 231, },
186ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STBUX",	.value = 247, },
187ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LHZX",	.value = 279, },
188ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LHZUX",	.value = 311, },
189ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LXVDSX",   .value = 332, },
190ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LWAX",	.value = 341, },
191ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LHAX",	.value = 343, },
192ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LWAUX",	.value = 373, },
193ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LHAUX",	.value = 375, },
194ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STHX",	.value = 407, },
195ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STHUX",	.value = 439, },
196ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LXSSPX",   .value = 524, },
197ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LDBRX",	.value = 532, },
198ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LSWX",	.value = 533, },
199ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LWBRX",	.value = 534, },
200ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LFSUX",    .value = 567, },
201ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LXSDX",    .value = 588, },
202ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LSWI",	.value = 597, },
203ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LFDX",     .value = 599, },
204ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LFDUX",    .value = 631, },
205ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STXSSPX",  .value = 652, },
206ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STDBRX",	.value = 660, },
207ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STXWX",	.value = 661, },
208ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STWBRX",	.value = 662, },
209ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STFSX",	.value = 663, },
210ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STFSUX",	.value = 695, },
211ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STXSDX",   .value = 716, },
212ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STSWI",	.value = 725, },
213ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STFDX",	.value = 727, },
214ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STFDUX",	.value = 759, },
215ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LXVW4X",   .value = 780, },
216ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LHBRX",	.value = 790, },
217ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LXVD2X",   .value = 844, },
218ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LFIWAX",	.value = 855, },
219ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_LFIWZX",	.value = 887, },
220ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STXVW4X",  .value = 908, },
221ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STHBRX",	.value = 918, },
222ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STXVD2X",  .value = 972, },
223ace7d681SAthira Rajeev 	{ .name = "OP_31_XOP_STFIWX",	.value = 983, },
224ace7d681SAthira Rajeev };
225ace7d681SAthira Rajeev 
226cd0b6f67SAthira Rajeev /*
227cd0b6f67SAthira Rajeev  * Arithmetic instructions which are having opcode as 31.
228cd0b6f67SAthira Rajeev  * These instructions are tracked to save the register state
229cd0b6f67SAthira Rajeev  * changes. Example:
230cd0b6f67SAthira Rajeev  *
231cd0b6f67SAthira Rajeev  * lwz	r10,264(r3)
232cd0b6f67SAthira Rajeev  * add	r31, r3, r3
233cd0b6f67SAthira Rajeev  * lwz	r9, 0(r31)
234cd0b6f67SAthira Rajeev  *
235cd0b6f67SAthira Rajeev  * Here instruction tracking needs to identify the "add"
236cd0b6f67SAthira Rajeev  * instruction and save data type of r3 to r31. If a sample
237cd0b6f67SAthira Rajeev  * is hit at next "lwz r9, 0(r31)", by this instruction tracking,
238cd0b6f67SAthira Rajeev  * data type of r31 can be resolved.
239cd0b6f67SAthira Rajeev  */
240cd0b6f67SAthira Rajeev static struct insn_offset arithmetic_ins_op_31[] = {
241cd0b6f67SAthira Rajeev 	{ .name = "SUB_CARRY_XO_FORM",  .value = 8, },
242cd0b6f67SAthira Rajeev 	{ .name = "MUL_HDW_XO_FORM1",   .value = 9, },
243cd0b6f67SAthira Rajeev 	{ .name = "ADD_CARRY_XO_FORM",  .value = 10, },
244cd0b6f67SAthira Rajeev 	{ .name = "MUL_HW_XO_FORM1",    .value = 11, },
245cd0b6f67SAthira Rajeev 	{ .name = "SUB_XO_FORM",        .value = 40, },
246cd0b6f67SAthira Rajeev 	{ .name = "MUL_HDW_XO_FORM",    .value = 73, },
247cd0b6f67SAthira Rajeev 	{ .name = "MUL_HW_XO_FORM",     .value = 75, },
248cd0b6f67SAthira Rajeev 	{ .name = "SUB_EXT_XO_FORM",    .value = 136, },
249cd0b6f67SAthira Rajeev 	{ .name = "ADD_EXT_XO_FORM",    .value = 138, },
250cd0b6f67SAthira Rajeev 	{ .name = "SUB_ZERO_EXT_XO_FORM",       .value = 200, },
251cd0b6f67SAthira Rajeev 	{ .name = "ADD_ZERO_EXT_XO_FORM",       .value = 202, },
252cd0b6f67SAthira Rajeev 	{ .name = "SUB_EXT_XO_FORM2",   .value = 232, },
253cd0b6f67SAthira Rajeev 	{ .name = "MUL_DW_XO_FORM",     .value = 233, },
254cd0b6f67SAthira Rajeev 	{ .name = "ADD_EXT_XO_FORM2",   .value = 234, },
255cd0b6f67SAthira Rajeev 	{ .name = "MUL_W_XO_FORM",      .value = 235, },
256cd0b6f67SAthira Rajeev 	{ .name = "ADD_XO_FORM",	.value = 266, },
257cd0b6f67SAthira Rajeev 	{ .name = "DIV_DW_XO_FORM1",    .value = 457, },
258cd0b6f67SAthira Rajeev 	{ .name = "DIV_W_XO_FORM1",     .value = 459, },
259cd0b6f67SAthira Rajeev 	{ .name = "DIV_DW_XO_FORM",	.value = 489, },
260cd0b6f67SAthira Rajeev 	{ .name = "DIV_W_XO_FORM",	.value = 491, },
261cd0b6f67SAthira Rajeev };
262cd0b6f67SAthira Rajeev 
263539bfea3SAthira Rajeev static struct insn_offset arithmetic_two_ops[] = {
264539bfea3SAthira Rajeev 	{ .name = "mulli",      .value = 7, },
265539bfea3SAthira Rajeev 	{ .name = "subfic",     .value = 8, },
266539bfea3SAthira Rajeev 	{ .name = "addic",      .value = 12, },
267539bfea3SAthira Rajeev 	{ .name = "addic.",     .value = 13, },
268539bfea3SAthira Rajeev 	{ .name = "addi",       .value = 14, },
269539bfea3SAthira Rajeev 	{ .name = "addis",      .value = 15, },
270539bfea3SAthira Rajeev };
271cd0b6f67SAthira Rajeev 
cmp_offset(const void * a,const void * b)272ace7d681SAthira Rajeev static int cmp_offset(const void *a, const void *b)
273ace7d681SAthira Rajeev {
274ace7d681SAthira Rajeev 	const struct insn_offset *val1 = a;
275ace7d681SAthira Rajeev 	const struct insn_offset *val2 = b;
276ace7d681SAthira Rajeev 
277ace7d681SAthira Rajeev 	return (val1->value - val2->value);
278ace7d681SAthira Rajeev }
2791acdad68SAthira Rajeev 
check_ppc_insn(struct disasm_line * dl)28007b972ffSIan Rogers const struct ins_ops *check_ppc_insn(struct disasm_line *dl)
2811acdad68SAthira Rajeev {
2822c9db747SAthira Rajeev 	int raw_insn = dl->raw.raw_insn;
2831acdad68SAthira Rajeev 	int opcode = PPC_OP(raw_insn);
284ace7d681SAthira Rajeev 	int mem_insn_31 = PPC_21_30(raw_insn);
285ace7d681SAthira Rajeev 	struct insn_offset *ret;
286ace7d681SAthira Rajeev 	struct insn_offset mem_insns_31_opcode = {
287ace7d681SAthira Rajeev 		"OP_31_INSN",
288ace7d681SAthira Rajeev 		mem_insn_31
289ace7d681SAthira Rajeev 	};
2902c9db747SAthira Rajeev 	char name_insn[32];
2911acdad68SAthira Rajeev 
2921acdad68SAthira Rajeev 	/*
2931acdad68SAthira Rajeev 	 * Instructions with opcode 32 to 63 are memory
2941acdad68SAthira Rajeev 	 * instructions in powerpc
2951acdad68SAthira Rajeev 	 */
296ace7d681SAthira Rajeev 	if ((opcode & 0x20)) {
2972c9db747SAthira Rajeev 		/*
2982c9db747SAthira Rajeev 		 * Set name in case of raw instruction to
2992c9db747SAthira Rajeev 		 * opcode to be used in insn-stat
3002c9db747SAthira Rajeev 		 */
3012c9db747SAthira Rajeev 		if (!strlen(dl->ins.name)) {
3022c9db747SAthira Rajeev 			sprintf(name_insn, "%d", opcode);
3032c9db747SAthira Rajeev 			dl->ins.name = strdup(name_insn);
3042c9db747SAthira Rajeev 		}
3051acdad68SAthira Rajeev 		return &load_store_ops;
306ace7d681SAthira Rajeev 	} else if (opcode == 31) {
307ace7d681SAthira Rajeev 		/* Check for memory instructions with opcode 31 */
308ace7d681SAthira Rajeev 		ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset);
3092c9db747SAthira Rajeev 		if (ret) {
3102c9db747SAthira Rajeev 			if (!strlen(dl->ins.name))
3112c9db747SAthira Rajeev 				dl->ins.name = strdup(ret->name);
312ace7d681SAthira Rajeev 			return &load_store_ops;
3132c9db747SAthira Rajeev 		} else {
314cd0b6f67SAthira Rajeev 			mem_insns_31_opcode.value = PPC_22_30(raw_insn);
315cd0b6f67SAthira Rajeev 			ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31),
316cd0b6f67SAthira Rajeev 					sizeof(arithmetic_ins_op_31[0]), cmp_offset);
317cd0b6f67SAthira Rajeev 			if (ret != NULL)
318cd0b6f67SAthira Rajeev 				return &arithmetic_ops;
319cd0b6f67SAthira Rajeev 			/* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */
320cd0b6f67SAthira Rajeev 			if (PPC_21_30(raw_insn) == 444)
321cd0b6f67SAthira Rajeev 				return &arithmetic_ops;
322cd0b6f67SAthira Rajeev 		}
323539bfea3SAthira Rajeev 	} else {
324539bfea3SAthira Rajeev 		mem_insns_31_opcode.value = opcode;
325539bfea3SAthira Rajeev 		ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops),
326539bfea3SAthira Rajeev 				sizeof(arithmetic_two_ops[0]), cmp_offset);
327539bfea3SAthira Rajeev 		if (ret != NULL)
328539bfea3SAthira Rajeev 			return &arithmetic_ops;
329ace7d681SAthira Rajeev 	}
3301acdad68SAthira Rajeev 
3311acdad68SAthira Rajeev 	return NULL;
3321acdad68SAthira Rajeev }
3331acdad68SAthira Rajeev 
33488444952SAthira Rajeev /*
33588444952SAthira Rajeev  * Instruction tracking function to track register state moves.
33688444952SAthira Rajeev  * Example sequence:
33788444952SAthira Rajeev  *    ld      r10,264(r3)
33888444952SAthira Rajeev  *    mr      r31,r3
33988444952SAthira Rajeev  *    <<after some sequence>
34088444952SAthira Rajeev  *    ld      r9,312(r31)
34188444952SAthira Rajeev  *
34288444952SAthira Rajeev  * Previous instruction sequence shows that register state of r3
34388444952SAthira Rajeev  * is moved to r31. update_insn_state_powerpc tracks these state
34488444952SAthira Rajeev  * changes
34588444952SAthira Rajeev  */
3468838abf6SIan Rogers #ifdef HAVE_LIBDW_SUPPORT
update_insn_state_powerpc(struct type_state * state,struct data_loc_info * dloc,Dwarf_Die * cu_die __maybe_unused,struct disasm_line * dl)34788444952SAthira Rajeev static void update_insn_state_powerpc(struct type_state *state,
34888444952SAthira Rajeev 		struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused,
34988444952SAthira Rajeev 		struct disasm_line *dl)
35088444952SAthira Rajeev {
35188444952SAthira Rajeev 	struct annotated_insn_loc loc;
35288444952SAthira Rajeev 	struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE];
35388444952SAthira Rajeev 	struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET];
35488444952SAthira Rajeev 	struct type_state_reg *tsr;
35588444952SAthira Rajeev 	u32 insn_offset = dl->al.offset;
35688444952SAthira Rajeev 
35788444952SAthira Rajeev 	if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0)
35888444952SAthira Rajeev 		return;
35988444952SAthira Rajeev 
36088444952SAthira Rajeev 	/*
36188444952SAthira Rajeev 	 * Value 444 for bits 21:30 is for "mr"
36288444952SAthira Rajeev 	 * instruction. "mr" is extended OR. So set the
36388444952SAthira Rajeev 	 * source and destination reg correctly
36488444952SAthira Rajeev 	 */
36588444952SAthira Rajeev 	if (PPC_21_30(dl->raw.raw_insn) == 444) {
36688444952SAthira Rajeev 		int src_reg = src->reg1;
36788444952SAthira Rajeev 
36888444952SAthira Rajeev 		src->reg1 = dst->reg1;
36988444952SAthira Rajeev 		dst->reg1 = src_reg;
37088444952SAthira Rajeev 	}
37188444952SAthira Rajeev 
37288444952SAthira Rajeev 	if (!has_reg_type(state, dst->reg1))
37388444952SAthira Rajeev 		return;
37488444952SAthira Rajeev 
37588444952SAthira Rajeev 	tsr = &state->regs[dst->reg1];
37688444952SAthira Rajeev 
37788444952SAthira Rajeev 	if (!has_reg_type(state, src->reg1) ||
37888444952SAthira Rajeev 			!state->regs[src->reg1].ok) {
37988444952SAthira Rajeev 		tsr->ok = false;
38088444952SAthira Rajeev 		return;
38188444952SAthira Rajeev 	}
38288444952SAthira Rajeev 
38388444952SAthira Rajeev 	tsr->type = state->regs[src->reg1].type;
38488444952SAthira Rajeev 	tsr->kind = state->regs[src->reg1].kind;
38588444952SAthira Rajeev 	tsr->ok = true;
38688444952SAthira Rajeev 
38788444952SAthira Rajeev 	pr_debug_dtp("mov [%x] reg%d -> reg%d",
38888444952SAthira Rajeev 			insn_offset, src->reg1, dst->reg1);
38988444952SAthira Rajeev 	pr_debug_type_name(&tsr->type, tsr->kind);
39088444952SAthira Rajeev }
3918838abf6SIan Rogers #endif /* HAVE_LIBDW_SUPPORT */
39288444952SAthira Rajeev 
arch__new_powerpc(const struct e_machine_and_e_flags * id,const char * cpuid __maybe_unused)393*0e26ba5aSIan Rogers const struct arch *arch__new_powerpc(const struct e_machine_and_e_flags *id,
394*0e26ba5aSIan Rogers 				     const char *cpuid __maybe_unused)
395dbdebdc5SRavi Bangoria {
396*0e26ba5aSIan Rogers 	struct arch *arch = zalloc(sizeof(*arch));
397*0e26ba5aSIan Rogers 
398*0e26ba5aSIan Rogers 	if (!arch)
399*0e26ba5aSIan Rogers 		return NULL;
400*0e26ba5aSIan Rogers 
401*0e26ba5aSIan Rogers 	arch->name = "powerpc";
402*0e26ba5aSIan Rogers 	arch->id = *id;
403dbdebdc5SRavi Bangoria 	arch->objdump.comment_char = '#';
40406dd4c5aSAthira Rajeev 	annotate_opts.show_asm_raw = true;
405*0e26ba5aSIan Rogers 	arch->associate_instruction_ops = powerpc__associate_instruction_ops;
40607b972ffSIan Rogers #ifdef HAVE_LIBDW_SUPPORT
40707b972ffSIan Rogers 	arch->update_insn_state = update_insn_state_powerpc;
40807b972ffSIan Rogers #endif
409*0e26ba5aSIan Rogers 	return arch;
410dbdebdc5SRavi Bangoria }
411