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