Coverage Report

Created: 2026-09-03 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/capstonenext/arch/Sparc/SparcInstPrinter.c
Line
Count
Source
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
//===-- SparcInstPrinter.cpp - Convert Sparc 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 Sparc MCInst to a .s file.
24
//
25
//===----------------------------------------------------------------------===//
26
27
#include <stdio.h>
28
#include <string.h>
29
#include <stdlib.h>
30
#include <capstone/platform.h>
31
32
#include "../../MCInstPrinter.h"
33
#include "../../Mapping.h"
34
#include "SparcInstPrinter.h"
35
#include "SparcLinkage.h"
36
#include "SparcMCTargetDesc.h"
37
#include "SparcMapping.h"
38
#include "SparcDisassemblerExtension.h"
39
40
#define CONCAT(a, b) CONCAT_(a, b)
41
#define CONCAT_(a, b) a##_##b
42
43
#define DEBUG_TYPE "asm-printer"
44
45
static void printCustomAliasOperand(MCInst *MI, uint64_t Address,
46
            unsigned OpIdx, unsigned PrintMethodIdx,
47
            SStream *OS);
48
static void printOperand(MCInst *MI, int opNum, SStream *O);
49
50
#define GET_INSTRUCTION_NAME
51
#define PRINT_ALIAS_INSTR
52
#include "SparcGenAsmWriter.inc"
53
54
static void printRegName(SStream *OS, MCRegister Reg)
55
8.27k
{
56
8.27k
  SStream_concat1(OS, '%');
57
8.27k
  SStream_concat0(OS, getRegisterName(Reg, Sparc_NoRegAltName));
58
8.27k
}
59
60
static void printRegNameAlt(SStream *OS, MCRegister Reg, unsigned AltIdx)
61
47.0k
{
62
47.0k
  SStream_concat1(OS, '%');
63
47.0k
  SStream_concat0(OS, getRegisterName(Reg, AltIdx));
64
47.0k
}
65
66
static void printInst(MCInst *MI, uint64_t Address, SStream *O)
67
47.5k
{
68
47.5k
  bool isAlias = false;
69
47.5k
  bool useAliasDetails = map_use_alias_details(MI);
70
47.5k
  map_set_fill_detail_ops(MI, useAliasDetails);
71
72
47.5k
  if (!printAliasInstr(MI, Address, O) && !printSparcAliasInstr(MI, O)) {
73
42.3k
    MCInst_setIsAlias(MI, false);
74
42.3k
  } else {
75
5.19k
    isAlias = true;
76
5.19k
    MCInst_setIsAlias(MI, isAlias);
77
5.19k
    if (useAliasDetails) {
78
5.19k
      return;
79
5.19k
    }
80
5.19k
  }
81
82
42.3k
  if (!isAlias || !useAliasDetails) {
83
42.3k
    map_set_fill_detail_ops(MI, !(isAlias && useAliasDetails));
84
42.3k
    if (isAlias)
85
0
      SStream_Close(O);
86
42.3k
    printInstruction(MI, Address, O);
87
42.3k
    if (isAlias)
88
0
      SStream_Open(O);
89
42.3k
  }
90
42.3k
}
91
92
bool printSparcAliasInstr(MCInst *MI, SStream *O)
93
44.2k
{
94
44.2k
  switch (MCInst_getOpcode(MI)) {
95
40.8k
  default:
96
40.8k
    return false;
97
66
  case Sparc_JMPLrr:
98
1.90k
  case Sparc_JMPLri: {
99
1.90k
    if (MCInst_getNumOperands(MI) != 3)
100
0
      return false;
101
1.90k
    if (!MCOperand_isReg(MCInst_getOperand(MI, (0))))
102
0
      return false;
103
1.90k
    switch (MCOperand_getReg(MCInst_getOperand(MI, (0)))) {
104
56
    default:
105
56
      return false;
106
1.81k
    case Sparc_G0: // jmp $addr | ret | retl
107
1.81k
      if (MCOperand_isImm(MCInst_getOperand(MI, (2))) &&
108
1.77k
          MCOperand_getImm(MCInst_getOperand(MI, (2))) == 8) {
109
1.26k
        switch (MCOperand_getReg(
110
1.26k
          MCInst_getOperand(MI, (1)))) {
111
428
        default:
112
428
          break;
113
783
        case Sparc_I7:
114
783
          SStream_concat0(O, "\tret");
115
783
          return true;
116
55
        case Sparc_O7:
117
55
          SStream_concat0(O, "\tretl");
118
55
          return true;
119
1.26k
        }
120
1.26k
      }
121
980
      SStream_concat0(O, "\tjmp ");
122
980
      printMemOperand(MI, 1, O);
123
980
      return true;
124
35
    case Sparc_O7: // call $addr
125
35
      SStream_concat0(O, "\tcall ");
126
35
      printMemOperand(MI, 1, O);
127
35
      return true;
128
1.90k
    }
129
1.90k
  }
130
165
  case Sparc_V9FCMPS:
131
687
  case Sparc_V9FCMPD:
132
1.00k
  case Sparc_V9FCMPQ:
133
1.23k
  case Sparc_V9FCMPES:
134
1.28k
  case Sparc_V9FCMPED:
135
1.43k
  case Sparc_V9FCMPEQ: {
136
1.43k
    if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9) ||
137
676
        (MCInst_getNumOperands(MI) != 3) ||
138
676
        (!MCOperand_isReg(MCInst_getOperand(MI, (0)))) ||
139
676
        (MCOperand_getReg(MCInst_getOperand(MI, (0))) !=
140
676
         Sparc_FCC0))
141
1.43k
      return false;
142
    // if V8, skip printing %fcc0.
143
0
    switch (MCInst_getOpcode(MI)) {
144
0
    default:
145
0
    case Sparc_V9FCMPS:
146
0
      SStream_concat0(O, "\tfcmps ");
147
0
      break;
148
0
    case Sparc_V9FCMPD:
149
0
      SStream_concat0(O, "\tfcmpd ");
150
0
      break;
151
0
    case Sparc_V9FCMPQ:
152
0
      SStream_concat0(O, "\tfcmpq ");
153
0
      break;
154
0
    case Sparc_V9FCMPES:
155
0
      SStream_concat0(O, "\tfcmpes ");
156
0
      break;
157
0
    case Sparc_V9FCMPED:
158
0
      SStream_concat0(O, "\tfcmped ");
159
0
      break;
160
0
    case Sparc_V9FCMPEQ:
161
0
      SStream_concat0(O, "\tfcmpeq ");
162
0
      break;
163
0
    }
164
0
    printOperand(MI, 1, O);
165
0
    SStream_concat0(O, ", ");
166
0
    printOperand(MI, 2, O);
167
0
    return true;
168
0
  }
169
44.2k
  }
170
44.2k
}
171
172
static void printOperand(MCInst *MI, int opNum, SStream *O)
173
87.0k
{
174
87.0k
  Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_Operand, opNum);
175
87.0k
  MCOperand *MO = MCInst_getOperand(MI, (opNum));
176
177
87.0k
  if (MCOperand_isReg(MO)) {
178
55.3k
    unsigned Reg = MCOperand_getReg(MO);
179
55.3k
    if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9))
180
47.0k
      printRegNameAlt(O, Reg, Sparc_RegNamesStateReg);
181
8.27k
    else
182
8.27k
      printRegName(O, Reg);
183
55.3k
    return;
184
55.3k
  }
185
186
31.7k
  if (MCOperand_isImm(MO)) {
187
31.7k
    switch (MCInst_getOpcode(MI)) {
188
31.5k
    default:
189
31.5k
      printInt32(O, (int)MCOperand_getImm(MO));
190
31.5k
      return;
191
192
68
    case Sparc_TICCri: // Fall through
193
68
    case Sparc_TICCrr: // Fall through
194
125
    case Sparc_TRAPri: // Fall through
195
125
    case Sparc_TRAPrr: // Fall through
196
166
    case Sparc_TXCCri: // Fall through
197
166
    case Sparc_TXCCrr: // Fall through
198
      // Only seven-bit values up to 127.
199
166
      printInt8(O, ((int)MCOperand_getImm(MO) & 0x7f));
200
166
      return;
201
31.7k
    }
202
31.7k
  }
203
204
0
  CS_ASSERT(MCOperand_isExpr(MO) &&
205
0
      "Unknown operand kind in printOperand");
206
0
}
207
208
void printMemOperand(MCInst *MI, int opNum, SStream *O)
209
12.1k
{
210
12.1k
  Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_MemOperand, opNum);
211
12.1k
  MCOperand *Op1 = MCInst_getOperand(MI, (opNum));
212
12.1k
  MCOperand *Op2 = MCInst_getOperand(MI, (opNum + 1));
213
214
12.1k
  bool PrintedFirstOperand = false;
215
12.1k
  if (MCOperand_isReg(Op1) && MCOperand_getReg(Op1) != Sparc_G0) {
216
11.2k
    printOperand(MI, opNum, O);
217
11.2k
    PrintedFirstOperand = true;
218
11.2k
  }
219
220
  // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've
221
  // already printed the first one
222
12.1k
  const bool SkipSecondOperand =
223
12.1k
    PrintedFirstOperand &&
224
11.2k
    ((MCOperand_isReg(Op2) && MCOperand_getReg(Op2) == Sparc_G0) ||
225
9.82k
     (MCOperand_isImm(Op2) && MCOperand_getImm(Op2) == 0));
226
227
12.1k
  if (!SkipSecondOperand) {
228
10.6k
    if (PrintedFirstOperand)
229
9.65k
      SStream_concat0(O, "+");
230
231
10.6k
    printOperand(MI, opNum + 1, O);
232
10.6k
  }
233
12.1k
}
234
235
void printCCOperand(MCInst *MI, int opNum, SStream *O)
236
7.20k
{
237
7.20k
  Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_CCOperand, opNum);
238
7.20k
  int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, (opNum)));
239
7.20k
  switch (MCInst_getOpcode(MI)) {
240
1.57k
  default:
241
1.57k
    break;
242
1.57k
  case Sparc_FBCOND:
243
946
  case Sparc_FBCONDA:
244
1.38k
  case Sparc_FBCOND_V9:
245
1.73k
  case Sparc_FBCONDA_V9:
246
2.11k
  case Sparc_BPFCC:
247
2.38k
  case Sparc_BPFCCA:
248
2.38k
  case Sparc_BPFCCNT:
249
2.38k
  case Sparc_BPFCCANT:
250
2.46k
  case Sparc_MOVFCCrr:
251
2.46k
  case Sparc_V9MOVFCCrr:
252
2.51k
  case Sparc_MOVFCCri:
253
2.51k
  case Sparc_V9MOVFCCri:
254
2.58k
  case Sparc_FMOVS_FCC:
255
2.58k
  case Sparc_V9FMOVS_FCC:
256
2.76k
  case Sparc_FMOVD_FCC:
257
2.76k
  case Sparc_V9FMOVD_FCC:
258
3.00k
  case Sparc_FMOVQ_FCC:
259
3.00k
  case Sparc_V9FMOVQ_FCC:
260
    // Make sure CC is a fp conditional flag.
261
3.00k
    CC = (CC < SPARC_CC_FCC_BEGIN) ? (CC + SPARC_CC_FCC_BEGIN) : CC;
262
3.00k
    break;
263
598
  case Sparc_CBCOND:
264
1.01k
  case Sparc_CBCONDA:
265
    // Make sure CC is a cp conditional flag.
266
1.01k
    CC = (CC < SPARC_CC_CPCC_BEGIN) ? (CC + SPARC_CC_CPCC_BEGIN) :
267
1.01k
              CC;
268
1.01k
    break;
269
477
  case Sparc_BPR:
270
664
  case Sparc_BPRA:
271
1.14k
  case Sparc_BPRNT:
272
1.23k
  case Sparc_BPRANT:
273
1.34k
  case Sparc_MOVRri:
274
1.42k
  case Sparc_MOVRrr:
275
1.46k
  case Sparc_FMOVRS:
276
1.53k
  case Sparc_FMOVRD:
277
1.61k
  case Sparc_FMOVRQ:
278
    // Make sure CC is a register conditional flag.
279
1.61k
    CC = (CC < SPARC_CC_REG_BEGIN) ? (CC + SPARC_CC_REG_BEGIN) : CC;
280
1.61k
    break;
281
7.20k
  }
282
7.20k
  SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC));
283
7.20k
}
284
285
bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O)
286
0
{
287
0
  printf("FIXME: Implement SparcInstPrinter::printGetPCX.");
288
0
  return true;
289
0
}
290
291
void printMembarTag(MCInst *MI, int opNum, SStream *O)
292
2.05k
{
293
2.05k
  Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_MembarTag, opNum);
294
2.05k
  static const char *const TagNames[] = { "#LoadLoad",  "#StoreLoad",
295
2.05k
            "#LoadStore", "#StoreStore",
296
2.05k
            "#Lookaside", "#MemIssue",
297
2.05k
            "#Sync" };
298
299
2.05k
  unsigned Imm = MCOperand_getImm(MCInst_getOperand(MI, (opNum)));
300
301
2.05k
  if (Imm > 127) {
302
649
    printUInt32(O, Imm);
303
649
    return;
304
649
  }
305
306
2.05k
  bool First = true;
307
11.2k
  for (unsigned i = 0; i < ARR_SIZE(TagNames); i++) {
308
9.86k
    if (Imm & (1ull << i)) {
309
5.31k
      SStream_concat(O, "%s", (First ? "" : " | "));
310
5.31k
      SStream_concat0(O, TagNames[i]);
311
5.31k
      First = false;
312
5.31k
    }
313
9.86k
  }
314
1.40k
}
315
316
#define GET_ASITAG_IMPL
317
#include "SparcGenSystemOperands.inc"
318
319
void printASITag(MCInst *MI, int opNum, SStream *O)
320
3.51k
{
321
3.51k
  Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_ASITag, opNum);
322
3.51k
  unsigned Imm = MCOperand_getImm(MCInst_getOperand(MI, (opNum)));
323
3.51k
  const Sparc_ASITag_ASITag *ASITag =
324
3.51k
    Sparc_ASITag_lookupASITagByEncoding(Imm);
325
3.51k
  if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9) && ASITag) {
326
113
    SStream_concat1(O, '#');
327
113
    SStream_concat0(O, ASITag->Name);
328
113
  } else
329
3.39k
    printUInt32(O, Imm);
330
3.51k
}
331
332
void Sparc_LLVM_printInst(MCInst *MI, uint64_t Address, const char *Annot,
333
        SStream *O)
334
47.5k
{
335
47.5k
  printInst(MI, Address, O);
336
47.5k
}
337
338
const char *Sparc_LLVM_getRegisterName(unsigned RegNo, unsigned AltIdx)
339
18.2k
{
340
18.2k
  return getRegisterName(RegNo, AltIdx);
341
18.2k
}