capstone/arch/PowerPC/PPCInstPrinter.c

756 lines
21 KiB
C

/* Capstone Disassembly Engine, http://www.capstone-engine.org */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2022, */
/* Rot127 <unisono@quyllur.org> 2022-2023 */
/* Automatically translated source file from LLVM. */
/* LLVM-commit: <commit> */
/* LLVM-tag: <tag> */
/* Only small edits allowed. */
/* For multiple similar edits, please create a Patch for the translator. */
/* Capstone's C++ file translator: */
/* https://github.com/capstone-engine/capstone/tree/next/suite/auto-sync */
//===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This class prints an PPC MCInst to a .s file.
//
//===----------------------------------------------------------------------===//
#include <capstone/platform.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../LEB128.h"
#include "../../Mapping.h"
#include "../../MCInst.h"
#include "../../MCInstPrinter.h"
#include "../../MCInstrDesc.h"
#include "../../MCRegisterInfo.h"
#include "PPCInstrInfo.h"
#include "PPCInstPrinter.h"
#include "PPCLinkage.h"
#include "PPCMCTargetDesc.h"
#include "PPCMapping.h"
#include "PPCPredicates.h"
#include "PPCRegisterInfo.h"
#define CONCAT(a, b) CONCAT_(a, b)
#define CONCAT_(a, b) a##_##b
#define DEBUG_TYPE "asm-printer"
// Static function declarations. These are functions which have the same identifiers
// over all architectures. Therefor they need to be static.
#ifndef CAPSTONE_DIET
static void printCustomAliasOperand(MCInst *MI, uint64_t Address,
unsigned OpIdx, unsigned PrintMethodIdx,
SStream *O);
#endif
static void printOperand(MCInst *MI, unsigned OpNo, SStream *O);
static void printPredicateOperand(MCInst *MI, unsigned OpNo, SStream *O,
const char *Modifier);
static void printInst(MCInst *MI, uint64_t Address, const char *Annot,
SStream *O);
#define PRINT_ALIAS_INSTR
#include "PPCGenAsmWriter.inc"
static void printInst(MCInst *MI, uint64_t Address, const char *Annot,
SStream *O)
{
bool isAlias = false;
bool useAliasDetails = false;
// Customize printing of the addis instruction on AIX. When an operand is a
// symbol reference, the instruction syntax is changed to look like a load
// operation, i.e:
// Transform: addis $rD, $rA, $src --> addis $rD, $src($rA).
if (PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs) &&
(MCInst_getOpcode(MI) == PPC_ADDIS8 ||
MCInst_getOpcode(MI) == PPC_ADDIS) &&
MCOperand_isExpr(MCInst_getOperand(MI, (2)))) {
SStream_concat0(O, "\taddis ");
printOperand(MI, 0, O);
SStream_concat0(O, ", ");
printOperand(MI, 2, O);
SStream_concat0(O, "(");
printOperand(MI, 1, O);
SStream_concat0(O, ")");
return;
}
// Check if the last operand is an expression with the variant kind
// VK_PPC_PCREL_OPT. If this is the case then this is a linker optimization
// relocation and the .reloc directive needs to be added.
unsigned LastOp = MCInst_getNumOperands(MI) - 1;
if (MCInst_getNumOperands(MI) > 1) {
MCOperand *Operand = MCInst_getOperand(MI, (LastOp));
if (MCOperand_isExpr(Operand)) {
assert(0 && "Expressions not supported.");
}
}
// Check for slwi/srwi mnemonics.
if (MCInst_getOpcode(MI) == PPC_RLWINM) {
unsigned char SH = MCOperand_getImm(MCInst_getOperand(MI, (2)));
unsigned char MB = MCOperand_getImm(MCInst_getOperand(MI, (3)));
unsigned char ME = MCOperand_getImm(MCInst_getOperand(MI, (4)));
bool useSubstituteMnemonic = false;
if (SH <= 31 && MB == 0 && ME == (31 - SH)) {
SStream_concat0(O, "slwi ");
useSubstituteMnemonic = true;
}
if (SH <= 31 && MB == (32 - SH) && ME == 31) {
SStream_concat0(O, "srwi ");
useSubstituteMnemonic = true;
SH = 32 - SH;
}
useAliasDetails |= map_use_alias_details(MI);
map_set_fill_detail_ops(MI, useAliasDetails &&
useSubstituteMnemonic);
if (useSubstituteMnemonic) {
isAlias |= true;
MCInst_setIsAlias(MI, isAlias);
printOperand(MI, 0, O);
SStream_concat0(O, ", ");
printOperand(MI, 1, O);
SStream_concat(O, "%s", ", ");
printUInt32(O, (unsigned int)SH);
PPC_insert_detail_op_imm_at(MI, 2, SH, CS_AC_READ);
if (useAliasDetails)
return;
}
}
if (MCInst_getOpcode(MI) == PPC_RLDICR ||
MCInst_getOpcode(MI) == PPC_RLDICR_32) {
unsigned char SH = MCOperand_getImm(MCInst_getOperand(MI, (2)));
unsigned char ME = MCOperand_getImm(MCInst_getOperand(MI, (3)));
useAliasDetails |= map_use_alias_details(MI);
map_set_fill_detail_ops(MI, useAliasDetails && 63 - SH == ME);
// rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
if (63 - SH == ME) {
isAlias |= true;
MCInst_setIsAlias(MI, isAlias);
SStream_concat0(O, "sldi ");
printOperand(MI, 0, O);
SStream_concat0(O, ", ");
printOperand(MI, 1, O);
SStream_concat(O, "%s", ", ");
printUInt32(O, (unsigned int)SH);
PPC_insert_detail_op_imm_at(MI, 2, SH, CS_AC_READ);
if (useAliasDetails)
return;
}
}
// dcbt[st] is printed manually here because:
// 1. The assembly syntax is different between embedded and server targets
// 2. We must print the short mnemonics for TH == 0 because the
// embedded/server syntax default will not be stable across assemblers
// The syntax for dcbt is:
// dcbt ra, rb, th [server]
// dcbt th, ra, rb [embedded]
// where th can be omitted when it is 0. dcbtst is the same.
// On AIX, only emit the extended mnemonics for dcbt and dcbtst if
// the "modern assembler" is available.
if ((MCInst_getOpcode(MI) == PPC_DCBT ||
MCInst_getOpcode(MI) == PPC_DCBTST) &&
(!PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))) {
unsigned char TH = MCOperand_getImm(MCInst_getOperand(MI, (0)));
SStream_concat0(O, "\tdcbt");
if (MCInst_getOpcode(MI) == PPC_DCBTST)
SStream_concat0(O, "st");
if (TH == 16)
SStream_concat0(O, "t");
SStream_concat0(O, " ");
bool IsBookE =
PPC_getFeatureBits(MI->csh->mode, PPC_FeatureBookE);
if (IsBookE && TH != 0 && TH != 16) {
SStream_concat(O, "%s", (unsigned int)TH);
SStream_concat0(O, ", ");
PPC_set_detail_op_imm(MI, 0, TH);
}
set_mem_access(MI, true);
printOperand(MI, 1, O);
SStream_concat0(O, ", ");
printOperand(MI, 2, O);
set_mem_access(MI, false);
if (!IsBookE && TH != 0 && TH != 16) {
SStream_concat(O, "%s", ", ");
printUInt32(O, (unsigned int)TH);
PPC_set_detail_op_imm(MI, 0, TH);
}
return;
}
if (MCInst_getOpcode(MI) == PPC_DCBF) {
unsigned char L = MCOperand_getImm(MCInst_getOperand(MI, (0)));
if (!L || L == 1 || L == 3 || L == 4 || L == 6) {
SStream_concat0(O, "\tdcb");
if (L != 6)
SStream_concat0(O, "f");
if (L == 1)
SStream_concat0(O, "l");
if (L == 3)
SStream_concat0(O, "lp");
if (L == 4)
SStream_concat0(O, "ps");
if (L == 6)
SStream_concat0(O, "stps");
SStream_concat0(O, " ");
printOperand(MI, 1, O);
SStream_concat0(O, ", ");
printOperand(MI, 2, O);
return;
}
}
// isAlias/useAliasDetails could have been set before.
useAliasDetails |= map_use_alias_details(MI);
map_set_fill_detail_ops(MI, useAliasDetails);
isAlias |= printAliasInstr(MI, Address, O);
MCInst_setIsAlias(MI, isAlias);
if (!isAlias || !useAliasDetails) {
map_set_fill_detail_ops(MI, true);
if (isAlias)
SStream_Close(O);
printInstruction(MI, Address, O);
if (isAlias)
SStream_Open(O);
}
}
void printPredicateOperand(MCInst *MI, unsigned OpNo, SStream *O,
const char *Modifier)
{
add_cs_detail(MI, PPC_OP_GROUP_PredicateOperand, OpNo, Modifier);
unsigned Code = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
if (strcmp(Modifier, "cc") == 0) {
switch ((PPC_Predicate)Code) {
default:
assert(0 && "Invalid predicate code");
case PPC_PRED_LT_MINUS:
case PPC_PRED_LT_PLUS:
case PPC_PRED_LT:
SStream_concat0(O, "lt");
return;
case PPC_PRED_LE_MINUS:
case PPC_PRED_LE_PLUS:
case PPC_PRED_LE:
SStream_concat0(O, "le");
return;
case PPC_PRED_EQ_MINUS:
case PPC_PRED_EQ_PLUS:
case PPC_PRED_EQ:
SStream_concat0(O, "eq");
return;
case PPC_PRED_GE_MINUS:
case PPC_PRED_GE_PLUS:
case PPC_PRED_GE:
SStream_concat0(O, "ge");
return;
case PPC_PRED_GT_MINUS:
case PPC_PRED_GT_PLUS:
case PPC_PRED_GT:
SStream_concat0(O, "gt");
return;
case PPC_PRED_NE_MINUS:
case PPC_PRED_NE_PLUS:
case PPC_PRED_NE:
SStream_concat0(O, "ne");
return;
case PPC_PRED_UN_MINUS:
case PPC_PRED_UN_PLUS:
case PPC_PRED_UN:
SStream_concat0(O, "un");
return;
case PPC_PRED_NU_MINUS:
case PPC_PRED_NU_PLUS:
case PPC_PRED_NU:
SStream_concat0(O, "nu");
return;
case PPC_PRED_BIT_SET:
case PPC_PRED_BIT_UNSET:
assert(0 && "Invalid use of bit predicate code");
}
assert(0 && "Invalid predicate code");
}
if (strcmp(Modifier, "pm") == 0) {
switch ((PPC_Predicate)Code) {
default:
assert(0 && "Invalid predicate code");
case PPC_PRED_LT:
case PPC_PRED_LE:
case PPC_PRED_EQ:
case PPC_PRED_GE:
case PPC_PRED_GT:
case PPC_PRED_NE:
case PPC_PRED_UN:
case PPC_PRED_NU:
return;
case PPC_PRED_LT_MINUS:
case PPC_PRED_LE_MINUS:
case PPC_PRED_EQ_MINUS:
case PPC_PRED_GE_MINUS:
case PPC_PRED_GT_MINUS:
case PPC_PRED_NE_MINUS:
case PPC_PRED_UN_MINUS:
case PPC_PRED_NU_MINUS:
SStream_concat0(O, "-");
return;
case PPC_PRED_LT_PLUS:
case PPC_PRED_LE_PLUS:
case PPC_PRED_EQ_PLUS:
case PPC_PRED_GE_PLUS:
case PPC_PRED_GT_PLUS:
case PPC_PRED_NE_PLUS:
case PPC_PRED_UN_PLUS:
case PPC_PRED_NU_PLUS:
SStream_concat0(O, "+");
return;
case PPC_PRED_BIT_SET:
case PPC_PRED_BIT_UNSET:
assert(0 && "Invalid use of bit predicate code");
}
assert(0 && "Invalid predicate code");
}
printOperand(MI, OpNo + 1, O);
}
void printATBitsAsHint(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_ATBitsAsHint, OpNo);
unsigned Code = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
if (Code == 2)
SStream_concat0(O, "-");
else if (Code == 3)
SStream_concat0(O, "+");
}
void printU1ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U1ImmOperand, OpNo);
unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U2ImmOperand, OpNo);
unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
void printU3ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U3ImmOperand, OpNo);
unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U4ImmOperand, OpNo);
unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_S5ImmOperand, OpNo);
int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
Value = SignExtend32((Value), 5);
printInt32(O, (int)Value);
}
void printImmZeroOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_ImmZeroOperand, OpNo);
unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U5ImmOperand, OpNo);
unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U6ImmOperand, OpNo);
unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
void printU7ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U7ImmOperand, OpNo);
unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
// Operands of BUILD_VECTOR are signed and we use this to print operands
// of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and
// print as unsigned.
void printU8ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U8ImmOperand, OpNo);
unsigned char Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned int)Value);
}
void printU10ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U10ImmOperand, OpNo);
unsigned short Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned short)Value);
}
void printU12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U12ImmOperand, OpNo);
unsigned short Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printUInt32(O, (unsigned short)Value);
}
void printS12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_S12ImmOperand, OpNo);
if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
int Imm = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
Imm = SignExtend32(Imm, 12);
printInt32(O, Imm);
} else
printOperand(MI, OpNo, O);
}
void printMemRegImmPS(MCInst *MI, unsigned OpNo, SStream *O)
{
set_mem_access(MI, true);
printS12ImmOperand(MI, OpNo, O);
SStream_concat0(O, "(");
printOperand(MI, OpNo + 1, O);
SStream_concat0(O, ")");
set_mem_access(MI, false);
}
void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_S16ImmOperand, OpNo);
if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo))))
printInt32(O, (short)MCOperand_getImm(
MCInst_getOperand(MI, (OpNo))));
else
printOperand(MI, OpNo, O);
}
void printS34ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_S34ImmOperand, OpNo);
if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) {
long long Value =
MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
printInt64(O, (long long)Value);
} else
printOperand(MI, OpNo, O);
}
void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_U16ImmOperand, OpNo);
if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo))))
printUInt32(O, (unsigned short)MCOperand_getImm(
MCInst_getOperand(MI, (OpNo))));
else
printOperand(MI, OpNo, O);
}
void printBranchOperand(MCInst *MI, uint64_t Address, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_BranchOperand, OpNo);
if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) {
printOperand(MI, OpNo, O);
return;
}
int32_t Imm = SignExtend32(
((unsigned)MCOperand_getImm(MCInst_getOperand(MI, (OpNo)))
<< 2),
32);
if (!MI->csh->PrintBranchImmNotAsAddress) {
uint64_t Target = Address + Imm;
if (!IS_64BIT(MI->csh->mode))
Target &= 0xffffffff;
printUInt64(O, (Target));
} else {
// Branches can take an immediate operand. This is used by the branch
// selection pass to print, for example `.+8` (for ELF) or `$+8` (for
// AIX) to express an eight byte displacement from the program counter.
if (!PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))
SStream_concat0(O, ".");
else
SStream_concat0(O, "$");
if (Imm >= 0)
SStream_concat0(O, "+");
printInt32(O, Imm);
}
}
void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_AbsBranchOperand, OpNo);
if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) {
printOperand(MI, OpNo, O);
return;
}
printInt32(O, SignExtend32(((unsigned)MCOperand_getImm(
MCInst_getOperand(MI, (OpNo)))
<< 2),
32));
}
void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_crbitm, OpNo);
unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, (OpNo)));
unsigned RegNo;
switch (CCReg) {
default:
assert(0 && "Unknown CR register");
case PPC_CR0:
RegNo = 0;
break;
case PPC_CR1:
RegNo = 1;
break;
case PPC_CR2:
RegNo = 2;
break;
case PPC_CR3:
RegNo = 3;
break;
case PPC_CR4:
RegNo = 4;
break;
case PPC_CR5:
RegNo = 5;
break;
case PPC_CR6:
RegNo = 6;
break;
case PPC_CR7:
RegNo = 7;
break;
}
printUInt32(O, (0x80 >> RegNo));
}
void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O)
{
set_mem_access(MI, true);
add_cs_detail(MI, PPC_OP_GROUP_MemRegImm, OpNo);
printS16ImmOperand(MI, OpNo, O);
SStream_concat0(O, "(");
if (MCOperand_getReg(MCInst_getOperand(MI, (OpNo + 1))) == PPC_R0)
SStream_concat0(O, "0");
else
printOperand(MI, OpNo + 1, O);
SStream_concat0(O, ")");
set_mem_access(MI, false);
}
void printMemRegImmHash(MCInst *MI, unsigned OpNo, SStream *O)
{
set_mem_access(MI, true);
add_cs_detail(MI, PPC_OP_GROUP_MemRegImmHash, OpNo);
printInt32(O, MCOperand_getImm(MCInst_getOperand(MI, (OpNo))));
SStream_concat0(O, "(");
printOperand(MI, OpNo + 1, O);
SStream_concat0(O, ")");
set_mem_access(MI, false);
}
void printMemRegImm34PCRel(MCInst *MI, unsigned OpNo, SStream *O)
{
set_mem_access(MI, true);
add_cs_detail(MI, PPC_OP_GROUP_MemRegImm34PCRel, OpNo);
printS34ImmOperand(MI, OpNo, O);
SStream_concat0(O, "(");
printImmZeroOperand(MI, OpNo + 1, O);
SStream_concat0(O, ")");
set_mem_access(MI, false);
}
void printMemRegImm34(MCInst *MI, unsigned OpNo, SStream *O)
{
set_mem_access(MI, true);
add_cs_detail(MI, PPC_OP_GROUP_MemRegImm34, OpNo);
printS34ImmOperand(MI, OpNo, O);
SStream_concat0(O, "(");
printOperand(MI, OpNo + 1, O);
SStream_concat0(O, ")");
set_mem_access(MI, false);
}
void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O)
{
set_mem_access(MI, true);
add_cs_detail(MI, PPC_OP_GROUP_MemRegReg, OpNo);
// When used as the base register, r0 reads constant zero rather than
// the value contained in the register. For this reason, the darwin
// assembler requires that we print r0 as 0 (no r) when used as the base.
if (MCOperand_getReg(MCInst_getOperand(MI, (OpNo))) == PPC_R0)
SStream_concat0(O, "0");
else
printOperand(MI, OpNo, O);
SStream_concat0(O, ", ");
printOperand(MI, OpNo + 1, O);
set_mem_access(MI, false);
}
void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_TLSCall, OpNo);
// Expression logic removed.
set_mem_access(MI, true);
SStream_concat0(O, "(");
printOperand(MI, OpNo + 1, O);
SStream_concat0(O, ")");
set_mem_access(MI, false);
}
/// showRegistersWithPercentPrefix - Check if this register name should be
/// printed with a percentage symbol as prefix.
bool showRegistersWithPercentPrefix(const MCInst *MI, const char *RegName)
{
if ((MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME) ||
!(MI->csh->syntax & CS_OPT_SYNTAX_PERCENT) ||
PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))
return false;
switch (RegName[0]) {
default:
return false;
case 'r':
case 'f':
case 'q':
case 'v':
case 'c':
return true;
}
}
/// getVerboseConditionalRegName - This method expands the condition register
/// when requested explicitly or targeting Darwin.
const char *getVerboseConditionRegName(const MCInst *MI, unsigned RegNum,
unsigned RegEncoding)
{
if (MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME)
return NULL;
if (RegNum < PPC_CR0EQ || RegNum > PPC_CR7UN)
return NULL;
const char *CRBits[] = {
"lt", "gt", "eq", "un", "4*cr1+lt",
"4*cr1+gt", "4*cr1+eq", "4*cr1+un", "4*cr2+lt", "4*cr2+gt",
"4*cr2+eq", "4*cr2+un", "4*cr3+lt", "4*cr3+gt", "4*cr3+eq",
"4*cr3+un", "4*cr4+lt", "4*cr4+gt", "4*cr4+eq", "4*cr4+un",
"4*cr5+lt", "4*cr5+gt", "4*cr5+eq", "4*cr5+un", "4*cr6+lt",
"4*cr6+gt", "4*cr6+eq", "4*cr6+un", "4*cr7+lt", "4*cr7+gt",
"4*cr7+eq", "4*cr7+un"
};
return CRBits[RegEncoding];
}
// showRegistersWithPrefix - This method determines whether registers
// should be number-only or include the prefix.
bool showRegistersWithPrefix(const MCInst *MI)
{
return !(MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME);
}
void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
{
add_cs_detail(MI, PPC_OP_GROUP_Operand, OpNo);
MCOperand *Op = MCInst_getOperand(MI, (OpNo));
if (MCOperand_isReg(Op)) {
unsigned Reg = MCOperand_getReg(Op);
if (!MI->csh->ShowVSRNumsAsVR)
Reg = PPCInstrInfo_getRegNumForOperand(
&PPCInsts[MCInst_getOpcode(MI)], Reg, OpNo);
const char *RegName;
RegName = getVerboseConditionRegName(
MI, Reg, MI->MRI->RegEncodingTable[Reg]);
if (RegName == NULL)
RegName = getRegisterName(Reg);
if (showRegistersWithPercentPrefix(MI, RegName))
SStream_concat0(O, "%");
if (!showRegistersWithPrefix(MI))
RegName = PPCRegisterInfo_stripRegisterPrefix(RegName);
SStream_concat0(O, RegName);
return;
}
if (MCOperand_isImm(Op)) {
printInt64(O, MCOperand_getImm(Op));
return;
}
}
const char *PPC_LLVM_getRegisterName(unsigned RegNo)
{
return getRegisterName(RegNo);
}
void PPC_LLVM_printInst(MCInst *MI, uint64_t Address, const char *Annot,
SStream *O)
{
printInst(MI, Address, Annot, O);
}