Coverage Report

Created: 2025-08-28 06:43

/src/capstonenext/arch/PowerPC/PPCInstPrinter.c
Line
Count
Source (jump to first uncovered line)
1
/* Capstone Disassembly Engine, http://www.capstone-engine.org */
2
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2022, */
3
/*    Rot127 <unisono@quyllur.org> 2022-2023 */
4
/* Automatically translated source file from LLVM. */
5
6
/* LLVM-commit: <commit> */
7
/* LLVM-tag: <tag> */
8
9
/* Only small edits allowed. */
10
/* For multiple similar edits, please create a Patch for the translator. */
11
12
/* Capstone's C++ file translator: */
13
/* https://github.com/capstone-engine/capstone/tree/next/suite/auto-sync */
14
15
//===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===//
16
//
17
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
18
// See https://llvm.org/LICENSE.txt for license information.
19
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
20
//
21
//===----------------------------------------------------------------------===//
22
//
23
// This class prints an PPC MCInst to a .s file.
24
//
25
//===----------------------------------------------------------------------===//
26
27
#include <capstone/platform.h>
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <string.h>
31
32
#include "../../utils.h"
33
#include "../../LEB128.h"
34
#include "../../Mapping.h"
35
#include "../../MCInst.h"
36
#include "../../MCInstPrinter.h"
37
#include "../../MCInstrDesc.h"
38
#include "../../MCRegisterInfo.h"
39
#include "PPCInstrInfo.h"
40
#include "PPCLinkage.h"
41
#include "PPCMCTargetDesc.h"
42
#include "PPCMapping.h"
43
#include "PPCPredicates.h"
44
#include "PPCRegisterInfo.h"
45
46
#define CONCAT(a, b) CONCAT_(a, b)
47
#define CONCAT_(a, b) a##_##b
48
49
#define DEBUG_TYPE "asm-printer"
50
51
extern const MCInstrDesc PPCInsts[];
52
53
// Static function declarations. These are functions which have the same identifiers
54
// over all architectures. Therefor they need to be static.
55
#ifndef CAPSTONE_DIET
56
static void printCustomAliasOperand(MCInst *MI, uint64_t Address,
57
            unsigned OpIdx, unsigned PrintMethodIdx,
58
            SStream *O);
59
#endif
60
61
static const char *getRegisterName(unsigned RegNo);
62
63
/// showRegistersWithPercentPrefix - Check if this register name should be
64
/// printed with a percentage symbol as prefix.
65
static inline bool showRegistersWithPercentPrefix(const MCInst *MI,
66
              const char *RegName)
67
122k
{
68
122k
  if ((MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME) ||
69
122k
      !(MI->csh->syntax & CS_OPT_SYNTAX_PERCENT) ||
70
122k
      PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))
71
122k
    return false;
72
73
0
  switch (RegName[0]) {
74
0
  default:
75
0
    return false;
76
0
  case 'r':
77
0
  case 'f':
78
0
  case 'q':
79
0
  case 'v':
80
0
  case 'c':
81
0
    return true;
82
0
  }
83
0
}
84
85
/// getVerboseConditionalRegName - This method expands the condition register
86
/// when requested explicitly or targeting Darwin.
87
static inline const char *getVerboseConditionRegName(const MCInst *MI,
88
                 unsigned RegNum,
89
                 unsigned RegEncoding)
90
122k
{
91
122k
  if (MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME)
92
0
    return NULL;
93
122k
  if (RegNum < PPC_CR0EQ || RegNum > PPC_CR7UN)
94
112k
    return NULL;
95
9.92k
  const char *CRBits[] = {
96
9.92k
    "lt",     "gt", "eq",     "un", "4*cr1+lt",
97
9.92k
    "4*cr1+gt", "4*cr1+eq", "4*cr1+un", "4*cr2+lt", "4*cr2+gt",
98
9.92k
    "4*cr2+eq", "4*cr2+un", "4*cr3+lt", "4*cr3+gt", "4*cr3+eq",
99
9.92k
    "4*cr3+un", "4*cr4+lt", "4*cr4+gt", "4*cr4+eq", "4*cr4+un",
100
9.92k
    "4*cr5+lt", "4*cr5+gt", "4*cr5+eq", "4*cr5+un", "4*cr6+lt",
101
9.92k
    "4*cr6+gt", "4*cr6+eq", "4*cr6+un", "4*cr7+lt", "4*cr7+gt",
102
9.92k
    "4*cr7+eq", "4*cr7+un"
103
9.92k
  };
104
9.92k
  return CRBits[RegEncoding];
105
122k
}
106
107
// showRegistersWithPrefix - This method determines whether registers
108
// should be number-only or include the prefix.
109
static inline bool showRegistersWithPrefix(const MCInst *MI)
110
122k
{
111
122k
  return !(MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME);
112
122k
}
113
114
static inline void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
115
123k
{
116
123k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_Operand, OpNo);
117
123k
  MCOperand *Op = MCInst_getOperand(MI, (OpNo));
118
123k
  if (MCOperand_isReg(Op)) {
119
122k
    unsigned Reg = MCOperand_getReg(Op);
120
122k
    if (!MI->csh->ShowVSRNumsAsVR)
121
122k
      Reg = PPCInstrInfo_getRegNumForOperand(
122
122k
        MCInstrDesc_get(MCInst_getOpcode(MI),
123
122k
            PPCDescs.Insts,
124
122k
            ARR_SIZE(PPCDescs.Insts)),
125
122k
        Reg, OpNo);
126
127
122k
    const char *RegName;
128
122k
    RegName = getVerboseConditionRegName(
129
122k
      MI, Reg, MI->MRI->RegEncodingTable[Reg]);
130
122k
    if (RegName == NULL)
131
112k
      RegName = getRegisterName(Reg);
132
122k
    if (showRegistersWithPercentPrefix(MI, RegName))
133
0
      SStream_concat0(O, "%");
134
122k
    if (!showRegistersWithPrefix(MI))
135
0
      RegName = PPCRegisterInfo_stripRegisterPrefix(RegName);
136
137
122k
    SStream_concat0(O, RegName);
138
122k
    return;
139
122k
  }
140
141
1.56k
  if (MCOperand_isImm(Op)) {
142
1.56k
    printInt64(O, MCOperand_getImm(Op));
143
1.56k
    return;
144
1.56k
  }
145
1.56k
}
146
147
static inline void printPredicateOperand(MCInst *MI, unsigned OpNo, SStream *O,
148
           const char *Modifier)
149
0
{
150
0
  PPC_add_cs_detail_1(MI, PPC_OP_GROUP_PredicateOperand, OpNo, Modifier);
151
0
  unsigned Code = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
152
153
0
  if (strcmp(Modifier, "cc") == 0) {
154
0
    switch ((PPC_Predicate)Code) {
155
0
    default:
156
0
      CS_ASSERT_RET(0 && "Invalid predicate code");
157
0
    case PPC_PRED_LT_MINUS:
158
0
    case PPC_PRED_LT_PLUS:
159
0
    case PPC_PRED_LT:
160
0
      SStream_concat0(O, "lt");
161
0
      return;
162
0
    case PPC_PRED_LE_MINUS:
163
0
    case PPC_PRED_LE_PLUS:
164
0
    case PPC_PRED_LE:
165
0
      SStream_concat0(O, "le");
166
0
      return;
167
0
    case PPC_PRED_EQ_MINUS:
168
0
    case PPC_PRED_EQ_PLUS:
169
0
    case PPC_PRED_EQ:
170
0
      SStream_concat0(O, "eq");
171
0
      return;
172
0
    case PPC_PRED_GE_MINUS:
173
0
    case PPC_PRED_GE_PLUS:
174
0
    case PPC_PRED_GE:
175
0
      SStream_concat0(O, "ge");
176
0
      return;
177
0
    case PPC_PRED_GT_MINUS:
178
0
    case PPC_PRED_GT_PLUS:
179
0
    case PPC_PRED_GT:
180
0
      SStream_concat0(O, "gt");
181
0
      return;
182
0
    case PPC_PRED_NE_MINUS:
183
0
    case PPC_PRED_NE_PLUS:
184
0
    case PPC_PRED_NE:
185
0
      SStream_concat0(O, "ne");
186
0
      return;
187
0
    case PPC_PRED_UN_MINUS:
188
0
    case PPC_PRED_UN_PLUS:
189
0
    case PPC_PRED_UN:
190
0
      SStream_concat0(O, "un");
191
0
      return;
192
0
    case PPC_PRED_NU_MINUS:
193
0
    case PPC_PRED_NU_PLUS:
194
0
    case PPC_PRED_NU:
195
0
      SStream_concat0(O, "nu");
196
0
      return;
197
0
    case PPC_PRED_BIT_SET:
198
0
    case PPC_PRED_BIT_UNSET:
199
0
      CS_ASSERT_RET(0 && "Invalid use of bit predicate code");
200
0
    }
201
0
    CS_ASSERT_RET(0 && "Invalid predicate code");
202
0
  }
203
204
0
  if (strcmp(Modifier, "pm") == 0) {
205
0
    switch ((PPC_Predicate)Code) {
206
0
    default:
207
0
      CS_ASSERT_RET(0 && "Invalid predicate code");
208
0
    case PPC_PRED_LT:
209
0
    case PPC_PRED_LE:
210
0
    case PPC_PRED_EQ:
211
0
    case PPC_PRED_GE:
212
0
    case PPC_PRED_GT:
213
0
    case PPC_PRED_NE:
214
0
    case PPC_PRED_UN:
215
0
    case PPC_PRED_NU:
216
0
      return;
217
0
    case PPC_PRED_LT_MINUS:
218
0
    case PPC_PRED_LE_MINUS:
219
0
    case PPC_PRED_EQ_MINUS:
220
0
    case PPC_PRED_GE_MINUS:
221
0
    case PPC_PRED_GT_MINUS:
222
0
    case PPC_PRED_NE_MINUS:
223
0
    case PPC_PRED_UN_MINUS:
224
0
    case PPC_PRED_NU_MINUS:
225
0
      SStream_concat0(O, "-");
226
0
      return;
227
0
    case PPC_PRED_LT_PLUS:
228
0
    case PPC_PRED_LE_PLUS:
229
0
    case PPC_PRED_EQ_PLUS:
230
0
    case PPC_PRED_GE_PLUS:
231
0
    case PPC_PRED_GT_PLUS:
232
0
    case PPC_PRED_NE_PLUS:
233
0
    case PPC_PRED_UN_PLUS:
234
0
    case PPC_PRED_NU_PLUS:
235
0
      SStream_concat0(O, "+");
236
0
      return;
237
0
    case PPC_PRED_BIT_SET:
238
0
    case PPC_PRED_BIT_UNSET:
239
0
      CS_ASSERT_RET(0 && "Invalid use of bit predicate code");
240
0
    }
241
0
    CS_ASSERT_RET(0 && "Invalid predicate code");
242
0
  }
243
244
0
  printOperand(MI, OpNo + 1, O);
245
0
}
246
247
static inline void printATBitsAsHint(MCInst *MI, unsigned OpNo, SStream *O)
248
0
{
249
0
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_ATBitsAsHint, OpNo);
250
0
  unsigned Code = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
251
0
  if (Code == 2)
252
0
    SStream_concat0(O, "-");
253
0
  else if (Code == 3)
254
0
    SStream_concat0(O, "+");
255
0
}
256
257
static inline void printU1ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
258
2.31k
{
259
2.31k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U1ImmOperand, OpNo);
260
2.31k
  unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
261
2.31k
  CS_ASSERT(Value <= 1 && "Invalid u1imm argument!");
262
2.31k
  printUInt32(O, (unsigned int)Value);
263
2.31k
}
264
265
static inline void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
266
1.36k
{
267
1.36k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U2ImmOperand, OpNo);
268
1.36k
  unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
269
1.36k
  CS_ASSERT(Value <= 3 && "Invalid u2imm argument!");
270
1.36k
  printUInt32(O, (unsigned int)Value);
271
1.36k
}
272
273
static inline void printU3ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
274
983
{
275
983
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U3ImmOperand, OpNo);
276
983
  unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
277
983
  CS_ASSERT(Value <= 8 && "Invalid u3imm argument!");
278
983
  printUInt32(O, (unsigned int)Value);
279
983
}
280
281
static inline void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
282
957
{
283
957
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U4ImmOperand, OpNo);
284
957
  unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
285
957
  CS_ASSERT(Value <= 15 && "Invalid u4imm argument!");
286
957
  printUInt32(O, (unsigned int)Value);
287
957
}
288
289
static inline void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
290
168
{
291
168
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S5ImmOperand, OpNo);
292
168
  int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
293
168
  Value = SignExtend32((Value), 5);
294
168
  printInt32(O, (int)Value);
295
168
}
296
297
static inline void printImmZeroOperand(MCInst *MI, unsigned OpNo, SStream *O)
298
321
{
299
321
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_ImmZeroOperand, OpNo);
300
321
  unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
301
321
  CS_ASSERT(Value == 0 && "Operand must be zero");
302
321
  printUInt32(O, (unsigned int)Value);
303
321
}
304
305
static inline void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
306
10.4k
{
307
10.4k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U5ImmOperand, OpNo);
308
10.4k
  unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
309
10.4k
  CS_ASSERT(Value <= 31 && "Invalid u5imm argument!");
310
10.4k
  printUInt32(O, (unsigned int)Value);
311
10.4k
}
312
313
static inline void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
314
1.94k
{
315
1.94k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U6ImmOperand, OpNo);
316
1.94k
  unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
317
1.94k
  CS_ASSERT(Value <= 63 && "Invalid u6imm argument!");
318
1.94k
  printUInt32(O, (unsigned int)Value);
319
1.94k
}
320
321
static inline void printU7ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
322
108
{
323
108
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U7ImmOperand, OpNo);
324
108
  unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
325
108
  CS_ASSERT(Value <= 127 && "Invalid u7imm argument!");
326
108
  printUInt32(O, (unsigned int)Value);
327
108
}
328
329
// Operands of BUILD_VECTOR are signed and we use this to print operands
330
// of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and
331
// print as unsigned.
332
static inline void printU8ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
333
79
{
334
79
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U8ImmOperand, OpNo);
335
79
  unsigned char Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
336
79
  CS_ASSERT(Value <= 255 && "Invalid u8imm argument!");
337
79
  printUInt32(O, (unsigned int)Value);
338
79
}
339
340
static inline void printU10ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
341
489
{
342
489
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U10ImmOperand, OpNo);
343
489
  unsigned short Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
344
489
  CS_ASSERT(Value <= 1023 && "Invalid u10imm argument!");
345
489
  printUInt32(O, (unsigned short)Value);
346
489
}
347
348
static inline void printU12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
349
134
{
350
134
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U12ImmOperand, OpNo);
351
134
  unsigned short Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
352
134
  CS_ASSERT(Value <= 4095 && "Invalid u12imm argument!");
353
134
  printUInt32(O, (unsigned short)Value);
354
134
}
355
356
static inline void printS12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
357
327
{
358
327
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S12ImmOperand, OpNo);
359
327
  if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
360
327
    int Imm = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
361
327
    Imm = SignExtend32(Imm, 12);
362
327
    printInt32(O, Imm);
363
327
  } else
364
0
    printOperand(MI, OpNo, O);
365
327
}
366
367
static inline void printMemRegImmPS(MCInst *MI, unsigned OpNo, SStream *O)
368
327
{
369
327
  set_mem_access(MI, true);
370
371
327
  printS12ImmOperand(MI, OpNo, O);
372
327
  SStream_concat0(O, "(");
373
327
  printOperand(MI, OpNo + 1, O);
374
327
  SStream_concat0(O, ")");
375
376
327
  set_mem_access(MI, false);
377
327
}
378
379
static inline void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
380
15.2k
{
381
15.2k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S16ImmOperand, OpNo);
382
15.2k
  if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo))))
383
15.2k
    printInt32(O, (short)MCOperand_getImm(
384
15.2k
              MCInst_getOperand(MI, (OpNo))));
385
0
  else
386
0
    printOperand(MI, OpNo, O);
387
15.2k
}
388
389
static inline void printS34ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
390
554
{
391
554
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S34ImmOperand, OpNo);
392
554
  if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) {
393
554
    long long Value =
394
554
      MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
395
396
554
    printInt64(O, (long long)Value);
397
554
  } else
398
0
    printOperand(MI, OpNo, O);
399
554
}
400
401
static inline void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
402
4.22k
{
403
4.22k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U16ImmOperand, OpNo);
404
4.22k
  if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo))))
405
4.22k
    printUInt32(O, (unsigned short)MCOperand_getImm(
406
4.22k
               MCInst_getOperand(MI, (OpNo))));
407
0
  else
408
0
    printOperand(MI, OpNo, O);
409
4.22k
}
410
411
static inline void printBranchOperand(MCInst *MI, uint64_t Address,
412
              unsigned OpNo, SStream *O)
413
5.57k
{
414
5.57k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_BranchOperand, OpNo);
415
5.57k
  if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) {
416
0
    printOperand(MI, OpNo, O);
417
0
    return;
418
0
  }
419
5.57k
  int32_t Imm = SignExtend32(
420
5.57k
    ((unsigned)MCOperand_getImm(MCInst_getOperand(MI, (OpNo)))
421
5.57k
     << 2),
422
5.57k
    32);
423
5.57k
  if (MI->csh->PrintBranchImmAsAddress) {
424
5.57k
    uint64_t Target = Address + Imm;
425
5.57k
    if (!IS_64BIT(MI->csh->mode))
426
1.28k
      Target &= 0xffffffff;
427
5.57k
    printUInt64(O, (Target));
428
5.57k
  } else {
429
    // Branches can take an immediate operand. This is used by the branch
430
    // selection pass to print, for example `.+8` (for ELF) or `$+8` (for
431
    // AIX) to express an eight byte displacement from the program counter.
432
0
    if (!PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))
433
0
      SStream_concat0(O, ".");
434
0
    else
435
0
      SStream_concat0(O, "$");
436
437
0
    if (Imm >= 0)
438
0
      SStream_concat0(O, "+");
439
0
    printInt32(O, Imm);
440
0
  }
441
5.57k
}
442
443
static inline void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
444
4.43k
{
445
4.43k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_AbsBranchOperand, OpNo);
446
4.43k
  if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) {
447
0
    printOperand(MI, OpNo, O);
448
0
    return;
449
0
  }
450
451
4.43k
  printUInt64(O,
452
4.43k
        ((unsigned)MCOperand_getImm(MCInst_getOperand(MI, (OpNo)))
453
4.43k
         << 2));
454
4.43k
}
455
456
static inline void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O)
457
1.02k
{
458
1.02k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_crbitm, OpNo);
459
1.02k
  unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, (OpNo)));
460
1.02k
  unsigned RegNo;
461
1.02k
  switch (CCReg) {
462
0
  default:
463
0
    CS_ASSERT_RET(0 && "Unknown CR register");
464
178
  case PPC_CR0:
465
178
    RegNo = 0;
466
178
    break;
467
25
  case PPC_CR1:
468
25
    RegNo = 1;
469
25
    break;
470
74
  case PPC_CR2:
471
74
    RegNo = 2;
472
74
    break;
473
192
  case PPC_CR3:
474
192
    RegNo = 3;
475
192
    break;
476
221
  case PPC_CR4:
477
221
    RegNo = 4;
478
221
    break;
479
73
  case PPC_CR5:
480
73
    RegNo = 5;
481
73
    break;
482
109
  case PPC_CR6:
483
109
    RegNo = 6;
484
109
    break;
485
153
  case PPC_CR7:
486
153
    RegNo = 7;
487
153
    break;
488
1.02k
  }
489
1.02k
  printUInt32(O, (0x80 >> RegNo));
490
1.02k
}
491
492
static inline void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O)
493
25.3k
{
494
25.3k
  set_mem_access(MI, true);
495
25.3k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm, OpNo);
496
25.3k
  printS16ImmOperand(MI, OpNo, O);
497
25.3k
  SStream_concat0(O, "(");
498
499
25.3k
  if (MCOperand_getReg(MCInst_getOperand(MI, (OpNo + 1))) == PPC_R0)
500
0
    SStream_concat0(O, "0");
501
25.3k
  else
502
25.3k
    printOperand(MI, OpNo + 1, O);
503
25.3k
  SStream_concat0(O, ")");
504
25.3k
  set_mem_access(MI, false);
505
25.3k
}
506
507
static inline void printMemRegImmHash(MCInst *MI, unsigned OpNo, SStream *O)
508
102
{
509
102
  set_mem_access(MI, true);
510
102
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImmHash, OpNo);
511
102
  printInt32(O, MCOperand_getImm(MCInst_getOperand(MI, (OpNo))));
512
102
  SStream_concat0(O, "(");
513
514
102
  printOperand(MI, OpNo + 1, O);
515
102
  SStream_concat0(O, ")");
516
102
  set_mem_access(MI, false);
517
102
}
518
519
static inline void printMemRegImm34PCRel(MCInst *MI, unsigned OpNo, SStream *O)
520
297
{
521
297
  set_mem_access(MI, true);
522
297
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm34PCRel, OpNo);
523
297
  printS34ImmOperand(MI, OpNo, O);
524
297
  SStream_concat0(O, "(");
525
526
297
  printImmZeroOperand(MI, OpNo + 1, O);
527
297
  SStream_concat0(O, ")");
528
297
  set_mem_access(MI, false);
529
297
}
530
531
static inline void printMemRegImm34(MCInst *MI, unsigned OpNo, SStream *O)
532
127
{
533
127
  set_mem_access(MI, true);
534
127
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm34, OpNo);
535
127
  printS34ImmOperand(MI, OpNo, O);
536
127
  SStream_concat0(O, "(");
537
538
127
  printOperand(MI, OpNo + 1, O);
539
127
  SStream_concat0(O, ")");
540
127
  set_mem_access(MI, false);
541
127
}
542
543
static inline void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O)
544
7.47k
{
545
7.47k
  set_mem_access(MI, true);
546
7.47k
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegReg, OpNo);
547
  // When used as the base register, r0 reads constant zero rather than
548
  // the value contained in the register.  For this reason, the darwin
549
  // assembler requires that we print r0 as 0 (no r) when used as the base.
550
7.47k
  if (MCOperand_getReg(MCInst_getOperand(MI, (OpNo))) == PPC_R0)
551
0
    SStream_concat0(O, "0");
552
7.47k
  else
553
7.47k
    printOperand(MI, OpNo, O);
554
7.47k
  SStream_concat0(O, ", ");
555
7.47k
  printOperand(MI, OpNo + 1, O);
556
7.47k
  set_mem_access(MI, false);
557
7.47k
}
558
559
static inline void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O)
560
0
{
561
0
  PPC_add_cs_detail_0(MI, PPC_OP_GROUP_TLSCall, OpNo);
562
563
  // Expression logic removed.
564
565
0
  set_mem_access(MI, true);
566
0
  SStream_concat0(O, "(");
567
568
0
  printOperand(MI, OpNo + 1, O);
569
0
  SStream_concat0(O, ")");
570
0
  set_mem_access(MI, false);
571
0
}
572
573
#define PRINT_ALIAS_INSTR
574
#include "PPCGenAsmWriter.inc"
575
576
static void printInst(MCInst *MI, uint64_t Address, const char *Annot,
577
          SStream *O)
578
62.0k
{
579
62.0k
  bool isAlias = false;
580
62.0k
  bool useAliasDetails = false;
581
  // Customize printing of the addis instruction on AIX. When an operand is a
582
  // symbol reference, the instruction syntax is changed to look like a load
583
  // operation, i.e:
584
  //     Transform:  addis $rD, $rA, $src --> addis $rD, $src($rA).
585
62.0k
  if (PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs) &&
586
62.0k
      (MCInst_getOpcode(MI) == PPC_ADDIS8 ||
587
0
       MCInst_getOpcode(MI) == PPC_ADDIS) &&
588
62.0k
      MCOperand_isExpr(MCInst_getOperand(MI, (2)))) {
589
0
    SStream_concat0(O, "\taddis ");
590
0
    printOperand(MI, 0, O);
591
0
    SStream_concat0(O, ", ");
592
0
    printOperand(MI, 2, O);
593
0
    SStream_concat0(O, "(");
594
0
    printOperand(MI, 1, O);
595
0
    SStream_concat0(O, ")");
596
0
    return;
597
0
  }
598
599
  // Check if the last operand is an expression with the variant kind
600
  // VK_PPC_PCREL_OPT. If this is the case then this is a linker optimization
601
  // relocation and the .reloc directive needs to be added.
602
62.0k
  unsigned LastOp = MCInst_getNumOperands(MI) - 1;
603
62.0k
  if (MCInst_getNumOperands(MI) > 1) {
604
60.2k
    MCOperand *Operand = MCInst_getOperand(MI, (LastOp));
605
60.2k
    if (MCOperand_isExpr(Operand)) {
606
0
      CS_ASSERT_RET(0 && "Expressions not supported.");
607
0
    }
608
60.2k
  }
609
610
  // Check for slwi/srwi mnemonics.
611
62.0k
  if (MCInst_getOpcode(MI) == PPC_RLWINM) {
612
1.10k
    unsigned char SH = MCOperand_getImm(MCInst_getOperand(MI, (2)));
613
1.10k
    unsigned char MB = MCOperand_getImm(MCInst_getOperand(MI, (3)));
614
1.10k
    unsigned char ME = MCOperand_getImm(MCInst_getOperand(MI, (4)));
615
1.10k
    bool useSubstituteMnemonic = false;
616
1.10k
    if (SH <= 31 && MB == 0 && ME == (31 - SH)) {
617
116
      SStream_concat0(O, "slwi ");
618
116
      useSubstituteMnemonic = true;
619
116
    }
620
1.10k
    if (SH <= 31 && MB == (32 - SH) && ME == 31) {
621
52
      SStream_concat0(O, "srwi ");
622
52
      useSubstituteMnemonic = true;
623
52
      SH = 32 - SH;
624
52
    }
625
1.10k
    useAliasDetails |= map_use_alias_details(MI);
626
1.10k
    map_set_fill_detail_ops(MI, useAliasDetails &&
627
1.10k
                useSubstituteMnemonic);
628
1.10k
    if (useSubstituteMnemonic) {
629
168
      isAlias |= true;
630
168
      MCInst_setIsAlias(MI, isAlias);
631
632
168
      printOperand(MI, 0, O);
633
168
      SStream_concat0(O, ", ");
634
168
      printOperand(MI, 1, O);
635
168
      SStream_concat(O, "%s", ", ");
636
168
      printUInt32(O, (unsigned int)SH);
637
168
      PPC_insert_detail_op_imm_at(MI, 2, SH, CS_AC_READ);
638
639
168
      if (useAliasDetails)
640
168
        return;
641
168
    }
642
1.10k
  }
643
644
61.8k
  if (MCInst_getOpcode(MI) == PPC_RLDICR ||
645
61.8k
      MCInst_getOpcode(MI) == PPC_RLDICR_32) {
646
256
    unsigned char SH = MCOperand_getImm(MCInst_getOperand(MI, (2)));
647
256
    unsigned char ME = MCOperand_getImm(MCInst_getOperand(MI, (3)));
648
649
256
    useAliasDetails |= map_use_alias_details(MI);
650
256
    map_set_fill_detail_ops(MI, useAliasDetails && 63 - SH == ME);
651
    // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
652
256
    if (63 - SH == ME) {
653
19
      isAlias |= true;
654
19
      MCInst_setIsAlias(MI, isAlias);
655
19
      SStream_concat0(O, "sldi ");
656
19
      printOperand(MI, 0, O);
657
19
      SStream_concat0(O, ", ");
658
19
      printOperand(MI, 1, O);
659
19
      SStream_concat(O, "%s", ", ");
660
19
      printUInt32(O, (unsigned int)SH);
661
19
      PPC_insert_detail_op_imm_at(MI, 2, SH, CS_AC_READ);
662
663
19
      if (useAliasDetails)
664
19
        return;
665
19
    }
666
256
  }
667
668
  // dcbt[st] is printed manually here because:
669
  //  1. The assembly syntax is different between embedded and server targets
670
  //  2. We must print the short mnemonics for TH == 0 because the
671
  //     embedded/server syntax default will not be stable across assemblers
672
  //  The syntax for dcbt is:
673
  //    dcbt ra, rb, th [server]
674
  //    dcbt th, ra, rb [embedded]
675
  //  where th can be omitted when it is 0. dcbtst is the same.
676
  // On AIX, only emit the extended mnemonics for dcbt and dcbtst if
677
  // the "modern assembler" is available.
678
61.8k
  if ((MCInst_getOpcode(MI) == PPC_DCBT ||
679
61.8k
       MCInst_getOpcode(MI) == PPC_DCBTST) &&
680
61.8k
      (!PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))) {
681
1.38k
    unsigned char TH = MCOperand_getImm(MCInst_getOperand(MI, (0)));
682
1.38k
    SStream_concat0(O, "dcbt");
683
1.38k
    if (MCInst_getOpcode(MI) == PPC_DCBTST)
684
134
      SStream_concat0(O, "st");
685
1.38k
    if (TH == 16)
686
123
      SStream_concat0(O, "t");
687
1.38k
    SStream_concat0(O, " ");
688
689
1.38k
    bool IsBookE =
690
1.38k
      PPC_getFeatureBits(MI->csh->mode, PPC_FeatureBookE);
691
1.38k
    if (IsBookE && TH != 0 && TH != 16) {
692
0
      printUInt32(O, (unsigned int)TH);
693
0
      SStream_concat0(O, ", ");
694
0
      PPC_set_detail_op_imm(MI, 0, TH);
695
0
    }
696
1.38k
    set_mem_access(MI, true);
697
1.38k
    printOperand(MI, 1, O);
698
1.38k
    SStream_concat0(O, ", ");
699
1.38k
    printOperand(MI, 2, O);
700
1.38k
    set_mem_access(MI, false);
701
702
1.38k
    if (!IsBookE && TH != 0 && TH != 16) {
703
868
      SStream_concat(O, "%s", ", ");
704
868
      printUInt32(O, (unsigned int)TH);
705
868
      PPC_set_detail_op_imm(MI, 0, TH);
706
868
    }
707
708
1.38k
    return;
709
1.38k
  }
710
711
60.4k
  if (MCInst_getOpcode(MI) == PPC_DCBF) {
712
2.02k
    unsigned char L = MCOperand_getImm(MCInst_getOperand(MI, (0)));
713
2.02k
    if (!L || L == 1 || L == 3 || L == 4 || L == 6) {
714
1.98k
      SStream_concat0(O, "dcb");
715
1.98k
      if (L != 6)
716
1.33k
        SStream_concat0(O, "f");
717
1.98k
      if (L == 1)
718
25
        SStream_concat0(O, "l");
719
1.98k
      if (L == 3)
720
1.19k
        SStream_concat0(O, "lp");
721
1.98k
      if (L == 4)
722
27
        SStream_concat0(O, "ps");
723
1.98k
      if (L == 6)
724
649
        SStream_concat0(O, "stps");
725
1.98k
      SStream_concat0(O, " ");
726
727
1.98k
      printOperand(MI, 1, O);
728
1.98k
      SStream_concat0(O, ", ");
729
1.98k
      printOperand(MI, 2, O);
730
731
1.98k
      return;
732
1.98k
    }
733
2.02k
  }
734
735
  // isAlias/useAliasDetails could have been set before.
736
58.4k
  useAliasDetails |= map_use_alias_details(MI);
737
58.4k
  map_set_fill_detail_ops(MI, useAliasDetails);
738
58.4k
  isAlias |= printAliasInstr(MI, Address, O);
739
58.4k
  MCInst_setIsAlias(MI, isAlias);
740
741
58.4k
  if (!isAlias || !useAliasDetails) {
742
49.1k
    map_set_fill_detail_ops(MI, true);
743
49.1k
    if (isAlias)
744
0
      SStream_Close(O);
745
49.1k
    printInstruction(MI, Address, O);
746
49.1k
    if (isAlias)
747
0
      SStream_Open(O);
748
49.1k
  }
749
58.4k
}
750
751
const char *PPC_LLVM_getRegisterName(unsigned RegNo)
752
48.4k
{
753
48.4k
  return getRegisterName(RegNo);
754
48.4k
}
755
756
void PPC_LLVM_printInst(MCInst *MI, uint64_t Address, const char *Annot,
757
      SStream *O)
758
62.0k
{
759
62.0k
  printInst(MI, Address, Annot, O);
760
62.0k
}