mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-25 19:29:53 +00:00
This adds support for the predicted forms of branches (+/-). There are three cases to consider: - Branches using a PPC::Predicate code For these, I've added new PPC::Predicate codes corresponding to the BO values for predicted branch forms, and updated insn printing to print them correctly. I've also added new aliases for the asm parser matching the new forms. - bt/bf I've added new aliases matching to gBC etc. - bd(n)z variants I've added new instruction patterns for the predicted forms. In all cases, the new patterns are used for the asm parser only. (The new infrastructure ought to be sufficient to allow use by the compiler too at some point.) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@184754 91177308-0d34-0410-b5e6-96231b3b80d8
312 lines
8.7 KiB
C++
312 lines
8.7 KiB
C++
//===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This class prints an PPC MCInst to a .s file.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
#include "PPCInstPrinter.h"
|
|
#include "MCTargetDesc/PPCMCTargetDesc.h"
|
|
#include "MCTargetDesc/PPCPredicates.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
#include "PPCGenAsmWriter.inc"
|
|
|
|
void PPCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
|
|
OS << getRegisterName(RegNo);
|
|
}
|
|
|
|
void PPCInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
|
|
StringRef Annot) {
|
|
// 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) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
printInstruction(MI, 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;
|
|
default:
|
|
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;
|
|
default:
|
|
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::printS5ImmOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) {
|
|
int Value = MI->getOperand(OpNo).getImm();
|
|
Value = SignExtend32<5>(Value);
|
|
O << (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::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::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) {
|
|
O << (unsigned short)MI->getOperand(OpNo).getImm();
|
|
}
|
|
|
|
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 << ".+";
|
|
printAbsBranchOperand(MI, OpNo, O);
|
|
}
|
|
|
|
void PPCInstPrinter::printAbsBranchOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) {
|
|
if (!MI->getOperand(OpNo).isImm())
|
|
return printOperand(MI, OpNo, O);
|
|
|
|
O << (int)MI->getOperand(OpNo).getImm()*4;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
/// stripRegisterPrefix - This method strips the character prefix from a
|
|
/// register name so that only the number is left. Used by for linux asm.
|
|
static const char *stripRegisterPrefix(const char *RegName) {
|
|
switch (RegName[0]) {
|
|
case 'r':
|
|
case 'f':
|
|
case 'v': return RegName + 1;
|
|
case 'c': if (RegName[1] == 'r') return RegName + 2;
|
|
}
|
|
|
|
return RegName;
|
|
}
|
|
|
|
void PPCInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) {
|
|
const MCOperand &Op = MI->getOperand(OpNo);
|
|
if (Op.isReg()) {
|
|
const char *RegName = getRegisterName(Op.getReg());
|
|
// The linux and AIX assembler does not take register prefixes.
|
|
if (!isDarwinSyntax())
|
|
RegName = stripRegisterPrefix(RegName);
|
|
|
|
O << RegName;
|
|
return;
|
|
}
|
|
|
|
if (Op.isImm()) {
|
|
O << Op.getImm();
|
|
return;
|
|
}
|
|
|
|
assert(Op.isExpr() && "unknown operand kind in printOperand");
|
|
O << *Op.getExpr();
|
|
}
|
|
|