2005-10-16 05:39:50 +00:00
|
|
|
//===-- PPCAsmPrinter.cpp - Print machine instrs to PowerPC assembly --------=//
|
2005-04-21 23:30:14 +00:00
|
|
|
//
|
2004-06-21 16:55:25 +00:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 20:36:04 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2005-04-21 23:30:14 +00:00
|
|
|
//
|
2004-06-21 16:55:25 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2004-07-08 17:58:04 +00:00
|
|
|
// This file contains a printer that converts from our internal representation
|
|
|
|
// of machine-dependent LLVM code to PowerPC assembly language. This printer is
|
2004-07-28 20:18:53 +00:00
|
|
|
// the output mechanism used by `llc'.
|
2004-06-21 16:55:25 +00:00
|
|
|
//
|
2004-07-08 17:58:04 +00:00
|
|
|
// Documentation at http://developer.apple.com/documentation/DeveloperTools/
|
|
|
|
// Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
|
2004-06-29 17:13:26 +00:00
|
|
|
//
|
2004-06-21 16:55:25 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2004-06-24 17:31:42 +00:00
|
|
|
#define DEBUG_TYPE "asmprinter"
|
2005-10-14 23:51:18 +00:00
|
|
|
#include "PPC.h"
|
2006-11-17 22:10:59 +00:00
|
|
|
#include "PPCPredicates.h"
|
2005-10-14 23:59:06 +00:00
|
|
|
#include "PPCTargetMachine.h"
|
2005-10-14 23:51:18 +00:00
|
|
|
#include "PPCSubtarget.h"
|
2004-06-21 16:55:25 +00:00
|
|
|
#include "llvm/Constants.h"
|
|
|
|
#include "llvm/DerivedTypes.h"
|
|
|
|
#include "llvm/Module.h"
|
|
|
|
#include "llvm/Assembly/Writer.h"
|
2004-08-16 23:25:21 +00:00
|
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
2006-01-04 13:52:30 +00:00
|
|
|
#include "llvm/CodeGen/DwarfWriter.h"
|
2007-01-26 21:22:28 +00:00
|
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
2004-06-24 17:31:42 +00:00
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
2004-06-21 16:55:25 +00:00
|
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
2008-01-26 06:51:24 +00:00
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2004-06-21 16:55:25 +00:00
|
|
|
#include "llvm/Support/Mangler.h"
|
2004-09-04 14:51:26 +00:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2004-09-01 22:55:40 +00:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
2006-08-27 12:54:02 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2008-08-21 00:14:44 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2006-09-06 18:34:40 +00:00
|
|
|
#include "llvm/Target/TargetAsmInfo.h"
|
2008-02-10 18:45:23 +00:00
|
|
|
#include "llvm/Target/TargetRegisterInfo.h"
|
2004-11-25 07:09:01 +00:00
|
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
2006-02-18 00:08:58 +00:00
|
|
|
#include "llvm/Target/TargetOptions.h"
|
2004-09-01 22:55:40 +00:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2008-12-05 01:06:39 +00:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2004-08-16 23:25:21 +00:00
|
|
|
using namespace llvm;
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2006-12-19 22:59:26 +00:00
|
|
|
STATISTIC(EmittedInsts, "Number of machine instrs printed");
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2006-12-19 22:59:26 +00:00
|
|
|
namespace {
|
2009-02-24 08:30:20 +00:00
|
|
|
class VISIBILITY_HIDDEN PPCAsmPrinter : public AsmPrinter {
|
|
|
|
protected:
|
2008-12-05 01:06:39 +00:00
|
|
|
StringSet<> FnStubs, GVStubs, HiddenGVStubs;
|
2006-09-20 17:07:15 +00:00
|
|
|
const PPCSubtarget &Subtarget;
|
2009-02-24 08:30:20 +00:00
|
|
|
public:
|
|
|
|
PPCAsmPrinter(raw_ostream &O, TargetMachine &TM,
|
2009-03-25 01:47:28 +00:00
|
|
|
const TargetAsmInfo *T, bool F, bool V)
|
|
|
|
: AsmPrinter(O, TM, T, F, V),
|
2009-02-24 08:30:20 +00:00
|
|
|
Subtarget(TM.getSubtarget<PPCSubtarget>()) {}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
virtual const char *getPassName() const {
|
2004-09-04 05:00:00 +00:00
|
|
|
return "PowerPC Assembly Printer";
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
2005-10-16 05:39:50 +00:00
|
|
|
PPCTargetMachine &getTM() {
|
|
|
|
return static_cast<PPCTargetMachine&>(TM);
|
2004-08-16 23:25:21 +00:00
|
|
|
}
|
|
|
|
|
2005-07-20 22:42:00 +00:00
|
|
|
unsigned enumRegToMachineReg(unsigned enumReg) {
|
|
|
|
switch (enumReg) {
|
|
|
|
default: assert(0 && "Unhandled register!"); break;
|
|
|
|
case PPC::CR0: return 0;
|
|
|
|
case PPC::CR1: return 1;
|
|
|
|
case PPC::CR2: return 2;
|
|
|
|
case PPC::CR3: return 3;
|
|
|
|
case PPC::CR4: return 4;
|
|
|
|
case PPC::CR5: return 5;
|
|
|
|
case PPC::CR6: return 6;
|
|
|
|
case PPC::CR7: return 7;
|
|
|
|
}
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2004-08-14 22:09:10 +00:00
|
|
|
/// printInstruction - This method is automatically generated by tablegen
|
|
|
|
/// from the instruction set description. This method returns true if the
|
|
|
|
/// machine instruction was sufficiently described to print it, otherwise it
|
|
|
|
/// returns false.
|
|
|
|
bool printInstruction(const MachineInstr *MI);
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
void printMachineInstruction(const MachineInstr *MI);
|
2005-11-17 19:25:59 +00:00
|
|
|
void printOp(const MachineOperand &MO);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-20 20:56:46 +00:00
|
|
|
/// stripRegisterPrefix - This method strips the character prefix from a
|
|
|
|
/// register name so that only the number is left. Used by for linux asm.
|
2006-12-20 21:33:34 +00:00
|
|
|
const char *stripRegisterPrefix(const char *RegName) {
|
|
|
|
switch (RegName[0]) {
|
|
|
|
case 'r':
|
|
|
|
case 'f':
|
|
|
|
case 'v': return RegName + 1;
|
2006-12-20 21:35:00 +00:00
|
|
|
case 'c': if (RegName[1] == 'r') return RegName + 2;
|
2006-12-20 20:56:46 +00:00
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-20 21:33:34 +00:00
|
|
|
return RegName;
|
2006-12-20 20:56:46 +00:00
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-20 20:56:46 +00:00
|
|
|
/// printRegister - Print register according to target requirements.
|
|
|
|
///
|
|
|
|
void printRegister(const MachineOperand &MO, bool R0AsZero) {
|
|
|
|
unsigned RegNo = MO.getReg();
|
2008-02-10 18:45:23 +00:00
|
|
|
assert(TargetRegisterInfo::isPhysicalRegister(RegNo) && "Not physreg??");
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-20 20:56:46 +00:00
|
|
|
// If we should use 0 for R0.
|
|
|
|
if (R0AsZero && RegNo == PPC::R0) {
|
|
|
|
O << "0";
|
|
|
|
return;
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-02-26 21:11:01 +00:00
|
|
|
const char *RegName = TM.getRegisterInfo()->get(RegNo).AsmName;
|
2006-12-20 20:56:46 +00:00
|
|
|
// Linux assembler (Others?) does not take register mnemonics.
|
|
|
|
// FIXME - What about special registers used in mfspr/mtspr?
|
2006-12-20 21:33:34 +00:00
|
|
|
if (!Subtarget.isDarwin()) RegName = stripRegisterPrefix(RegName);
|
|
|
|
O << RegName;
|
2006-12-20 20:56:46 +00:00
|
|
|
}
|
2004-08-14 23:27:29 +00:00
|
|
|
|
2006-02-01 22:38:46 +00:00
|
|
|
void printOperand(const MachineInstr *MI, unsigned OpNo) {
|
2004-08-14 23:27:29 +00:00
|
|
|
const MachineOperand &MO = MI->getOperand(OpNo);
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MO.isReg()) {
|
2006-12-20 20:56:46 +00:00
|
|
|
printRegister(MO, false);
|
2008-10-03 15:45:36 +00:00
|
|
|
} else if (MO.isImm()) {
|
2007-12-30 20:49:49 +00:00
|
|
|
O << MO.getImm();
|
2004-08-14 23:27:29 +00:00
|
|
|
} else {
|
|
|
|
printOp(MO);
|
|
|
|
}
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-02-01 22:38:46 +00:00
|
|
|
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
2006-02-23 19:31:10 +00:00
|
|
|
unsigned AsmVariant, const char *ExtraCode);
|
2006-02-24 20:27:40 +00:00
|
|
|
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
|
|
|
unsigned AsmVariant, const char *ExtraCode);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
|
|
|
|
2006-03-25 06:12:06 +00:00
|
|
|
void printS5ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
2007-12-30 20:49:49 +00:00
|
|
|
char value = MI->getOperand(OpNo).getImm();
|
2006-03-25 06:12:06 +00:00
|
|
|
value = (value << (32-5)) >> (32-5);
|
|
|
|
O << (int)value;
|
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printU5ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
2007-12-30 20:49:49 +00:00
|
|
|
unsigned char value = MI->getOperand(OpNo).getImm();
|
2004-08-21 19:11:03 +00:00
|
|
|
assert(value <= 31 && "Invalid u5imm argument!");
|
2004-08-21 05:56:39 +00:00
|
|
|
O << (unsigned int)value;
|
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printU6ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
2007-12-30 20:49:49 +00:00
|
|
|
unsigned char value = MI->getOperand(OpNo).getImm();
|
2004-08-30 02:28:06 +00:00
|
|
|
assert(value <= 63 && "Invalid u6imm argument!");
|
|
|
|
O << (unsigned int)value;
|
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printS16ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
2007-12-30 20:49:49 +00:00
|
|
|
O << (short)MI->getOperand(OpNo).getImm();
|
2004-09-04 05:00:00 +00:00
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printU16ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
2007-12-30 20:49:49 +00:00
|
|
|
O << (unsigned short)MI->getOperand(OpNo).getImm();
|
2004-08-15 05:20:16 +00:00
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printS16X4ImmOperand(const MachineInstr *MI, unsigned OpNo) {
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo).isImm()) {
|
2007-12-30 20:49:49 +00:00
|
|
|
O << (short)(MI->getOperand(OpNo).getImm()*4);
|
2006-11-16 21:45:30 +00:00
|
|
|
} else {
|
|
|
|
O << "lo16(";
|
|
|
|
printOp(MI->getOperand(OpNo));
|
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_)
|
2007-10-14 05:57:21 +00:00
|
|
|
O << "-\"L" << getFunctionNumber() << "$pb\")";
|
2006-11-16 21:45:30 +00:00
|
|
|
else
|
|
|
|
O << ')';
|
|
|
|
}
|
2005-10-18 16:51:22 +00:00
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printBranchOperand(const MachineInstr *MI, unsigned OpNo) {
|
2004-09-04 05:00:00 +00:00
|
|
|
// Branches can take an immediate operand. This is used by the branch
|
|
|
|
// selection pass to print $+8, an eight byte displacement from the PC.
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo).isImm()) {
|
2007-12-30 20:49:49 +00:00
|
|
|
O << "$+" << MI->getOperand(OpNo).getImm()*4;
|
2004-09-04 05:00:00 +00:00
|
|
|
} else {
|
2005-11-17 19:16:08 +00:00
|
|
|
printOp(MI->getOperand(OpNo));
|
2004-09-04 05:00:00 +00:00
|
|
|
}
|
2004-09-02 08:13:00 +00:00
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
|
2005-11-17 19:25:59 +00:00
|
|
|
const MachineOperand &MO = MI->getOperand(OpNo);
|
2006-02-22 20:19:42 +00:00
|
|
|
if (TM.getRelocationModel() != Reloc::Static) {
|
2005-12-16 00:22:14 +00:00
|
|
|
if (MO.getType() == MachineOperand::MO_GlobalAddress) {
|
|
|
|
GlobalValue *GV = MO.getGlobal();
|
2007-01-30 20:08:39 +00:00
|
|
|
if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
|
2008-05-14 20:12:51 +00:00
|
|
|
GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
|
2005-12-16 00:22:14 +00:00
|
|
|
// Dynamically-resolved functions need a stub for the function.
|
|
|
|
std::string Name = Mang->getValueName(GV);
|
|
|
|
FnStubs.insert(Name);
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(Name, "$stub");
|
2006-12-01 07:56:37 +00:00
|
|
|
if (GV->hasExternalWeakLinkage())
|
2006-12-18 03:37:18 +00:00
|
|
|
ExtWeakSymbols.insert(GV);
|
2005-12-16 00:22:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2005-11-17 19:40:30 +00:00
|
|
|
if (MO.getType() == MachineOperand::MO_ExternalSymbol) {
|
2006-09-06 18:34:40 +00:00
|
|
|
std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
|
2005-11-17 19:40:30 +00:00
|
|
|
FnStubs.insert(Name);
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(Name, "$stub");
|
2005-11-17 19:40:30 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-11-17 19:25:59 +00:00
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2005-11-17 19:40:30 +00:00
|
|
|
printOp(MI->getOperand(OpNo));
|
2005-11-17 19:16:08 +00:00
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printAbsAddrOperand(const MachineInstr *MI, unsigned OpNo) {
|
2007-12-30 20:49:49 +00:00
|
|
|
O << (int)MI->getOperand(OpNo).getImm()*4;
|
2005-11-16 00:48:01 +00:00
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printPICLabel(const MachineInstr *MI, unsigned OpNo) {
|
2007-10-14 05:57:21 +00:00
|
|
|
O << "\"L" << getFunctionNumber() << "$pb\"\n";
|
|
|
|
O << "\"L" << getFunctionNumber() << "$pb\":";
|
2004-09-02 08:13:00 +00:00
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo).isImm()) {
|
2005-11-30 18:54:35 +00:00
|
|
|
printS16ImmOperand(MI, OpNo);
|
2005-07-21 20:44:43 +00:00
|
|
|
} else {
|
2007-03-03 05:29:51 +00:00
|
|
|
if (Subtarget.isDarwin()) O << "ha16(";
|
2005-07-21 20:44:43 +00:00
|
|
|
printOp(MI->getOperand(OpNo));
|
2006-07-26 21:12:04 +00:00
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_)
|
2007-10-14 05:57:21 +00:00
|
|
|
O << "-\"L" << getFunctionNumber() << "$pb\"";
|
2007-03-03 05:29:51 +00:00
|
|
|
if (Subtarget.isDarwin())
|
2005-07-21 20:44:43 +00:00
|
|
|
O << ')';
|
2007-03-03 05:29:51 +00:00
|
|
|
else
|
|
|
|
O << "@ha";
|
2005-07-21 20:44:43 +00:00
|
|
|
}
|
2004-09-04 05:00:00 +00:00
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo).isImm()) {
|
2005-11-30 18:54:35 +00:00
|
|
|
printS16ImmOperand(MI, OpNo);
|
2004-09-04 05:00:00 +00:00
|
|
|
} else {
|
2007-03-03 05:29:51 +00:00
|
|
|
if (Subtarget.isDarwin()) O << "lo16(";
|
2004-11-25 07:09:01 +00:00
|
|
|
printOp(MI->getOperand(OpNo));
|
2006-07-26 21:12:04 +00:00
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_)
|
2007-10-14 05:57:21 +00:00
|
|
|
O << "-\"L" << getFunctionNumber() << "$pb\"";
|
2007-03-03 05:29:51 +00:00
|
|
|
if (Subtarget.isDarwin())
|
2005-07-21 20:44:43 +00:00
|
|
|
O << ')';
|
2007-03-03 05:29:51 +00:00
|
|
|
else
|
|
|
|
O << "@l";
|
2004-09-04 05:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
2005-11-30 18:54:35 +00:00
|
|
|
void printcrbitm(const MachineInstr *MI, unsigned OpNo) {
|
2005-07-20 22:42:00 +00:00
|
|
|
unsigned CCReg = MI->getOperand(OpNo).getReg();
|
|
|
|
unsigned RegNo = enumRegToMachineReg(CCReg);
|
|
|
|
O << (0x80 >> RegNo);
|
|
|
|
}
|
2006-02-24 20:27:40 +00:00
|
|
|
// The new addressing mode printers.
|
2005-12-19 23:25:09 +00:00
|
|
|
void printMemRegImm(const MachineInstr *MI, unsigned OpNo) {
|
|
|
|
printSymbolLo(MI, OpNo);
|
|
|
|
O << '(';
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo+1).isReg() &&
|
2006-03-21 17:21:13 +00:00
|
|
|
MI->getOperand(OpNo+1).getReg() == PPC::R0)
|
|
|
|
O << "0";
|
|
|
|
else
|
|
|
|
printOperand(MI, OpNo+1);
|
2005-12-19 23:25:09 +00:00
|
|
|
O << ')';
|
|
|
|
}
|
2006-03-22 05:26:03 +00:00
|
|
|
void printMemRegImmShifted(const MachineInstr *MI, unsigned OpNo) {
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo).isImm())
|
2006-03-22 05:26:03 +00:00
|
|
|
printS16X4ImmOperand(MI, OpNo);
|
2008-08-08 18:22:59 +00:00
|
|
|
else
|
2006-03-22 05:26:03 +00:00
|
|
|
printSymbolLo(MI, OpNo);
|
|
|
|
O << '(';
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo+1).isReg() &&
|
2006-03-22 05:26:03 +00:00
|
|
|
MI->getOperand(OpNo+1).getReg() == PPC::R0)
|
|
|
|
O << "0";
|
|
|
|
else
|
|
|
|
printOperand(MI, OpNo+1);
|
|
|
|
O << ')';
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2005-12-19 23:25:09 +00:00
|
|
|
void printMemRegReg(const MachineInstr *MI, unsigned OpNo) {
|
Fix a couple of the FIXMEs, thanks to suggestion from Chris. This allows
us to load and store vectors directly at a pointer (offset of zero) by
using r0 as the base register. This also requires some asm printer work
to satisfy the darwin assembler.
For
void %foo(<4 x float> * %a) {
entry:
%tmp1 = load <4 x float> * %a;
%tmp2 = add <4 x float> %tmp1, %tmp1
store <4 x float> %tmp2, <4 x float> *%a
ret void
}
We now produce:
_foo:
lvx v0, 0, r3
vaddfp v0, v0, v0
stvx v0, 0, r3
blr
Instead of:
_foo:
li r2, 0
lvx v0, r2, r3
vaddfp v0, v0, v0
stvx v0, r2, r3
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24872 91177308-0d34-0410-b5e6-96231b3b80d8
2005-12-19 23:40:42 +00:00
|
|
|
// 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.
|
|
|
|
const MachineOperand &MO = MI->getOperand(OpNo);
|
2006-12-20 20:56:46 +00:00
|
|
|
printRegister(MO, true);
|
2005-12-19 23:25:09 +00:00
|
|
|
O << ", ";
|
|
|
|
printOperand(MI, OpNo+1);
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
|
|
|
void printPredicateOperand(const MachineInstr *MI, unsigned OpNo,
|
2006-11-04 05:27:39 +00:00
|
|
|
const char *Modifier);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
virtual bool runOnMachineFunction(MachineFunction &F) = 0;
|
2004-09-04 05:00:00 +00:00
|
|
|
virtual bool doFinalization(Module &M) = 0;
|
2007-02-21 22:47:38 +00:00
|
|
|
|
|
|
|
virtual void EmitExternalGlobal(const GlobalVariable *GV);
|
2004-09-04 05:00:00 +00:00
|
|
|
};
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2008-08-08 18:22:59 +00:00
|
|
|
/// PPCLinuxAsmPrinter - PowerPC assembly printer, customized for Linux
|
2009-02-24 08:30:20 +00:00
|
|
|
class VISIBILITY_HIDDEN PPCLinuxAsmPrinter : public PPCAsmPrinter {
|
2009-01-08 23:40:34 +00:00
|
|
|
DwarfWriter *DW;
|
2008-07-09 21:24:07 +00:00
|
|
|
MachineModuleInfo *MMI;
|
2009-02-24 08:30:20 +00:00
|
|
|
public:
|
2008-08-21 00:14:44 +00:00
|
|
|
PPCLinuxAsmPrinter(raw_ostream &O, PPCTargetMachine &TM,
|
2009-03-25 01:47:28 +00:00
|
|
|
const TargetAsmInfo *T, bool F, bool V)
|
|
|
|
: PPCAsmPrinter(O, TM, T, F, V), DW(0), MMI(0) {}
|
2006-12-21 20:26:09 +00:00
|
|
|
|
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "Linux PPC Assembly Printer";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnMachineFunction(MachineFunction &F);
|
|
|
|
bool doInitialization(Module &M);
|
|
|
|
bool doFinalization(Module &M);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
AU.setPreservesAll();
|
2007-01-26 21:22:28 +00:00
|
|
|
AU.addRequired<MachineModuleInfo>();
|
2009-01-08 23:40:34 +00:00
|
|
|
AU.addRequired<DwarfWriter>();
|
2006-12-21 20:26:09 +00:00
|
|
|
PPCAsmPrinter::getAnalysisUsage(AU);
|
|
|
|
}
|
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
void printModuleLevelGV(const GlobalVariable* GVar);
|
2006-12-21 20:26:09 +00:00
|
|
|
};
|
|
|
|
|
2008-08-08 18:22:59 +00:00
|
|
|
/// PPCDarwinAsmPrinter - PowerPC assembly printer, customized for Darwin/Mac
|
|
|
|
/// OS X
|
2009-02-24 08:30:20 +00:00
|
|
|
class VISIBILITY_HIDDEN PPCDarwinAsmPrinter : public PPCAsmPrinter {
|
2009-01-08 23:40:34 +00:00
|
|
|
DwarfWriter *DW;
|
2007-11-20 23:24:42 +00:00
|
|
|
MachineModuleInfo *MMI;
|
2009-01-08 23:40:34 +00:00
|
|
|
raw_ostream &OS;
|
2009-02-24 08:30:20 +00:00
|
|
|
public:
|
2008-08-21 00:14:44 +00:00
|
|
|
PPCDarwinAsmPrinter(raw_ostream &O, PPCTargetMachine &TM,
|
2009-03-25 01:47:28 +00:00
|
|
|
const TargetAsmInfo *T, bool F, bool V)
|
|
|
|
: PPCAsmPrinter(O, TM, T, F, V), DW(0), MMI(0), OS(O) {}
|
2004-09-04 05:00:00 +00:00
|
|
|
|
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "Darwin PPC Assembly Printer";
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
bool runOnMachineFunction(MachineFunction &F);
|
2005-07-21 01:25:49 +00:00
|
|
|
bool doInitialization(Module &M);
|
2004-06-21 16:55:25 +00:00
|
|
|
bool doFinalization(Module &M);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-01-04 22:28:25 +00:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const {
|
2006-01-05 01:25:28 +00:00
|
|
|
AU.setPreservesAll();
|
2007-01-26 21:22:28 +00:00
|
|
|
AU.addRequired<MachineModuleInfo>();
|
2009-01-08 23:40:34 +00:00
|
|
|
AU.addRequired<DwarfWriter>();
|
2006-01-05 01:25:28 +00:00
|
|
|
PPCAsmPrinter::getAnalysisUsage(AU);
|
2006-01-04 22:28:25 +00:00
|
|
|
}
|
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
void printModuleLevelGV(const GlobalVariable* GVar);
|
2004-06-21 16:55:25 +00:00
|
|
|
};
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
2004-09-04 05:00:00 +00:00
|
|
|
// Include the auto-generated portion of the assembly writer
|
2005-10-14 23:37:35 +00:00
|
|
|
#include "PPCGenAsmWriter.inc"
|
2004-09-04 05:00:00 +00:00
|
|
|
|
2005-11-17 19:25:59 +00:00
|
|
|
void PPCAsmPrinter::printOp(const MachineOperand &MO) {
|
2004-06-21 16:55:25 +00:00
|
|
|
switch (MO.getType()) {
|
2006-05-04 17:21:20 +00:00
|
|
|
case MachineOperand::MO_Immediate:
|
2006-12-07 22:21:48 +00:00
|
|
|
cerr << "printOp() does not handle immediate values\n";
|
2004-07-28 00:00:48 +00:00
|
|
|
abort();
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
2004-07-28 00:00:48 +00:00
|
|
|
|
2006-04-22 18:53:45 +00:00
|
|
|
case MachineOperand::MO_MachineBasicBlock:
|
2007-12-30 23:10:15 +00:00
|
|
|
printBasicBlockLabel(MO.getMBB());
|
2006-04-22 18:53:45 +00:00
|
|
|
return;
|
|
|
|
case MachineOperand::MO_JumpTableIndex:
|
2007-10-14 05:57:21 +00:00
|
|
|
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
2007-12-30 23:10:15 +00:00
|
|
|
<< '_' << MO.getIndex();
|
2006-04-22 18:53:45 +00:00
|
|
|
// FIXME: PIC relocation model
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
2004-07-08 17:58:04 +00:00
|
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
2007-10-14 05:57:21 +00:00
|
|
|
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
|
2007-12-30 23:10:15 +00:00
|
|
|
<< '_' << MO.getIndex();
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
2004-07-08 17:58:04 +00:00
|
|
|
case MachineOperand::MO_ExternalSymbol:
|
2005-12-16 00:22:14 +00:00
|
|
|
// Computing the address of an external symbol, not calling it.
|
2006-02-22 20:19:42 +00:00
|
|
|
if (TM.getRelocationModel() != Reloc::Static) {
|
2006-09-06 18:34:40 +00:00
|
|
|
std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
|
2005-12-16 00:22:14 +00:00
|
|
|
GVStubs.insert(Name);
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(Name, "$non_lazy_ptr");
|
2005-12-16 00:22:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-09-06 18:34:40 +00:00
|
|
|
O << TAI->getGlobalPrefix() << MO.getSymbolName();
|
2004-07-08 17:58:04 +00:00
|
|
|
return;
|
2004-08-13 09:32:01 +00:00
|
|
|
case MachineOperand::MO_GlobalAddress: {
|
2005-12-16 00:22:14 +00:00
|
|
|
// Computing the address of a global symbol, not calling it.
|
2004-08-13 09:32:01 +00:00
|
|
|
GlobalValue *GV = MO.getGlobal();
|
|
|
|
std::string Name = Mang->getValueName(GV);
|
|
|
|
|
2004-10-17 23:01:34 +00:00
|
|
|
// External or weakly linked global variables need non-lazily-resolved stubs
|
2006-02-22 20:19:42 +00:00
|
|
|
if (TM.getRelocationModel() != Reloc::Static) {
|
Introduce new linkage types linkonce_odr, weak_odr, common_odr
and extern_weak_odr. These are the same as the non-odr versions,
except that they indicate that the global will only be overridden
by an *equivalent* global. In C, a function with weak linkage can
be overridden by a function which behaves completely differently.
This means that IP passes have to skip weak functions, since any
deductions made from the function definition might be wrong, since
the definition could be replaced by something completely different
at link time. This is not allowed in C++, thanks to the ODR
(One-Definition-Rule): if a function is replaced by another at
link-time, then the new function must be the same as the original
function. If a language knows that a function or other global can
only be overridden by an equivalent global, it can give it the
weak_odr linkage type, and the optimizers will understand that it
is alright to make deductions based on the function body. The
code generators on the other hand map weak and weak_odr linkage
to the same thing.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66339 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-07 15:45:40 +00:00
|
|
|
if (GV->isDeclaration() || GV->isWeakForLinker()) {
|
2008-12-05 01:06:39 +00:00
|
|
|
if (GV->hasHiddenVisibility()) {
|
|
|
|
if (!GV->isDeclaration() && !GV->hasCommonLinkage())
|
|
|
|
O << Name;
|
|
|
|
else {
|
|
|
|
HiddenGVStubs.insert(Name);
|
|
|
|
printSuffixedName(Name, "$non_lazy_ptr");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
GVStubs.insert(Name);
|
|
|
|
printSuffixedName(Name, "$non_lazy_ptr");
|
|
|
|
}
|
2008-05-16 20:09:25 +00:00
|
|
|
if (GV->hasExternalWeakLinkage())
|
|
|
|
ExtWeakSymbols.insert(GV);
|
2005-12-16 00:22:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2005-11-17 19:40:30 +00:00
|
|
|
O << Name;
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-11-22 16:15:34 +00:00
|
|
|
printOffset(MO.getOffset());
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-01 07:56:37 +00:00
|
|
|
if (GV->hasExternalWeakLinkage())
|
2006-12-18 03:37:18 +00:00
|
|
|
ExtWeakSymbols.insert(GV);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
2004-08-13 09:32:01 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
default:
|
2004-07-08 17:58:04 +00:00
|
|
|
O << "<unknown operand type: " << MO.getType() << ">";
|
2004-06-25 15:11:34 +00:00
|
|
|
return;
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-21 22:47:38 +00:00
|
|
|
/// EmitExternalGlobal - In this case we need to use the indirect symbol.
|
|
|
|
///
|
|
|
|
void PPCAsmPrinter::EmitExternalGlobal(const GlobalVariable *GV) {
|
2009-04-10 00:12:49 +00:00
|
|
|
std::string Name;
|
|
|
|
getGlobalLinkName(GV, Name);
|
2007-02-21 22:47:38 +00:00
|
|
|
if (TM.getRelocationModel() != Reloc::Static) {
|
2008-12-05 01:06:39 +00:00
|
|
|
if (GV->hasHiddenVisibility())
|
|
|
|
HiddenGVStubs.insert(Name);
|
|
|
|
else
|
|
|
|
GVStubs.insert(Name);
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(Name, "$non_lazy_ptr");
|
2007-02-21 22:47:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
O << Name;
|
|
|
|
}
|
|
|
|
|
2006-02-23 19:31:10 +00:00
|
|
|
/// PrintAsmOperand - Print out an operand for an inline asm expression.
|
|
|
|
///
|
|
|
|
bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
2008-08-08 18:22:59 +00:00
|
|
|
unsigned AsmVariant,
|
2006-02-23 19:31:10 +00:00
|
|
|
const char *ExtraCode) {
|
|
|
|
// Does this asm operand have a single letter operand modifier?
|
|
|
|
if (ExtraCode && ExtraCode[0]) {
|
|
|
|
if (ExtraCode[1] != 0) return true; // Unknown modifier.
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-02-23 19:31:10 +00:00
|
|
|
switch (ExtraCode[0]) {
|
|
|
|
default: return true; // Unknown modifier.
|
2007-01-25 02:52:50 +00:00
|
|
|
case 'c': // Don't print "$" before a global var name or constant.
|
|
|
|
// PPC never has a prefix.
|
|
|
|
printOperand(MI, OpNo);
|
|
|
|
return false;
|
2008-08-08 18:22:59 +00:00
|
|
|
case 'L': // Write second word of DImode reference.
|
2006-02-23 19:31:10 +00:00
|
|
|
// Verify that this operand has two consecutive registers.
|
2008-10-03 15:45:36 +00:00
|
|
|
if (!MI->getOperand(OpNo).isReg() ||
|
2006-02-23 19:31:10 +00:00
|
|
|
OpNo+1 == MI->getNumOperands() ||
|
2008-10-03 15:45:36 +00:00
|
|
|
!MI->getOperand(OpNo+1).isReg())
|
2006-02-23 19:31:10 +00:00
|
|
|
return true;
|
|
|
|
++OpNo; // Return the high-part.
|
|
|
|
break;
|
2007-04-24 22:51:03 +00:00
|
|
|
case 'I':
|
|
|
|
// Write 'i' if an integer constant, otherwise nothing. Used to print
|
|
|
|
// addi vs add, etc.
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo).isImm())
|
2007-04-24 22:51:03 +00:00
|
|
|
O << "i";
|
|
|
|
return false;
|
2006-02-23 19:31:10 +00:00
|
|
|
}
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-02-23 19:31:10 +00:00
|
|
|
printOperand(MI, OpNo);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-02-24 20:27:40 +00:00
|
|
|
bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
2008-08-08 18:22:59 +00:00
|
|
|
unsigned AsmVariant,
|
2006-02-24 20:27:40 +00:00
|
|
|
const char *ExtraCode) {
|
|
|
|
if (ExtraCode && ExtraCode[0])
|
|
|
|
return true; // Unknown modifier.
|
2008-10-03 15:45:36 +00:00
|
|
|
if (MI->getOperand(OpNo).isReg())
|
2007-02-01 00:39:08 +00:00
|
|
|
printMemRegReg(MI, OpNo);
|
|
|
|
else
|
|
|
|
printMemRegImm(MI, OpNo);
|
2006-02-24 20:27:40 +00:00
|
|
|
return false;
|
|
|
|
}
|
2006-02-23 19:31:10 +00:00
|
|
|
|
2008-08-08 18:22:59 +00:00
|
|
|
void PPCAsmPrinter::printPredicateOperand(const MachineInstr *MI, unsigned OpNo,
|
2006-11-04 05:27:39 +00:00
|
|
|
const char *Modifier) {
|
|
|
|
assert(Modifier && "Must specify 'cc' or 'reg' as predicate op modifier!");
|
|
|
|
unsigned Code = MI->getOperand(OpNo).getImm();
|
|
|
|
if (!strcmp(Modifier, "cc")) {
|
|
|
|
switch ((PPC::Predicate)Code) {
|
|
|
|
case PPC::PRED_ALWAYS: return; // Don't print anything for always.
|
|
|
|
case PPC::PRED_LT: O << "lt"; return;
|
|
|
|
case PPC::PRED_LE: O << "le"; return;
|
|
|
|
case PPC::PRED_EQ: O << "eq"; return;
|
|
|
|
case PPC::PRED_GE: O << "ge"; return;
|
|
|
|
case PPC::PRED_GT: O << "gt"; return;
|
|
|
|
case PPC::PRED_NE: O << "ne"; return;
|
|
|
|
case PPC::PRED_UN: O << "un"; return;
|
|
|
|
case PPC::PRED_NU: O << "nu"; return;
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-11-04 05:27:39 +00:00
|
|
|
} else {
|
|
|
|
assert(!strcmp(Modifier, "reg") &&
|
|
|
|
"Need to specify 'cc' or 'reg' as predicate op modifier!");
|
|
|
|
// Don't print the register for 'always'.
|
|
|
|
if (Code == PPC::PRED_ALWAYS) return;
|
|
|
|
printOperand(MI, OpNo+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-14 22:09:10 +00:00
|
|
|
/// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax to
|
|
|
|
/// the current output stream.
|
2004-06-21 16:55:25 +00:00
|
|
|
///
|
2005-10-14 23:37:35 +00:00
|
|
|
void PPCAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
2004-08-14 22:09:10 +00:00
|
|
|
++EmittedInsts;
|
2005-10-14 22:44:13 +00:00
|
|
|
|
2005-04-05 18:19:50 +00:00
|
|
|
// Check for slwi/srwi mnemonics.
|
|
|
|
if (MI->getOpcode() == PPC::RLWINM) {
|
|
|
|
bool FoundMnemonic = false;
|
2007-12-30 20:49:49 +00:00
|
|
|
unsigned char SH = MI->getOperand(2).getImm();
|
|
|
|
unsigned char MB = MI->getOperand(3).getImm();
|
|
|
|
unsigned char ME = MI->getOperand(4).getImm();
|
2005-04-05 18:19:50 +00:00
|
|
|
if (SH <= 31 && MB == 0 && ME == (31-SH)) {
|
2008-02-05 08:49:09 +00:00
|
|
|
O << "\tslwi "; FoundMnemonic = true;
|
2005-04-05 18:19:50 +00:00
|
|
|
}
|
|
|
|
if (SH <= 31 && MB == (32-SH) && ME == 31) {
|
2008-02-05 08:49:09 +00:00
|
|
|
O << "\tsrwi "; FoundMnemonic = true;
|
2005-04-05 18:19:50 +00:00
|
|
|
SH = 32-SH;
|
|
|
|
}
|
|
|
|
if (FoundMnemonic) {
|
2005-11-30 18:54:35 +00:00
|
|
|
printOperand(MI, 0);
|
2005-04-21 23:30:14 +00:00
|
|
|
O << ", ";
|
2005-11-30 18:54:35 +00:00
|
|
|
printOperand(MI, 1);
|
2008-08-08 18:24:10 +00:00
|
|
|
O << ", " << (unsigned int)SH << '\n';
|
2005-04-05 18:19:50 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-06-20 23:18:58 +00:00
|
|
|
} else if (MI->getOpcode() == PPC::OR || MI->getOpcode() == PPC::OR8) {
|
2006-02-08 06:56:40 +00:00
|
|
|
if (MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) {
|
2008-02-05 08:49:09 +00:00
|
|
|
O << "\tmr ";
|
2006-02-08 06:56:40 +00:00
|
|
|
printOperand(MI, 0);
|
|
|
|
O << ", ";
|
|
|
|
printOperand(MI, 1);
|
2008-08-08 18:24:10 +00:00
|
|
|
O << '\n';
|
2006-02-08 06:56:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-11-18 01:23:56 +00:00
|
|
|
} else if (MI->getOpcode() == PPC::RLDICR) {
|
2007-12-30 20:49:49 +00:00
|
|
|
unsigned char SH = MI->getOperand(2).getImm();
|
|
|
|
unsigned char ME = MI->getOperand(3).getImm();
|
2006-11-18 01:23:56 +00:00
|
|
|
// rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
|
|
|
|
if (63-SH == ME) {
|
2008-02-05 08:49:09 +00:00
|
|
|
O << "\tsldi ";
|
2006-11-18 01:23:56 +00:00
|
|
|
printOperand(MI, 0);
|
|
|
|
O << ", ";
|
|
|
|
printOperand(MI, 1);
|
2008-08-08 18:24:10 +00:00
|
|
|
O << ", " << (unsigned int)SH << '\n';
|
2006-11-18 01:23:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-04-05 18:19:50 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2004-08-14 22:09:10 +00:00
|
|
|
if (printInstruction(MI))
|
|
|
|
return; // Printer was automatically generated
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2004-09-04 05:00:00 +00:00
|
|
|
assert(0 && "Unhandled instruction in asm writer!");
|
|
|
|
abort();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
/// runOnMachineFunction - This uses the printMachineInstruction()
|
|
|
|
/// method to print assembly for each instruction.
|
|
|
|
///
|
2008-08-08 18:22:59 +00:00
|
|
|
bool PPCLinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
2009-02-24 08:30:20 +00:00
|
|
|
this->MF = &MF;
|
2006-12-21 20:26:09 +00:00
|
|
|
|
|
|
|
SetupMachineFunction(MF);
|
|
|
|
O << "\n\n";
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
// Print out constants referenced by the function
|
|
|
|
EmitConstantPool(MF.getConstantPool());
|
|
|
|
|
|
|
|
// Print out labels for the function.
|
|
|
|
const Function *F = MF.getFunction();
|
2008-09-24 22:14:23 +00:00
|
|
|
SwitchToSection(TAI->SectionForGlobal(F));
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
switch (F->getLinkage()) {
|
|
|
|
default: assert(0 && "Unknown linkage type!");
|
2009-01-15 20:18:42 +00:00
|
|
|
case Function::PrivateLinkage:
|
2006-12-21 20:26:09 +00:00
|
|
|
case Function::InternalLinkage: // Symbols default to internal.
|
|
|
|
break;
|
|
|
|
case Function::ExternalLinkage:
|
|
|
|
O << "\t.global\t" << CurrentFnName << '\n'
|
|
|
|
<< "\t.type\t" << CurrentFnName << ", @function\n";
|
|
|
|
break;
|
Introduce new linkage types linkonce_odr, weak_odr, common_odr
and extern_weak_odr. These are the same as the non-odr versions,
except that they indicate that the global will only be overridden
by an *equivalent* global. In C, a function with weak linkage can
be overridden by a function which behaves completely differently.
This means that IP passes have to skip weak functions, since any
deductions made from the function definition might be wrong, since
the definition could be replaced by something completely different
at link time. This is not allowed in C++, thanks to the ODR
(One-Definition-Rule): if a function is replaced by another at
link-time, then the new function must be the same as the original
function. If a language knows that a function or other global can
only be overridden by an equivalent global, it can give it the
weak_odr linkage type, and the optimizers will understand that it
is alright to make deductions based on the function body. The
code generators on the other hand map weak and weak_odr linkage
to the same thing.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66339 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-07 15:45:40 +00:00
|
|
|
case Function::WeakAnyLinkage:
|
|
|
|
case Function::WeakODRLinkage:
|
|
|
|
case Function::LinkOnceAnyLinkage:
|
|
|
|
case Function::LinkOnceODRLinkage:
|
2006-12-21 20:26:09 +00:00
|
|
|
O << "\t.global\t" << CurrentFnName << '\n';
|
|
|
|
O << "\t.weak\t" << CurrentFnName << '\n';
|
|
|
|
break;
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-08-08 18:25:07 +00:00
|
|
|
printVisibility(CurrentFnName, F->getVisibility());
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
EmitAlignment(2, F);
|
|
|
|
O << CurrentFnName << ":\n";
|
|
|
|
|
|
|
|
// Emit pre-function debug information.
|
2009-01-08 23:40:34 +00:00
|
|
|
DW->BeginFunction(&MF);
|
2006-12-21 20:26:09 +00:00
|
|
|
|
|
|
|
// Print out code for the function.
|
|
|
|
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
// Print a label for the basic block.
|
|
|
|
if (I != MF.begin()) {
|
2008-02-28 00:43:03 +00:00
|
|
|
printBasicBlockLabel(I, true, true);
|
2006-12-21 20:26:09 +00:00
|
|
|
O << '\n';
|
|
|
|
}
|
|
|
|
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
|
|
|
II != E; ++II) {
|
|
|
|
// Print the assembly for the instruction.
|
|
|
|
printMachineInstruction(II);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-08 18:24:10 +00:00
|
|
|
O << "\t.size\t" << CurrentFnName << ",.-" << CurrentFnName << '\n';
|
2006-12-21 20:26:09 +00:00
|
|
|
|
|
|
|
// Print out jump tables referenced by the function.
|
|
|
|
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-12-03 19:33:10 +00:00
|
|
|
SwitchToSection(TAI->SectionForGlobal(F));
|
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
// Emit post-function debug information.
|
2009-01-08 23:40:34 +00:00
|
|
|
DW->EndFunction(&MF);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-11-07 19:49:17 +00:00
|
|
|
O.flush();
|
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
// We didn't modify anything.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-08-08 18:22:59 +00:00
|
|
|
bool PPCLinuxAsmPrinter::doInitialization(Module &M) {
|
2007-07-25 19:33:14 +00:00
|
|
|
bool Result = AsmPrinter::doInitialization(M);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-07-09 21:24:07 +00:00
|
|
|
// Emit initial debug information.
|
2009-01-28 13:14:17 +00:00
|
|
|
MMI = getAnalysisIfAvailable<MachineModuleInfo>();
|
2008-07-09 21:24:07 +00:00
|
|
|
assert(MMI);
|
2009-01-28 13:14:17 +00:00
|
|
|
DW = getAnalysisIfAvailable<DwarfWriter>();
|
2009-01-08 23:40:34 +00:00
|
|
|
assert(DW && "DwarfWriter is not available");
|
|
|
|
DW->BeginModule(&M, MMI, O, this, TAI);
|
2008-07-09 21:24:07 +00:00
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
// GNU as handles section names wrapped in quotes
|
|
|
|
Mang->setUseQuotes(true);
|
|
|
|
|
2008-09-24 22:15:21 +00:00
|
|
|
SwitchToSection(TAI->getTextSection());
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2007-07-25 19:33:14 +00:00
|
|
|
return Result;
|
2006-12-21 20:26:09 +00:00
|
|
|
}
|
|
|
|
|
2008-02-15 19:04:54 +00:00
|
|
|
/// PrintUnmangledNameSafely - Print out the printable characters in the name.
|
2009-03-03 02:55:14 +00:00
|
|
|
/// Don't print things like \\n or \\0.
|
2008-08-21 00:14:44 +00:00
|
|
|
static void PrintUnmangledNameSafely(const Value *V, raw_ostream &OS) {
|
2008-02-15 19:04:54 +00:00
|
|
|
for (const char *Name = V->getNameStart(), *E = Name+V->getNameLen();
|
|
|
|
Name != E; ++Name)
|
|
|
|
if (isprint(*Name))
|
|
|
|
OS << *Name;
|
|
|
|
}
|
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
void PPCLinuxAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
|
2006-12-21 20:26:09 +00:00
|
|
|
const TargetData *TD = TM.getTargetData();
|
2006-10-05 02:42:20 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
if (!GVar->hasInitializer())
|
|
|
|
return; // External global require no code
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
// Check to see if this is a special global used by LLVM, if so, emit it.
|
|
|
|
if (EmitSpecialLLVMGlobal(GVar))
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::string name = Mang->getValueName(GVar);
|
2007-01-14 06:37:54 +00:00
|
|
|
|
2008-08-08 18:25:07 +00:00
|
|
|
printVisibility(name, GVar->getVisibility());
|
2007-01-14 06:37:54 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
Constant *C = GVar->getInitializer();
|
|
|
|
const Type *Type = C->getType();
|
2009-01-12 20:38:59 +00:00
|
|
|
unsigned Size = TD->getTypePaddedSize(Type);
|
2008-08-08 18:23:49 +00:00
|
|
|
unsigned Align = TD->getPreferredAlignmentLog(GVar);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-09-24 22:14:23 +00:00
|
|
|
SwitchToSection(TAI->SectionForGlobal(GVar));
|
2006-12-21 20:26:09 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
if (C->isNullValue() && /* FIXME: Verify correct */
|
|
|
|
!GVar->hasSection() &&
|
2009-01-15 20:18:42 +00:00
|
|
|
(GVar->hasLocalLinkage() || GVar->hasExternalLinkage() ||
|
Introduce new linkage types linkonce_odr, weak_odr, common_odr
and extern_weak_odr. These are the same as the non-odr versions,
except that they indicate that the global will only be overridden
by an *equivalent* global. In C, a function with weak linkage can
be overridden by a function which behaves completely differently.
This means that IP passes have to skip weak functions, since any
deductions made from the function definition might be wrong, since
the definition could be replaced by something completely different
at link time. This is not allowed in C++, thanks to the ODR
(One-Definition-Rule): if a function is replaced by another at
link-time, then the new function must be the same as the original
function. If a language knows that a function or other global can
only be overridden by an equivalent global, it can give it the
weak_odr linkage type, and the optimizers will understand that it
is alright to make deductions based on the function body. The
code generators on the other hand map weak and weak_odr linkage
to the same thing.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66339 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-07 15:45:40 +00:00
|
|
|
GVar->isWeakForLinker())) {
|
2006-12-21 20:26:09 +00:00
|
|
|
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
|
2008-08-08 18:23:49 +00:00
|
|
|
|
|
|
|
if (GVar->hasExternalLinkage()) {
|
2006-12-21 20:26:09 +00:00
|
|
|
O << "\t.global " << name << '\n';
|
|
|
|
O << "\t.type " << name << ", @object\n";
|
2007-07-25 03:48:45 +00:00
|
|
|
O << name << ":\n";
|
2008-08-08 18:24:10 +00:00
|
|
|
O << "\t.zero " << Size << '\n';
|
2009-01-15 20:18:42 +00:00
|
|
|
} else if (GVar->hasLocalLinkage()) {
|
2008-08-08 18:24:10 +00:00
|
|
|
O << TAI->getLCOMMDirective() << name << ',' << Size;
|
2006-12-21 20:26:09 +00:00
|
|
|
} else {
|
2008-08-08 18:24:10 +00:00
|
|
|
O << ".comm " << name << ',' << Size;
|
2006-12-21 20:26:09 +00:00
|
|
|
}
|
2009-03-24 00:17:40 +00:00
|
|
|
if (VerboseAsm) {
|
|
|
|
O << "\t\t" << TAI->getCommentString() << " '";
|
|
|
|
PrintUnmangledNameSafely(GVar, O);
|
|
|
|
O << "'";
|
|
|
|
}
|
|
|
|
O << '\n';
|
2008-08-08 18:23:49 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-12-21 20:26:09 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
switch (GVar->getLinkage()) {
|
Introduce new linkage types linkonce_odr, weak_odr, common_odr
and extern_weak_odr. These are the same as the non-odr versions,
except that they indicate that the global will only be overridden
by an *equivalent* global. In C, a function with weak linkage can
be overridden by a function which behaves completely differently.
This means that IP passes have to skip weak functions, since any
deductions made from the function definition might be wrong, since
the definition could be replaced by something completely different
at link time. This is not allowed in C++, thanks to the ODR
(One-Definition-Rule): if a function is replaced by another at
link-time, then the new function must be the same as the original
function. If a language knows that a function or other global can
only be overridden by an equivalent global, it can give it the
weak_odr linkage type, and the optimizers will understand that it
is alright to make deductions based on the function body. The
code generators on the other hand map weak and weak_odr linkage
to the same thing.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66339 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-07 15:45:40 +00:00
|
|
|
case GlobalValue::LinkOnceAnyLinkage:
|
|
|
|
case GlobalValue::LinkOnceODRLinkage:
|
|
|
|
case GlobalValue::WeakAnyLinkage:
|
|
|
|
case GlobalValue::WeakODRLinkage:
|
2009-03-11 20:14:15 +00:00
|
|
|
case GlobalValue::CommonLinkage:
|
2008-08-08 18:23:49 +00:00
|
|
|
O << "\t.global " << name << '\n'
|
|
|
|
<< "\t.type " << name << ", @object\n"
|
|
|
|
<< "\t.weak " << name << '\n';
|
|
|
|
break;
|
|
|
|
case GlobalValue::AppendingLinkage:
|
|
|
|
// FIXME: appending linkage variables should go into a section of
|
|
|
|
// their name or something. For now, just emit them as external.
|
|
|
|
case GlobalValue::ExternalLinkage:
|
|
|
|
// If external or appending, declare as a global symbol
|
2008-08-08 18:24:10 +00:00
|
|
|
O << "\t.global " << name << '\n'
|
2008-08-08 18:23:49 +00:00
|
|
|
<< "\t.type " << name << ", @object\n";
|
|
|
|
// FALL THROUGH
|
|
|
|
case GlobalValue::InternalLinkage:
|
2009-01-15 20:18:42 +00:00
|
|
|
case GlobalValue::PrivateLinkage:
|
2008-08-08 18:23:49 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cerr << "Unknown linkage type!";
|
|
|
|
abort();
|
|
|
|
}
|
2006-12-21 20:26:09 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
EmitAlignment(Align, GVar);
|
2009-03-24 00:17:40 +00:00
|
|
|
O << name << ":";
|
|
|
|
if (VerboseAsm) {
|
|
|
|
O << "\t\t\t\t" << TAI->getCommentString() << " '";
|
|
|
|
PrintUnmangledNameSafely(GVar, O);
|
|
|
|
O << "'";
|
|
|
|
}
|
|
|
|
O << '\n';
|
2006-12-21 20:26:09 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
// If the initializer is a extern weak symbol, remember to emit the weak
|
|
|
|
// reference!
|
|
|
|
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
|
|
|
|
if (GV->hasExternalWeakLinkage())
|
|
|
|
ExtWeakSymbols.insert(GV);
|
2006-12-21 20:26:09 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
EmitGlobalConstant(C);
|
|
|
|
O << '\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PPCLinuxAsmPrinter::doFinalization(Module &M) {
|
|
|
|
// Print out module-level global variables here.
|
|
|
|
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
|
|
|
|
I != E; ++I)
|
|
|
|
printModuleLevelGV(I);
|
2006-12-21 20:26:09 +00:00
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// Emit initial debug information.
|
2009-01-08 23:40:34 +00:00
|
|
|
DW->EndModule();
|
2006-12-21 20:26:09 +00:00
|
|
|
|
2007-07-25 19:33:14 +00:00
|
|
|
return AsmPrinter::doFinalization(M);
|
2006-12-21 20:26:09 +00:00
|
|
|
}
|
|
|
|
|
2004-09-04 05:00:00 +00:00
|
|
|
/// runOnMachineFunction - This uses the printMachineInstruction()
|
|
|
|
/// method to print assembly for each instruction.
|
|
|
|
///
|
2008-08-08 18:22:59 +00:00
|
|
|
bool PPCDarwinAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
2009-02-24 08:30:20 +00:00
|
|
|
this->MF = &MF;
|
|
|
|
|
2005-11-21 07:51:23 +00:00
|
|
|
SetupMachineFunction(MF);
|
2004-09-04 05:00:00 +00:00
|
|
|
O << "\n\n";
|
2007-11-20 23:24:42 +00:00
|
|
|
|
2004-09-04 05:00:00 +00:00
|
|
|
// Print out constants referenced by the function
|
2005-11-21 08:26:15 +00:00
|
|
|
EmitConstantPool(MF.getConstantPool());
|
2004-09-04 05:00:00 +00:00
|
|
|
|
|
|
|
// Print out labels for the function.
|
2005-11-14 18:52:46 +00:00
|
|
|
const Function *F = MF.getFunction();
|
2008-09-24 22:14:23 +00:00
|
|
|
SwitchToSection(TAI->SectionForGlobal(F));
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2005-12-16 00:22:14 +00:00
|
|
|
switch (F->getLinkage()) {
|
|
|
|
default: assert(0 && "Unknown linkage type!");
|
2009-01-25 06:32:01 +00:00
|
|
|
case Function::PrivateLinkage:
|
2005-12-16 00:22:14 +00:00
|
|
|
case Function::InternalLinkage: // Symbols default to internal.
|
|
|
|
break;
|
|
|
|
case Function::ExternalLinkage:
|
2008-08-08 18:24:10 +00:00
|
|
|
O << "\t.globl\t" << CurrentFnName << '\n';
|
2005-12-16 00:22:14 +00:00
|
|
|
break;
|
Introduce new linkage types linkonce_odr, weak_odr, common_odr
and extern_weak_odr. These are the same as the non-odr versions,
except that they indicate that the global will only be overridden
by an *equivalent* global. In C, a function with weak linkage can
be overridden by a function which behaves completely differently.
This means that IP passes have to skip weak functions, since any
deductions made from the function definition might be wrong, since
the definition could be replaced by something completely different
at link time. This is not allowed in C++, thanks to the ODR
(One-Definition-Rule): if a function is replaced by another at
link-time, then the new function must be the same as the original
function. If a language knows that a function or other global can
only be overridden by an equivalent global, it can give it the
weak_odr linkage type, and the optimizers will understand that it
is alright to make deductions based on the function body. The
code generators on the other hand map weak and weak_odr linkage
to the same thing.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66339 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-07 15:45:40 +00:00
|
|
|
case Function::WeakAnyLinkage:
|
|
|
|
case Function::WeakODRLinkage:
|
|
|
|
case Function::LinkOnceAnyLinkage:
|
|
|
|
case Function::LinkOnceODRLinkage:
|
2008-08-08 18:24:10 +00:00
|
|
|
O << "\t.globl\t" << CurrentFnName << '\n';
|
|
|
|
O << "\t.weak_definition\t" << CurrentFnName << '\n';
|
2005-12-16 00:22:14 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-08-08 18:25:07 +00:00
|
|
|
printVisibility(CurrentFnName, F->getVisibility());
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-10-01 23:18:38 +00:00
|
|
|
EmitAlignment(F->hasFnAttr(Attribute::OptimizeForSize) ? 2 : 4, F);
|
2004-09-04 05:00:00 +00:00
|
|
|
O << CurrentFnName << ":\n";
|
|
|
|
|
2006-04-07 20:44:42 +00:00
|
|
|
// Emit pre-function debug information.
|
2009-01-08 23:40:34 +00:00
|
|
|
DW->BeginFunction(&MF);
|
2006-04-07 20:44:42 +00:00
|
|
|
|
2008-01-26 06:51:24 +00:00
|
|
|
// If the function is empty, then we need to emit *something*. Otherwise, the
|
|
|
|
// function's label might be associated with something that it wasn't meant to
|
|
|
|
// be associated with. We emit a noop in this situation.
|
|
|
|
MachineFunction::iterator I = MF.begin();
|
|
|
|
|
2008-01-26 09:03:52 +00:00
|
|
|
if (++I == MF.end() && MF.front().empty())
|
|
|
|
O << "\tnop\n";
|
2008-01-26 06:51:24 +00:00
|
|
|
|
2004-09-04 05:00:00 +00:00
|
|
|
// Print out code for the function.
|
|
|
|
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
// Print a label for the basic block.
|
2005-08-21 19:09:33 +00:00
|
|
|
if (I != MF.begin()) {
|
2009-03-24 00:17:40 +00:00
|
|
|
printBasicBlockLabel(I, true, true, VerboseAsm);
|
2006-05-02 05:37:32 +00:00
|
|
|
O << '\n';
|
2005-08-21 19:09:33 +00:00
|
|
|
}
|
2008-01-26 06:51:24 +00:00
|
|
|
for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end();
|
|
|
|
II != IE; ++II) {
|
2004-09-04 05:00:00 +00:00
|
|
|
// Print the assembly for the instruction.
|
|
|
|
printMachineInstruction(II);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
2004-09-04 05:00:00 +00:00
|
|
|
|
2006-10-05 00:26:05 +00:00
|
|
|
// Print out jump tables referenced by the function.
|
2006-10-05 03:01:21 +00:00
|
|
|
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-01-04 13:52:30 +00:00
|
|
|
// Emit post-function debug information.
|
2009-01-08 23:40:34 +00:00
|
|
|
DW->EndFunction(&MF);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2004-09-04 05:00:00 +00:00
|
|
|
// We didn't modify anything.
|
|
|
|
return false;
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-08 18:22:59 +00:00
|
|
|
bool PPCDarwinAsmPrinter::doInitialization(Module &M) {
|
2008-03-25 21:45:14 +00:00
|
|
|
static const char *const CPUDirectives[] = {
|
2008-02-14 23:35:16 +00:00
|
|
|
"",
|
2006-12-12 20:57:08 +00:00
|
|
|
"ppc",
|
|
|
|
"ppc601",
|
|
|
|
"ppc602",
|
|
|
|
"ppc603",
|
|
|
|
"ppc7400",
|
|
|
|
"ppc750",
|
|
|
|
"ppc970",
|
|
|
|
"ppc64"
|
|
|
|
};
|
|
|
|
|
|
|
|
unsigned Directive = Subtarget.getDarwinDirective();
|
|
|
|
if (Subtarget.isGigaProcessor() && Directive < PPC::DIR_970)
|
|
|
|
Directive = PPC::DIR_970;
|
|
|
|
if (Subtarget.hasAltivec() && Directive < PPC::DIR_7400)
|
|
|
|
Directive = PPC::DIR_7400;
|
|
|
|
if (Subtarget.isPPC64() && Directive < PPC::DIR_970)
|
|
|
|
Directive = PPC::DIR_64;
|
|
|
|
assert(Directive <= PPC::DIR_64 && "Directive out of range.");
|
2008-08-08 18:24:10 +00:00
|
|
|
O << "\t.machine " << CPUDirectives[Directive] << '\n';
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2007-07-25 19:33:14 +00:00
|
|
|
bool Result = AsmPrinter::doInitialization(M);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-07-09 20:43:39 +00:00
|
|
|
// Emit initial debug information.
|
|
|
|
// We need this for Personality functions.
|
|
|
|
// AsmPrinter::doInitialization should have done this analysis.
|
2009-01-28 13:14:17 +00:00
|
|
|
MMI = getAnalysisIfAvailable<MachineModuleInfo>();
|
2008-07-09 20:43:39 +00:00
|
|
|
assert(MMI);
|
2009-01-28 13:14:17 +00:00
|
|
|
DW = getAnalysisIfAvailable<DwarfWriter>();
|
2009-01-08 23:40:34 +00:00
|
|
|
assert(DW && "DwarfWriter is not available");
|
|
|
|
DW->BeginModule(&M, MMI, O, this, TAI);
|
2008-07-09 20:43:39 +00:00
|
|
|
|
2005-11-10 19:33:43 +00:00
|
|
|
// Darwin wants symbols to be quoted if they have complex names.
|
|
|
|
Mang->setUseQuotes(true);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-11-28 18:21:52 +00:00
|
|
|
// Prime text sections so they are adjacent. This reduces the likelihood a
|
|
|
|
// large data or debug section causes a branch to exceed 16M limit.
|
2008-01-11 00:54:37 +00:00
|
|
|
SwitchToTextSection("\t.section __TEXT,__textcoal_nt,coalesced,"
|
2006-11-28 18:21:52 +00:00
|
|
|
"pure_instructions");
|
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_) {
|
2008-01-11 00:54:37 +00:00
|
|
|
SwitchToTextSection("\t.section __TEXT,__picsymbolstub1,symbol_stubs,"
|
2006-11-28 18:21:52 +00:00
|
|
|
"pure_instructions,32");
|
|
|
|
} else if (TM.getRelocationModel() == Reloc::DynamicNoPIC) {
|
2008-01-11 00:54:37 +00:00
|
|
|
SwitchToTextSection("\t.section __TEXT,__symbol_stub1,symbol_stubs,"
|
2006-11-28 18:21:52 +00:00
|
|
|
"pure_instructions,16");
|
|
|
|
}
|
2008-09-24 22:15:21 +00:00
|
|
|
SwitchToSection(TAI->getTextSection());
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2007-07-25 19:33:14 +00:00
|
|
|
return Result;
|
2005-07-21 01:25:49 +00:00
|
|
|
}
|
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
void PPCDarwinAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
|
2006-05-03 01:29:57 +00:00
|
|
|
const TargetData *TD = TM.getTargetData();
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
if (!GVar->hasInitializer())
|
|
|
|
return; // External global require no code
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
// Check to see if this is a special global used by LLVM, if so, emit it.
|
|
|
|
if (EmitSpecialLLVMGlobal(GVar)) {
|
|
|
|
if (TM.getRelocationModel() == Reloc::Static) {
|
|
|
|
if (GVar->getName() == "llvm.global_ctors")
|
|
|
|
O << ".reference .constructors_used\n";
|
|
|
|
else if (GVar->getName() == "llvm.global_dtors")
|
|
|
|
O << ".reference .destructors_used\n";
|
2007-01-30 08:04:53 +00:00
|
|
|
}
|
2008-08-08 18:23:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
std::string name = Mang->getValueName(GVar);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-08-08 18:25:07 +00:00
|
|
|
printVisibility(name, GVar->getVisibility());
|
2008-08-08 18:23:25 +00:00
|
|
|
|
|
|
|
Constant *C = GVar->getInitializer();
|
|
|
|
const Type *Type = C->getType();
|
2009-01-12 20:38:59 +00:00
|
|
|
unsigned Size = TD->getTypePaddedSize(Type);
|
2008-08-08 18:23:25 +00:00
|
|
|
unsigned Align = TD->getPreferredAlignmentLog(GVar);
|
|
|
|
|
2008-09-24 22:14:23 +00:00
|
|
|
SwitchToSection(TAI->SectionForGlobal(GVar));
|
2008-08-08 18:23:25 +00:00
|
|
|
|
|
|
|
if (C->isNullValue() && /* FIXME: Verify correct */
|
|
|
|
!GVar->hasSection() &&
|
2009-01-15 20:18:42 +00:00
|
|
|
(GVar->hasLocalLinkage() || GVar->hasExternalLinkage() ||
|
Introduce new linkage types linkonce_odr, weak_odr, common_odr
and extern_weak_odr. These are the same as the non-odr versions,
except that they indicate that the global will only be overridden
by an *equivalent* global. In C, a function with weak linkage can
be overridden by a function which behaves completely differently.
This means that IP passes have to skip weak functions, since any
deductions made from the function definition might be wrong, since
the definition could be replaced by something completely different
at link time. This is not allowed in C++, thanks to the ODR
(One-Definition-Rule): if a function is replaced by another at
link-time, then the new function must be the same as the original
function. If a language knows that a function or other global can
only be overridden by an equivalent global, it can give it the
weak_odr linkage type, and the optimizers will understand that it
is alright to make deductions based on the function body. The
code generators on the other hand map weak and weak_odr linkage
to the same thing.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66339 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-07 15:45:40 +00:00
|
|
|
GVar->isWeakForLinker()) &&
|
2009-02-18 02:19:52 +00:00
|
|
|
TAI->SectionKindForGlobal(GVar) != SectionKind::RODataMergeStr) {
|
2008-08-08 18:23:25 +00:00
|
|
|
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
|
|
|
|
|
|
|
|
if (GVar->hasExternalLinkage()) {
|
|
|
|
O << "\t.globl " << name << '\n';
|
|
|
|
O << "\t.zerofill __DATA, __common, " << name << ", "
|
|
|
|
<< Size << ", " << Align;
|
2009-01-15 20:18:42 +00:00
|
|
|
} else if (GVar->hasLocalLinkage()) {
|
2008-08-08 18:24:10 +00:00
|
|
|
O << TAI->getLCOMMDirective() << name << ',' << Size << ',' << Align;
|
2008-08-08 18:23:25 +00:00
|
|
|
} else if (!GVar->hasCommonLinkage()) {
|
2008-08-08 18:24:10 +00:00
|
|
|
O << "\t.globl " << name << '\n'
|
|
|
|
<< TAI->getWeakDefDirective() << name << '\n';
|
2008-08-08 18:23:25 +00:00
|
|
|
EmitAlignment(Align, GVar);
|
2009-03-24 00:17:40 +00:00
|
|
|
O << name << ":";
|
|
|
|
if (VerboseAsm) {
|
|
|
|
O << "\t\t\t\t" << TAI->getCommentString() << " ";
|
|
|
|
PrintUnmangledNameSafely(GVar, O);
|
|
|
|
}
|
2008-08-08 18:24:10 +00:00
|
|
|
O << '\n';
|
2008-08-08 18:23:25 +00:00
|
|
|
EmitGlobalConstant(C);
|
|
|
|
return;
|
|
|
|
} else {
|
2008-08-08 18:24:10 +00:00
|
|
|
O << ".comm " << name << ',' << Size;
|
2008-08-08 18:23:25 +00:00
|
|
|
// Darwin 9 and above support aligned common data.
|
|
|
|
if (Subtarget.isDarwin9())
|
2008-08-08 18:24:10 +00:00
|
|
|
O << ',' << Align;
|
2008-08-08 18:23:25 +00:00
|
|
|
}
|
2009-03-24 00:17:40 +00:00
|
|
|
if (VerboseAsm) {
|
|
|
|
O << "\t\t" << TAI->getCommentString() << " '";
|
|
|
|
PrintUnmangledNameSafely(GVar, O);
|
|
|
|
O << "'";
|
|
|
|
}
|
|
|
|
O << '\n';
|
2008-08-08 18:23:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
switch (GVar->getLinkage()) {
|
Introduce new linkage types linkonce_odr, weak_odr, common_odr
and extern_weak_odr. These are the same as the non-odr versions,
except that they indicate that the global will only be overridden
by an *equivalent* global. In C, a function with weak linkage can
be overridden by a function which behaves completely differently.
This means that IP passes have to skip weak functions, since any
deductions made from the function definition might be wrong, since
the definition could be replaced by something completely different
at link time. This is not allowed in C++, thanks to the ODR
(One-Definition-Rule): if a function is replaced by another at
link-time, then the new function must be the same as the original
function. If a language knows that a function or other global can
only be overridden by an equivalent global, it can give it the
weak_odr linkage type, and the optimizers will understand that it
is alright to make deductions based on the function body. The
code generators on the other hand map weak and weak_odr linkage
to the same thing.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66339 91177308-0d34-0410-b5e6-96231b3b80d8
2009-03-07 15:45:40 +00:00
|
|
|
case GlobalValue::LinkOnceAnyLinkage:
|
|
|
|
case GlobalValue::LinkOnceODRLinkage:
|
|
|
|
case GlobalValue::WeakAnyLinkage:
|
|
|
|
case GlobalValue::WeakODRLinkage:
|
2009-03-11 20:14:15 +00:00
|
|
|
case GlobalValue::CommonLinkage:
|
2008-08-08 18:23:25 +00:00
|
|
|
O << "\t.globl " << name << '\n'
|
|
|
|
<< "\t.weak_definition " << name << '\n';
|
|
|
|
break;
|
|
|
|
case GlobalValue::AppendingLinkage:
|
|
|
|
// FIXME: appending linkage variables should go into a section of
|
|
|
|
// their name or something. For now, just emit them as external.
|
|
|
|
case GlobalValue::ExternalLinkage:
|
|
|
|
// If external or appending, declare as a global symbol
|
2008-08-08 18:24:10 +00:00
|
|
|
O << "\t.globl " << name << '\n';
|
2008-08-08 18:23:25 +00:00
|
|
|
// FALL THROUGH
|
|
|
|
case GlobalValue::InternalLinkage:
|
2009-01-25 06:32:01 +00:00
|
|
|
case GlobalValue::PrivateLinkage:
|
2008-08-08 18:23:25 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cerr << "Unknown linkage type!";
|
|
|
|
abort();
|
|
|
|
}
|
2005-12-13 04:33:58 +00:00
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
EmitAlignment(Align, GVar);
|
2009-03-24 00:17:40 +00:00
|
|
|
O << name << ":";
|
|
|
|
if (VerboseAsm) {
|
|
|
|
O << "\t\t\t\t" << TAI->getCommentString() << " '";
|
|
|
|
PrintUnmangledNameSafely(GVar, O);
|
|
|
|
O << "'";
|
|
|
|
}
|
|
|
|
O << '\n';
|
2005-12-13 04:33:58 +00:00
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
// If the initializer is a extern weak symbol, remember to emit the weak
|
|
|
|
// reference!
|
|
|
|
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
|
|
|
|
if (GV->hasExternalWeakLinkage())
|
|
|
|
ExtWeakSymbols.insert(GV);
|
2006-12-01 09:13:26 +00:00
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
EmitGlobalConstant(C);
|
|
|
|
O << '\n';
|
|
|
|
}
|
2006-12-01 09:13:26 +00:00
|
|
|
|
2008-08-08 18:23:25 +00:00
|
|
|
bool PPCDarwinAsmPrinter::doFinalization(Module &M) {
|
|
|
|
const TargetData *TD = TM.getTargetData();
|
|
|
|
|
|
|
|
// Print out module-level global variables here.
|
|
|
|
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
|
|
|
|
I != E; ++I)
|
|
|
|
printModuleLevelGV(I);
|
2004-07-16 20:29:04 +00:00
|
|
|
|
2006-06-27 01:02:25 +00:00
|
|
|
bool isPPC64 = TD->getPointerSizeInBits() == 64;
|
|
|
|
|
2004-07-16 20:29:04 +00:00
|
|
|
// Output stubs for dynamically-linked functions
|
2006-07-26 21:12:04 +00:00
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_) {
|
2008-12-05 01:06:39 +00:00
|
|
|
for (StringSet<>::iterator i = FnStubs.begin(), e = FnStubs.end();
|
2005-12-13 04:33:58 +00:00
|
|
|
i != e; ++i) {
|
2008-01-11 00:54:37 +00:00
|
|
|
SwitchToTextSection("\t.section __TEXT,__picsymbolstub1,symbol_stubs,"
|
2006-10-31 08:31:24 +00:00
|
|
|
"pure_instructions,32");
|
2006-06-27 01:02:25 +00:00
|
|
|
EmitAlignment(4);
|
2008-12-05 01:06:39 +00:00
|
|
|
const char *p = i->getKeyData();
|
|
|
|
bool hasQuote = p[0]=='\"';
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(p, "$stub");
|
|
|
|
O << ":\n";
|
2008-12-05 01:06:39 +00:00
|
|
|
O << "\t.indirect_symbol " << p << '\n';
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmflr r0\n";
|
2008-12-05 01:06:39 +00:00
|
|
|
O << "\tbcl 20,31,";
|
|
|
|
if (hasQuote)
|
|
|
|
O << "\"L0$" << &p[1];
|
|
|
|
else
|
|
|
|
O << "L0$" << p;
|
|
|
|
O << '\n';
|
|
|
|
if (hasQuote)
|
|
|
|
O << "\"L0$" << &p[1];
|
|
|
|
else
|
|
|
|
O << "L0$" << p;
|
|
|
|
O << ":\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmflr r11\n";
|
2008-05-19 21:38:18 +00:00
|
|
|
O << "\taddis r11,r11,ha16(";
|
|
|
|
printSuffixedName(p, "$lazy_ptr");
|
2008-12-05 01:06:39 +00:00
|
|
|
O << "-";
|
|
|
|
if (hasQuote)
|
|
|
|
O << "\"L0$" << &p[1];
|
|
|
|
else
|
|
|
|
O << "L0$" << p;
|
|
|
|
O << ")\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmtlr r0\n";
|
2006-06-27 01:02:25 +00:00
|
|
|
if (isPPC64)
|
2008-05-19 21:38:18 +00:00
|
|
|
O << "\tldu r12,lo16(";
|
2006-06-27 01:02:25 +00:00
|
|
|
else
|
2008-05-19 21:38:18 +00:00
|
|
|
O << "\tlwzu r12,lo16(";
|
|
|
|
printSuffixedName(p, "$lazy_ptr");
|
2008-12-05 01:06:39 +00:00
|
|
|
O << "-";
|
|
|
|
if (hasQuote)
|
|
|
|
O << "\"L0$" << &p[1];
|
|
|
|
else
|
|
|
|
O << "L0$" << p;
|
|
|
|
O << ")(r11)\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmtctr r12\n";
|
|
|
|
O << "\tbctr\n";
|
2006-10-31 08:31:24 +00:00
|
|
|
SwitchToDataSection(".lazy_symbol_pointer");
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(p, "$lazy_ptr");
|
|
|
|
O << ":\n";
|
2008-12-05 01:06:39 +00:00
|
|
|
O << "\t.indirect_symbol " << p << '\n';
|
2006-06-27 01:02:25 +00:00
|
|
|
if (isPPC64)
|
|
|
|
O << "\t.quad dyld_stub_binding_helper\n";
|
|
|
|
else
|
|
|
|
O << "\t.long dyld_stub_binding_helper\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
}
|
|
|
|
} else {
|
2008-12-05 01:06:39 +00:00
|
|
|
for (StringSet<>::iterator i = FnStubs.begin(), e = FnStubs.end();
|
2005-12-13 04:33:58 +00:00
|
|
|
i != e; ++i) {
|
2008-01-11 00:54:37 +00:00
|
|
|
SwitchToTextSection("\t.section __TEXT,__symbol_stub1,symbol_stubs,"
|
2006-10-31 08:31:24 +00:00
|
|
|
"pure_instructions,16");
|
2005-12-13 04:33:58 +00:00
|
|
|
EmitAlignment(4);
|
2008-12-05 01:06:39 +00:00
|
|
|
const char *p = i->getKeyData();
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(p, "$stub");
|
|
|
|
O << ":\n";
|
2008-12-05 01:06:39 +00:00
|
|
|
O << "\t.indirect_symbol " << p << '\n';
|
2008-05-19 21:38:18 +00:00
|
|
|
O << "\tlis r11,ha16(";
|
|
|
|
printSuffixedName(p, "$lazy_ptr");
|
|
|
|
O << ")\n";
|
2006-06-27 01:02:25 +00:00
|
|
|
if (isPPC64)
|
2008-05-19 21:38:18 +00:00
|
|
|
O << "\tldu r12,lo16(";
|
2006-06-27 01:02:25 +00:00
|
|
|
else
|
2008-05-19 21:38:18 +00:00
|
|
|
O << "\tlwzu r12,lo16(";
|
|
|
|
printSuffixedName(p, "$lazy_ptr");
|
|
|
|
O << ")(r11)\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmtctr r12\n";
|
|
|
|
O << "\tbctr\n";
|
2006-10-31 08:31:24 +00:00
|
|
|
SwitchToDataSection(".lazy_symbol_pointer");
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(p, "$lazy_ptr");
|
|
|
|
O << ":\n";
|
2008-12-05 01:06:39 +00:00
|
|
|
O << "\t.indirect_symbol " << p << '\n';
|
2006-06-27 01:02:25 +00:00
|
|
|
if (isPPC64)
|
|
|
|
O << "\t.quad dyld_stub_binding_helper\n";
|
|
|
|
else
|
|
|
|
O << "\t.long dyld_stub_binding_helper\n";
|
2005-07-21 20:44:43 +00:00
|
|
|
}
|
2004-06-24 23:04:11 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2008-08-08 18:24:10 +00:00
|
|
|
O << '\n';
|
2004-07-16 20:29:04 +00:00
|
|
|
|
2008-04-02 00:25:04 +00:00
|
|
|
if (TAI->doesSupportExceptionHandling() && MMI) {
|
2007-11-20 23:24:42 +00:00
|
|
|
// Add the (possibly multiple) personalities to the set of global values.
|
2008-04-02 00:25:04 +00:00
|
|
|
// Only referenced functions get into the Personalities list.
|
2007-11-20 23:24:42 +00:00
|
|
|
const std::vector<Function *>& Personalities = MMI->getPersonalities();
|
|
|
|
|
|
|
|
for (std::vector<Function *>::const_iterator I = Personalities.begin(),
|
|
|
|
E = Personalities.end(); I != E; ++I)
|
|
|
|
if (*I) GVStubs.insert("_" + (*I)->getName());
|
|
|
|
}
|
|
|
|
|
2005-12-16 00:22:14 +00:00
|
|
|
// Output stubs for external and common global variables.
|
2007-10-03 19:26:29 +00:00
|
|
|
if (!GVStubs.empty()) {
|
2006-10-31 08:31:24 +00:00
|
|
|
SwitchToDataSection(".non_lazy_symbol_pointer");
|
2008-12-05 01:06:39 +00:00
|
|
|
for (StringSet<>::iterator i = GVStubs.begin(), e = GVStubs.end();
|
|
|
|
i != e; ++i) {
|
|
|
|
std::string p = i->getKeyData();
|
2008-05-19 21:38:18 +00:00
|
|
|
printSuffixedName(p, "$non_lazy_ptr");
|
|
|
|
O << ":\n";
|
2008-12-05 01:06:39 +00:00
|
|
|
O << "\t.indirect_symbol " << p << '\n';
|
2006-06-27 20:20:53 +00:00
|
|
|
if (isPPC64)
|
|
|
|
O << "\t.quad\t0\n";
|
|
|
|
else
|
|
|
|
O << "\t.long\t0\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
}
|
2004-08-14 22:09:10 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2008-12-05 01:06:39 +00:00
|
|
|
if (!HiddenGVStubs.empty()) {
|
|
|
|
SwitchToSection(TAI->getDataSection());
|
|
|
|
for (StringSet<>::iterator i = HiddenGVStubs.begin(), e = HiddenGVStubs.end();
|
|
|
|
i != e; ++i) {
|
|
|
|
std::string p = i->getKeyData();
|
|
|
|
EmitAlignment(isPPC64 ? 3 : 2);
|
|
|
|
printSuffixedName(p, "$non_lazy_ptr");
|
|
|
|
O << ":\n";
|
|
|
|
if (isPPC64)
|
|
|
|
O << "\t.quad\t";
|
|
|
|
else
|
|
|
|
O << "\t.long\t";
|
|
|
|
O << p << '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-17 17:31:53 +00:00
|
|
|
// Emit initial debug information.
|
2009-01-08 23:40:34 +00:00
|
|
|
DW->EndModule();
|
2006-01-17 17:31:53 +00:00
|
|
|
|
2005-11-01 00:12:36 +00:00
|
|
|
// Funny Darwin hack: This flag tells the linker that no global symbols
|
|
|
|
// contain code that falls through to other global symbols (e.g. the obvious
|
|
|
|
// implementation of multiple entry points). If this doesn't occur, the
|
|
|
|
// linker can safely perform dead code stripping. Since LLVM never generates
|
|
|
|
// code that does this, it is always safe to set.
|
2006-09-20 17:12:19 +00:00
|
|
|
O << "\t.subsections_via_symbols\n";
|
2005-11-01 00:12:36 +00:00
|
|
|
|
2007-07-25 19:33:14 +00:00
|
|
|
return AsmPrinter::doFinalization(M);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-09-04 05:00:00 +00:00
|
|
|
|
2006-09-20 17:12:19 +00:00
|
|
|
|
|
|
|
|
2006-12-20 20:56:46 +00:00
|
|
|
/// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code
|
|
|
|
/// for a MachineFunction to the given output stream, in a format that the
|
2006-09-20 17:12:19 +00:00
|
|
|
/// Darwin assembler can deal with.
|
|
|
|
///
|
2008-08-21 00:14:44 +00:00
|
|
|
FunctionPass *llvm::createPPCAsmPrinterPass(raw_ostream &o,
|
2009-02-24 08:30:20 +00:00
|
|
|
PPCTargetMachine &tm,
|
2009-03-25 01:47:28 +00:00
|
|
|
bool fast, bool verbose) {
|
2006-12-21 20:26:09 +00:00
|
|
|
const PPCSubtarget *Subtarget = &tm.getSubtarget<PPCSubtarget>();
|
|
|
|
|
|
|
|
if (Subtarget->isDarwin()) {
|
2009-03-25 01:47:28 +00:00
|
|
|
return new PPCDarwinAsmPrinter(o, tm, tm.getTargetAsmInfo(), fast, verbose);
|
2006-12-21 20:26:09 +00:00
|
|
|
} else {
|
2009-03-25 01:47:28 +00:00
|
|
|
return new PPCLinuxAsmPrinter(o, tm, tm.getTargetAsmInfo(), fast, verbose);
|
2006-12-21 20:26:09 +00:00
|
|
|
}
|
2006-09-20 17:12:19 +00:00
|
|
|
}
|
2008-08-17 13:54:28 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
static struct Register {
|
|
|
|
Register() {
|
|
|
|
PPCTargetMachine::registerAsmPrinter(createPPCAsmPrinterPass);
|
|
|
|
}
|
|
|
|
} Registrator;
|
|
|
|
}
|
2008-11-15 21:36:30 +00:00
|
|
|
|
|
|
|
extern "C" int PowerPCAsmPrinterForceLink;
|
|
|
|
int PowerPCAsmPrinterForceLink = 0;
|