teak-llvm/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
Victor Huang 5cee34013c [PowerPC][Future] Add prefixed instruction paddi to future CPU
Future CPU will include support for prefixed instructions.
These prefixed instructions are formed by a 4 byte prefix
immediately followed by a 4 byte instruction effectively
making an 8 byte instruction. The new instruction paddi
is a prefixed form of addi.

This patch adds paddi and all of the support required
for that instruction. The majority of the patch deals with
supporting the new prefixed instructions. The addition of
paddi is mainly to allow for testing.

Differential Revision: https://reviews.llvm.org/D72569
2020-01-24 07:27:25 -06:00

583 lines
18 KiB
C++

//===-- 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 "MCTargetDesc/PPCInstPrinter.h"
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPCInstrInfo.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "asm-printer"
// FIXME: Once the integrated assembler supports full register names, tie this
// to the verbose-asm setting.
static cl::opt<bool>
FullRegNames("ppc-asm-full-reg-names", cl::Hidden, cl::init(false),
cl::desc("Use full register names when printing assembly"));
// Useful for testing purposes. Prints vs{31-63} as v{0-31} respectively.
static cl::opt<bool>
ShowVSRNumsAsVR("ppc-vsr-nums-as-vr", cl::Hidden, cl::init(false),
cl::desc("Prints full register names with vs{31-63} as v{0-31}"));
// Prints full register names with percent symbol.
static cl::opt<bool>
FullRegNamesWithPercent("ppc-reg-with-percent-prefix", cl::Hidden,
cl::init(false),
cl::desc("Prints full register names with percent"));
#define PRINT_ALIAS_INSTR
#include "PPCGenAsmWriter.inc"
void PPCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
const char *RegName = getRegisterName(RegNo);
if (RegName[0] == 'q' /* QPX */) {
// The system toolchain on the BG/Q does not understand QPX register names
// in .cfi_* directives, so print the name of the floating-point
// subregister instead.
std::string RN(RegName);
RN[0] = 'f';
OS << RN;
return;
}
OS << RegName;
}
void PPCInstPrinter::printInst(const MCInst *MI, uint64_t Address,
StringRef Annot, const MCSubtargetInfo &STI,
raw_ostream &O) {
// 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 (TT.isOSAIX() &&
(MI->getOpcode() == PPC::ADDIS8 || MI->getOpcode() == PPC::ADDIS) &&
MI->getOperand(2).isExpr()) {
assert((MI->getOperand(0).isReg() && MI->getOperand(1).isReg()) &&
"The first and the second operand of an addis instruction"
" should be registers.");
assert(isa<MCSymbolRefExpr>(MI->getOperand(2).getExpr()) &&
"The third operand of an addis instruction should be a symbol "
"reference expression if it is an expression at all.");
O << "\taddis ";
printOperand(MI, 0, O);
O << ", ";
printOperand(MI, 2, O);
O << "(";
printOperand(MI, 1, O);
O << ")";
return;
}
// Check for slwi/srwi mnemonics.
if (MI->getOpcode() == PPC::RLWINM) {
unsigned char SH = MI->getOperand(2).getImm();
unsigned char MB = MI->getOperand(3).getImm();
unsigned char ME = MI->getOperand(4).getImm();
bool useSubstituteMnemonic = false;
if (SH <= 31 && MB == 0 && ME == (31-SH)) {
O << "\tslwi "; useSubstituteMnemonic = true;
}
if (SH <= 31 && MB == (32-SH) && ME == 31) {
O << "\tsrwi "; useSubstituteMnemonic = true;
SH = 32-SH;
}
if (useSubstituteMnemonic) {
printOperand(MI, 0, O);
O << ", ";
printOperand(MI, 1, O);
O << ", " << (unsigned int)SH;
printAnnotation(O, Annot);
return;
}
}
if ((MI->getOpcode() == PPC::OR || MI->getOpcode() == PPC::OR8) &&
MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) {
O << "\tmr ";
printOperand(MI, 0, O);
O << ", ";
printOperand(MI, 1, O);
printAnnotation(O, Annot);
return;
}
if (MI->getOpcode() == PPC::RLDICR ||
MI->getOpcode() == PPC::RLDICR_32) {
unsigned char SH = MI->getOperand(2).getImm();
unsigned char ME = MI->getOperand(3).getImm();
// rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
if (63-SH == ME) {
O << "\tsldi ";
printOperand(MI, 0, O);
O << ", ";
printOperand(MI, 1, O);
O << ", " << (unsigned int)SH;
printAnnotation(O, Annot);
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.
if (MI->getOpcode() == PPC::DCBT || MI->getOpcode() == PPC::DCBTST) {
unsigned char TH = MI->getOperand(0).getImm();
O << "\tdcbt";
if (MI->getOpcode() == PPC::DCBTST)
O << "st";
if (TH == 16)
O << "t";
O << " ";
bool IsBookE = STI.getFeatureBits()[PPC::FeatureBookE];
if (IsBookE && TH != 0 && TH != 16)
O << (unsigned int) TH << ", ";
printOperand(MI, 1, O);
O << ", ";
printOperand(MI, 2, O);
if (!IsBookE && TH != 0 && TH != 16)
O << ", " << (unsigned int) TH;
printAnnotation(O, Annot);
return;
}
if (MI->getOpcode() == PPC::DCBF) {
unsigned char L = MI->getOperand(0).getImm();
if (!L || L == 1 || L == 3) {
O << "\tdcbf";
if (L == 1 || L == 3)
O << "l";
if (L == 3)
O << "p";
O << " ";
printOperand(MI, 1, O);
O << ", ";
printOperand(MI, 2, O);
printAnnotation(O, Annot);
return;
}
}
if (!printAliasInstr(MI, O))
printInstruction(MI, Address, O);
printAnnotation(O, Annot);
}
void PPCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O,
const char *Modifier) {
unsigned Code = MI->getOperand(OpNo).getImm();
if (StringRef(Modifier) == "cc") {
switch ((PPC::Predicate)Code) {
case PPC::PRED_LT_MINUS:
case PPC::PRED_LT_PLUS:
case PPC::PRED_LT:
O << "lt";
return;
case PPC::PRED_LE_MINUS:
case PPC::PRED_LE_PLUS:
case PPC::PRED_LE:
O << "le";
return;
case PPC::PRED_EQ_MINUS:
case PPC::PRED_EQ_PLUS:
case PPC::PRED_EQ:
O << "eq";
return;
case PPC::PRED_GE_MINUS:
case PPC::PRED_GE_PLUS:
case PPC::PRED_GE:
O << "ge";
return;
case PPC::PRED_GT_MINUS:
case PPC::PRED_GT_PLUS:
case PPC::PRED_GT:
O << "gt";
return;
case PPC::PRED_NE_MINUS:
case PPC::PRED_NE_PLUS:
case PPC::PRED_NE:
O << "ne";
return;
case PPC::PRED_UN_MINUS:
case PPC::PRED_UN_PLUS:
case PPC::PRED_UN:
O << "un";
return;
case PPC::PRED_NU_MINUS:
case PPC::PRED_NU_PLUS:
case PPC::PRED_NU:
O << "nu";
return;
case PPC::PRED_BIT_SET:
case PPC::PRED_BIT_UNSET:
llvm_unreachable("Invalid use of bit predicate code");
}
llvm_unreachable("Invalid predicate code");
}
if (StringRef(Modifier) == "pm") {
switch ((PPC::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:
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:
O << "+";
return;
case PPC::PRED_BIT_SET:
case PPC::PRED_BIT_UNSET:
llvm_unreachable("Invalid use of bit predicate code");
}
llvm_unreachable("Invalid predicate code");
}
assert(StringRef(Modifier) == "reg" &&
"Need to specify 'cc', 'pm' or 'reg' as predicate op modifier!");
printOperand(MI, OpNo+1, O);
}
void PPCInstPrinter::printATBitsAsHint(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned Code = MI->getOperand(OpNo).getImm();
if (Code == 2)
O << "-";
else if (Code == 3)
O << "+";
}
void PPCInstPrinter::printU1ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 1 && "Invalid u1imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU2ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 3 && "Invalid u2imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU3ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 8 && "Invalid u3imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU4ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 15 && "Invalid u4imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printS5ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
int Value = MI->getOperand(OpNo).getImm();
Value = SignExtend32<5>(Value);
O << (int)Value;
}
void PPCInstPrinter::printImmZeroOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value == 0 && "Operand must be zero");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU5ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 31 && "Invalid u5imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU6ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 63 && "Invalid u6imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU7ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 127 && "Invalid u7imm argument!");
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 PPCInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned char Value = MI->getOperand(OpNo).getImm();
O << (unsigned int)Value;
}
void PPCInstPrinter::printU10ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned short Value = MI->getOperand(OpNo).getImm();
assert(Value <= 1023 && "Invalid u10imm argument!");
O << (unsigned short)Value;
}
void PPCInstPrinter::printU12ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned short Value = MI->getOperand(OpNo).getImm();
assert(Value <= 4095 && "Invalid u12imm argument!");
O << (unsigned short)Value;
}
void PPCInstPrinter::printS16ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (MI->getOperand(OpNo).isImm())
O << (short)MI->getOperand(OpNo).getImm();
else
printOperand(MI, OpNo, O);
}
void PPCInstPrinter::printS34ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
long long Value = MI->getOperand(OpNo).getImm();
assert(isInt<34>(Value) && "Invalid s34imm argument!");
O << (long long)Value;
}
void PPCInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (MI->getOperand(OpNo).isImm())
O << (unsigned short)MI->getOperand(OpNo).getImm();
else
printOperand(MI, OpNo, O);
}
void PPCInstPrinter::printBranchOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (!MI->getOperand(OpNo).isImm())
return printOperand(MI, OpNo, O);
// Branches can take an immediate operand. This is used by the branch
// selection pass to print .+8, an eight byte displacement from the PC.
O << ".";
int32_t Imm = SignExtend32<32>((unsigned)MI->getOperand(OpNo).getImm() << 2);
if (Imm >= 0)
O << "+";
O << Imm;
}
void PPCInstPrinter::printAbsBranchOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (!MI->getOperand(OpNo).isImm())
return printOperand(MI, OpNo, O);
O << SignExtend32<32>((unsigned)MI->getOperand(OpNo).getImm() << 2);
}
void PPCInstPrinter::printcrbitm(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned CCReg = MI->getOperand(OpNo).getReg();
unsigned RegNo;
switch (CCReg) {
default: llvm_unreachable("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;
}
O << (0x80 >> RegNo);
}
void PPCInstPrinter::printMemRegImm(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
printS16ImmOperand(MI, OpNo, O);
O << '(';
if (MI->getOperand(OpNo+1).getReg() == PPC::R0)
O << "0";
else
printOperand(MI, OpNo+1, O);
O << ')';
}
void PPCInstPrinter::printMemRegReg(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
// 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 (MI->getOperand(OpNo).getReg() == PPC::R0)
O << "0";
else
printOperand(MI, OpNo, O);
O << ", ";
printOperand(MI, OpNo+1, O);
}
void PPCInstPrinter::printTLSCall(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
// On PPC64, VariantKind is VK_None, but on PPC32, it's VK_PLT, and it must
// come at the _end_ of the expression.
const MCOperand &Op = MI->getOperand(OpNo);
const MCSymbolRefExpr *RefExp = nullptr;
const MCConstantExpr *ConstExp = nullptr;
if (const MCBinaryExpr *BinExpr = dyn_cast<MCBinaryExpr>(Op.getExpr())) {
RefExp = cast<MCSymbolRefExpr>(BinExpr->getLHS());
ConstExp = cast<MCConstantExpr>(BinExpr->getRHS());
} else
RefExp = cast<MCSymbolRefExpr>(Op.getExpr());
O << RefExp->getSymbol().getName();
O << '(';
printOperand(MI, OpNo+1, O);
O << ')';
if (RefExp->getKind() != MCSymbolRefExpr::VK_None)
O << '@' << MCSymbolRefExpr::getVariantKindName(RefExp->getKind());
if (ConstExp != nullptr)
O << '+' << ConstExp->getValue();
}
/// showRegistersWithPercentPrefix - Check if this register name should be
/// printed with a percentage symbol as prefix.
bool PPCInstPrinter::showRegistersWithPercentPrefix(const char *RegName) const {
if (!FullRegNamesWithPercent || TT.isOSDarwin() || TT.getOS() == Triple::AIX)
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 targetting Darwin.
const char *PPCInstPrinter::getVerboseConditionRegName(unsigned RegNum,
unsigned RegEncoding)
const {
if (!TT.isOSDarwin() && !FullRegNames)
return nullptr;
if (RegNum < PPC::CR0EQ || RegNum > PPC::CR7UN)
return nullptr;
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 PPCInstPrinter::showRegistersWithPrefix() const {
if (TT.getOS() == Triple::AIX)
return false;
return TT.isOSDarwin() || FullRegNamesWithPercent || FullRegNames;
}
void PPCInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg()) {
unsigned Reg = Op.getReg();
if (!ShowVSRNumsAsVR)
Reg = PPCInstrInfo::getRegNumForOperand(MII.get(MI->getOpcode()),
Reg, OpNo);
const char *RegName;
RegName = getVerboseConditionRegName(Reg, MRI.getEncodingValue(Reg));
if (RegName == nullptr)
RegName = getRegisterName(Reg);
if (showRegistersWithPercentPrefix(RegName))
O << "%";
if (!showRegistersWithPrefix())
RegName = PPCRegisterInfo::stripRegisterPrefix(RegName);
O << RegName;
return;
}
if (Op.isImm()) {
O << Op.getImm();
return;
}
assert(Op.isExpr() && "unknown operand kind in printOperand");
Op.getExpr()->print(O, &MAI);
}