/src/capstonev5/arch/Mips/MipsInstPrinter.c
Line  | Count  | Source  | 
1  |  | //===-- MipsInstPrinter.cpp - Convert Mips 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 Mips MCInst to a .s file.  | 
11  |  | //  | 
12  |  | //===----------------------------------------------------------------------===//  | 
13  |  |  | 
14  |  | /* Capstone Disassembly Engine */  | 
15  |  | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */  | 
16  |  |  | 
17  |  | #ifdef CAPSTONE_HAS_MIPS  | 
18  |  |  | 
19  |  | #include <capstone/platform.h>  | 
20  |  | #include <stdlib.h>  | 
21  |  | #include <stdio.h>  // debug  | 
22  |  | #include <string.h>  | 
23  |  |  | 
24  |  | #include "MipsInstPrinter.h"  | 
25  |  | #include "../../MCInst.h"  | 
26  |  | #include "../../utils.h"  | 
27  |  | #include "../../SStream.h"  | 
28  |  | #include "../../MCRegisterInfo.h"  | 
29  |  | #include "MipsMapping.h"  | 
30  |  |  | 
31  |  | #include "MipsInstPrinter.h"  | 
32  |  |  | 
33  |  | static void printUnsignedImm(MCInst *MI, int opNum, SStream *O);  | 
34  |  | static char *printAliasInstr(MCInst *MI, SStream *O, void *info);  | 
35  |  | static char *printAlias(MCInst *MI, SStream *OS);  | 
36  |  |  | 
37  |  | // These enumeration declarations were originally in MipsInstrInfo.h but  | 
38  |  | // had to be moved here to avoid circular dependencies between  | 
39  |  | // LLVMMipsCodeGen and LLVMMipsAsmPrinter.  | 
40  |  |  | 
41  |  | // Mips Condition Codes  | 
42  |  | typedef enum Mips_CondCode { | 
43  |  |   // To be used with float branch True  | 
44  |  |   Mips_FCOND_F,  | 
45  |  |   Mips_FCOND_UN,  | 
46  |  |   Mips_FCOND_OEQ,  | 
47  |  |   Mips_FCOND_UEQ,  | 
48  |  |   Mips_FCOND_OLT,  | 
49  |  |   Mips_FCOND_ULT,  | 
50  |  |   Mips_FCOND_OLE,  | 
51  |  |   Mips_FCOND_ULE,  | 
52  |  |   Mips_FCOND_SF,  | 
53  |  |   Mips_FCOND_NGLE,  | 
54  |  |   Mips_FCOND_SEQ,  | 
55  |  |   Mips_FCOND_NGL,  | 
56  |  |   Mips_FCOND_LT,  | 
57  |  |   Mips_FCOND_NGE,  | 
58  |  |   Mips_FCOND_LE,  | 
59  |  |   Mips_FCOND_NGT,  | 
60  |  |  | 
61  |  |   // To be used with float branch False  | 
62  |  |   // This conditions have the same mnemonic as the  | 
63  |  |   // above ones, but are used with a branch False;  | 
64  |  |   Mips_FCOND_T,  | 
65  |  |   Mips_FCOND_OR,  | 
66  |  |   Mips_FCOND_UNE,  | 
67  |  |   Mips_FCOND_ONE,  | 
68  |  |   Mips_FCOND_UGE,  | 
69  |  |   Mips_FCOND_OGE,  | 
70  |  |   Mips_FCOND_UGT,  | 
71  |  |   Mips_FCOND_OGT,  | 
72  |  |   Mips_FCOND_ST,  | 
73  |  |   Mips_FCOND_GLE,  | 
74  |  |   Mips_FCOND_SNE,  | 
75  |  |   Mips_FCOND_GL,  | 
76  |  |   Mips_FCOND_NLT,  | 
77  |  |   Mips_FCOND_GE,  | 
78  |  |   Mips_FCOND_NLE,  | 
79  |  |   Mips_FCOND_GT  | 
80  |  | } Mips_CondCode;  | 
81  |  |  | 
82  |  | #define GET_INSTRINFO_ENUM  | 
83  |  | #include "MipsGenInstrInfo.inc"  | 
84  |  |  | 
85  |  | static const char *getRegisterName(unsigned RegNo);  | 
86  |  | static void printInstruction(MCInst *MI, SStream *O, const MCRegisterInfo *MRI);  | 
87  |  |  | 
88  |  | static void set_mem_access(MCInst *MI, bool status)  | 
89  | 33.4k  | { | 
90  | 33.4k  |   MI->csh->doing_mem = status;  | 
91  |  |  | 
92  | 33.4k  |   if (MI->csh->detail != CS_OPT_ON)  | 
93  | 0  |     return;  | 
94  |  |  | 
95  | 33.4k  |   if (status) { | 
96  | 16.7k  |     MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_MEM;  | 
97  | 16.7k  |     MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.base = MIPS_REG_INVALID;  | 
98  | 16.7k  |     MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.disp = 0;  | 
99  | 16.7k  |   } else { | 
100  |  |     // done, create the next operand slot  | 
101  | 16.7k  |     MI->flat_insn->detail->mips.op_count++;  | 
102  | 16.7k  |   }  | 
103  | 33.4k  | }  | 
104  |  |  | 
105  |  | static bool isReg(MCInst *MI, unsigned OpNo, unsigned R)  | 
106  | 6.31k  | { | 
107  | 6.31k  |   return (MCOperand_isReg(MCInst_getOperand(MI, OpNo)) &&  | 
108  | 6.31k  |       MCOperand_getReg(MCInst_getOperand(MI, OpNo)) == R);  | 
109  | 6.31k  | }  | 
110  |  |  | 
111  |  | static const char* MipsFCCToString(Mips_CondCode CC)  | 
112  | 0  | { | 
113  | 0  |   switch (CC) { | 
114  | 0  |     default: return 0; // never reach  | 
115  | 0  |     case Mips_FCOND_F:  | 
116  | 0  |     case Mips_FCOND_T:   return "f";  | 
117  | 0  |     case Mips_FCOND_UN:  | 
118  | 0  |     case Mips_FCOND_OR:  return "un";  | 
119  | 0  |     case Mips_FCOND_OEQ:  | 
120  | 0  |     case Mips_FCOND_UNE: return "eq";  | 
121  | 0  |     case Mips_FCOND_UEQ:  | 
122  | 0  |     case Mips_FCOND_ONE: return "ueq";  | 
123  | 0  |     case Mips_FCOND_OLT:  | 
124  | 0  |     case Mips_FCOND_UGE: return "olt";  | 
125  | 0  |     case Mips_FCOND_ULT:  | 
126  | 0  |     case Mips_FCOND_OGE: return "ult";  | 
127  | 0  |     case Mips_FCOND_OLE:  | 
128  | 0  |     case Mips_FCOND_UGT: return "ole";  | 
129  | 0  |     case Mips_FCOND_ULE:  | 
130  | 0  |     case Mips_FCOND_OGT: return "ule";  | 
131  | 0  |     case Mips_FCOND_SF:  | 
132  | 0  |     case Mips_FCOND_ST:  return "sf";  | 
133  | 0  |     case Mips_FCOND_NGLE:  | 
134  | 0  |     case Mips_FCOND_GLE: return "ngle";  | 
135  | 0  |     case Mips_FCOND_SEQ:  | 
136  | 0  |     case Mips_FCOND_SNE: return "seq";  | 
137  | 0  |     case Mips_FCOND_NGL:  | 
138  | 0  |     case Mips_FCOND_GL:  return "ngl";  | 
139  | 0  |     case Mips_FCOND_LT:  | 
140  | 0  |     case Mips_FCOND_NLT: return "lt";  | 
141  | 0  |     case Mips_FCOND_NGE:  | 
142  | 0  |     case Mips_FCOND_GE:  return "nge";  | 
143  | 0  |     case Mips_FCOND_LE:  | 
144  | 0  |     case Mips_FCOND_NLE: return "le";  | 
145  | 0  |     case Mips_FCOND_NGT:  | 
146  | 0  |     case Mips_FCOND_GT:  return "ngt";  | 
147  | 0  |   }  | 
148  | 0  | }  | 
149  |  |  | 
150  |  | static void printRegName(SStream *OS, unsigned RegNo)  | 
151  | 153k  | { | 
152  | 153k  |   SStream_concat(OS, "$%s", getRegisterName(RegNo));  | 
153  | 153k  | }  | 
154  |  |  | 
155  |  | void Mips_printInst(MCInst *MI, SStream *O, void *info)  | 
156  | 90.9k  | { | 
157  | 90.9k  |   char *mnem;  | 
158  |  |  | 
159  | 90.9k  |   switch (MCInst_getOpcode(MI)) { | 
160  | 90.9k  |     default: break;  | 
161  | 90.9k  |     case Mips_Save16:  | 
162  | 0  |     case Mips_SaveX16:  | 
163  | 0  |     case Mips_Restore16:  | 
164  | 0  |     case Mips_RestoreX16:  | 
165  | 0  |       return;  | 
166  | 90.9k  |   }  | 
167  |  |  | 
168  |  |   // Try to print any aliases first.  | 
169  | 90.9k  |   mnem = printAliasInstr(MI, O, info);  | 
170  | 90.9k  |   if (!mnem) { | 
171  | 83.6k  |     mnem = printAlias(MI, O);  | 
172  | 83.6k  |     if (!mnem) { | 
173  | 81.9k  |       printInstruction(MI, O, NULL);  | 
174  | 81.9k  |     }  | 
175  | 83.6k  |   }  | 
176  |  |  | 
177  | 90.9k  |   if (mnem) { | 
178  |  |     // fixup instruction id due to the change in alias instruction  | 
179  | 9.02k  |     MCInst_setOpcodePub(MI, Mips_map_insn(mnem));  | 
180  | 9.02k  |     cs_mem_free(mnem);  | 
181  | 9.02k  |   }  | 
182  | 90.9k  | }  | 
183  |  |  | 
184  |  | static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
185  | 200k  | { | 
186  | 200k  |   MCOperand *Op;  | 
187  |  |  | 
188  | 200k  |   if (OpNo >= MI->size)  | 
189  | 0  |     return;  | 
190  |  |  | 
191  | 200k  |   Op = MCInst_getOperand(MI, OpNo);  | 
192  | 200k  |   if (MCOperand_isReg(Op)) { | 
193  | 148k  |     unsigned int reg = MCOperand_getReg(Op);  | 
194  | 148k  |     printRegName(O, reg);  | 
195  | 148k  |     reg = Mips_map_register(reg);  | 
196  | 148k  |     if (MI->csh->detail) { | 
197  | 148k  |       if (MI->csh->doing_mem) { | 
198  | 16.7k  |         MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.base = reg;  | 
199  | 132k  |       } else { | 
200  | 132k  |         MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_REG;  | 
201  | 132k  |         MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].reg = reg;  | 
202  | 132k  |         MI->flat_insn->detail->mips.op_count++;  | 
203  | 132k  |       }  | 
204  | 148k  |     }  | 
205  | 148k  |   } else if (MCOperand_isImm(Op)) { | 
206  | 51.4k  |     int64_t imm = MCOperand_getImm(Op);  | 
207  | 51.4k  |     if (MI->csh->doing_mem) { | 
208  | 16.7k  |       if (imm) { // only print Imm offset if it is not 0 | 
209  | 16.1k  |         printInt64(O, imm);  | 
210  | 16.1k  |       }  | 
211  | 16.7k  |       if (MI->csh->detail)  | 
212  | 16.7k  |         MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.disp = imm;  | 
213  | 34.7k  |     } else { | 
214  | 34.7k  |       printInt64(O, imm);  | 
215  |  |  | 
216  | 34.7k  |       if (MI->csh->detail) { | 
217  | 34.7k  |         MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;  | 
218  | 34.7k  |         MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = imm;  | 
219  | 34.7k  |         MI->flat_insn->detail->mips.op_count++;  | 
220  | 34.7k  |       }  | 
221  | 34.7k  |     }  | 
222  | 51.4k  |   }  | 
223  | 200k  | }  | 
224  |  |  | 
225  |  | static void printUnsignedImm(MCInst *MI, int opNum, SStream *O)  | 
226  | 13.9k  | { | 
227  | 13.9k  |   MCOperand *MO = MCInst_getOperand(MI, opNum);  | 
228  | 13.9k  |   if (MCOperand_isImm(MO)) { | 
229  | 13.9k  |     int64_t imm = MCOperand_getImm(MO);  | 
230  | 13.9k  |     printInt64(O, imm);  | 
231  |  |  | 
232  | 13.9k  |     if (MI->csh->detail) { | 
233  | 13.9k  |       MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;  | 
234  | 13.9k  |       MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = (unsigned short int)imm;  | 
235  | 13.9k  |       MI->flat_insn->detail->mips.op_count++;  | 
236  | 13.9k  |     }  | 
237  | 13.9k  |   } else  | 
238  | 0  |     printOperand(MI, opNum, O);  | 
239  | 13.9k  | }  | 
240  |  |  | 
241  |  | static void printUnsignedImm8(MCInst *MI, int opNum, SStream *O)  | 
242  | 3.93k  | { | 
243  | 3.93k  |   MCOperand *MO = MCInst_getOperand(MI, opNum);  | 
244  | 3.93k  |   if (MCOperand_isImm(MO)) { | 
245  | 3.93k  |     uint8_t imm = (uint8_t)MCOperand_getImm(MO);  | 
246  | 3.93k  |     if (imm > HEX_THRESHOLD)  | 
247  | 972  |       SStream_concat(O, "0x%x", imm);  | 
248  | 2.96k  |     else  | 
249  | 2.96k  |       SStream_concat(O, "%u", imm);  | 
250  | 3.93k  |     if (MI->csh->detail) { | 
251  | 3.93k  |       MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;  | 
252  | 3.93k  |       MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = imm;  | 
253  | 3.93k  |       MI->flat_insn->detail->mips.op_count++;  | 
254  | 3.93k  |     }  | 
255  | 3.93k  |   } else  | 
256  | 0  |     printOperand(MI, opNum, O);  | 
257  | 3.93k  | }  | 
258  |  |  | 
259  |  | static void printMemOperand(MCInst *MI, int opNum, SStream *O)  | 
260  | 16.7k  | { | 
261  |  |   // Load/Store memory operands -- imm($reg)  | 
262  |  |   // If PIC target the target is loaded as the  | 
263  |  |   // pattern lw $25,%call16($28)  | 
264  |  |  | 
265  |  |   // opNum can be invalid if instruction had reglist as operand.  | 
266  |  |   // MemOperand is always last operand of instruction (base + offset).  | 
267  | 16.7k  |   switch (MCInst_getOpcode(MI)) { | 
268  | 15.6k  |     default:  | 
269  | 15.6k  |       break;  | 
270  | 15.6k  |     case Mips_SWM32_MM:  | 
271  | 503  |     case Mips_LWM32_MM:  | 
272  | 741  |     case Mips_SWM16_MM:  | 
273  | 1.03k  |     case Mips_LWM16_MM:  | 
274  | 1.03k  |       opNum = MCInst_getNumOperands(MI) - 2;  | 
275  | 1.03k  |       break;  | 
276  | 16.7k  |   }  | 
277  |  |  | 
278  | 16.7k  |   set_mem_access(MI, true);  | 
279  | 16.7k  |   printOperand(MI, opNum + 1, O);  | 
280  | 16.7k  |   SStream_concat0(O, "("); | 
281  | 16.7k  |   printOperand(MI, opNum, O);  | 
282  | 16.7k  |   SStream_concat0(O, ")");  | 
283  | 16.7k  |   set_mem_access(MI, false);  | 
284  | 16.7k  | }  | 
285  |  |  | 
286  |  | // TODO???  | 
287  |  | static void printMemOperandEA(MCInst *MI, int opNum, SStream *O)  | 
288  | 0  | { | 
289  |  |   // when using stack locations for not load/store instructions  | 
290  |  |   // print the same way as all normal 3 operand instructions.  | 
291  | 0  |   printOperand(MI, opNum, O);  | 
292  | 0  |   SStream_concat0(O, ", ");  | 
293  | 0  |   printOperand(MI, opNum + 1, O);  | 
294  | 0  |   return;  | 
295  | 0  | }  | 
296  |  |  | 
297  |  | static void printFCCOperand(MCInst *MI, int opNum, SStream *O)  | 
298  | 0  | { | 
299  | 0  |   MCOperand *MO = MCInst_getOperand(MI, opNum);  | 
300  | 0  |   SStream_concat0(O, MipsFCCToString((Mips_CondCode)MCOperand_getImm(MO)));  | 
301  | 0  | }  | 
302  |  |  | 
303  |  | static void printRegisterPair(MCInst *MI, int opNum, SStream *O)  | 
304  | 287  | { | 
305  | 287  |   printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, opNum)));  | 
306  | 287  | }  | 
307  |  |  | 
308  |  | static char *printAlias1(const char *Str, MCInst *MI, unsigned OpNo, SStream *OS)  | 
309  | 1.72k  | { | 
310  | 1.72k  |   SStream_concat(OS, "%s\t", Str);  | 
311  | 1.72k  |   printOperand(MI, OpNo, OS);  | 
312  | 1.72k  |   return cs_strdup(Str);  | 
313  | 1.72k  | }  | 
314  |  |  | 
315  |  | static char *printAlias2(const char *Str, MCInst *MI,  | 
316  |  |     unsigned OpNo0, unsigned OpNo1, SStream *OS)  | 
317  | 1.07k  | { | 
318  | 1.07k  |   char *tmp;  | 
319  |  |  | 
320  | 1.07k  |   tmp = printAlias1(Str, MI, OpNo0, OS);  | 
321  | 1.07k  |   SStream_concat0(OS, ", ");  | 
322  | 1.07k  |   printOperand(MI, OpNo1, OS);  | 
323  |  |  | 
324  | 1.07k  |   return tmp;  | 
325  | 1.07k  | }  | 
326  |  |  | 
327  |  | #define GET_REGINFO_ENUM  | 
328  |  | #include "MipsGenRegisterInfo.inc"  | 
329  |  |  | 
330  |  | static char *printAlias(MCInst *MI, SStream *OS)  | 
331  | 83.6k  | { | 
332  | 83.6k  |   switch (MCInst_getOpcode(MI)) { | 
333  | 1.33k  |     case Mips_BEQ:  | 
334  | 1.57k  |     case Mips_BEQ_MM:  | 
335  |  |       // beq $zero, $zero, $L2 => b $L2  | 
336  |  |       // beq $r0, $zero, $L2 => beqz $r0, $L2  | 
337  | 1.57k  |       if (isReg(MI, 0, Mips_ZERO) && isReg(MI, 1, Mips_ZERO))  | 
338  | 379  |         return printAlias1("b", MI, 2, OS); | 
339  | 1.19k  |       if (isReg(MI, 1, Mips_ZERO))  | 
340  | 217  |         return printAlias2("beqz", MI, 0, 2, OS); | 
341  | 977  |       return NULL;  | 
342  | 0  |     case Mips_BEQ64:  | 
343  |  |       // beq $r0, $zero, $L2 => beqz $r0, $L2  | 
344  | 0  |       if (isReg(MI, 1, Mips_ZERO_64))  | 
345  | 0  |         return printAlias2("beqz", MI, 0, 2, OS); | 
346  | 0  |       return NULL;  | 
347  | 945  |     case Mips_BNE:  | 
348  |  |       // bne $r0, $zero, $L2 => bnez $r0, $L2  | 
349  | 945  |       if (isReg(MI, 1, Mips_ZERO))  | 
350  | 204  |         return printAlias2("bnez", MI, 0, 2, OS); | 
351  | 741  |       return NULL;  | 
352  | 0  |     case Mips_BNE64:  | 
353  |  |       // bne $r0, $zero, $L2 => bnez $r0, $L2  | 
354  | 0  |       if (isReg(MI, 1, Mips_ZERO_64))  | 
355  | 0  |         return printAlias2("bnez", MI, 0, 2, OS); | 
356  | 0  |       return NULL;  | 
357  | 145  |     case Mips_BGEZAL:  | 
358  |  |       // bgezal $zero, $L1 => bal $L1  | 
359  | 145  |       if (isReg(MI, 0, Mips_ZERO))  | 
360  | 66  |         return printAlias1("bal", MI, 1, OS); | 
361  | 79  |       return NULL;  | 
362  | 207  |     case Mips_BC1T:  | 
363  |  |       // bc1t $fcc0, $L1 => bc1t $L1  | 
364  | 207  |       if (isReg(MI, 0, Mips_FCC0))  | 
365  | 0  |         return printAlias1("bc1t", MI, 1, OS); | 
366  | 207  |       return NULL;  | 
367  | 207  |     case Mips_BC1F:  | 
368  |  |       // bc1f $fcc0, $L1 => bc1f $L1  | 
369  | 207  |       if (isReg(MI, 0, Mips_FCC0))  | 
370  | 0  |         return printAlias1("bc1f", MI, 1, OS); | 
371  | 207  |       return NULL;  | 
372  | 270  |     case Mips_JALR:  | 
373  |  |       // jalr $ra, $r1 => jalr $r1  | 
374  | 270  |       if (isReg(MI, 0, Mips_RA))  | 
375  | 202  |         return printAlias1("jalr", MI, 1, OS); | 
376  | 68  |       return NULL;  | 
377  | 0  |     case Mips_JALR64:  | 
378  |  |       // jalr $ra, $r1 => jalr $r1  | 
379  | 0  |       if (isReg(MI, 0, Mips_RA_64))  | 
380  | 0  |         return printAlias1("jalr", MI, 1, OS); | 
381  | 0  |       return NULL;  | 
382  | 71  |     case Mips_NOR:  | 
383  | 867  |     case Mips_NOR_MM:  | 
384  |  |       // nor $r0, $r1, $zero => not $r0, $r1  | 
385  | 867  |       if (isReg(MI, 2, Mips_ZERO))  | 
386  | 454  |         return printAlias2("not", MI, 0, 1, OS); | 
387  | 413  |       return NULL;  | 
388  | 0  |     case Mips_NOR64:  | 
389  |  |       // nor $r0, $r1, $zero => not $r0, $r1  | 
390  | 0  |       if (isReg(MI, 2, Mips_ZERO_64))  | 
391  | 0  |         return printAlias2("not", MI, 0, 1, OS); | 
392  | 0  |       return NULL;  | 
393  | 276  |     case Mips_OR:  | 
394  |  |       // or $r0, $r1, $zero => move $r0, $r1  | 
395  | 276  |       if (isReg(MI, 2, Mips_ZERO))  | 
396  | 198  |         return printAlias2("move", MI, 0, 1, OS); | 
397  | 78  |       return NULL;  | 
398  | 79.1k  |     default: return NULL;  | 
399  | 83.6k  |   }  | 
400  | 83.6k  | }  | 
401  |  |  | 
402  |  | static void printRegisterList(MCInst *MI, int opNum, SStream *O)  | 
403  | 1.30k  | { | 
404  | 1.30k  |   int i, e, reg;  | 
405  |  |  | 
406  |  |   // - 2 because register List is always first operand of instruction and it is  | 
407  |  |   // always followed by memory operand (base + offset).  | 
408  | 5.72k  |   for (i = opNum, e = MCInst_getNumOperands(MI) - 2; i != e; ++i) { | 
409  | 4.42k  |     if (i != opNum)  | 
410  | 3.12k  |       SStream_concat0(O, ", ");  | 
411  | 4.42k  |     reg = MCOperand_getReg(MCInst_getOperand(MI, i));  | 
412  | 4.42k  |     printRegName(O, reg);  | 
413  | 4.42k  |     if (MI->csh->detail) { | 
414  | 4.42k  |       MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_REG;  | 
415  | 4.42k  |       MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].reg = reg;  | 
416  | 4.42k  |       MI->flat_insn->detail->mips.op_count++;  | 
417  | 4.42k  |     }  | 
418  | 4.42k  |   }  | 
419  | 1.30k  | }  | 
420  |  |  | 
421  |  | #define PRINT_ALIAS_INSTR  | 
422  |  | #include "MipsGenAsmWriter.inc"  | 
423  |  |  | 
424  |  | #endif  |