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