blob: 92b4b756ca5de6e863405dd639a0f9dc00565834 [file] [log] [blame]
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +08001//===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This class prints an PPC MCInst to a .s file.
11//
12//===----------------------------------------------------------------------===//
13
Nguyen Anh Quynh1514d5c2014-03-06 14:04:45 +080014/* Capstone Disassembly Engine */
15/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080016
Nguyen Anh Quynh8598a212014-05-14 11:26:41 +080017#ifdef CAPSTONE_HAS_POWERPC
18
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080019#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "PPCInstPrinter.h"
24#include "PPCPredicates.h"
25#include "../../MCInst.h"
Nguyen Anh Quynhc7404072014-01-05 11:35:47 +080026#include "../../utils.h"
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080027#include "../../SStream.h"
28#include "../../MCRegisterInfo.h"
29#include "../../MathExtras.h"
Nguyen Anh Quynh37327252014-01-20 09:47:21 +080030#include "PPCMapping.h"
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080031
Nguyen Anh Quynh2eb37ee2014-03-28 10:38:55 +080032#ifndef CAPSTONE_DIET
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +080033static char *getRegisterName(unsigned RegNo);
Nguyen Anh Quynh2eb37ee2014-03-28 10:38:55 +080034#endif
35
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080036static void printOperand(MCInst *MI, unsigned OpNo, SStream *O);
Nguyen Anh Quynhe51e2272014-01-12 20:27:54 +080037static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080038static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O);
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +080039static char *printAliasInstr(MCInst *MI, SStream *OS, void *info);
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +080040static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info);
41static void printCustomAliasOperand(MCInst *MI, unsigned OpIdx,
42 unsigned PrintMethodIdx, SStream *OS);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080043
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080044static void set_mem_access(MCInst *MI, bool status)
45{
46 if (MI->csh->detail != CS_OPT_ON)
47 return;
48
Nguyen Anh Quynh19b0de32013-12-31 22:40:04 +080049 MI->csh->doing_mem = status;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080050
Nguyen Anh Quynh19b0de32013-12-31 22:40:04 +080051 if (status) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +070052 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_MEM;
53 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = PPC_REG_INVALID;
54 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = 0;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080055 } else {
56 // done, create the next operand slot
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +070057 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080058 }
59}
60
Nguyen Anh Quynh64564812014-05-19 16:46:31 +080061void PPC_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
Nguyen Anh Quynh2b14fcd2014-01-05 10:37:50 +080062{
63 if (((cs_struct *)ud)->detail != CS_OPT_ON)
64 return;
65
66 // check if this insn has branch hint
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +080067 if (strrchr(insn_asm, '+') != NULL && !strstr(insn_asm, ".+")) {
Nguyen Anh Quynh2b14fcd2014-01-05 10:37:50 +080068 insn->detail->ppc.bh = PPC_BH_PLUS;
69 } else if (strrchr(insn_asm, '-') != NULL) {
70 insn->detail->ppc.bh = PPC_BH_MINUS;
71 }
72}
73
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080074#define GET_INSTRINFO_ENUM
75#include "PPCGenInstrInfo.inc"
76
kratolpf0221a22014-09-29 10:59:12 +020077static int isBOCTRBranch(unsigned int op)
78{
79 return ((op >= PPC_BDNZ) && (op <= PPC_BDZp));
80}
81
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080082void PPC_printInst(MCInst *MI, SStream *O, void *Info)
83{
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +080084 char *mnem;
85
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080086 // Check for slwi/srwi mnemonics.
87 if (MCInst_getOpcode(MI) == PPC_RLWINM) {
Alex Ionescu46018db2014-01-22 09:45:00 -080088 unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2));
89 unsigned char MB = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3));
90 unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 4));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080091 bool useSubstituteMnemonic = false;
92
93 if (SH <= 31 && MB == 0 && ME == (31-SH)) {
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +080094 SStream_concat0(O, "slwi\t");
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +080095 MCInst_setOpcodePub(MI, PPC_INS_SLWI);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +080096 useSubstituteMnemonic = true;
97 }
98
99 if (SH <= 31 && MB == (32-SH) && ME == 31) {
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800100 SStream_concat0(O, "srwi\t");
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800101 MCInst_setOpcodePub(MI, PPC_INS_SRWI);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800102 useSubstituteMnemonic = true;
103 SH = 32-SH;
104 }
105
106 if (useSubstituteMnemonic) {
107 printOperand(MI, 0, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800108 SStream_concat0(O, ", ");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800109 printOperand(MI, 1, O);
110 if (SH > HEX_THRESHOLD)
111 SStream_concat(O, ", 0x%x", (unsigned int)SH);
112 else
113 SStream_concat(O, ", %u", (unsigned int)SH);
114
Peter Mackay4e732c72014-11-22 23:44:35 +0000115 if (MI->csh->detail) {
116 cs_ppc *ppc = &MI->flat_insn->detail->ppc;
117
118 ppc->operands[ppc->op_count].type = PPC_OP_IMM;
119 ppc->operands[ppc->op_count].imm = SH;
120 ++ppc->op_count;
121 }
122
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800123 return;
124 }
125 }
126
127 if ((MCInst_getOpcode(MI) == PPC_OR || MCInst_getOpcode(MI) == PPC_OR8) &&
Nguyen Anh Quynhe07bc912014-11-11 13:12:22 +0800128 MCOperand_getReg(MCInst_getOperand(MI, 1)) == MCOperand_getReg(MCInst_getOperand(MI, 2))) {
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800129 SStream_concat0(O, "mr\t");
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800130 MCInst_setOpcodePub(MI, PPC_INS_MR);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800131 printOperand(MI, 0, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800132 SStream_concat0(O, ", ");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800133 printOperand(MI, 1, O);
134 return;
135 }
136
137 if (MCInst_getOpcode(MI) == PPC_RLDICR) {
Alex Ionescu46018db2014-01-22 09:45:00 -0800138 unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2));
139 unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800140 // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
141 if (63-SH == ME) {
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800142 SStream_concat0(O, "sldi\t");
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800143 MCInst_setOpcodePub(MI, PPC_INS_SLDI);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800144 printOperand(MI, 0, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800145 SStream_concat0(O, ", ");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800146 printOperand(MI, 1, O);
147 if (SH > HEX_THRESHOLD)
148 SStream_concat(O, ", 0x%x", (unsigned int)SH);
149 else
150 SStream_concat(O, ", %u", (unsigned int)SH);
151
152 return;
153 }
154 }
155
kratolpa3f0aef2014-10-01 11:39:15 +0200156 if ((MCInst_getOpcode(MI) == PPC_gBC)||(MCInst_getOpcode(MI) == PPC_gBCA)||
157 (MCInst_getOpcode(MI) == PPC_gBCL)||(MCInst_getOpcode(MI) == PPC_gBCLA)) {
kratolpf0221a22014-09-29 10:59:12 +0200158 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 2));
159 bd = SignExtend64(bd, 14);
160 MCOperand_setImm(MCInst_getOperand(MI, 2),bd);
161 }
162
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800163 if (isBOCTRBranch(MCInst_getOpcode(MI))) {
kratolpf0221a22014-09-29 10:59:12 +0200164 if (MCOperand_isImm(MCInst_getOperand(MI,0)))
165 {
166 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0));
167 bd = SignExtend64(bd, 14);
168 MCOperand_setImm(MCInst_getOperand(MI, 0),bd);
169 }
170 }
171
172 if ((MCInst_getOpcode(MI) == PPC_B)||(MCInst_getOpcode(MI) == PPC_BA)||
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800173 (MCInst_getOpcode(MI) == PPC_BL)||(MCInst_getOpcode(MI) == PPC_BLA)) {
kratolpf0221a22014-09-29 10:59:12 +0200174 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0));
175 bd = SignExtend64(bd, 24);
176 MCOperand_setImm(MCInst_getOperand(MI, 0),bd);
177 }
178
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800179 // consider our own alias instructions first
180 mnem = printAliasInstrEx(MI, O, Info);
181 if (!mnem)
182 mnem = printAliasInstr(MI, O, Info);
183
Nguyen Anh Quynhc4dbf072015-06-06 16:09:15 +0800184 if ((mnem != NULL) && (strlen(mnem) > 0)) {
Nguyen Anh Quynh7e57e792014-09-21 13:04:50 +0800185 struct ppc_alias alias;
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800186 // check to remove the last letter of ('.', '-', '+')
187 if (mnem[strlen(mnem) - 1] == '-' || mnem[strlen(mnem) - 1] == '+' || mnem[strlen(mnem) - 1] == '.')
188 mnem[strlen(mnem) - 1] = '\0';
189
Nguyen Anh Quynh7e57e792014-09-21 13:04:50 +0800190 if (PPC_alias_insn(mnem, &alias)) {
191 MCInst_setOpcodePub(MI, alias.id);
192 if (MI->csh->detail) {
193 MI->flat_insn->detail->ppc.bc = (ppc_bc)alias.cc;
194 }
195 }
196
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800197 cs_mem_free(mnem);
198 } else
199 printInstruction(MI, O, NULL);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800200}
201
Nguyen Anh Quynh7e57e792014-09-21 13:04:50 +0800202enum ppc_bc_hint {
203 PPC_BC_LT_MINUS = (0 << 5) | 14,
204 PPC_BC_LE_MINUS = (1 << 5) | 6,
205 PPC_BC_EQ_MINUS = (2 << 5) | 14,
206 PPC_BC_GE_MINUS = (0 << 5) | 6,
207 PPC_BC_GT_MINUS = (1 << 5) | 14,
208 PPC_BC_NE_MINUS = (2 << 5) | 6,
209 PPC_BC_UN_MINUS = (3 << 5) | 14,
210 PPC_BC_NU_MINUS = (3 << 5) | 6,
211 PPC_BC_LT_PLUS = (0 << 5) | 15,
212 PPC_BC_LE_PLUS = (1 << 5) | 7,
213 PPC_BC_EQ_PLUS = (2 << 5) | 15,
214 PPC_BC_GE_PLUS = (0 << 5) | 7,
215 PPC_BC_GT_PLUS = (1 << 5) | 15,
216 PPC_BC_NE_PLUS = (2 << 5) | 7,
217 PPC_BC_UN_PLUS = (3 << 5) | 15,
218 PPC_BC_NU_PLUS = (3 << 5) | 7,
219};
220
221// normalize CC to remove _MINUS & _PLUS
222static int cc_normalize(int cc)
223{
224 switch(cc) {
225 default: return cc;
226 case PPC_BC_LT_MINUS: return PPC_BC_LT;
227 case PPC_BC_LE_MINUS: return PPC_BC_LE;
228 case PPC_BC_EQ_MINUS: return PPC_BC_EQ;
229 case PPC_BC_GE_MINUS: return PPC_BC_GE;
230 case PPC_BC_GT_MINUS: return PPC_BC_GT;
231 case PPC_BC_NE_MINUS: return PPC_BC_NE;
232 case PPC_BC_UN_MINUS: return PPC_BC_UN;
233 case PPC_BC_NU_MINUS: return PPC_BC_NU;
234 case PPC_BC_LT_PLUS : return PPC_BC_LT;
235 case PPC_BC_LE_PLUS : return PPC_BC_LE;
236 case PPC_BC_EQ_PLUS : return PPC_BC_EQ;
237 case PPC_BC_GE_PLUS : return PPC_BC_GE;
238 case PPC_BC_GT_PLUS : return PPC_BC_GT;
239 case PPC_BC_NE_PLUS : return PPC_BC_NE;
240 case PPC_BC_UN_PLUS : return PPC_BC_UN;
241 case PPC_BC_NU_PLUS : return PPC_BC_NU;
242 }
243}
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800244
245static void printPredicateOperand(MCInst *MI, unsigned OpNo,
246 SStream *O, const char *Modifier)
247{
Alex Ionescu46018db2014-01-22 09:45:00 -0800248 unsigned Code = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800249
Nguyen Anh Quynh7e57e792014-09-21 13:04:50 +0800250 MI->flat_insn->detail->ppc.bc = (ppc_bc)cc_normalize(Code);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800251
252 if (!strcmp(Modifier, "cc")) {
253 switch ((ppc_predicate)Code) {
Nguyen Anh Quynh1514d5c2014-03-06 14:04:45 +0800254 default: // unreachable
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800255 case PPC_PRED_LT_MINUS:
256 case PPC_PRED_LT_PLUS:
257 case PPC_PRED_LT:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800258 SStream_concat0(O, "lt");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800259 return;
260 case PPC_PRED_LE_MINUS:
261 case PPC_PRED_LE_PLUS:
262 case PPC_PRED_LE:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800263 SStream_concat0(O, "le");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800264 return;
265 case PPC_PRED_EQ_MINUS:
266 case PPC_PRED_EQ_PLUS:
267 case PPC_PRED_EQ:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800268 SStream_concat0(O, "eq");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800269 return;
270 case PPC_PRED_GE_MINUS:
271 case PPC_PRED_GE_PLUS:
272 case PPC_PRED_GE:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800273 SStream_concat0(O, "ge");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800274 return;
275 case PPC_PRED_GT_MINUS:
276 case PPC_PRED_GT_PLUS:
277 case PPC_PRED_GT:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800278 SStream_concat0(O, "gt");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800279 return;
280 case PPC_PRED_NE_MINUS:
281 case PPC_PRED_NE_PLUS:
282 case PPC_PRED_NE:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800283 SStream_concat0(O, "ne");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800284 return;
285 case PPC_PRED_UN_MINUS:
286 case PPC_PRED_UN_PLUS:
287 case PPC_PRED_UN:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800288 SStream_concat0(O, "un");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800289 return;
290 case PPC_PRED_NU_MINUS:
291 case PPC_PRED_NU_PLUS:
292 case PPC_PRED_NU:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800293 SStream_concat0(O, "nu");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800294 return;
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800295 case PPC_PRED_BIT_SET:
296 case PPC_PRED_BIT_UNSET:
297 // llvm_unreachable("Invalid use of bit predicate code");
298 SStream_concat0(O, "invalid-predicate");
299 return;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800300 }
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800301 }
302
303 if (!strcmp(Modifier, "pm")) {
304 switch ((ppc_predicate)Code) {
305 case PPC_PRED_LT:
306 case PPC_PRED_LE:
307 case PPC_PRED_EQ:
308 case PPC_PRED_GE:
309 case PPC_PRED_GT:
310 case PPC_PRED_NE:
311 case PPC_PRED_UN:
312 case PPC_PRED_NU:
313 return;
314 case PPC_PRED_LT_MINUS:
315 case PPC_PRED_LE_MINUS:
316 case PPC_PRED_EQ_MINUS:
317 case PPC_PRED_GE_MINUS:
318 case PPC_PRED_GT_MINUS:
319 case PPC_PRED_NE_MINUS:
320 case PPC_PRED_UN_MINUS:
321 case PPC_PRED_NU_MINUS:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800322 SStream_concat0(O, "-");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800323 return;
324 case PPC_PRED_LT_PLUS:
325 case PPC_PRED_LE_PLUS:
326 case PPC_PRED_EQ_PLUS:
327 case PPC_PRED_GE_PLUS:
328 case PPC_PRED_GT_PLUS:
329 case PPC_PRED_NE_PLUS:
330 case PPC_PRED_UN_PLUS:
331 case PPC_PRED_NU_PLUS:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800332 SStream_concat0(O, "+");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800333 return;
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800334 case PPC_PRED_BIT_SET:
335 case PPC_PRED_BIT_UNSET:
336 // llvm_unreachable("Invalid use of bit predicate code");
337 SStream_concat0(O, "invalid-predicate");
338 return;
Nguyen Anh Quynh1514d5c2014-03-06 14:04:45 +0800339 default: // unreachable
340 return;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800341 }
342 // llvm_unreachable("Invalid predicate code");
343 }
344
345 //assert(StringRef(Modifier) == "reg" &&
346 // "Need to specify 'cc', 'pm' or 'reg' as predicate op modifier!");
347 printOperand(MI, OpNo + 1, O);
348}
349
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800350static void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
351{
352 unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
353 //assert(Value <= 3 && "Invalid u2imm argument!");
354
355 if (Value > HEX_THRESHOLD)
356 SStream_concat(O, "0x%x", Value);
357 else
358 SStream_concat(O, "%u", Value);
359
360 if (MI->csh->detail) {
361 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
362 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
363 MI->flat_insn->detail->ppc.op_count++;
364 }
365}
366
367static void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
368{
369 unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
370 //assert(Value <= 15 && "Invalid u4imm argument!");
371
372 if (Value > HEX_THRESHOLD)
373 SStream_concat(O, "0x%x", Value);
374 else
375 SStream_concat(O, "%u", Value);
376
377 if (MI->csh->detail) {
378 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
379 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
380 MI->flat_insn->detail->ppc.op_count++;
381 }
382}
383
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800384static void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
385{
Alex Ionescu46018db2014-01-22 09:45:00 -0800386 int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800387 Value = SignExtend32(Value, 5);
388
389 if (Value >= 0) {
390 if (Value > HEX_THRESHOLD)
391 SStream_concat(O, "0x%x", Value);
392 else
393 SStream_concat(O, "%u", Value);
394 } else {
395 if (Value < -HEX_THRESHOLD)
396 SStream_concat(O, "-0x%x", -Value);
397 else
398 SStream_concat(O, "-%u", -Value);
399 }
400
401 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700402 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
403 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
404 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800405 }
406}
407
408static void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
409{
Alex Ionescu46018db2014-01-22 09:45:00 -0800410 unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800411 //assert(Value <= 31 && "Invalid u5imm argument!");
412 if (Value > HEX_THRESHOLD)
413 SStream_concat(O, "0x%x", Value);
414 else
415 SStream_concat(O, "%u", Value);
416
417 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700418 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
419 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
420 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800421 }
422}
423
424static void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
425{
Alex Ionescu46018db2014-01-22 09:45:00 -0800426 unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800427 //assert(Value <= 63 && "Invalid u6imm argument!");
428 if (Value > HEX_THRESHOLD)
429 SStream_concat(O, "0x%x", Value);
430 else
431 SStream_concat(O, "%u", Value);
432
433 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700434 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
435 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
436 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800437 }
438}
439
440static void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
441{
442 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
443 short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
444 if (Imm >= 0) {
445 if (Imm > HEX_THRESHOLD)
446 SStream_concat(O, "0x%x", Imm);
447 else
448 SStream_concat(O, "%u", Imm);
449 } else {
450 if (Imm < -HEX_THRESHOLD)
451 SStream_concat(O, "-0x%x", -Imm);
452 else
453 SStream_concat(O, "-%u", -Imm);
454 }
455
456 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700457 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
458 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm;
459 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800460 }
461 } else
462 printOperand(MI, OpNo, O);
463}
464
465static void printS16ImmOperand_Mem(MCInst *MI, unsigned OpNo, SStream *O)
466{
467 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
468 short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
469 // Do not print zero offset
470 if (Imm == 0)
471 return;
472
473 if (Imm >= 0) {
474 if (Imm > HEX_THRESHOLD)
475 SStream_concat(O, "0x%x", Imm);
476 else
477 SStream_concat(O, "%u", Imm);
478 } else {
479 if (Imm < -HEX_THRESHOLD)
480 SStream_concat(O, "-0x%x", -Imm);
481 else
482 SStream_concat(O, "-%u", -Imm);
483 }
484
485 if (MI->csh->detail) {
Nguyen Anh Quynh19b0de32013-12-31 22:40:04 +0800486 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700487 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = Imm;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800488 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700489 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
490 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm;
491 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800492 }
493 }
494 } else
495 printOperand(MI, OpNo, O);
496}
497
498static void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
499{
500 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
501 unsigned short Imm = (unsigned short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
502 if (Imm > HEX_THRESHOLD)
503 SStream_concat(O, "0x%x", Imm);
504 else
505 SStream_concat(O, "%u", Imm);
506
507 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700508 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
509 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm;
510 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800511 }
512 } else
513 printOperand(MI, OpNo, O);
514}
515
516static void printBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
517{
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800518 if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
Alex Ionescu46018db2014-01-22 09:45:00 -0800519 printOperand(MI, OpNo, O);
Nguyen Anh Quynha82a0892014-01-23 23:42:40 +0800520 return;
521 }
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800522
523 // Branches can take an immediate operand. This is used by the branch
524 // selection pass to print .+8, an eight byte displacement from the PC.
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800525 printAbsBranchOperand(MI, OpNo, O);
526}
527
528static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
529{
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800530 int imm;
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800531
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800532 if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
Alex Ionescu46018db2014-01-22 09:45:00 -0800533 printOperand(MI, OpNo, O);
Nguyen Anh Quynha82a0892014-01-23 23:42:40 +0800534 return;
535 }
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800536
kratolpf0221a22014-09-29 10:59:12 +0200537 imm = ((int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)) << 2);
kratolpa3f0aef2014-10-01 11:39:15 +0200538
539 if (!PPC_abs_branch(MI->csh, MCInst_getOpcode(MI))) {
540 imm = (int)MI->address + imm;
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800541 }
Nguyen Anh Quynhf46ef2e2014-09-15 12:12:10 +0800542
Nguyen Anh Quynhd82b28a2014-11-11 11:05:20 +0800543 SStream_concat(O, "0x%x", imm);
kratolpa3f0aef2014-10-01 11:39:15 +0200544
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800545 if (MI->csh->detail) {
546 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
547 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm;
548 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800549 }
550}
551
552
553#define GET_REGINFO_ENUM
554#include "PPCGenRegisterInfo.inc"
555
556static void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O)
557{
Axel 0vercl0k Souchet779d4c72014-05-08 23:44:49 +0100558 unsigned RegNo, tmp;
Nguyen Anh Quynh630bcd62014-10-01 21:02:30 +0800559 unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, OpNo));
560
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800561 switch (CCReg) {
562 default: // llvm_unreachable("Unknown CR register");
563 case PPC_CR0: RegNo = 0; break;
564 case PPC_CR1: RegNo = 1; break;
565 case PPC_CR2: RegNo = 2; break;
566 case PPC_CR3: RegNo = 3; break;
567 case PPC_CR4: RegNo = 4; break;
568 case PPC_CR5: RegNo = 5; break;
569 case PPC_CR6: RegNo = 6; break;
570 case PPC_CR7: RegNo = 7; break;
571 }
572
Axel 0vercl0k Souchet779d4c72014-05-08 23:44:49 +0100573 tmp = 0x80 >> RegNo;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800574 if (tmp > HEX_THRESHOLD)
575 SStream_concat(O, "0x%x", tmp);
576 else
577 SStream_concat(O, "%u", tmp);
578}
579
580static void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O)
581{
582 set_mem_access(MI, true);
583
584 printS16ImmOperand_Mem(MI, OpNo, O);
585
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800586 SStream_concat0(O, "(");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800587
588 if (MCOperand_getReg(MCInst_getOperand(MI, OpNo + 1)) == PPC_R0)
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800589 SStream_concat0(O, "0");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800590 else
591 printOperand(MI, OpNo + 1, O);
592
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800593 SStream_concat0(O, ")");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800594 set_mem_access(MI, false);
595}
596
597static void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O)
598{
599 // When used as the base register, r0 reads constant zero rather than
600 // the value contained in the register. For this reason, the darwin
601 // assembler requires that we print r0 as 0 (no r) when used as the base.
602 if (MCOperand_getReg(MCInst_getOperand(MI, OpNo)) == PPC_R0)
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800603 SStream_concat0(O, "0");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800604 else
605 printOperand(MI, OpNo, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800606 SStream_concat0(O, ", ");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800607
608 printOperand(MI, OpNo + 1, O);
609}
610
611static void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O)
612{
613 set_mem_access(MI, true);
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800614 //printBranchOperand(MI, OpNo, O);
615
616 // On PPC64, VariantKind is VK_None, but on PPC32, it's VK_PLT, and it must
617 // come at the _end_ of the expression.
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800618
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800619 SStream_concat0(O, "(");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800620 printOperand(MI, OpNo + 1, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800621 SStream_concat0(O, ")");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800622 set_mem_access(MI, false);
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800623}
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800624
Nguyen Anh Quynh2eb37ee2014-03-28 10:38:55 +0800625#ifndef CAPSTONE_DIET
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800626/// stripRegisterPrefix - This method strips the character prefix from a
627/// register name so that only the number is left. Used by for linux asm.
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800628static char *stripRegisterPrefix(char *RegName)
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800629{
630 switch (RegName[0]) {
631 case 'r':
632 case 'f':
633 case 'v':
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800634 if (RegName[1] == 's')
635 return RegName + 2;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800636 return RegName + 1;
637 case 'c':
638 if (RegName[1] == 'r')
639 return RegName + 2;
640 }
641
642 return RegName;
643}
Nguyen Anh Quynh2eb37ee2014-03-28 10:38:55 +0800644#endif
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800645
646static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
647{
648 MCOperand *Op = MCInst_getOperand(MI, OpNo);
649 if (MCOperand_isReg(Op)) {
650 unsigned reg = MCOperand_getReg(Op);
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800651#ifndef CAPSTONE_DIET
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800652 char *RegName = getRegisterName(reg);
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800653#endif
Nguyen Anh Quynhf1d489b2014-01-05 00:00:05 +0800654 // map to public register
655 reg = PPC_map_register(reg);
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800656#ifndef CAPSTONE_DIET
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800657 // The linux and AIX assembler does not take register prefixes.
Nguyen Anh Quynhf1d489b2014-01-05 00:00:05 +0800658 if (MI->csh->syntax == CS_OPT_SYNTAX_NOREGNAME)
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800659 RegName = stripRegisterPrefix(RegName);
660
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800661 SStream_concat0(O, RegName);
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800662#endif
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800663
664 if (MI->csh->detail) {
Nguyen Anh Quynh19b0de32013-12-31 22:40:04 +0800665 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700666 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = reg;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800667 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700668 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG;
669 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg;
670 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800671 }
672 }
673
674 return;
675 }
676
677 if (MCOperand_isImm(Op)) {
Alex Ionescu46018db2014-01-22 09:45:00 -0800678 int32_t imm = (int32_t)MCOperand_getImm(Op);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800679 if (imm >= 0) {
680 if (imm > HEX_THRESHOLD)
681 SStream_concat(O, "0x%x", imm);
682 else
683 SStream_concat(O, "%u", imm);
684 } else {
Nguyen Anh Quynh2c20a1b2014-05-30 17:00:20 +0800685 if (imm < -HEX_THRESHOLD)
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800686 SStream_concat(O, "-0x%x", -imm);
687 else
688 SStream_concat(O, "-%u", -imm);
689 }
690
691 if (MI->csh->detail) {
Nguyen Anh Quynh19b0de32013-12-31 22:40:04 +0800692 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700693 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = imm;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800694 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700695 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
696 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm;
697 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800698 }
699 }
700 }
701}
702
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800703static void op_addImm(MCInst *MI, int v)
704{
705 if (MI->csh->detail) {
Nguyen Anh Quynh6756edd2014-09-29 23:32:14 +0800706 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
707 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = v;
708 MI->flat_insn->detail->ppc.op_count++;
709 }
710}
711
712static void op_addReg(MCInst *MI, unsigned int reg)
713{
714 if (MI->csh->detail) {
715 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG;
716 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg;
717 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800718 }
719}
720
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800721static void op_addBC(MCInst *MI, unsigned int bc)
722{
723 if (MI->csh->detail) {
724 MI->flat_insn->detail->ppc.bc = (ppc_bc)bc;
725 }
726}
727
kratolpf0221a22014-09-29 10:59:12 +0200728#define CREQ (0)
729#define CRGT (1)
730#define CRLT (2)
731#define CRUN (3)
732
733static int getBICRCond(int bi)
734{
735 return (bi-PPC_CR0EQ) >> 3;
736}
737
738static int getBICR(int bi)
739{
740 return ((bi - PPC_CR0EQ) & 7) + PPC_CR0;
741}
742
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800743static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info)
744{
745#define GETREGCLASS_CONTAIN(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), MCOperand_getReg(MCInst_getOperand(MI, _reg)))
kratolpf0221a22014-09-29 10:59:12 +0200746 SStream ss;
Nguyen Anh Quynh6b731a02014-10-01 21:05:51 +0800747 const char *opCode;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800748 char *tmp, *AsmMnem, *AsmOps, *c;
749 int OpIdx, PrintMethodIdx;
Nguyen Anh Quynh6b731a02014-10-01 21:05:51 +0800750 int decCtr = false, needComma = false;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800751 MCRegisterInfo *MRI = (MCRegisterInfo *)info;
Nguyen Anh Quynh630bcd62014-10-01 21:02:30 +0800752
kratolpf0221a22014-09-29 10:59:12 +0200753 SStream_Init(&ss);
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800754 switch (MCInst_getOpcode(MI)) {
755 default: return NULL;
756 case PPC_gBC:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800757 opCode = "b%s";
758 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800759 case PPC_gBCA:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800760 opCode = "b%sa";
761 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800762 case PPC_gBCCTR:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800763 opCode = "b%sctr";
764 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800765 case PPC_gBCCTRL:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800766 opCode = "b%sctrl";
767 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800768 case PPC_gBCL:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800769 opCode = "b%sl";
770 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800771 case PPC_gBCLA:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800772 opCode = "b%sla";
773 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800774 case PPC_gBCLR:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800775 opCode = "b%slr";
776 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800777 case PPC_gBCLRL:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800778 opCode = "b%slrl";
779 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800780 }
781
kratolpf0221a22014-09-29 10:59:12 +0200782 if (MCInst_getNumOperands(MI) == 3 &&
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800783 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
kratolpa3f0aef2014-10-01 11:39:15 +0200784 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 0) &&
785 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 1)) {
786 SStream_concat(&ss, opCode, "dnzf");
kratolp73835102014-10-01 11:54:14 +0200787 decCtr = true;
kratolpf0221a22014-09-29 10:59:12 +0200788 }
789
790 if (MCInst_getNumOperands(MI) == 3 &&
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800791 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
kratolpa3f0aef2014-10-01 11:39:15 +0200792 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 2) &&
793 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 3)) {
794 SStream_concat(&ss, opCode, "dzf");
kratolp73835102014-10-01 11:54:14 +0200795 decCtr = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200796 }
797
798 if (MCInst_getNumOperands(MI) == 3 &&
799 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
800 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 4) &&
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800801 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 7) &&
802 MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
803 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) {
804 int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
805 switch(cr) {
806 case CREQ:
807 SStream_concat(&ss, opCode, "ne");
808 break;
809 case CRGT:
810 SStream_concat(&ss, opCode, "le");
811 break;
812 case CRLT:
813 SStream_concat(&ss, opCode, "ge");
814 break;
815 case CRUN:
816 SStream_concat(&ss, opCode, "ns");
817 break;
818 }
kratolpf0221a22014-09-29 10:59:12 +0200819
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800820 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 6)
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800821 SStream_concat0(&ss, "-");
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800822
823 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7)
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800824 SStream_concat0(&ss, "+");
kratolpa3f0aef2014-10-01 11:39:15 +0200825
kratolp73835102014-10-01 11:54:14 +0200826 decCtr = false;
kratolpa3f0aef2014-10-01 11:39:15 +0200827 }
828
829 if (MCInst_getNumOperands(MI) == 3 &&
830 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
831 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 8) &&
832 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 9)) {
833 SStream_concat(&ss, opCode, "dnzt");
kratolp73835102014-10-01 11:54:14 +0200834 decCtr = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200835 }
836
837 if (MCInst_getNumOperands(MI) == 3 &&
838 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
839 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 10) &&
840 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 11)) {
841 SStream_concat(&ss, opCode, "dzt");
kratolp73835102014-10-01 11:54:14 +0200842 decCtr = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200843 }
844
845 if (MCInst_getNumOperands(MI) == 3 &&
846 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
847 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 12) &&
848 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 15) &&
849 MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
850 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) {
851 int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
852 switch(cr) {
853 case CREQ:
854 SStream_concat(&ss, opCode, "eq");
855 break;
856 case CRGT:
857 SStream_concat(&ss, opCode, "gt");
858 break;
859 case CRLT:
860 SStream_concat(&ss, opCode, "lt");
861 break;
862 case CRUN:
863 SStream_concat(&ss, opCode, "so");
864 break;
865 }
866
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800867 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 14)
kratolpa3f0aef2014-10-01 11:39:15 +0200868 SStream_concat0(&ss, "-");
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800869
870 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 15)
kratolpa3f0aef2014-10-01 11:39:15 +0200871 SStream_concat0(&ss, "+");
872
kratolp73835102014-10-01 11:54:14 +0200873 decCtr = false;
kratolpa3f0aef2014-10-01 11:39:15 +0200874 }
875
876 if (MCInst_getNumOperands(MI) == 3 &&
877 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
878 ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 16)) {
879 SStream_concat(&ss, opCode, "dnz");
880
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800881 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 24)
kratolpa3f0aef2014-10-01 11:39:15 +0200882 SStream_concat0(&ss, "-");
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800883
884 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 25)
kratolpa3f0aef2014-10-01 11:39:15 +0200885 SStream_concat0(&ss, "+");
886
kratolp73835102014-10-01 11:54:14 +0200887 needComma = false;
kratolpa3f0aef2014-10-01 11:39:15 +0200888 }
889
890 if (MCInst_getNumOperands(MI) == 3 &&
891 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
892 ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 18)) {
893 SStream_concat(&ss, opCode, "dz");
894
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800895 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 26)
kratolpa3f0aef2014-10-01 11:39:15 +0200896 SStream_concat0(&ss, "-");
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800897
898 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 27)
kratolpa3f0aef2014-10-01 11:39:15 +0200899 SStream_concat0(&ss, "+");
900
kratolp73835102014-10-01 11:54:14 +0200901 needComma = false;
kratolpf0221a22014-09-29 10:59:12 +0200902 }
903
904 if (MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
kratolpa3f0aef2014-10-01 11:39:15 +0200905 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1) &&
906 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
907 (MCOperand_getImm(MCInst_getOperand(MI, 0)) < 16)) {
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800908 int cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1)));
Nguyen Anh Quynhe96935e2014-10-02 17:09:22 +0800909
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800910 if (decCtr) {
kratolp73835102014-10-01 11:54:14 +0200911 needComma = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200912 SStream_concat0(&ss, " ");
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800913
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800914 if (cr > PPC_CR0) {
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800915 SStream_concat(&ss, "4*cr%d+", cr - PPC_CR0);
kratolpa3f0aef2014-10-01 11:39:15 +0200916 }
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800917
kratolpa3f0aef2014-10-01 11:39:15 +0200918 cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
919 switch(cr) {
920 case CREQ:
921 SStream_concat0(&ss, "eq");
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800922 op_addBC(MI, PPC_BC_EQ);
kratolpa3f0aef2014-10-01 11:39:15 +0200923 break;
924 case CRGT:
925 SStream_concat0(&ss, "gt");
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800926 op_addBC(MI, PPC_BC_GT);
kratolpa3f0aef2014-10-01 11:39:15 +0200927 break;
928 case CRLT:
929 SStream_concat0(&ss, "lt");
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800930 op_addBC(MI, PPC_BC_LT);
kratolpa3f0aef2014-10-01 11:39:15 +0200931 break;
932 case CRUN:
933 SStream_concat0(&ss, "so");
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800934 op_addBC(MI, PPC_BC_SO);
kratolpa3f0aef2014-10-01 11:39:15 +0200935 break;
936 }
kratolp5c0d9a42014-10-17 14:52:03 +0200937
938 cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1)));
939 if (cr > PPC_CR0) {
940 if (MI->csh->detail) {
941 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_CRX;
942 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.scale = 4;
943 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.reg = PPC_REG_CR0 + cr - PPC_CR0;
944 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.cond = MI->flat_insn->detail->ppc.bc;
945 MI->flat_insn->detail->ppc.op_count++;
946 }
947 }
kratolpa3f0aef2014-10-01 11:39:15 +0200948 } else {
Nguyen Anh Quynh70fa90f2014-10-01 18:21:02 +0800949 if (cr > PPC_CR0) {
Nguyen Anh Quynh7e644f02014-10-01 14:13:48 +0800950 needComma = true;
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800951 SStream_concat(&ss, " cr%d", cr - PPC_CR0);
kratolp5c0d9a42014-10-17 14:52:03 +0200952 op_addReg(MI, PPC_REG_CR0 + cr - PPC_CR0);
kratolpa3f0aef2014-10-01 11:39:15 +0200953 }
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800954 }
kratolpf0221a22014-09-29 10:59:12 +0200955 }
956
957 if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800958 MCOperand_getImm(MCInst_getOperand(MI, 2)) != 0) {
Nguyen Anh Quynh7e644f02014-10-01 14:13:48 +0800959 if (needComma)
kratolpf0221a22014-09-29 10:59:12 +0200960 SStream_concat0(&ss, ",");
Nguyen Anh Quynh48eb13c2014-10-01 21:18:55 +0800961
kratolpf0221a22014-09-29 10:59:12 +0200962 SStream_concat0(&ss, " $\xFF\x03\x01");
963 }
964
965 tmp = cs_strdup(ss.buffer);
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800966 AsmMnem = tmp;
967 for(AsmOps = tmp; *AsmOps; AsmOps++) {
968 if (*AsmOps == ' ' || *AsmOps == '\t') {
969 *AsmOps = '\0';
970 AsmOps++;
971 break;
972 }
973 }
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800974
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800975 SStream_concat0(OS, AsmMnem);
976 if (*AsmOps) {
977 SStream_concat0(OS, "\t");
978 for (c = AsmOps; *c; c++) {
979 if (*c == '$') {
980 c += 1;
981 if (*c == (char)0xff) {
982 c += 1;
983 OpIdx = *c - 1;
984 c += 1;
985 PrintMethodIdx = *c - 1;
986 printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, OS);
987 } else
988 printOperand(MI, *c - 1, OS);
989 } else {
990 SStream_concat(OS, "%c", *c);
991 }
992 }
993 }
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800994
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800995 return tmp;
996}
997
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800998#define PRINT_ALIAS_INSTR
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800999#include "PPCGenAsmWriter.inc"
1000
Nguyen Anh Quynh8598a212014-05-14 11:26:41 +08001001#endif