12754fe60SDimitry Andric //===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===//
22754fe60SDimitry Andric //
32754fe60SDimitry Andric //                     The LLVM Compiler Infrastructure
42754fe60SDimitry Andric //
52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric // License. See LICENSE.TXT for details.
72754fe60SDimitry Andric //
82754fe60SDimitry Andric //===----------------------------------------------------------------------===//
92754fe60SDimitry Andric //
102754fe60SDimitry Andric // This class prints an PPC MCInst to a .s file.
112754fe60SDimitry Andric //
122754fe60SDimitry Andric //===----------------------------------------------------------------------===//
132754fe60SDimitry Andric 
142754fe60SDimitry Andric #define DEBUG_TYPE "asm-printer"
152754fe60SDimitry Andric #include "PPCInstPrinter.h"
166122f3e6SDimitry Andric #include "MCTargetDesc/PPCBaseInfo.h"
176122f3e6SDimitry Andric #include "MCTargetDesc/PPCPredicates.h"
182754fe60SDimitry Andric #include "llvm/MC/MCExpr.h"
192754fe60SDimitry Andric #include "llvm/MC/MCInst.h"
20dff0c46cSDimitry Andric #include "llvm/MC/MCInstrInfo.h"
212754fe60SDimitry Andric #include "llvm/Support/raw_ostream.h"
222754fe60SDimitry Andric using namespace llvm;
232754fe60SDimitry Andric 
242754fe60SDimitry Andric #include "PPCGenAsmWriter.inc"
252754fe60SDimitry Andric 
26bd5abe19SDimitry Andric void PPCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
27bd5abe19SDimitry Andric   OS << getRegisterName(RegNo);
28bd5abe19SDimitry Andric }
292754fe60SDimitry Andric 
306122f3e6SDimitry Andric void PPCInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
316122f3e6SDimitry Andric                                StringRef Annot) {
322754fe60SDimitry Andric   // Check for slwi/srwi mnemonics.
332754fe60SDimitry Andric   if (MI->getOpcode() == PPC::RLWINM) {
342754fe60SDimitry Andric     unsigned char SH = MI->getOperand(2).getImm();
352754fe60SDimitry Andric     unsigned char MB = MI->getOperand(3).getImm();
362754fe60SDimitry Andric     unsigned char ME = MI->getOperand(4).getImm();
372754fe60SDimitry Andric     bool useSubstituteMnemonic = false;
382754fe60SDimitry Andric     if (SH <= 31 && MB == 0 && ME == (31-SH)) {
392754fe60SDimitry Andric       O << "\tslwi "; useSubstituteMnemonic = true;
402754fe60SDimitry Andric     }
412754fe60SDimitry Andric     if (SH <= 31 && MB == (32-SH) && ME == 31) {
422754fe60SDimitry Andric       O << "\tsrwi "; useSubstituteMnemonic = true;
432754fe60SDimitry Andric       SH = 32-SH;
442754fe60SDimitry Andric     }
452754fe60SDimitry Andric     if (useSubstituteMnemonic) {
462754fe60SDimitry Andric       printOperand(MI, 0, O);
472754fe60SDimitry Andric       O << ", ";
482754fe60SDimitry Andric       printOperand(MI, 1, O);
492754fe60SDimitry Andric       O << ", " << (unsigned int)SH;
506122f3e6SDimitry Andric 
516122f3e6SDimitry Andric       printAnnotation(O, Annot);
522754fe60SDimitry Andric       return;
532754fe60SDimitry Andric     }
542754fe60SDimitry Andric   }
552754fe60SDimitry Andric 
562754fe60SDimitry Andric   if ((MI->getOpcode() == PPC::OR || MI->getOpcode() == PPC::OR8) &&
572754fe60SDimitry Andric       MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) {
582754fe60SDimitry Andric     O << "\tmr ";
592754fe60SDimitry Andric     printOperand(MI, 0, O);
602754fe60SDimitry Andric     O << ", ";
612754fe60SDimitry Andric     printOperand(MI, 1, O);
626122f3e6SDimitry Andric     printAnnotation(O, Annot);
632754fe60SDimitry Andric     return;
642754fe60SDimitry Andric   }
652754fe60SDimitry Andric 
662754fe60SDimitry Andric   if (MI->getOpcode() == PPC::RLDICR) {
672754fe60SDimitry Andric     unsigned char SH = MI->getOperand(2).getImm();
682754fe60SDimitry Andric     unsigned char ME = MI->getOperand(3).getImm();
692754fe60SDimitry Andric     // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
702754fe60SDimitry Andric     if (63-SH == ME) {
712754fe60SDimitry Andric       O << "\tsldi ";
722754fe60SDimitry Andric       printOperand(MI, 0, O);
732754fe60SDimitry Andric       O << ", ";
742754fe60SDimitry Andric       printOperand(MI, 1, O);
752754fe60SDimitry Andric       O << ", " << (unsigned int)SH;
766122f3e6SDimitry Andric       printAnnotation(O, Annot);
772754fe60SDimitry Andric       return;
782754fe60SDimitry Andric     }
792754fe60SDimitry Andric   }
802754fe60SDimitry Andric 
812754fe60SDimitry Andric   printInstruction(MI, O);
826122f3e6SDimitry Andric   printAnnotation(O, Annot);
832754fe60SDimitry Andric }
842754fe60SDimitry Andric 
852754fe60SDimitry Andric 
862754fe60SDimitry Andric void PPCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
872754fe60SDimitry Andric                                            raw_ostream &O,
882754fe60SDimitry Andric                                            const char *Modifier) {
892754fe60SDimitry Andric   unsigned Code = MI->getOperand(OpNo).getImm();
907ae0e2c9SDimitry Andric   if (!Modifier) {
917ae0e2c9SDimitry Andric     unsigned CCReg = MI->getOperand(OpNo+1).getReg();
927ae0e2c9SDimitry Andric     unsigned RegNo;
937ae0e2c9SDimitry Andric     switch (CCReg) {
947ae0e2c9SDimitry Andric     default: llvm_unreachable("Unknown CR register");
957ae0e2c9SDimitry Andric     case PPC::CR0: RegNo = 0; break;
967ae0e2c9SDimitry Andric     case PPC::CR1: RegNo = 1; break;
977ae0e2c9SDimitry Andric     case PPC::CR2: RegNo = 2; break;
987ae0e2c9SDimitry Andric     case PPC::CR3: RegNo = 3; break;
997ae0e2c9SDimitry Andric     case PPC::CR4: RegNo = 4; break;
1007ae0e2c9SDimitry Andric     case PPC::CR5: RegNo = 5; break;
1017ae0e2c9SDimitry Andric     case PPC::CR6: RegNo = 6; break;
1027ae0e2c9SDimitry Andric     case PPC::CR7: RegNo = 7; break;
1037ae0e2c9SDimitry Andric     }
1047ae0e2c9SDimitry Andric 
1057ae0e2c9SDimitry Andric     // Print the CR bit number. The Code is ((BI << 5) | BO) for a
1067ae0e2c9SDimitry Andric     // BCC, but we must have the positive form here (BO == 12)
1077ae0e2c9SDimitry Andric     unsigned BI = Code >> 5;
1087ae0e2c9SDimitry Andric     assert((Code & 0xF) == 12 &&
1097ae0e2c9SDimitry Andric            "BO in predicate bit must have the positive form");
1107ae0e2c9SDimitry Andric 
1117ae0e2c9SDimitry Andric     unsigned Value = 4*RegNo + BI;
1127ae0e2c9SDimitry Andric     O << Value;
1137ae0e2c9SDimitry Andric     return;
1147ae0e2c9SDimitry Andric   }
1157ae0e2c9SDimitry Andric 
1162754fe60SDimitry Andric   if (StringRef(Modifier) == "cc") {
1172754fe60SDimitry Andric     switch ((PPC::Predicate)Code) {
1182754fe60SDimitry Andric     case PPC::PRED_ALWAYS: return; // Don't print anything for always.
1192754fe60SDimitry Andric     case PPC::PRED_LT: O << "lt"; return;
1202754fe60SDimitry Andric     case PPC::PRED_LE: O << "le"; return;
1212754fe60SDimitry Andric     case PPC::PRED_EQ: O << "eq"; return;
1222754fe60SDimitry Andric     case PPC::PRED_GE: O << "ge"; return;
1232754fe60SDimitry Andric     case PPC::PRED_GT: O << "gt"; return;
1242754fe60SDimitry Andric     case PPC::PRED_NE: O << "ne"; return;
1252754fe60SDimitry Andric     case PPC::PRED_UN: O << "un"; return;
1262754fe60SDimitry Andric     case PPC::PRED_NU: O << "nu"; return;
1272754fe60SDimitry Andric     }
1282754fe60SDimitry Andric   }
1292754fe60SDimitry Andric 
1302754fe60SDimitry Andric   assert(StringRef(Modifier) == "reg" &&
1312754fe60SDimitry Andric          "Need to specify 'cc' or 'reg' as predicate op modifier!");
1322754fe60SDimitry Andric   // Don't print the register for 'always'.
1332754fe60SDimitry Andric   if (Code == PPC::PRED_ALWAYS) return;
1342754fe60SDimitry Andric   printOperand(MI, OpNo+1, O);
1352754fe60SDimitry Andric }
1362754fe60SDimitry Andric 
1372754fe60SDimitry Andric void PPCInstPrinter::printS5ImmOperand(const MCInst *MI, unsigned OpNo,
1382754fe60SDimitry Andric                                        raw_ostream &O) {
1392754fe60SDimitry Andric   char Value = MI->getOperand(OpNo).getImm();
1402754fe60SDimitry Andric   Value = (Value << (32-5)) >> (32-5);
1412754fe60SDimitry Andric   O << (int)Value;
1422754fe60SDimitry Andric }
1432754fe60SDimitry Andric 
1442754fe60SDimitry Andric void PPCInstPrinter::printU5ImmOperand(const MCInst *MI, unsigned OpNo,
1452754fe60SDimitry Andric                                        raw_ostream &O) {
1462754fe60SDimitry Andric   unsigned char Value = MI->getOperand(OpNo).getImm();
1472754fe60SDimitry Andric   assert(Value <= 31 && "Invalid u5imm argument!");
1482754fe60SDimitry Andric   O << (unsigned int)Value;
1492754fe60SDimitry Andric }
1502754fe60SDimitry Andric 
1512754fe60SDimitry Andric void PPCInstPrinter::printU6ImmOperand(const MCInst *MI, unsigned OpNo,
1522754fe60SDimitry Andric                                        raw_ostream &O) {
1532754fe60SDimitry Andric   unsigned char Value = MI->getOperand(OpNo).getImm();
1542754fe60SDimitry Andric   assert(Value <= 63 && "Invalid u6imm argument!");
1552754fe60SDimitry Andric   O << (unsigned int)Value;
1562754fe60SDimitry Andric }
1572754fe60SDimitry Andric 
1582754fe60SDimitry Andric void PPCInstPrinter::printS16ImmOperand(const MCInst *MI, unsigned OpNo,
1592754fe60SDimitry Andric                                         raw_ostream &O) {
1602754fe60SDimitry Andric   O << (short)MI->getOperand(OpNo).getImm();
1612754fe60SDimitry Andric }
1622754fe60SDimitry Andric 
1632754fe60SDimitry Andric void PPCInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
1642754fe60SDimitry Andric                                         raw_ostream &O) {
1652754fe60SDimitry Andric   O << (unsigned short)MI->getOperand(OpNo).getImm();
1662754fe60SDimitry Andric }
1672754fe60SDimitry Andric 
1682754fe60SDimitry Andric void PPCInstPrinter::printS16X4ImmOperand(const MCInst *MI, unsigned OpNo,
1692754fe60SDimitry Andric                                           raw_ostream &O) {
1702754fe60SDimitry Andric   if (MI->getOperand(OpNo).isImm())
1712754fe60SDimitry Andric     O << (short)(MI->getOperand(OpNo).getImm()*4);
1722754fe60SDimitry Andric   else
1732754fe60SDimitry Andric     printOperand(MI, OpNo, O);
1742754fe60SDimitry Andric }
1752754fe60SDimitry Andric 
1762754fe60SDimitry Andric void PPCInstPrinter::printBranchOperand(const MCInst *MI, unsigned OpNo,
1772754fe60SDimitry Andric                                         raw_ostream &O) {
1782754fe60SDimitry Andric   if (!MI->getOperand(OpNo).isImm())
1792754fe60SDimitry Andric     return printOperand(MI, OpNo, O);
1802754fe60SDimitry Andric 
1812754fe60SDimitry Andric   // Branches can take an immediate operand.  This is used by the branch
1822754fe60SDimitry Andric   // selection pass to print $+8, an eight byte displacement from the PC.
1832754fe60SDimitry Andric   O << "$+";
1842754fe60SDimitry Andric   printAbsAddrOperand(MI, OpNo, O);
1852754fe60SDimitry Andric }
1862754fe60SDimitry Andric 
1872754fe60SDimitry Andric void PPCInstPrinter::printAbsAddrOperand(const MCInst *MI, unsigned OpNo,
1882754fe60SDimitry Andric                                          raw_ostream &O) {
1892754fe60SDimitry Andric   O << (int)MI->getOperand(OpNo).getImm()*4;
1902754fe60SDimitry Andric }
1912754fe60SDimitry Andric 
1922754fe60SDimitry Andric 
1932754fe60SDimitry Andric void PPCInstPrinter::printcrbitm(const MCInst *MI, unsigned OpNo,
1942754fe60SDimitry Andric                                  raw_ostream &O) {
1952754fe60SDimitry Andric   unsigned CCReg = MI->getOperand(OpNo).getReg();
1962754fe60SDimitry Andric   unsigned RegNo;
1972754fe60SDimitry Andric   switch (CCReg) {
198dff0c46cSDimitry Andric   default: llvm_unreachable("Unknown CR register");
1992754fe60SDimitry Andric   case PPC::CR0: RegNo = 0; break;
2002754fe60SDimitry Andric   case PPC::CR1: RegNo = 1; break;
2012754fe60SDimitry Andric   case PPC::CR2: RegNo = 2; break;
2022754fe60SDimitry Andric   case PPC::CR3: RegNo = 3; break;
2032754fe60SDimitry Andric   case PPC::CR4: RegNo = 4; break;
2042754fe60SDimitry Andric   case PPC::CR5: RegNo = 5; break;
2052754fe60SDimitry Andric   case PPC::CR6: RegNo = 6; break;
2062754fe60SDimitry Andric   case PPC::CR7: RegNo = 7; break;
2072754fe60SDimitry Andric   }
2082754fe60SDimitry Andric   O << (0x80 >> RegNo);
2092754fe60SDimitry Andric }
2102754fe60SDimitry Andric 
2112754fe60SDimitry Andric void PPCInstPrinter::printMemRegImm(const MCInst *MI, unsigned OpNo,
2122754fe60SDimitry Andric                                     raw_ostream &O) {
2132754fe60SDimitry Andric   printSymbolLo(MI, OpNo, O);
2142754fe60SDimitry Andric   O << '(';
2152754fe60SDimitry Andric   if (MI->getOperand(OpNo+1).getReg() == PPC::R0)
2162754fe60SDimitry Andric     O << "0";
2172754fe60SDimitry Andric   else
2182754fe60SDimitry Andric     printOperand(MI, OpNo+1, O);
2192754fe60SDimitry Andric   O << ')';
2202754fe60SDimitry Andric }
2212754fe60SDimitry Andric 
2222754fe60SDimitry Andric void PPCInstPrinter::printMemRegImmShifted(const MCInst *MI, unsigned OpNo,
2232754fe60SDimitry Andric                                            raw_ostream &O) {
2242754fe60SDimitry Andric   if (MI->getOperand(OpNo).isImm())
2252754fe60SDimitry Andric     printS16X4ImmOperand(MI, OpNo, O);
2262754fe60SDimitry Andric   else
2272754fe60SDimitry Andric     printSymbolLo(MI, OpNo, O);
2282754fe60SDimitry Andric   O << '(';
2292754fe60SDimitry Andric 
2302754fe60SDimitry Andric   if (MI->getOperand(OpNo+1).getReg() == PPC::R0)
2312754fe60SDimitry Andric     O << "0";
2322754fe60SDimitry Andric   else
2332754fe60SDimitry Andric     printOperand(MI, OpNo+1, O);
2342754fe60SDimitry Andric   O << ')';
2352754fe60SDimitry Andric }
2362754fe60SDimitry Andric 
2372754fe60SDimitry Andric 
2382754fe60SDimitry Andric void PPCInstPrinter::printMemRegReg(const MCInst *MI, unsigned OpNo,
2392754fe60SDimitry Andric                                     raw_ostream &O) {
2402754fe60SDimitry Andric   // When used as the base register, r0 reads constant zero rather than
2412754fe60SDimitry Andric   // the value contained in the register.  For this reason, the darwin
2422754fe60SDimitry Andric   // assembler requires that we print r0 as 0 (no r) when used as the base.
2432754fe60SDimitry Andric   if (MI->getOperand(OpNo).getReg() == PPC::R0)
2442754fe60SDimitry Andric     O << "0";
2452754fe60SDimitry Andric   else
2462754fe60SDimitry Andric     printOperand(MI, OpNo, O);
2472754fe60SDimitry Andric   O << ", ";
2482754fe60SDimitry Andric   printOperand(MI, OpNo+1, O);
2492754fe60SDimitry Andric }
2502754fe60SDimitry Andric 
2512754fe60SDimitry Andric 
2522754fe60SDimitry Andric 
2532754fe60SDimitry Andric /// stripRegisterPrefix - This method strips the character prefix from a
2542754fe60SDimitry Andric /// register name so that only the number is left.  Used by for linux asm.
2552754fe60SDimitry Andric static const char *stripRegisterPrefix(const char *RegName) {
2562754fe60SDimitry Andric   switch (RegName[0]) {
2572754fe60SDimitry Andric   case 'r':
2582754fe60SDimitry Andric   case 'f':
2592754fe60SDimitry Andric   case 'v': return RegName + 1;
2602754fe60SDimitry Andric   case 'c': if (RegName[1] == 'r') return RegName + 2;
2612754fe60SDimitry Andric   }
2622754fe60SDimitry Andric 
2632754fe60SDimitry Andric   return RegName;
2642754fe60SDimitry Andric }
2652754fe60SDimitry Andric 
2662754fe60SDimitry Andric void PPCInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
2672754fe60SDimitry Andric                                   raw_ostream &O) {
2682754fe60SDimitry Andric   const MCOperand &Op = MI->getOperand(OpNo);
2692754fe60SDimitry Andric   if (Op.isReg()) {
2702754fe60SDimitry Andric     const char *RegName = getRegisterName(Op.getReg());
2712754fe60SDimitry Andric     // The linux and AIX assembler does not take register prefixes.
2722754fe60SDimitry Andric     if (!isDarwinSyntax())
2732754fe60SDimitry Andric       RegName = stripRegisterPrefix(RegName);
2742754fe60SDimitry Andric 
2752754fe60SDimitry Andric     O << RegName;
2762754fe60SDimitry Andric     return;
2772754fe60SDimitry Andric   }
2782754fe60SDimitry Andric 
2792754fe60SDimitry Andric   if (Op.isImm()) {
2802754fe60SDimitry Andric     O << Op.getImm();
2812754fe60SDimitry Andric     return;
2822754fe60SDimitry Andric   }
2832754fe60SDimitry Andric 
2842754fe60SDimitry Andric   assert(Op.isExpr() && "unknown operand kind in printOperand");
2852754fe60SDimitry Andric   O << *Op.getExpr();
2862754fe60SDimitry Andric }
2872754fe60SDimitry Andric 
2882754fe60SDimitry Andric void PPCInstPrinter::printSymbolLo(const MCInst *MI, unsigned OpNo,
2892754fe60SDimitry Andric                                    raw_ostream &O) {
2902754fe60SDimitry Andric   if (MI->getOperand(OpNo).isImm())
2912754fe60SDimitry Andric     return printS16ImmOperand(MI, OpNo, O);
2922754fe60SDimitry Andric 
2932754fe60SDimitry Andric   // FIXME: This is a terrible hack because we can't encode lo16() as an operand
2942754fe60SDimitry Andric   // flag of a subtraction.  See the FIXME in GetSymbolRef in PPCMCInstLower.
2952754fe60SDimitry Andric   if (MI->getOperand(OpNo).isExpr() &&
2962754fe60SDimitry Andric       isa<MCBinaryExpr>(MI->getOperand(OpNo).getExpr())) {
2972754fe60SDimitry Andric     O << "lo16(";
2982754fe60SDimitry Andric     printOperand(MI, OpNo, O);
2992754fe60SDimitry Andric     O << ')';
3002754fe60SDimitry Andric   } else {
3012754fe60SDimitry Andric     printOperand(MI, OpNo, O);
3022754fe60SDimitry Andric   }
3032754fe60SDimitry Andric }
3042754fe60SDimitry Andric 
3052754fe60SDimitry Andric void PPCInstPrinter::printSymbolHi(const MCInst *MI, unsigned OpNo,
3062754fe60SDimitry Andric                                    raw_ostream &O) {
3072754fe60SDimitry Andric   if (MI->getOperand(OpNo).isImm())
3082754fe60SDimitry Andric     return printS16ImmOperand(MI, OpNo, O);
3092754fe60SDimitry Andric 
3102754fe60SDimitry Andric   // FIXME: This is a terrible hack because we can't encode lo16() as an operand
3112754fe60SDimitry Andric   // flag of a subtraction.  See the FIXME in GetSymbolRef in PPCMCInstLower.
3122754fe60SDimitry Andric   if (MI->getOperand(OpNo).isExpr() &&
3132754fe60SDimitry Andric       isa<MCBinaryExpr>(MI->getOperand(OpNo).getExpr())) {
3142754fe60SDimitry Andric     O << "ha16(";
3152754fe60SDimitry Andric     printOperand(MI, OpNo, O);
3162754fe60SDimitry Andric     O << ')';
3172754fe60SDimitry Andric   } else {
3182754fe60SDimitry Andric     printOperand(MI, OpNo, O);
3192754fe60SDimitry Andric   }
3202754fe60SDimitry Andric }
3212754fe60SDimitry Andric 
3222754fe60SDimitry Andric 
323