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