xref: /linux/tools/perf/util/annotate-arch/annotate-powerpc.c (revision 07b972ff09f45cfb7acd20cd9b3769c6975bc434)
1*07b972ffSIan Rogers // SPDX-License-Identifier: GPL-2.0
2*07b972ffSIan Rogers #include <string.h>
3*07b972ffSIan Rogers #include <linux/compiler.h>
4*07b972ffSIan Rogers #include <linux/kernel.h>
5*07b972ffSIan Rogers #include "../annotate-data.h"
6*07b972ffSIan Rogers #include "../debug.h"
7*07b972ffSIan Rogers #include "../disasm.h"
8*07b972ffSIan Rogers 
9*07b972ffSIan Rogers #define PPC_OP(op)	(((op) >> 26) & 0x3F)
10*07b972ffSIan Rogers #define PPC_21_30(R)	(((R) >> 1) & 0x3ff)
11*07b972ffSIan Rogers #define PPC_22_30(R)	(((R) >> 1) & 0x1ff)
12*07b972ffSIan Rogers 
13*07b972ffSIan Rogers #define MINUS_EXT_XO_FORM	234
14*07b972ffSIan Rogers #define SUB_EXT_XO_FORM		232
15*07b972ffSIan Rogers #define	ADD_ZERO_EXT_XO_FORM	202
16*07b972ffSIan Rogers #define	SUB_ZERO_EXT_XO_FORM	200
17*07b972ffSIan Rogers 
18*07b972ffSIan Rogers static int arithmetic__scnprintf(const struct ins *ins, char *bf, size_t size,
19*07b972ffSIan Rogers 		struct ins_operands *ops, int max_ins_name)
20*07b972ffSIan Rogers {
21*07b972ffSIan Rogers 	return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
22*07b972ffSIan Rogers 			ops->raw);
23*07b972ffSIan Rogers }
24*07b972ffSIan Rogers 
25*07b972ffSIan Rogers /*
26*07b972ffSIan Rogers  * Sets the fields: multi_regs and "mem_ref".
27*07b972ffSIan Rogers  * "mem_ref" is set for ops->source which is later used to
28*07b972ffSIan Rogers  * fill the objdump->memory_ref-char field. This ops is currently
29*07b972ffSIan Rogers  * used by powerpc and since binary instruction code is used to
30*07b972ffSIan Rogers  * extract opcode, regs and offset, no other parsing is needed here.
31*07b972ffSIan Rogers  *
32*07b972ffSIan Rogers  * Dont set multi regs for 4 cases since it has only one operand
33*07b972ffSIan Rogers  * for source:
34*07b972ffSIan Rogers  * - Add to Minus One Extended XO-form ( Ex: addme, addmeo )
35*07b972ffSIan Rogers  * - Subtract From Minus One Extended XO-form ( Ex: subfme )
36*07b972ffSIan Rogers  * - Add to Zero Extended XO-form ( Ex: addze, addzeo )
37*07b972ffSIan Rogers  * - Subtract From Zero Extended XO-form ( Ex: subfze )
38*07b972ffSIan Rogers  */
39*07b972ffSIan Rogers static int arithmetic__parse(const struct arch *arch __maybe_unused, struct ins_operands *ops,
40*07b972ffSIan Rogers 		struct map_symbol *ms __maybe_unused, struct disasm_line *dl)
41*07b972ffSIan Rogers {
42*07b972ffSIan Rogers 	int opcode = PPC_OP(dl->raw.raw_insn);
43*07b972ffSIan Rogers 
44*07b972ffSIan Rogers 	ops->source.mem_ref = false;
45*07b972ffSIan Rogers 	if (opcode == 31) {
46*07b972ffSIan Rogers 		if ((opcode != MINUS_EXT_XO_FORM) && (opcode != SUB_EXT_XO_FORM) &&
47*07b972ffSIan Rogers 		    (opcode != ADD_ZERO_EXT_XO_FORM) && (opcode != SUB_ZERO_EXT_XO_FORM))
48*07b972ffSIan Rogers 			ops->source.multi_regs = true;
49*07b972ffSIan Rogers 	}
50*07b972ffSIan Rogers 
51*07b972ffSIan Rogers 	ops->target.mem_ref = false;
52*07b972ffSIan Rogers 	ops->target.multi_regs = false;
53*07b972ffSIan Rogers 
54*07b972ffSIan Rogers 	return 0;
55*07b972ffSIan Rogers }
56*07b972ffSIan Rogers 
57*07b972ffSIan Rogers static const struct ins_ops arithmetic_ops = {
58*07b972ffSIan Rogers 	.parse     = arithmetic__parse,
59*07b972ffSIan Rogers 	.scnprintf = arithmetic__scnprintf,
60*07b972ffSIan Rogers };
61*07b972ffSIan Rogers 
62*07b972ffSIan Rogers static int load_store__scnprintf(const struct ins *ins, char *bf, size_t size,
63*07b972ffSIan Rogers 		struct ins_operands *ops, int max_ins_name)
64*07b972ffSIan Rogers {
65*07b972ffSIan Rogers 	return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
66*07b972ffSIan Rogers 			ops->raw);
67*07b972ffSIan Rogers }
68*07b972ffSIan Rogers 
69*07b972ffSIan Rogers /*
70*07b972ffSIan Rogers  * Sets the fields: multi_regs and "mem_ref".
71*07b972ffSIan Rogers  * "mem_ref" is set for ops->source which is later used to
72*07b972ffSIan Rogers  * fill the objdump->memory_ref-char field. This ops is currently
73*07b972ffSIan Rogers  * used by powerpc and since binary instruction code is used to
74*07b972ffSIan Rogers  * extract opcode, regs and offset, no other parsing is needed here
75*07b972ffSIan Rogers  */
76*07b972ffSIan Rogers static int load_store__parse(const struct arch *arch __maybe_unused, struct ins_operands *ops,
77*07b972ffSIan Rogers 		struct map_symbol *ms __maybe_unused, struct disasm_line *dl __maybe_unused)
78*07b972ffSIan Rogers {
79*07b972ffSIan Rogers 	ops->source.mem_ref = true;
80*07b972ffSIan Rogers 	ops->source.multi_regs = false;
81*07b972ffSIan Rogers 	/* opcode 31 is of X form */
82*07b972ffSIan Rogers 	if (PPC_OP(dl->raw.raw_insn) == 31)
83*07b972ffSIan Rogers 		ops->source.multi_regs = true;
84*07b972ffSIan Rogers 
85*07b972ffSIan Rogers 	ops->target.mem_ref = false;
86*07b972ffSIan Rogers 	ops->target.multi_regs = false;
87*07b972ffSIan Rogers 
88*07b972ffSIan Rogers 	return 0;
89*07b972ffSIan Rogers }
90*07b972ffSIan Rogers 
91*07b972ffSIan Rogers static const struct ins_ops load_store_ops = {
92*07b972ffSIan Rogers 	.parse     = load_store__parse,
93*07b972ffSIan Rogers 	.scnprintf = load_store__scnprintf,
94*07b972ffSIan Rogers };
95*07b972ffSIan Rogers 
96*07b972ffSIan Rogers static const struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name)
97*07b972ffSIan Rogers {
98*07b972ffSIan Rogers 	int i;
99*07b972ffSIan Rogers 	const struct ins_ops *ops;
100*07b972ffSIan Rogers 
101*07b972ffSIan Rogers 	/*
102*07b972ffSIan Rogers 	 * - Interested only if instruction starts with 'b'.
103*07b972ffSIan Rogers 	 * - Few start with 'b', but aren't branch instructions.
104*07b972ffSIan Rogers 	 */
105*07b972ffSIan Rogers 	if (name[0] != 'b'             ||
106*07b972ffSIan Rogers 	    !strncmp(name, "bcd", 3)   ||
107*07b972ffSIan Rogers 	    !strncmp(name, "brinc", 5) ||
108*07b972ffSIan Rogers 	    !strncmp(name, "bper", 4))
109*07b972ffSIan Rogers 		return NULL;
110*07b972ffSIan Rogers 
111*07b972ffSIan Rogers 	ops = &jump_ops;
112*07b972ffSIan Rogers 
113*07b972ffSIan Rogers 	i = strlen(name) - 1;
114*07b972ffSIan Rogers 	if (i < 0)
115*07b972ffSIan Rogers 		return NULL;
116*07b972ffSIan Rogers 
117*07b972ffSIan Rogers 	/* ignore optional hints at the end of the instructions */
118*07b972ffSIan Rogers 	if (name[i] == '+' || name[i] == '-')
119*07b972ffSIan Rogers 		i--;
120*07b972ffSIan Rogers 
121*07b972ffSIan Rogers 	if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) {
122*07b972ffSIan Rogers 		/*
123*07b972ffSIan Rogers 		 * if the instruction ends up with 'l' or 'la', then
124*07b972ffSIan Rogers 		 * those are considered 'calls' since they update LR.
125*07b972ffSIan Rogers 		 * ... except for 'bnl' which is branch if not less than
126*07b972ffSIan Rogers 		 * and the absolute form of the same.
127*07b972ffSIan Rogers 		 */
128*07b972ffSIan Rogers 		if (strcmp(name, "bnl") && strcmp(name, "bnl+") &&
129*07b972ffSIan Rogers 		    strcmp(name, "bnl-") && strcmp(name, "bnla") &&
130*07b972ffSIan Rogers 		    strcmp(name, "bnla+") && strcmp(name, "bnla-"))
131*07b972ffSIan Rogers 			ops = &call_ops;
132*07b972ffSIan Rogers 	}
133*07b972ffSIan Rogers 	if (name[i] == 'r' && name[i-1] == 'l')
134*07b972ffSIan Rogers 		/*
135*07b972ffSIan Rogers 		 * instructions ending with 'lr' are considered to be
136*07b972ffSIan Rogers 		 * return instructions
137*07b972ffSIan Rogers 		 */
138*07b972ffSIan Rogers 		ops = &ret_ops;
139*07b972ffSIan Rogers 
140*07b972ffSIan Rogers 	arch__associate_ins_ops(arch, name, ops);
141*07b972ffSIan Rogers 	return ops;
142*07b972ffSIan Rogers }
143*07b972ffSIan Rogers 
144*07b972ffSIan Rogers struct insn_offset {
145*07b972ffSIan Rogers 	const char	*name;
146*07b972ffSIan Rogers 	int		value;
147*07b972ffSIan Rogers };
148*07b972ffSIan Rogers 
149*07b972ffSIan Rogers /*
150*07b972ffSIan Rogers  * There are memory instructions with opcode 31 which are
151*07b972ffSIan Rogers  * of X Form, Example:
152*07b972ffSIan Rogers  * ldx RT,RA,RB
153*07b972ffSIan Rogers  * ______________________________________
154*07b972ffSIan Rogers  * | 31 |  RT  |  RA |  RB |   21     |/|
155*07b972ffSIan Rogers  * --------------------------------------
156*07b972ffSIan Rogers  * 0    6     11    16    21         30 31
157*07b972ffSIan Rogers  *
158*07b972ffSIan Rogers  * But all instructions with opcode 31 are not memory.
159*07b972ffSIan Rogers  * Example: add RT,RA,RB
160*07b972ffSIan Rogers  *
161*07b972ffSIan Rogers  * Use bits 21 to 30 to check memory insns with 31 as opcode.
162*07b972ffSIan Rogers  * In ins_array below, for ldx instruction:
163*07b972ffSIan Rogers  * name => OP_31_XOP_LDX
164*07b972ffSIan Rogers  * value => 21
165*07b972ffSIan Rogers  */
166*07b972ffSIan Rogers 
167*07b972ffSIan Rogers static struct insn_offset ins_array[] = {
168*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LXSIWZX",  .value = 12, },
169*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LWARX",	.value = 20, },
170*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LDX",	.value = 21, },
171*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LWZX",	.value = 23, },
172*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LDUX",	.value = 53, },
173*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LWZUX",	.value = 55, },
174*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LXSIWAX",  .value = 76, },
175*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LDARX",    .value = 84, },
176*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LBZX",	.value = 87, },
177*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LVX",      .value = 103, },
178*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LBZUX",    .value = 119, },
179*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STXSIWX",  .value = 140, },
180*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STDX",	.value = 149, },
181*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STWX",	.value = 151, },
182*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STDUX",	.value = 181, },
183*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STWUX",	.value = 183, },
184*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STBX",	.value = 215, },
185*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STVX",     .value = 231, },
186*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STBUX",	.value = 247, },
187*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LHZX",	.value = 279, },
188*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LHZUX",	.value = 311, },
189*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LXVDSX",   .value = 332, },
190*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LWAX",	.value = 341, },
191*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LHAX",	.value = 343, },
192*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LWAUX",	.value = 373, },
193*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LHAUX",	.value = 375, },
194*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STHX",	.value = 407, },
195*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STHUX",	.value = 439, },
196*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LXSSPX",   .value = 524, },
197*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LDBRX",	.value = 532, },
198*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LSWX",	.value = 533, },
199*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LWBRX",	.value = 534, },
200*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LFSUX",    .value = 567, },
201*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LXSDX",    .value = 588, },
202*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LSWI",	.value = 597, },
203*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LFDX",     .value = 599, },
204*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LFDUX",    .value = 631, },
205*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STXSSPX",  .value = 652, },
206*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STDBRX",	.value = 660, },
207*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STXWX",	.value = 661, },
208*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STWBRX",	.value = 662, },
209*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STFSX",	.value = 663, },
210*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STFSUX",	.value = 695, },
211*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STXSDX",   .value = 716, },
212*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STSWI",	.value = 725, },
213*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STFDX",	.value = 727, },
214*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STFDUX",	.value = 759, },
215*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LXVW4X",   .value = 780, },
216*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LHBRX",	.value = 790, },
217*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LXVD2X",   .value = 844, },
218*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LFIWAX",	.value = 855, },
219*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_LFIWZX",	.value = 887, },
220*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STXVW4X",  .value = 908, },
221*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STHBRX",	.value = 918, },
222*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STXVD2X",  .value = 972, },
223*07b972ffSIan Rogers 	{ .name = "OP_31_XOP_STFIWX",	.value = 983, },
224*07b972ffSIan Rogers };
225*07b972ffSIan Rogers 
226*07b972ffSIan Rogers /*
227*07b972ffSIan Rogers  * Arithmetic instructions which are having opcode as 31.
228*07b972ffSIan Rogers  * These instructions are tracked to save the register state
229*07b972ffSIan Rogers  * changes. Example:
230*07b972ffSIan Rogers  *
231*07b972ffSIan Rogers  * lwz	r10,264(r3)
232*07b972ffSIan Rogers  * add	r31, r3, r3
233*07b972ffSIan Rogers  * lwz	r9, 0(r31)
234*07b972ffSIan Rogers  *
235*07b972ffSIan Rogers  * Here instruction tracking needs to identify the "add"
236*07b972ffSIan Rogers  * instruction and save data type of r3 to r31. If a sample
237*07b972ffSIan Rogers  * is hit at next "lwz r9, 0(r31)", by this instruction tracking,
238*07b972ffSIan Rogers  * data type of r31 can be resolved.
239*07b972ffSIan Rogers  */
240*07b972ffSIan Rogers static struct insn_offset arithmetic_ins_op_31[] = {
241*07b972ffSIan Rogers 	{ .name = "SUB_CARRY_XO_FORM",  .value = 8, },
242*07b972ffSIan Rogers 	{ .name = "MUL_HDW_XO_FORM1",   .value = 9, },
243*07b972ffSIan Rogers 	{ .name = "ADD_CARRY_XO_FORM",  .value = 10, },
244*07b972ffSIan Rogers 	{ .name = "MUL_HW_XO_FORM1",    .value = 11, },
245*07b972ffSIan Rogers 	{ .name = "SUB_XO_FORM",        .value = 40, },
246*07b972ffSIan Rogers 	{ .name = "MUL_HDW_XO_FORM",    .value = 73, },
247*07b972ffSIan Rogers 	{ .name = "MUL_HW_XO_FORM",     .value = 75, },
248*07b972ffSIan Rogers 	{ .name = "SUB_EXT_XO_FORM",    .value = 136, },
249*07b972ffSIan Rogers 	{ .name = "ADD_EXT_XO_FORM",    .value = 138, },
250*07b972ffSIan Rogers 	{ .name = "SUB_ZERO_EXT_XO_FORM",       .value = 200, },
251*07b972ffSIan Rogers 	{ .name = "ADD_ZERO_EXT_XO_FORM",       .value = 202, },
252*07b972ffSIan Rogers 	{ .name = "SUB_EXT_XO_FORM2",   .value = 232, },
253*07b972ffSIan Rogers 	{ .name = "MUL_DW_XO_FORM",     .value = 233, },
254*07b972ffSIan Rogers 	{ .name = "ADD_EXT_XO_FORM2",   .value = 234, },
255*07b972ffSIan Rogers 	{ .name = "MUL_W_XO_FORM",      .value = 235, },
256*07b972ffSIan Rogers 	{ .name = "ADD_XO_FORM",	.value = 266, },
257*07b972ffSIan Rogers 	{ .name = "DIV_DW_XO_FORM1",    .value = 457, },
258*07b972ffSIan Rogers 	{ .name = "DIV_W_XO_FORM1",     .value = 459, },
259*07b972ffSIan Rogers 	{ .name = "DIV_DW_XO_FORM",	.value = 489, },
260*07b972ffSIan Rogers 	{ .name = "DIV_W_XO_FORM",	.value = 491, },
261*07b972ffSIan Rogers };
262*07b972ffSIan Rogers 
263*07b972ffSIan Rogers static struct insn_offset arithmetic_two_ops[] = {
264*07b972ffSIan Rogers 	{ .name = "mulli",      .value = 7, },
265*07b972ffSIan Rogers 	{ .name = "subfic",     .value = 8, },
266*07b972ffSIan Rogers 	{ .name = "addic",      .value = 12, },
267*07b972ffSIan Rogers 	{ .name = "addic.",     .value = 13, },
268*07b972ffSIan Rogers 	{ .name = "addi",       .value = 14, },
269*07b972ffSIan Rogers 	{ .name = "addis",      .value = 15, },
270*07b972ffSIan Rogers };
271*07b972ffSIan Rogers 
272*07b972ffSIan Rogers static int cmp_offset(const void *a, const void *b)
273*07b972ffSIan Rogers {
274*07b972ffSIan Rogers 	const struct insn_offset *val1 = a;
275*07b972ffSIan Rogers 	const struct insn_offset *val2 = b;
276*07b972ffSIan Rogers 
277*07b972ffSIan Rogers 	return (val1->value - val2->value);
278*07b972ffSIan Rogers }
279*07b972ffSIan Rogers 
280*07b972ffSIan Rogers const struct ins_ops *check_ppc_insn(struct disasm_line *dl)
281*07b972ffSIan Rogers {
282*07b972ffSIan Rogers 	int raw_insn = dl->raw.raw_insn;
283*07b972ffSIan Rogers 	int opcode = PPC_OP(raw_insn);
284*07b972ffSIan Rogers 	int mem_insn_31 = PPC_21_30(raw_insn);
285*07b972ffSIan Rogers 	struct insn_offset *ret;
286*07b972ffSIan Rogers 	struct insn_offset mem_insns_31_opcode = {
287*07b972ffSIan Rogers 		"OP_31_INSN",
288*07b972ffSIan Rogers 		mem_insn_31
289*07b972ffSIan Rogers 	};
290*07b972ffSIan Rogers 	char name_insn[32];
291*07b972ffSIan Rogers 
292*07b972ffSIan Rogers 	/*
293*07b972ffSIan Rogers 	 * Instructions with opcode 32 to 63 are memory
294*07b972ffSIan Rogers 	 * instructions in powerpc
295*07b972ffSIan Rogers 	 */
296*07b972ffSIan Rogers 	if ((opcode & 0x20)) {
297*07b972ffSIan Rogers 		/*
298*07b972ffSIan Rogers 		 * Set name in case of raw instruction to
299*07b972ffSIan Rogers 		 * opcode to be used in insn-stat
300*07b972ffSIan Rogers 		 */
301*07b972ffSIan Rogers 		if (!strlen(dl->ins.name)) {
302*07b972ffSIan Rogers 			sprintf(name_insn, "%d", opcode);
303*07b972ffSIan Rogers 			dl->ins.name = strdup(name_insn);
304*07b972ffSIan Rogers 		}
305*07b972ffSIan Rogers 		return &load_store_ops;
306*07b972ffSIan Rogers 	} else if (opcode == 31) {
307*07b972ffSIan Rogers 		/* Check for memory instructions with opcode 31 */
308*07b972ffSIan Rogers 		ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset);
309*07b972ffSIan Rogers 		if (ret) {
310*07b972ffSIan Rogers 			if (!strlen(dl->ins.name))
311*07b972ffSIan Rogers 				dl->ins.name = strdup(ret->name);
312*07b972ffSIan Rogers 			return &load_store_ops;
313*07b972ffSIan Rogers 		} else {
314*07b972ffSIan Rogers 			mem_insns_31_opcode.value = PPC_22_30(raw_insn);
315*07b972ffSIan Rogers 			ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31),
316*07b972ffSIan Rogers 					sizeof(arithmetic_ins_op_31[0]), cmp_offset);
317*07b972ffSIan Rogers 			if (ret != NULL)
318*07b972ffSIan Rogers 				return &arithmetic_ops;
319*07b972ffSIan Rogers 			/* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */
320*07b972ffSIan Rogers 			if (PPC_21_30(raw_insn) == 444)
321*07b972ffSIan Rogers 				return &arithmetic_ops;
322*07b972ffSIan Rogers 		}
323*07b972ffSIan Rogers 	} else {
324*07b972ffSIan Rogers 		mem_insns_31_opcode.value = opcode;
325*07b972ffSIan Rogers 		ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops),
326*07b972ffSIan Rogers 				sizeof(arithmetic_two_ops[0]), cmp_offset);
327*07b972ffSIan Rogers 		if (ret != NULL)
328*07b972ffSIan Rogers 			return &arithmetic_ops;
329*07b972ffSIan Rogers 	}
330*07b972ffSIan Rogers 
331*07b972ffSIan Rogers 	return NULL;
332*07b972ffSIan Rogers }
333*07b972ffSIan Rogers 
334*07b972ffSIan Rogers /*
335*07b972ffSIan Rogers  * Instruction tracking function to track register state moves.
336*07b972ffSIan Rogers  * Example sequence:
337*07b972ffSIan Rogers  *    ld      r10,264(r3)
338*07b972ffSIan Rogers  *    mr      r31,r3
339*07b972ffSIan Rogers  *    <<after some sequence>
340*07b972ffSIan Rogers  *    ld      r9,312(r31)
341*07b972ffSIan Rogers  *
342*07b972ffSIan Rogers  * Previous instruction sequence shows that register state of r3
343*07b972ffSIan Rogers  * is moved to r31. update_insn_state_powerpc tracks these state
344*07b972ffSIan Rogers  * changes
345*07b972ffSIan Rogers  */
346*07b972ffSIan Rogers #ifdef HAVE_LIBDW_SUPPORT
347*07b972ffSIan Rogers static void update_insn_state_powerpc(struct type_state *state,
348*07b972ffSIan Rogers 		struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused,
349*07b972ffSIan Rogers 		struct disasm_line *dl)
350*07b972ffSIan Rogers {
351*07b972ffSIan Rogers 	struct annotated_insn_loc loc;
352*07b972ffSIan Rogers 	struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE];
353*07b972ffSIan Rogers 	struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET];
354*07b972ffSIan Rogers 	struct type_state_reg *tsr;
355*07b972ffSIan Rogers 	u32 insn_offset = dl->al.offset;
356*07b972ffSIan Rogers 
357*07b972ffSIan Rogers 	if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0)
358*07b972ffSIan Rogers 		return;
359*07b972ffSIan Rogers 
360*07b972ffSIan Rogers 	/*
361*07b972ffSIan Rogers 	 * Value 444 for bits 21:30 is for "mr"
362*07b972ffSIan Rogers 	 * instruction. "mr" is extended OR. So set the
363*07b972ffSIan Rogers 	 * source and destination reg correctly
364*07b972ffSIan Rogers 	 */
365*07b972ffSIan Rogers 	if (PPC_21_30(dl->raw.raw_insn) == 444) {
366*07b972ffSIan Rogers 		int src_reg = src->reg1;
367*07b972ffSIan Rogers 
368*07b972ffSIan Rogers 		src->reg1 = dst->reg1;
369*07b972ffSIan Rogers 		dst->reg1 = src_reg;
370*07b972ffSIan Rogers 	}
371*07b972ffSIan Rogers 
372*07b972ffSIan Rogers 	if (!has_reg_type(state, dst->reg1))
373*07b972ffSIan Rogers 		return;
374*07b972ffSIan Rogers 
375*07b972ffSIan Rogers 	tsr = &state->regs[dst->reg1];
376*07b972ffSIan Rogers 
377*07b972ffSIan Rogers 	if (!has_reg_type(state, src->reg1) ||
378*07b972ffSIan Rogers 			!state->regs[src->reg1].ok) {
379*07b972ffSIan Rogers 		tsr->ok = false;
380*07b972ffSIan Rogers 		return;
381*07b972ffSIan Rogers 	}
382*07b972ffSIan Rogers 
383*07b972ffSIan Rogers 	tsr->type = state->regs[src->reg1].type;
384*07b972ffSIan Rogers 	tsr->kind = state->regs[src->reg1].kind;
385*07b972ffSIan Rogers 	tsr->ok = true;
386*07b972ffSIan Rogers 
387*07b972ffSIan Rogers 	pr_debug_dtp("mov [%x] reg%d -> reg%d",
388*07b972ffSIan Rogers 			insn_offset, src->reg1, dst->reg1);
389*07b972ffSIan Rogers 	pr_debug_type_name(&tsr->type, tsr->kind);
390*07b972ffSIan Rogers }
391*07b972ffSIan Rogers #endif /* HAVE_LIBDW_SUPPORT */
392*07b972ffSIan Rogers 
393*07b972ffSIan Rogers int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
394*07b972ffSIan Rogers {
395*07b972ffSIan Rogers 	if (!arch->initialized) {
396*07b972ffSIan Rogers 		arch->initialized = true;
397*07b972ffSIan Rogers 		arch->associate_instruction_ops = powerpc__associate_instruction_ops;
398*07b972ffSIan Rogers 		arch->objdump.comment_char      = '#';
399*07b972ffSIan Rogers 		annotate_opts.show_asm_raw = true;
400*07b972ffSIan Rogers #ifdef HAVE_LIBDW_SUPPORT
401*07b972ffSIan Rogers 		arch->update_insn_state = update_insn_state_powerpc;
402*07b972ffSIan Rogers #endif
403*07b972ffSIan Rogers 	}
404*07b972ffSIan Rogers 
405*07b972ffSIan Rogers 	return 0;
406*07b972ffSIan Rogers }
407