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 assert(Modifier && "Must specify 'cc' or 'reg' as predicate op modifier!"); 902754fe60SDimitry Andric unsigned Code = MI->getOperand(OpNo).getImm(); 912754fe60SDimitry Andric if (StringRef(Modifier) == "cc") { 922754fe60SDimitry Andric switch ((PPC::Predicate)Code) { 932754fe60SDimitry Andric case PPC::PRED_ALWAYS: return; // Don't print anything for always. 942754fe60SDimitry Andric case PPC::PRED_LT: O << "lt"; return; 952754fe60SDimitry Andric case PPC::PRED_LE: O << "le"; return; 962754fe60SDimitry Andric case PPC::PRED_EQ: O << "eq"; return; 972754fe60SDimitry Andric case PPC::PRED_GE: O << "ge"; return; 982754fe60SDimitry Andric case PPC::PRED_GT: O << "gt"; return; 992754fe60SDimitry Andric case PPC::PRED_NE: O << "ne"; return; 1002754fe60SDimitry Andric case PPC::PRED_UN: O << "un"; return; 1012754fe60SDimitry Andric case PPC::PRED_NU: O << "nu"; return; 1022754fe60SDimitry Andric } 1032754fe60SDimitry Andric } 1042754fe60SDimitry Andric 1052754fe60SDimitry Andric assert(StringRef(Modifier) == "reg" && 1062754fe60SDimitry Andric "Need to specify 'cc' or 'reg' as predicate op modifier!"); 1072754fe60SDimitry Andric // Don't print the register for 'always'. 1082754fe60SDimitry Andric if (Code == PPC::PRED_ALWAYS) return; 1092754fe60SDimitry Andric printOperand(MI, OpNo+1, O); 1102754fe60SDimitry Andric } 1112754fe60SDimitry Andric 1122754fe60SDimitry Andric void PPCInstPrinter::printS5ImmOperand(const MCInst *MI, unsigned OpNo, 1132754fe60SDimitry Andric raw_ostream &O) { 1142754fe60SDimitry Andric char Value = MI->getOperand(OpNo).getImm(); 1152754fe60SDimitry Andric Value = (Value << (32-5)) >> (32-5); 1162754fe60SDimitry Andric O << (int)Value; 1172754fe60SDimitry Andric } 1182754fe60SDimitry Andric 1192754fe60SDimitry Andric void PPCInstPrinter::printU5ImmOperand(const MCInst *MI, unsigned OpNo, 1202754fe60SDimitry Andric raw_ostream &O) { 1212754fe60SDimitry Andric unsigned char Value = MI->getOperand(OpNo).getImm(); 1222754fe60SDimitry Andric assert(Value <= 31 && "Invalid u5imm argument!"); 1232754fe60SDimitry Andric O << (unsigned int)Value; 1242754fe60SDimitry Andric } 1252754fe60SDimitry Andric 1262754fe60SDimitry Andric void PPCInstPrinter::printU6ImmOperand(const MCInst *MI, unsigned OpNo, 1272754fe60SDimitry Andric raw_ostream &O) { 1282754fe60SDimitry Andric unsigned char Value = MI->getOperand(OpNo).getImm(); 1292754fe60SDimitry Andric assert(Value <= 63 && "Invalid u6imm argument!"); 1302754fe60SDimitry Andric O << (unsigned int)Value; 1312754fe60SDimitry Andric } 1322754fe60SDimitry Andric 1332754fe60SDimitry Andric void PPCInstPrinter::printS16ImmOperand(const MCInst *MI, unsigned OpNo, 1342754fe60SDimitry Andric raw_ostream &O) { 1352754fe60SDimitry Andric O << (short)MI->getOperand(OpNo).getImm(); 1362754fe60SDimitry Andric } 1372754fe60SDimitry Andric 1382754fe60SDimitry Andric void PPCInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo, 1392754fe60SDimitry Andric raw_ostream &O) { 1402754fe60SDimitry Andric O << (unsigned short)MI->getOperand(OpNo).getImm(); 1412754fe60SDimitry Andric } 1422754fe60SDimitry Andric 1432754fe60SDimitry Andric void PPCInstPrinter::printS16X4ImmOperand(const MCInst *MI, unsigned OpNo, 1442754fe60SDimitry Andric raw_ostream &O) { 1452754fe60SDimitry Andric if (MI->getOperand(OpNo).isImm()) 1462754fe60SDimitry Andric O << (short)(MI->getOperand(OpNo).getImm()*4); 1472754fe60SDimitry Andric else 1482754fe60SDimitry Andric printOperand(MI, OpNo, O); 1492754fe60SDimitry Andric } 1502754fe60SDimitry Andric 1512754fe60SDimitry Andric void PPCInstPrinter::printBranchOperand(const MCInst *MI, unsigned OpNo, 1522754fe60SDimitry Andric raw_ostream &O) { 1532754fe60SDimitry Andric if (!MI->getOperand(OpNo).isImm()) 1542754fe60SDimitry Andric return printOperand(MI, OpNo, O); 1552754fe60SDimitry Andric 1562754fe60SDimitry Andric // Branches can take an immediate operand. This is used by the branch 1572754fe60SDimitry Andric // selection pass to print $+8, an eight byte displacement from the PC. 1582754fe60SDimitry Andric O << "$+"; 1592754fe60SDimitry Andric printAbsAddrOperand(MI, OpNo, O); 1602754fe60SDimitry Andric } 1612754fe60SDimitry Andric 1622754fe60SDimitry Andric void PPCInstPrinter::printAbsAddrOperand(const MCInst *MI, unsigned OpNo, 1632754fe60SDimitry Andric raw_ostream &O) { 1642754fe60SDimitry Andric O << (int)MI->getOperand(OpNo).getImm()*4; 1652754fe60SDimitry Andric } 1662754fe60SDimitry Andric 1672754fe60SDimitry Andric 1682754fe60SDimitry Andric void PPCInstPrinter::printcrbitm(const MCInst *MI, unsigned OpNo, 1692754fe60SDimitry Andric raw_ostream &O) { 1702754fe60SDimitry Andric unsigned CCReg = MI->getOperand(OpNo).getReg(); 1712754fe60SDimitry Andric unsigned RegNo; 1722754fe60SDimitry Andric switch (CCReg) { 173dff0c46cSDimitry Andric default: llvm_unreachable("Unknown CR register"); 1742754fe60SDimitry Andric case PPC::CR0: RegNo = 0; break; 1752754fe60SDimitry Andric case PPC::CR1: RegNo = 1; break; 1762754fe60SDimitry Andric case PPC::CR2: RegNo = 2; break; 1772754fe60SDimitry Andric case PPC::CR3: RegNo = 3; break; 1782754fe60SDimitry Andric case PPC::CR4: RegNo = 4; break; 1792754fe60SDimitry Andric case PPC::CR5: RegNo = 5; break; 1802754fe60SDimitry Andric case PPC::CR6: RegNo = 6; break; 1812754fe60SDimitry Andric case PPC::CR7: RegNo = 7; break; 1822754fe60SDimitry Andric } 1832754fe60SDimitry Andric O << (0x80 >> RegNo); 1842754fe60SDimitry Andric } 1852754fe60SDimitry Andric 1862754fe60SDimitry Andric void PPCInstPrinter::printMemRegImm(const MCInst *MI, unsigned OpNo, 1872754fe60SDimitry Andric raw_ostream &O) { 1882754fe60SDimitry Andric printSymbolLo(MI, OpNo, O); 1892754fe60SDimitry Andric O << '('; 1902754fe60SDimitry Andric if (MI->getOperand(OpNo+1).getReg() == PPC::R0) 1912754fe60SDimitry Andric O << "0"; 1922754fe60SDimitry Andric else 1932754fe60SDimitry Andric printOperand(MI, OpNo+1, O); 1942754fe60SDimitry Andric O << ')'; 1952754fe60SDimitry Andric } 1962754fe60SDimitry Andric 1972754fe60SDimitry Andric void PPCInstPrinter::printMemRegImmShifted(const MCInst *MI, unsigned OpNo, 1982754fe60SDimitry Andric raw_ostream &O) { 1992754fe60SDimitry Andric if (MI->getOperand(OpNo).isImm()) 2002754fe60SDimitry Andric printS16X4ImmOperand(MI, OpNo, O); 2012754fe60SDimitry Andric else 2022754fe60SDimitry Andric printSymbolLo(MI, OpNo, O); 2032754fe60SDimitry Andric O << '('; 2042754fe60SDimitry Andric 2052754fe60SDimitry Andric if (MI->getOperand(OpNo+1).getReg() == PPC::R0) 2062754fe60SDimitry Andric O << "0"; 2072754fe60SDimitry Andric else 2082754fe60SDimitry Andric printOperand(MI, OpNo+1, O); 2092754fe60SDimitry Andric O << ')'; 2102754fe60SDimitry Andric } 2112754fe60SDimitry Andric 2122754fe60SDimitry Andric 2132754fe60SDimitry Andric void PPCInstPrinter::printMemRegReg(const MCInst *MI, unsigned OpNo, 2142754fe60SDimitry Andric raw_ostream &O) { 2152754fe60SDimitry Andric // When used as the base register, r0 reads constant zero rather than 2162754fe60SDimitry Andric // the value contained in the register. For this reason, the darwin 2172754fe60SDimitry Andric // assembler requires that we print r0 as 0 (no r) when used as the base. 2182754fe60SDimitry Andric if (MI->getOperand(OpNo).getReg() == PPC::R0) 2192754fe60SDimitry Andric O << "0"; 2202754fe60SDimitry Andric else 2212754fe60SDimitry Andric printOperand(MI, OpNo, O); 2222754fe60SDimitry Andric O << ", "; 2232754fe60SDimitry Andric printOperand(MI, OpNo+1, O); 2242754fe60SDimitry Andric } 2252754fe60SDimitry Andric 2262754fe60SDimitry Andric 2272754fe60SDimitry Andric 2282754fe60SDimitry Andric /// stripRegisterPrefix - This method strips the character prefix from a 2292754fe60SDimitry Andric /// register name so that only the number is left. Used by for linux asm. 2302754fe60SDimitry Andric static const char *stripRegisterPrefix(const char *RegName) { 2312754fe60SDimitry Andric switch (RegName[0]) { 2322754fe60SDimitry Andric case 'r': 2332754fe60SDimitry Andric case 'f': 2342754fe60SDimitry Andric case 'v': return RegName + 1; 2352754fe60SDimitry Andric case 'c': if (RegName[1] == 'r') return RegName + 2; 2362754fe60SDimitry Andric } 2372754fe60SDimitry Andric 2382754fe60SDimitry Andric return RegName; 2392754fe60SDimitry Andric } 2402754fe60SDimitry Andric 2412754fe60SDimitry Andric void PPCInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 2422754fe60SDimitry Andric raw_ostream &O) { 2432754fe60SDimitry Andric const MCOperand &Op = MI->getOperand(OpNo); 2442754fe60SDimitry Andric if (Op.isReg()) { 2452754fe60SDimitry Andric const char *RegName = getRegisterName(Op.getReg()); 2462754fe60SDimitry Andric // The linux and AIX assembler does not take register prefixes. 2472754fe60SDimitry Andric if (!isDarwinSyntax()) 2482754fe60SDimitry Andric RegName = stripRegisterPrefix(RegName); 2492754fe60SDimitry Andric 2502754fe60SDimitry Andric O << RegName; 2512754fe60SDimitry Andric return; 2522754fe60SDimitry Andric } 2532754fe60SDimitry Andric 2542754fe60SDimitry Andric if (Op.isImm()) { 2552754fe60SDimitry Andric O << Op.getImm(); 2562754fe60SDimitry Andric return; 2572754fe60SDimitry Andric } 2582754fe60SDimitry Andric 2592754fe60SDimitry Andric assert(Op.isExpr() && "unknown operand kind in printOperand"); 2602754fe60SDimitry Andric O << *Op.getExpr(); 2612754fe60SDimitry Andric } 2622754fe60SDimitry Andric 2632754fe60SDimitry Andric void PPCInstPrinter::printSymbolLo(const MCInst *MI, unsigned OpNo, 2642754fe60SDimitry Andric raw_ostream &O) { 2652754fe60SDimitry Andric if (MI->getOperand(OpNo).isImm()) 2662754fe60SDimitry Andric return printS16ImmOperand(MI, OpNo, O); 2672754fe60SDimitry Andric 2682754fe60SDimitry Andric // FIXME: This is a terrible hack because we can't encode lo16() as an operand 2692754fe60SDimitry Andric // flag of a subtraction. See the FIXME in GetSymbolRef in PPCMCInstLower. 2702754fe60SDimitry Andric if (MI->getOperand(OpNo).isExpr() && 2712754fe60SDimitry Andric isa<MCBinaryExpr>(MI->getOperand(OpNo).getExpr())) { 2722754fe60SDimitry Andric O << "lo16("; 2732754fe60SDimitry Andric printOperand(MI, OpNo, O); 2742754fe60SDimitry Andric O << ')'; 2752754fe60SDimitry Andric } else { 2762754fe60SDimitry Andric printOperand(MI, OpNo, O); 2772754fe60SDimitry Andric } 2782754fe60SDimitry Andric } 2792754fe60SDimitry Andric 2802754fe60SDimitry Andric void PPCInstPrinter::printSymbolHi(const MCInst *MI, unsigned OpNo, 2812754fe60SDimitry Andric raw_ostream &O) { 2822754fe60SDimitry Andric if (MI->getOperand(OpNo).isImm()) 2832754fe60SDimitry Andric return printS16ImmOperand(MI, OpNo, O); 2842754fe60SDimitry Andric 2852754fe60SDimitry Andric // FIXME: This is a terrible hack because we can't encode lo16() as an operand 2862754fe60SDimitry Andric // flag of a subtraction. See the FIXME in GetSymbolRef in PPCMCInstLower. 2872754fe60SDimitry Andric if (MI->getOperand(OpNo).isExpr() && 2882754fe60SDimitry Andric isa<MCBinaryExpr>(MI->getOperand(OpNo).getExpr())) { 2892754fe60SDimitry Andric O << "ha16("; 2902754fe60SDimitry Andric printOperand(MI, OpNo, O); 2912754fe60SDimitry Andric O << ')'; 2922754fe60SDimitry Andric } else { 2932754fe60SDimitry Andric printOperand(MI, OpNo, O); 2942754fe60SDimitry Andric } 2952754fe60SDimitry Andric } 2962754fe60SDimitry Andric 2972754fe60SDimitry Andric 298