blob: fcd3799aa611f9db44f972d53b4bc07149bac051 [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
115 return;
116 }
117 }
118
119 if ((MCInst_getOpcode(MI) == PPC_OR || MCInst_getOpcode(MI) == PPC_OR8) &&
120 MCOperand_getReg(MCInst_getOperand(MI, 1)) == MCOperand_getReg(MCInst_getOperand(MI, 1))) {
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800121 SStream_concat0(O, "mr\t");
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800122 MCInst_setOpcodePub(MI, PPC_INS_MR);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800123 printOperand(MI, 0, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800124 SStream_concat0(O, ", ");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800125 printOperand(MI, 1, O);
126 return;
127 }
128
129 if (MCInst_getOpcode(MI) == PPC_RLDICR) {
Alex Ionescu46018db2014-01-22 09:45:00 -0800130 unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2));
131 unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800132 // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
133 if (63-SH == ME) {
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800134 SStream_concat0(O, "sldi\t");
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800135 MCInst_setOpcodePub(MI, PPC_INS_SLDI);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800136 printOperand(MI, 0, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800137 SStream_concat0(O, ", ");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800138 printOperand(MI, 1, O);
139 if (SH > HEX_THRESHOLD)
140 SStream_concat(O, ", 0x%x", (unsigned int)SH);
141 else
142 SStream_concat(O, ", %u", (unsigned int)SH);
143
144 return;
145 }
146 }
147
kratolpa3f0aef2014-10-01 11:39:15 +0200148 if ((MCInst_getOpcode(MI) == PPC_gBC)||(MCInst_getOpcode(MI) == PPC_gBCA)||
149 (MCInst_getOpcode(MI) == PPC_gBCL)||(MCInst_getOpcode(MI) == PPC_gBCLA)) {
kratolpf0221a22014-09-29 10:59:12 +0200150 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 2));
151 bd = SignExtend64(bd, 14);
152 MCOperand_setImm(MCInst_getOperand(MI, 2),bd);
153 }
154
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800155 if (isBOCTRBranch(MCInst_getOpcode(MI))) {
kratolpf0221a22014-09-29 10:59:12 +0200156 if (MCOperand_isImm(MCInst_getOperand(MI,0)))
157 {
158 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0));
159 bd = SignExtend64(bd, 14);
160 MCOperand_setImm(MCInst_getOperand(MI, 0),bd);
161 }
162 }
163
164 if ((MCInst_getOpcode(MI) == PPC_B)||(MCInst_getOpcode(MI) == PPC_BA)||
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800165 (MCInst_getOpcode(MI) == PPC_BL)||(MCInst_getOpcode(MI) == PPC_BLA)) {
kratolpf0221a22014-09-29 10:59:12 +0200166 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0));
167 bd = SignExtend64(bd, 24);
168 MCOperand_setImm(MCInst_getOperand(MI, 0),bd);
169 }
170
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800171 // consider our own alias instructions first
172 mnem = printAliasInstrEx(MI, O, Info);
173 if (!mnem)
174 mnem = printAliasInstr(MI, O, Info);
175
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800176 if (mnem) {
Nguyen Anh Quynh7e57e792014-09-21 13:04:50 +0800177 struct ppc_alias alias;
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800178 // check to remove the last letter of ('.', '-', '+')
179 if (mnem[strlen(mnem) - 1] == '-' || mnem[strlen(mnem) - 1] == '+' || mnem[strlen(mnem) - 1] == '.')
180 mnem[strlen(mnem) - 1] = '\0';
181
Nguyen Anh Quynh7e57e792014-09-21 13:04:50 +0800182 if (PPC_alias_insn(mnem, &alias)) {
183 MCInst_setOpcodePub(MI, alias.id);
184 if (MI->csh->detail) {
185 MI->flat_insn->detail->ppc.bc = (ppc_bc)alias.cc;
186 }
187 }
188
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800189 cs_mem_free(mnem);
190 } else
191 printInstruction(MI, O, NULL);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800192}
193
Nguyen Anh Quynh7e57e792014-09-21 13:04:50 +0800194enum ppc_bc_hint {
195 PPC_BC_LT_MINUS = (0 << 5) | 14,
196 PPC_BC_LE_MINUS = (1 << 5) | 6,
197 PPC_BC_EQ_MINUS = (2 << 5) | 14,
198 PPC_BC_GE_MINUS = (0 << 5) | 6,
199 PPC_BC_GT_MINUS = (1 << 5) | 14,
200 PPC_BC_NE_MINUS = (2 << 5) | 6,
201 PPC_BC_UN_MINUS = (3 << 5) | 14,
202 PPC_BC_NU_MINUS = (3 << 5) | 6,
203 PPC_BC_LT_PLUS = (0 << 5) | 15,
204 PPC_BC_LE_PLUS = (1 << 5) | 7,
205 PPC_BC_EQ_PLUS = (2 << 5) | 15,
206 PPC_BC_GE_PLUS = (0 << 5) | 7,
207 PPC_BC_GT_PLUS = (1 << 5) | 15,
208 PPC_BC_NE_PLUS = (2 << 5) | 7,
209 PPC_BC_UN_PLUS = (3 << 5) | 15,
210 PPC_BC_NU_PLUS = (3 << 5) | 7,
211};
212
213// normalize CC to remove _MINUS & _PLUS
214static int cc_normalize(int cc)
215{
216 switch(cc) {
217 default: return cc;
218 case PPC_BC_LT_MINUS: return PPC_BC_LT;
219 case PPC_BC_LE_MINUS: return PPC_BC_LE;
220 case PPC_BC_EQ_MINUS: return PPC_BC_EQ;
221 case PPC_BC_GE_MINUS: return PPC_BC_GE;
222 case PPC_BC_GT_MINUS: return PPC_BC_GT;
223 case PPC_BC_NE_MINUS: return PPC_BC_NE;
224 case PPC_BC_UN_MINUS: return PPC_BC_UN;
225 case PPC_BC_NU_MINUS: return PPC_BC_NU;
226 case PPC_BC_LT_PLUS : return PPC_BC_LT;
227 case PPC_BC_LE_PLUS : return PPC_BC_LE;
228 case PPC_BC_EQ_PLUS : return PPC_BC_EQ;
229 case PPC_BC_GE_PLUS : return PPC_BC_GE;
230 case PPC_BC_GT_PLUS : return PPC_BC_GT;
231 case PPC_BC_NE_PLUS : return PPC_BC_NE;
232 case PPC_BC_UN_PLUS : return PPC_BC_UN;
233 case PPC_BC_NU_PLUS : return PPC_BC_NU;
234 }
235}
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800236
237static void printPredicateOperand(MCInst *MI, unsigned OpNo,
238 SStream *O, const char *Modifier)
239{
Alex Ionescu46018db2014-01-22 09:45:00 -0800240 unsigned Code = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800241
Nguyen Anh Quynh7e57e792014-09-21 13:04:50 +0800242 MI->flat_insn->detail->ppc.bc = (ppc_bc)cc_normalize(Code);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800243
244 if (!strcmp(Modifier, "cc")) {
245 switch ((ppc_predicate)Code) {
Nguyen Anh Quynh1514d5c2014-03-06 14:04:45 +0800246 default: // unreachable
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800247 case PPC_PRED_LT_MINUS:
248 case PPC_PRED_LT_PLUS:
249 case PPC_PRED_LT:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800250 SStream_concat0(O, "lt");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800251 return;
252 case PPC_PRED_LE_MINUS:
253 case PPC_PRED_LE_PLUS:
254 case PPC_PRED_LE:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800255 SStream_concat0(O, "le");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800256 return;
257 case PPC_PRED_EQ_MINUS:
258 case PPC_PRED_EQ_PLUS:
259 case PPC_PRED_EQ:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800260 SStream_concat0(O, "eq");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800261 return;
262 case PPC_PRED_GE_MINUS:
263 case PPC_PRED_GE_PLUS:
264 case PPC_PRED_GE:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800265 SStream_concat0(O, "ge");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800266 return;
267 case PPC_PRED_GT_MINUS:
268 case PPC_PRED_GT_PLUS:
269 case PPC_PRED_GT:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800270 SStream_concat0(O, "gt");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800271 return;
272 case PPC_PRED_NE_MINUS:
273 case PPC_PRED_NE_PLUS:
274 case PPC_PRED_NE:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800275 SStream_concat0(O, "ne");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800276 return;
277 case PPC_PRED_UN_MINUS:
278 case PPC_PRED_UN_PLUS:
279 case PPC_PRED_UN:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800280 SStream_concat0(O, "un");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800281 return;
282 case PPC_PRED_NU_MINUS:
283 case PPC_PRED_NU_PLUS:
284 case PPC_PRED_NU:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800285 SStream_concat0(O, "nu");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800286 return;
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800287 case PPC_PRED_BIT_SET:
288 case PPC_PRED_BIT_UNSET:
289 // llvm_unreachable("Invalid use of bit predicate code");
290 SStream_concat0(O, "invalid-predicate");
291 return;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800292 }
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800293 }
294
295 if (!strcmp(Modifier, "pm")) {
296 switch ((ppc_predicate)Code) {
297 case PPC_PRED_LT:
298 case PPC_PRED_LE:
299 case PPC_PRED_EQ:
300 case PPC_PRED_GE:
301 case PPC_PRED_GT:
302 case PPC_PRED_NE:
303 case PPC_PRED_UN:
304 case PPC_PRED_NU:
305 return;
306 case PPC_PRED_LT_MINUS:
307 case PPC_PRED_LE_MINUS:
308 case PPC_PRED_EQ_MINUS:
309 case PPC_PRED_GE_MINUS:
310 case PPC_PRED_GT_MINUS:
311 case PPC_PRED_NE_MINUS:
312 case PPC_PRED_UN_MINUS:
313 case PPC_PRED_NU_MINUS:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800314 SStream_concat0(O, "-");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800315 return;
316 case PPC_PRED_LT_PLUS:
317 case PPC_PRED_LE_PLUS:
318 case PPC_PRED_EQ_PLUS:
319 case PPC_PRED_GE_PLUS:
320 case PPC_PRED_GT_PLUS:
321 case PPC_PRED_NE_PLUS:
322 case PPC_PRED_UN_PLUS:
323 case PPC_PRED_NU_PLUS:
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800324 SStream_concat0(O, "+");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800325 return;
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800326 case PPC_PRED_BIT_SET:
327 case PPC_PRED_BIT_UNSET:
328 // llvm_unreachable("Invalid use of bit predicate code");
329 SStream_concat0(O, "invalid-predicate");
330 return;
Nguyen Anh Quynh1514d5c2014-03-06 14:04:45 +0800331 default: // unreachable
332 return;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800333 }
334 // llvm_unreachable("Invalid predicate code");
335 }
336
337 //assert(StringRef(Modifier) == "reg" &&
338 // "Need to specify 'cc', 'pm' or 'reg' as predicate op modifier!");
339 printOperand(MI, OpNo + 1, O);
340}
341
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800342static void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
343{
344 unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
345 //assert(Value <= 3 && "Invalid u2imm argument!");
346
347 if (Value > HEX_THRESHOLD)
348 SStream_concat(O, "0x%x", Value);
349 else
350 SStream_concat(O, "%u", Value);
351
352 if (MI->csh->detail) {
353 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
354 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
355 MI->flat_insn->detail->ppc.op_count++;
356 }
357}
358
359static void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
360{
361 unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
362 //assert(Value <= 15 && "Invalid u4imm argument!");
363
364 if (Value > HEX_THRESHOLD)
365 SStream_concat(O, "0x%x", Value);
366 else
367 SStream_concat(O, "%u", Value);
368
369 if (MI->csh->detail) {
370 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
371 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
372 MI->flat_insn->detail->ppc.op_count++;
373 }
374}
375
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800376static void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
377{
Alex Ionescu46018db2014-01-22 09:45:00 -0800378 int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800379 Value = SignExtend32(Value, 5);
380
381 if (Value >= 0) {
382 if (Value > HEX_THRESHOLD)
383 SStream_concat(O, "0x%x", Value);
384 else
385 SStream_concat(O, "%u", Value);
386 } else {
387 if (Value < -HEX_THRESHOLD)
388 SStream_concat(O, "-0x%x", -Value);
389 else
390 SStream_concat(O, "-%u", -Value);
391 }
392
393 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700394 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
395 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
396 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800397 }
398}
399
400static void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
401{
Alex Ionescu46018db2014-01-22 09:45:00 -0800402 unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800403 //assert(Value <= 31 && "Invalid u5imm argument!");
404 if (Value > HEX_THRESHOLD)
405 SStream_concat(O, "0x%x", Value);
406 else
407 SStream_concat(O, "%u", Value);
408
409 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700410 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
411 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
412 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800413 }
414}
415
416static void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
417{
Alex Ionescu46018db2014-01-22 09:45:00 -0800418 unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800419 //assert(Value <= 63 && "Invalid u6imm argument!");
420 if (Value > HEX_THRESHOLD)
421 SStream_concat(O, "0x%x", Value);
422 else
423 SStream_concat(O, "%u", Value);
424
425 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700426 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
427 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
428 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800429 }
430}
431
432static void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
433{
434 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
435 short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
436 if (Imm >= 0) {
437 if (Imm > HEX_THRESHOLD)
438 SStream_concat(O, "0x%x", Imm);
439 else
440 SStream_concat(O, "%u", Imm);
441 } else {
442 if (Imm < -HEX_THRESHOLD)
443 SStream_concat(O, "-0x%x", -Imm);
444 else
445 SStream_concat(O, "-%u", -Imm);
446 }
447
448 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700449 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
450 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm;
451 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800452 }
453 } else
454 printOperand(MI, OpNo, O);
455}
456
457static void printS16ImmOperand_Mem(MCInst *MI, unsigned OpNo, SStream *O)
458{
459 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
460 short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
461 // Do not print zero offset
462 if (Imm == 0)
463 return;
464
465 if (Imm >= 0) {
466 if (Imm > HEX_THRESHOLD)
467 SStream_concat(O, "0x%x", Imm);
468 else
469 SStream_concat(O, "%u", Imm);
470 } else {
471 if (Imm < -HEX_THRESHOLD)
472 SStream_concat(O, "-0x%x", -Imm);
473 else
474 SStream_concat(O, "-%u", -Imm);
475 }
476
477 if (MI->csh->detail) {
Nguyen Anh Quynh19b0de32013-12-31 22:40:04 +0800478 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700479 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = Imm;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800480 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700481 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
482 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm;
483 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800484 }
485 }
486 } else
487 printOperand(MI, OpNo, O);
488}
489
490static void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
491{
492 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
493 unsigned short Imm = (unsigned short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
494 if (Imm > HEX_THRESHOLD)
495 SStream_concat(O, "0x%x", Imm);
496 else
497 SStream_concat(O, "%u", Imm);
498
499 if (MI->csh->detail) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700500 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
501 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm;
502 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800503 }
504 } else
505 printOperand(MI, OpNo, O);
506}
507
508static void printBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
509{
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800510 if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
Alex Ionescu46018db2014-01-22 09:45:00 -0800511 printOperand(MI, OpNo, O);
Nguyen Anh Quynha82a0892014-01-23 23:42:40 +0800512 return;
513 }
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800514
515 // Branches can take an immediate operand. This is used by the branch
516 // selection pass to print .+8, an eight byte displacement from the PC.
kratolp05d4b832014-09-16 17:15:50 +0200517 //SStream_concat0(O, ".+");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800518 printAbsBranchOperand(MI, OpNo, O);
519}
520
521static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
522{
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800523 int imm;
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800524 if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
Alex Ionescu46018db2014-01-22 09:45:00 -0800525 printOperand(MI, OpNo, O);
Nguyen Anh Quynha82a0892014-01-23 23:42:40 +0800526 return;
527 }
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800528
kratolpf0221a22014-09-29 10:59:12 +0200529 imm = ((int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)) << 2);
kratolpa3f0aef2014-10-01 11:39:15 +0200530
531 if (!PPC_abs_branch(MI->csh, MCInst_getOpcode(MI))) {
532 imm = (int)MI->address + imm;
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800533 }
Nguyen Anh Quynhf46ef2e2014-09-15 12:12:10 +0800534
kratolpa3f0aef2014-10-01 11:39:15 +0200535 SStream_concat(O, ".0x%x", imm);
536
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800537 if (MI->csh->detail) {
538 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
539 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm;
540 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800541 }
542}
543
544
545#define GET_REGINFO_ENUM
546#include "PPCGenRegisterInfo.inc"
547
548static void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O)
549{
550 unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, OpNo));
Axel 0vercl0k Souchet779d4c72014-05-08 23:44:49 +0100551 unsigned RegNo, tmp;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800552 switch (CCReg) {
553 default: // llvm_unreachable("Unknown CR register");
554 case PPC_CR0: RegNo = 0; break;
555 case PPC_CR1: RegNo = 1; break;
556 case PPC_CR2: RegNo = 2; break;
557 case PPC_CR3: RegNo = 3; break;
558 case PPC_CR4: RegNo = 4; break;
559 case PPC_CR5: RegNo = 5; break;
560 case PPC_CR6: RegNo = 6; break;
561 case PPC_CR7: RegNo = 7; break;
562 }
563
Axel 0vercl0k Souchet779d4c72014-05-08 23:44:49 +0100564 tmp = 0x80 >> RegNo;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800565 if (tmp > HEX_THRESHOLD)
566 SStream_concat(O, "0x%x", tmp);
567 else
568 SStream_concat(O, "%u", tmp);
569}
570
571static void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O)
572{
573 set_mem_access(MI, true);
574
575 printS16ImmOperand_Mem(MI, OpNo, O);
576
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800577 SStream_concat0(O, "(");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800578
579 if (MCOperand_getReg(MCInst_getOperand(MI, OpNo + 1)) == PPC_R0)
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800580 SStream_concat0(O, "0");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800581 else
582 printOperand(MI, OpNo + 1, O);
583
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800584 SStream_concat0(O, ")");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800585 set_mem_access(MI, false);
586}
587
588static void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O)
589{
590 // When used as the base register, r0 reads constant zero rather than
591 // the value contained in the register. For this reason, the darwin
592 // assembler requires that we print r0 as 0 (no r) when used as the base.
593 if (MCOperand_getReg(MCInst_getOperand(MI, OpNo)) == PPC_R0)
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800594 SStream_concat0(O, "0");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800595 else
596 printOperand(MI, OpNo, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800597 SStream_concat0(O, ", ");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800598
599 printOperand(MI, OpNo + 1, O);
600}
601
602static void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O)
603{
604 set_mem_access(MI, true);
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800605 //printBranchOperand(MI, OpNo, O);
606
607 // On PPC64, VariantKind is VK_None, but on PPC32, it's VK_PLT, and it must
608 // come at the _end_ of the expression.
Nguyen Anh Quynh1ce5dea2014-08-20 11:38:57 +0800609 // MCOperand *Op;
610 // Op = MCInst_getOperand(MI, OpNo);
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800611 //const MCSymbolRefExpr &refExp = cast<MCSymbolRefExpr>(*Op.getExpr());
612 //O << refExp.getSymbol().getName();
613
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800614 SStream_concat0(O, "(");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800615 printOperand(MI, OpNo + 1, O);
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800616 SStream_concat0(O, ")");
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800617 set_mem_access(MI, false);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800618
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800619 //if (refExp.getKind() != MCSymbolRefExpr::VK_None)
620 // O << '@' << MCSymbolRefExpr::getVariantKindName(refExp.getKind());
621}
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800622
Nguyen Anh Quynh2eb37ee2014-03-28 10:38:55 +0800623#ifndef CAPSTONE_DIET
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800624/// stripRegisterPrefix - This method strips the character prefix from a
625/// register name so that only the number is left. Used by for linux asm.
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800626static char *stripRegisterPrefix(char *RegName)
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800627{
628 switch (RegName[0]) {
629 case 'r':
630 case 'f':
631 case 'v':
Nguyen Anh Quynhdd3deec2014-08-15 13:26:12 +0800632 if (RegName[1] == 's')
633 return RegName + 2;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800634 return RegName + 1;
635 case 'c':
636 if (RegName[1] == 'r')
637 return RegName + 2;
638 }
639
640 return RegName;
641}
Nguyen Anh Quynh2eb37ee2014-03-28 10:38:55 +0800642#endif
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800643
644static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
645{
646 MCOperand *Op = MCInst_getOperand(MI, OpNo);
647 if (MCOperand_isReg(Op)) {
648 unsigned reg = MCOperand_getReg(Op);
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800649#ifndef CAPSTONE_DIET
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800650 char *RegName = getRegisterName(reg);
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800651#endif
Nguyen Anh Quynhf1d489b2014-01-05 00:00:05 +0800652 // map to public register
653 reg = PPC_map_register(reg);
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800654#ifndef CAPSTONE_DIET
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800655 // The linux and AIX assembler does not take register prefixes.
Nguyen Anh Quynhf1d489b2014-01-05 00:00:05 +0800656 if (MI->csh->syntax == CS_OPT_SYNTAX_NOREGNAME)
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800657 RegName = stripRegisterPrefix(RegName);
658
Nguyen Anh Quynh7f15f672014-06-16 12:11:50 +0800659 SStream_concat0(O, RegName);
Nguyen Anh Quynhca9a7ab2014-03-04 14:59:54 +0800660#endif
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800661
662 if (MI->csh->detail) {
Nguyen Anh Quynh19b0de32013-12-31 22:40:04 +0800663 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700664 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = reg;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800665 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700666 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG;
667 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg;
668 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800669 }
670 }
671
672 return;
673 }
674
675 if (MCOperand_isImm(Op)) {
Alex Ionescu46018db2014-01-22 09:45:00 -0800676 int32_t imm = (int32_t)MCOperand_getImm(Op);
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800677 if (imm >= 0) {
678 if (imm > HEX_THRESHOLD)
679 SStream_concat(O, "0x%x", imm);
680 else
681 SStream_concat(O, "%u", imm);
682 } else {
Nguyen Anh Quynh2c20a1b2014-05-30 17:00:20 +0800683 if (imm < -HEX_THRESHOLD)
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800684 SStream_concat(O, "-0x%x", -imm);
685 else
686 SStream_concat(O, "-%u", -imm);
687 }
688
689 if (MI->csh->detail) {
Nguyen Anh Quynh19b0de32013-12-31 22:40:04 +0800690 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700691 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = imm;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800692 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700693 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
694 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm;
695 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800696 }
697 }
698 }
699}
700
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800701static void op_addImm(MCInst *MI, int v)
702{
703 if (MI->csh->detail) {
Nguyen Anh Quynh6756edd2014-09-29 23:32:14 +0800704 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
705 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = v;
706 MI->flat_insn->detail->ppc.op_count++;
707 }
708}
709
710static void op_addReg(MCInst *MI, unsigned int reg)
711{
712 if (MI->csh->detail) {
713 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG;
714 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg;
715 MI->flat_insn->detail->ppc.op_count++;
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800716 }
717}
718
kratolpf0221a22014-09-29 10:59:12 +0200719#define CREQ (0)
720#define CRGT (1)
721#define CRLT (2)
722#define CRUN (3)
723
724static int getBICRCond(int bi)
725{
726 return (bi-PPC_CR0EQ) >> 3;
727}
728
729static int getBICR(int bi)
730{
731 return ((bi - PPC_CR0EQ) & 7) + PPC_CR0;
732}
733
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800734static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info)
735{
736#define GETREGCLASS_CONTAIN(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), MCOperand_getReg(MCInst_getOperand(MI, _reg)))
kratolpf0221a22014-09-29 10:59:12 +0200737 SStream ss;
738 const char* opCode;
kratolp73835102014-10-01 11:54:14 +0200739 int decCtr = false, needComma = false;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800740 char *tmp, *AsmMnem, *AsmOps, *c;
741 int OpIdx, PrintMethodIdx;
742 MCRegisterInfo *MRI = (MCRegisterInfo *)info;
kratolpf0221a22014-09-29 10:59:12 +0200743 SStream_Init(&ss);
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800744 switch (MCInst_getOpcode(MI)) {
745 default: return NULL;
746 case PPC_gBC:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800747 opCode = "b%s";
748 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800749 case PPC_gBCA:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800750 opCode = "b%sa";
751 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800752 case PPC_gBCCTR:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800753 opCode = "b%sctr";
754 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800755 case PPC_gBCCTRL:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800756 opCode = "b%sctrl";
757 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800758 case PPC_gBCL:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800759 opCode = "b%sl";
760 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800761 case PPC_gBCLA:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800762 opCode = "b%sla";
763 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800764 case PPC_gBCLR:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800765 opCode = "b%slr";
766 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800767 case PPC_gBCLRL:
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800768 opCode = "b%slrl";
769 break;
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800770 }
771
kratolpf0221a22014-09-29 10:59:12 +0200772 if (MCInst_getNumOperands(MI) == 3 &&
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800773 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
kratolpa3f0aef2014-10-01 11:39:15 +0200774 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 0) &&
775 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 1)) {
776 SStream_concat(&ss, opCode, "dnzf");
kratolp73835102014-10-01 11:54:14 +0200777 decCtr = true;
kratolpf0221a22014-09-29 10:59:12 +0200778 }
779
780 if (MCInst_getNumOperands(MI) == 3 &&
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800781 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
kratolpa3f0aef2014-10-01 11:39:15 +0200782 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 2) &&
783 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 3)) {
784 SStream_concat(&ss, opCode, "dzf");
kratolp73835102014-10-01 11:54:14 +0200785 decCtr = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200786 }
787
788 if (MCInst_getNumOperands(MI) == 3 &&
789 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
790 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 4) &&
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800791 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 7) &&
792 MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
793 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) {
794 int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
795 switch(cr) {
796 case CREQ:
797 SStream_concat(&ss, opCode, "ne");
798 break;
799 case CRGT:
800 SStream_concat(&ss, opCode, "le");
801 break;
802 case CRLT:
803 SStream_concat(&ss, opCode, "ge");
804 break;
805 case CRUN:
806 SStream_concat(&ss, opCode, "ns");
807 break;
808 }
kratolpf0221a22014-09-29 10:59:12 +0200809
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800810 if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 6)
811 SStream_concat0(&ss, "-");
812 if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7)
813 SStream_concat0(&ss, "+");
kratolpa3f0aef2014-10-01 11:39:15 +0200814
kratolp73835102014-10-01 11:54:14 +0200815 decCtr = false;
kratolpa3f0aef2014-10-01 11:39:15 +0200816 }
817
818 if (MCInst_getNumOperands(MI) == 3 &&
819 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
820 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 8) &&
821 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 9)) {
822 SStream_concat(&ss, opCode, "dnzt");
kratolp73835102014-10-01 11:54:14 +0200823 decCtr = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200824 }
825
826 if (MCInst_getNumOperands(MI) == 3 &&
827 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
828 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 10) &&
829 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 11)) {
830 SStream_concat(&ss, opCode, "dzt");
kratolp73835102014-10-01 11:54:14 +0200831 decCtr = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200832 }
833
834 if (MCInst_getNumOperands(MI) == 3 &&
835 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
836 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 12) &&
837 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 15) &&
838 MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
839 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) {
840 int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
841 switch(cr) {
842 case CREQ:
843 SStream_concat(&ss, opCode, "eq");
844 break;
845 case CRGT:
846 SStream_concat(&ss, opCode, "gt");
847 break;
848 case CRLT:
849 SStream_concat(&ss, opCode, "lt");
850 break;
851 case CRUN:
852 SStream_concat(&ss, opCode, "so");
853 break;
854 }
855
856 if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 14)
857 SStream_concat0(&ss, "-");
858 if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 15)
859 SStream_concat0(&ss, "+");
860
kratolp73835102014-10-01 11:54:14 +0200861 decCtr = false;
kratolpa3f0aef2014-10-01 11:39:15 +0200862 }
863
864 if (MCInst_getNumOperands(MI) == 3 &&
865 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
866 ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 16)) {
867 SStream_concat(&ss, opCode, "dnz");
868
869 if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 24)
870 SStream_concat0(&ss, "-");
871 if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 25)
872 SStream_concat0(&ss, "+");
873
kratolp73835102014-10-01 11:54:14 +0200874 needComma = false;
kratolpa3f0aef2014-10-01 11:39:15 +0200875 }
876
877 if (MCInst_getNumOperands(MI) == 3 &&
878 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
879 ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 18)) {
880 SStream_concat(&ss, opCode, "dz");
881
882 if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 26)
883 SStream_concat0(&ss, "-");
884 if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 27)
885 SStream_concat0(&ss, "+");
886
kratolp73835102014-10-01 11:54:14 +0200887 needComma = false;
kratolpf0221a22014-09-29 10:59:12 +0200888 }
889
890 if (MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
kratolpa3f0aef2014-10-01 11:39:15 +0200891 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1) &&
892 MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
893 (MCOperand_getImm(MCInst_getOperand(MI, 0)) < 16)) {
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800894 int cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1)));
kratolp73835102014-10-01 11:54:14 +0200895 op_addReg(MI, PPC_REG_CR0+cr-PPC_CR0);
kratolpa3f0aef2014-10-01 11:39:15 +0200896 if(decCtr) {
kratolp73835102014-10-01 11:54:14 +0200897 needComma = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200898 SStream_concat0(&ss, " ");
899 if(cr > PPC_CR0) {
900 SStream_concat(&ss, "4*cr%d+", cr-PPC_CR0);
901 }
902 cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
903 switch(cr) {
904 case CREQ:
905 SStream_concat0(&ss, "eq");
906 break;
907 case CRGT:
908 SStream_concat0(&ss, "gt");
909 break;
910 case CRLT:
911 SStream_concat0(&ss, "lt");
912 break;
913 case CRUN:
914 SStream_concat0(&ss, "so");
915 break;
916 }
917 } else {
918 if(cr > PPC_CR0) {
Nguyen Anh Quynh7e644f02014-10-01 14:13:48 +0800919 needComma = true;
kratolpa3f0aef2014-10-01 11:39:15 +0200920 SStream_concat(&ss, " cr%d", cr-PPC_CR0);
kratolpa3f0aef2014-10-01 11:39:15 +0200921 }
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800922 }
kratolpf0221a22014-09-29 10:59:12 +0200923 }
924
925 if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800926 MCOperand_getImm(MCInst_getOperand(MI, 2)) != 0) {
Nguyen Anh Quynh7e644f02014-10-01 14:13:48 +0800927 if (needComma)
kratolpf0221a22014-09-29 10:59:12 +0200928 SStream_concat0(&ss, ",");
929 SStream_concat0(&ss, " $\xFF\x03\x01");
930 }
931
932 tmp = cs_strdup(ss.buffer);
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800933 AsmMnem = tmp;
934 for(AsmOps = tmp; *AsmOps; AsmOps++) {
935 if (*AsmOps == ' ' || *AsmOps == '\t') {
936 *AsmOps = '\0';
937 AsmOps++;
938 break;
939 }
940 }
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800941
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800942 SStream_concat0(OS, AsmMnem);
943 if (*AsmOps) {
944 SStream_concat0(OS, "\t");
945 for (c = AsmOps; *c; c++) {
946 if (*c == '$') {
947 c += 1;
948 if (*c == (char)0xff) {
949 c += 1;
950 OpIdx = *c - 1;
951 c += 1;
952 PrintMethodIdx = *c - 1;
953 printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, OS);
954 } else
955 printOperand(MI, *c - 1, OS);
956 } else {
957 SStream_concat(OS, "%c", *c);
958 }
959 }
960 }
Nguyen Anh Quynhca44c482014-09-29 17:58:20 +0800961
Nguyen Anh Quynh9d638392014-09-20 12:02:19 +0800962 return tmp;
963}
964
Nguyen Anh Quynh721d07f2014-09-04 12:03:31 +0800965#define PRINT_ALIAS_INSTR
Nguyen Anh Quynhbacf4c82013-12-30 00:29:32 +0800966#include "PPCGenAsmWriter.inc"
967
Nguyen Anh Quynh8598a212014-05-14 11:26:41 +0800968#endif