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"
|
2009-09-13 17:14:04 +00:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2009-08-10 18:15:01 +00:00
|
|
|
#include "llvm/MC/MCSectionMachO.h"
|
2009-08-19 05:49:37 +00:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
2009-09-13 17:14:04 +00:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2009-07-31 18:48:30 +00:00
|
|
|
#include "llvm/Target/TargetLoweringObjectFile.h"
|
|
|
|
#include "llvm/Target/TargetRegisterInfo.h"
|
|
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
|
|
#include "llvm/Target/TargetOptions.h"
|
|
|
|
#include "llvm/Target/TargetRegistry.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"
|
2009-07-08 20:53:28 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2006-08-27 12:54:02 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2009-07-14 20:18:05 +00:00
|
|
|
#include "llvm/Support/FormattedStream.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:
|
2009-07-15 02:28:57 +00:00
|
|
|
struct FnStubInfo {
|
|
|
|
std::string Stub, LazyPtr, AnonSymbol;
|
|
|
|
|
|
|
|
FnStubInfo() {}
|
|
|
|
|
|
|
|
void Init(const GlobalValue *GV, Mangler *Mang) {
|
|
|
|
// Already initialized.
|
|
|
|
if (!Stub.empty()) return;
|
|
|
|
Stub = Mang->getMangledName(GV, "$stub", true);
|
|
|
|
LazyPtr = Mang->getMangledName(GV, "$lazy_ptr", true);
|
|
|
|
AnonSymbol = Mang->getMangledName(GV, "$stub$tmp", true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Init(const std::string &GV, Mangler *Mang) {
|
|
|
|
// Already initialized.
|
|
|
|
if (!Stub.empty()) return;
|
2009-07-20 01:03:30 +00:00
|
|
|
Stub = Mang->makeNameProper(GV + "$stub",
|
2009-07-20 19:41:27 +00:00
|
|
|
Mangler::Private);
|
2009-07-20 01:03:30 +00:00
|
|
|
LazyPtr = Mang->makeNameProper(GV + "$lazy_ptr",
|
2009-07-20 19:41:27 +00:00
|
|
|
Mangler::Private);
|
2009-07-20 01:03:30 +00:00
|
|
|
AnonSymbol = Mang->makeNameProper(GV + "$stub$tmp",
|
2009-07-20 19:41:27 +00:00
|
|
|
Mangler::Private);
|
2009-07-15 02:28:57 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
StringMap<FnStubInfo> FnStubs;
|
2009-08-15 11:54:46 +00:00
|
|
|
StringMap<std::string> GVStubs, HiddenGVStubs, TOC;
|
2006-09-20 17:07:15 +00:00
|
|
|
const PPCSubtarget &Subtarget;
|
2009-08-15 11:54:46 +00:00
|
|
|
uint64_t LabelID;
|
2009-02-24 08:30:20 +00:00
|
|
|
public:
|
2009-07-14 20:18:05 +00:00
|
|
|
explicit PPCAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
|
2009-08-22 20:48:53 +00:00
|
|
|
const MCAsmInfo *T, bool V)
|
2009-07-01 01:48:54 +00:00
|
|
|
: AsmPrinter(O, TM, T, V),
|
2009-08-15 11:54:46 +00:00
|
|
|
Subtarget(TM.getSubtarget<PPCSubtarget>()), LabelID(0) {}
|
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) {
|
2009-07-14 16:55:14 +00:00
|
|
|
default: llvm_unreachable("Unhandled register!");
|
2005-07-20 22:42:00 +00:00
|
|
|
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;
|
|
|
|
}
|
2009-07-14 16:55:14 +00:00
|
|
|
llvm_unreachable(0);
|
2005-07-20 22:42:00 +00:00
|
|
|
}
|
|
|
|
|
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.
|
2009-08-08 01:32:19 +00:00
|
|
|
void printInstruction(const MachineInstr *MI);
|
2009-09-13 20:19:22 +00:00
|
|
|
static const char *getRegisterName(unsigned RegNo);
|
2009-09-13 20:08:00 +00:00
|
|
|
|
2004-08-14 22:09:10 +00:00
|
|
|
|
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
|
|
|
|
2009-09-13 20:31:40 +00:00
|
|
|
const char *RegName = getRegisterName(RegNo);
|
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();
|
2009-07-02 16:08:53 +00:00
|
|
|
if (GV->isDeclaration() || GV->isWeakForLinker()) {
|
2005-12-16 00:22:14 +00:00
|
|
|
// Dynamically-resolved functions need a stub for the function.
|
2009-07-15 02:28:57 +00:00
|
|
|
FnStubInfo &FnInfo = FnStubs[Mang->getMangledName(GV)];
|
|
|
|
FnInfo.Init(GV, Mang);
|
|
|
|
O << FnInfo.Stub;
|
2005-12-16 00:22:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2005-11-17 19:40:30 +00:00
|
|
|
if (MO.getType() == MachineOperand::MO_ExternalSymbol) {
|
2009-07-15 02:28:57 +00:00
|
|
|
FnStubInfo &FnInfo =FnStubs[Mang->makeNameProper(MO.getSymbolName())];
|
|
|
|
FnInfo.Init(MO.getSymbolName(), Mang);
|
|
|
|
O << FnInfo.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
|
|
|
|
2009-08-15 11:54:46 +00:00
|
|
|
void printTOCEntryLabel(const MachineInstr *MI, unsigned OpNo) {
|
|
|
|
const MachineOperand &MO = MI->getOperand(OpNo);
|
|
|
|
|
|
|
|
assert(MO.getType() == MachineOperand::MO_GlobalAddress);
|
|
|
|
|
|
|
|
GlobalValue *GV = MO.getGlobal();
|
|
|
|
|
|
|
|
std::string Name = Mang->getMangledName(GV);
|
|
|
|
|
|
|
|
// Map symbol -> label of TOC entry.
|
|
|
|
if (TOC.count(Name) == 0) {
|
|
|
|
std::string Label;
|
2009-08-22 21:43:10 +00:00
|
|
|
Label += MAI->getPrivateGlobalPrefix();
|
2009-08-15 11:54:46 +00:00
|
|
|
Label += "C";
|
|
|
|
Label += utostr(LabelID++);
|
|
|
|
|
|
|
|
TOC[Name] = Label;
|
|
|
|
}
|
|
|
|
|
|
|
|
O << TOC[Name] << "@toc";
|
|
|
|
}
|
|
|
|
|
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
|
|
|
};
|
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 {
|
|
|
|
public:
|
2009-07-15 20:24:03 +00:00
|
|
|
explicit PPCLinuxAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
|
2009-08-22 20:48:53 +00:00
|
|
|
const MCAsmInfo *T, bool V)
|
2009-07-01 01:48:54 +00:00
|
|
|
: PPCAsmPrinter(O, TM, T, V){}
|
2006-12-21 20:26:09 +00:00
|
|
|
|
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "Linux PPC Assembly Printer";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnMachineFunction(MachineFunction &F);
|
2009-08-15 11:54:46 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-07-21 18:38:57 +00:00
|
|
|
void PrintGlobalVariable(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-07-14 20:18:05 +00:00
|
|
|
formatted_raw_ostream &OS;
|
2009-02-24 08:30:20 +00:00
|
|
|
public:
|
2009-07-15 20:24:03 +00:00
|
|
|
explicit PPCDarwinAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
|
2009-08-22 20:48:53 +00:00
|
|
|
const MCAsmInfo *T, bool V)
|
2009-07-01 01:48:54 +00:00
|
|
|
: PPCAsmPrinter(O, TM, T, V), 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
|
|
|
}
|
|
|
|
|
2009-07-21 18:38:57 +00:00
|
|
|
void PrintGlobalVariable(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:
|
2009-07-14 16:55:14 +00:00
|
|
|
llvm_unreachable("printOp() does not handle immediate values");
|
2004-07-28 00:00:48 +00:00
|
|
|
|
2006-04-22 18:53:45 +00:00
|
|
|
case MachineOperand::MO_MachineBasicBlock:
|
2009-09-13 17:14:04 +00:00
|
|
|
GetMBBSymbol(MO.getMBB()->getNumber())->print(O, MAI);
|
2006-04-22 18:53:45 +00:00
|
|
|
return;
|
|
|
|
case MachineOperand::MO_JumpTableIndex:
|
2009-08-22 21:43:10 +00:00
|
|
|
O << MAI->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:
|
2009-08-22 21:43:10 +00:00
|
|
|
O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
|
2007-12-30 23:10:15 +00:00
|
|
|
<< '_' << MO.getIndex();
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
2009-07-15 01:14:44 +00:00
|
|
|
case MachineOperand::MO_ExternalSymbol: {
|
2005-12-16 00:22:14 +00:00
|
|
|
// Computing the address of an external symbol, not calling it.
|
2009-08-22 21:43:10 +00:00
|
|
|
std::string Name(MAI->getGlobalPrefix());
|
2009-07-15 01:14:44 +00:00
|
|
|
Name += MO.getSymbolName();
|
|
|
|
|
2006-02-22 20:19:42 +00:00
|
|
|
if (TM.getRelocationModel() != Reloc::Static) {
|
2009-07-15 01:14:44 +00:00
|
|
|
GVStubs[Name] = Name+"$non_lazy_ptr";
|
|
|
|
Name += "$non_lazy_ptr";
|
2005-12-16 00:22:14 +00:00
|
|
|
}
|
2009-07-15 01:14:44 +00:00
|
|
|
O << Name;
|
2004-07-08 17:58:04 +00:00
|
|
|
return;
|
2009-07-15 01:14:44 +00:00
|
|
|
}
|
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();
|
2009-07-15 01:14:44 +00:00
|
|
|
std::string Name;
|
2004-08-13 09:32:01 +00:00
|
|
|
|
2004-10-17 23:01:34 +00:00
|
|
|
// External or weakly linked global variables need non-lazily-resolved stubs
|
2009-07-15 01:14:44 +00:00
|
|
|
if (TM.getRelocationModel() != Reloc::Static &&
|
|
|
|
(GV->isDeclaration() || GV->isWeakForLinker())) {
|
|
|
|
if (!GV->hasHiddenVisibility()) {
|
|
|
|
Name = Mang->getMangledName(GV, "$non_lazy_ptr", true);
|
|
|
|
GVStubs[Mang->getMangledName(GV)] = Name;
|
|
|
|
} else if (GV->isDeclaration() || GV->hasCommonLinkage() ||
|
|
|
|
GV->hasAvailableExternallyLinkage()) {
|
|
|
|
Name = Mang->getMangledName(GV, "$non_lazy_ptr", true);
|
|
|
|
HiddenGVStubs[Mang->getMangledName(GV)] = Name;
|
|
|
|
} else {
|
|
|
|
Name = Mang->getMangledName(GV);
|
2005-12-16 00:22:14 +00:00
|
|
|
}
|
2009-07-15 01:14:44 +00:00
|
|
|
} else {
|
|
|
|
Name = Mang->getMangledName(GV);
|
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());
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-08-18 00:18:39 +00:00
|
|
|
// At the moment, all inline asm memory operands are a single register.
|
|
|
|
// In any case, the output of this routine should always be just one
|
|
|
|
// assembler operand.
|
|
|
|
|
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.
|
2009-08-18 00:18:39 +00:00
|
|
|
assert (MI->getOperand(OpNo).isReg());
|
2009-08-26 18:10:32 +00:00
|
|
|
O << "0(";
|
2009-08-18 00:18:39 +00:00
|
|
|
printOperand(MI, OpNo);
|
2009-08-26 18:10:32 +00:00
|
|
|
O << ")";
|
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;
|
2009-09-09 20:34:59 +00:00
|
|
|
|
|
|
|
processDebugLoc(MI->getDebugLoc());
|
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
|
|
|
|
2009-08-08 00:05:42 +00:00
|
|
|
printInstruction(MI);
|
2009-09-09 23:14:36 +00:00
|
|
|
|
|
|
|
if (VerboseAsm && !MI->getDebugLoc().isUnknown())
|
|
|
|
EmitComments(*MI);
|
|
|
|
O << '\n';
|
2004-09-04 05:00:00 +00:00
|
|
|
}
|
|
|
|
|
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();
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
switch (F->getLinkage()) {
|
2009-07-14 16:55:14 +00:00
|
|
|
default: llvm_unreachable("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;
|
2009-08-24 01:03:42 +00:00
|
|
|
case Function::LinkerPrivateLinkage:
|
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
|
|
|
|
2009-06-30 22:38:32 +00:00
|
|
|
EmitAlignment(MF.getAlignment(), F);
|
2009-08-15 11:54:46 +00:00
|
|
|
|
|
|
|
if (Subtarget.isPPC64()) {
|
|
|
|
// Emit an official procedure descriptor.
|
|
|
|
// FIXME 64-bit SVR4: Use MCSection here?
|
|
|
|
O << "\t.section\t\".opd\",\"aw\"\n";
|
|
|
|
O << "\t.align 3\n";
|
|
|
|
O << CurrentFnName << ":\n";
|
|
|
|
O << "\t.quad .L." << CurrentFnName << ",.TOC.@tocbase\n";
|
|
|
|
O << "\t.previous\n";
|
|
|
|
O << ".L." << CurrentFnName << ":\n";
|
|
|
|
} else {
|
|
|
|
O << CurrentFnName << ":\n";
|
|
|
|
}
|
2006-12-21 20:26:09 +00:00
|
|
|
|
|
|
|
// 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()) {
|
2009-09-13 18:25:37 +00:00
|
|
|
EmitBasicBlockStart(I);
|
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
|
|
|
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
|
2008-12-03 19:33:10 +00:00
|
|
|
|
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
|
|
|
|
2006-12-21 20:26:09 +00:00
|
|
|
// We didn't modify anything.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-07-21 18:38:57 +00:00
|
|
|
void PPCLinuxAsmPrinter::PrintGlobalVariable(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;
|
|
|
|
|
2009-07-14 18:17:16 +00:00
|
|
|
std::string name = Mang->getMangledName(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-05-09 07:06:46 +00:00
|
|
|
unsigned Size = TD->getTypeAllocSize(Type);
|
2008-08-08 18:23:49 +00:00
|
|
|
unsigned Align = TD->getPreferredAlignmentLog(GVar);
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GVar, Mang,
|
|
|
|
TM));
|
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()) {
|
2009-08-22 21:43:10 +00:00
|
|
|
O << MAI->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) {
|
2009-08-22 21:43:10 +00:00
|
|
|
O << "\t\t" << MAI->getCommentString() << " '";
|
2009-08-13 01:36:44 +00:00
|
|
|
WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
|
2009-03-24 00:17:40 +00:00
|
|
|
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:
|
2009-08-24 01:03:42 +00:00
|
|
|
case GlobalValue::LinkerPrivateLinkage:
|
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:
|
2009-07-14 16:55:14 +00:00
|
|
|
llvm_unreachable("Unknown linkage type!");
|
2008-08-08 18:23:49 +00:00
|
|
|
}
|
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) {
|
2009-08-22 21:43:10 +00:00
|
|
|
O << "\t\t\t\t" << MAI->getCommentString() << " '";
|
2009-08-13 01:36:44 +00:00
|
|
|
WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
|
2009-03-24 00:17:40 +00:00
|
|
|
O << "'";
|
|
|
|
}
|
|
|
|
O << '\n';
|
2006-12-21 20:26:09 +00:00
|
|
|
|
2008-08-08 18:23:49 +00:00
|
|
|
EmitGlobalConstant(C);
|
|
|
|
O << '\n';
|
|
|
|
}
|
|
|
|
|
2009-08-15 11:54:46 +00:00
|
|
|
bool PPCLinuxAsmPrinter::doFinalization(Module &M) {
|
|
|
|
const TargetData *TD = TM.getTargetData();
|
|
|
|
|
|
|
|
bool isPPC64 = TD->getPointerSizeInBits() == 64;
|
|
|
|
|
|
|
|
if (isPPC64 && !TOC.empty()) {
|
|
|
|
// FIXME 64-bit SVR4: Use MCSection here?
|
|
|
|
O << "\t.section\t\".toc\",\"aw\"\n";
|
|
|
|
|
|
|
|
for (StringMap<std::string>::iterator I = TOC.begin(), E = TOC.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
O << I->second << ":\n";
|
|
|
|
O << "\t.tc " << I->getKeyData() << "[TC]," << I->getKeyData() << '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
|
2008-08-08 18:22:59 +00:00
|
|
|
|
2005-12-16 00:22:14 +00:00
|
|
|
switch (F->getLinkage()) {
|
2009-07-14 16:55:14 +00:00
|
|
|
default: llvm_unreachable("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:
|
2009-08-24 01:03:42 +00:00
|
|
|
case Function::LinkerPrivateLinkage:
|
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
|
|
|
|
2009-06-30 22:38:32 +00:00
|
|
|
EmitAlignment(MF.getAlignment(), 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-09-13 18:25:37 +00:00
|
|
|
EmitBasicBlockStart(I);
|
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);
|
2009-06-20 01:00:07 +00:00
|
|
|
assert(MMI);
|
2008-07-09 20:43:39 +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.
|
2009-08-03 22:52:21 +00:00
|
|
|
TargetLoweringObjectFileMachO &TLOFMacho =
|
|
|
|
static_cast<TargetLoweringObjectFileMachO &>(getObjFileLowering());
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(TLOFMacho.getTextCoalSection());
|
2006-11-28 18:21:52 +00:00
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_) {
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(
|
|
|
|
TLOFMacho.getMachOSection("__TEXT", "__picsymbolstub1",
|
|
|
|
MCSectionMachO::S_SYMBOL_STUBS |
|
|
|
|
MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS,
|
|
|
|
32, SectionKind::getText()));
|
2006-11-28 18:21:52 +00:00
|
|
|
} else if (TM.getRelocationModel() == Reloc::DynamicNoPIC) {
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(
|
|
|
|
TLOFMacho.getMachOSection("__TEXT","__symbol_stub1",
|
|
|
|
MCSectionMachO::S_SYMBOL_STUBS |
|
|
|
|
MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS,
|
|
|
|
16, SectionKind::getText()));
|
2006-11-28 18:21:52 +00:00
|
|
|
}
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().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
|
|
|
}
|
|
|
|
|
2009-07-21 18:38:57 +00:00
|
|
|
void PPCDarwinAsmPrinter::PrintGlobalVariable(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) {
|
2009-07-25 23:55:21 +00:00
|
|
|
if (GVar->getName() == "llvm.global_ctors")
|
2008-08-08 18:23:25 +00:00
|
|
|
O << ".reference .constructors_used\n";
|
2009-07-25 23:55:21 +00:00
|
|
|
else if (GVar->getName() == "llvm.global_dtors")
|
2008-08-08 18:23:25 +00:00
|
|
|
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
|
|
|
|
2009-07-14 18:17:16 +00:00
|
|
|
std::string name = Mang->getMangledName(GVar);
|
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-05-09 07:06:46 +00:00
|
|
|
unsigned Size = TD->getTypeAllocSize(Type);
|
2008-08-08 18:23:25 +00:00
|
|
|
unsigned Align = TD->getPreferredAlignmentLog(GVar);
|
|
|
|
|
2009-07-31 18:48:30 +00:00
|
|
|
const MCSection *TheSection =
|
2009-07-29 05:09:30 +00:00
|
|
|
getObjFileLowering().SectionForGlobal(GVar, Mang, TM);
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(TheSection);
|
2008-08-08 18:23:25 +00:00
|
|
|
|
2009-08-04 05:35:56 +00:00
|
|
|
/// FIXME: Drive this off the section!
|
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-07-24 04:08:17 +00:00
|
|
|
// Don't put things that should go in the cstring section into "comm".
|
2009-07-27 05:32:16 +00:00
|
|
|
!TheSection->getKind().isMergeableCString()) {
|
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()) {
|
2009-08-22 21:43:10 +00:00
|
|
|
O << MAI->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'
|
2009-08-22 21:43:10 +00:00
|
|
|
<< MAI->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) {
|
2009-08-22 21:43:10 +00:00
|
|
|
O << "\t\t\t\t" << MAI->getCommentString() << " ";
|
2009-08-13 01:36:44 +00:00
|
|
|
WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
|
2009-03-24 00:17:40 +00:00
|
|
|
}
|
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) {
|
2009-08-22 21:43:10 +00:00
|
|
|
O << "\t\t" << MAI->getCommentString() << " '";
|
2009-08-13 01:36:44 +00:00
|
|
|
WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
|
2009-03-24 00:17:40 +00:00
|
|
|
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:
|
2009-08-24 01:03:42 +00:00
|
|
|
case GlobalValue::LinkerPrivateLinkage:
|
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:
|
2009-07-14 16:55:14 +00:00
|
|
|
llvm_unreachable("Unknown linkage type!");
|
2008-08-08 18:23:25 +00:00
|
|
|
}
|
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) {
|
2009-08-22 21:43:10 +00:00
|
|
|
O << "\t\t\t\t" << MAI->getCommentString() << " '";
|
2009-08-13 01:36:44 +00:00
|
|
|
WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
|
2009-03-24 00:17:40 +00:00
|
|
|
O << "'";
|
|
|
|
}
|
|
|
|
O << '\n';
|
2005-12-13 04:33:58 +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();
|
|
|
|
|
2006-06-27 01:02:25 +00:00
|
|
|
bool isPPC64 = TD->getPointerSizeInBits() == 64;
|
|
|
|
|
2009-08-03 22:52:21 +00:00
|
|
|
// Darwin/PPC always uses mach-o.
|
|
|
|
TargetLoweringObjectFileMachO &TLOFMacho =
|
|
|
|
static_cast<TargetLoweringObjectFileMachO &>(getObjFileLowering());
|
|
|
|
|
2009-08-10 01:39:42 +00:00
|
|
|
|
|
|
|
const MCSection *LSPSection = 0;
|
|
|
|
if (!FnStubs.empty()) // .lazy_symbol_pointer
|
|
|
|
LSPSection = TLOFMacho.getLazySymbolPointerSection();
|
|
|
|
|
|
|
|
|
2004-07-16 20:29:04 +00:00
|
|
|
// Output stubs for dynamically-linked functions
|
2009-07-15 00:55:58 +00:00
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_ && !FnStubs.empty()) {
|
2009-08-03 22:52:21 +00:00
|
|
|
const MCSection *StubSection =
|
2009-08-10 01:39:42 +00:00
|
|
|
TLOFMacho.getMachOSection("__TEXT", "__picsymbolstub1",
|
|
|
|
MCSectionMachO::S_SYMBOL_STUBS |
|
|
|
|
MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS,
|
|
|
|
32, SectionKind::getText());
|
|
|
|
for (StringMap<FnStubInfo>::iterator I = FnStubs.begin(), E = FnStubs.end();
|
2009-07-15 01:14:44 +00:00
|
|
|
I != E; ++I) {
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(StubSection);
|
2006-06-27 01:02:25 +00:00
|
|
|
EmitAlignment(4);
|
2009-07-15 02:33:19 +00:00
|
|
|
const FnStubInfo &Info = I->second;
|
|
|
|
O << Info.Stub << ":\n";
|
|
|
|
O << "\t.indirect_symbol " << I->getKeyData() << '\n';
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmflr r0\n";
|
2009-07-15 02:56:53 +00:00
|
|
|
O << "\tbcl 20,31," << Info.AnonSymbol << '\n';
|
|
|
|
O << Info.AnonSymbol << ":\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmflr r11\n";
|
2009-07-15 02:56:53 +00:00
|
|
|
O << "\taddis r11,r11,ha16(" << Info.LazyPtr << "-" << Info.AnonSymbol;
|
2008-12-05 01:06:39 +00:00
|
|
|
O << ")\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmtlr r0\n";
|
2009-07-15 02:56:53 +00:00
|
|
|
O << (isPPC64 ? "\tldu" : "\tlwzu") << " r12,lo16(";
|
|
|
|
O << Info.LazyPtr << "-" << Info.AnonSymbol << ")(r11)\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmtctr r12\n";
|
|
|
|
O << "\tbctr\n";
|
2009-07-16 01:23:26 +00:00
|
|
|
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(LSPSection);
|
2009-07-15 02:33:19 +00:00
|
|
|
O << Info.LazyPtr << ":\n";
|
|
|
|
O << "\t.indirect_symbol " << I->getKeyData() << '\n';
|
2009-07-15 02:36:21 +00:00
|
|
|
O << (isPPC64 ? "\t.quad" : "\t.long") << " dyld_stub_binding_helper\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
}
|
2009-07-15 00:55:58 +00:00
|
|
|
} else if (!FnStubs.empty()) {
|
2009-08-10 01:39:42 +00:00
|
|
|
const MCSection *StubSection =
|
|
|
|
TLOFMacho.getMachOSection("__TEXT","__symbol_stub1",
|
|
|
|
MCSectionMachO::S_SYMBOL_STUBS |
|
|
|
|
MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS,
|
|
|
|
16, SectionKind::getText());
|
2009-08-03 22:52:21 +00:00
|
|
|
|
2009-07-15 02:28:57 +00:00
|
|
|
for (StringMap<FnStubInfo>::iterator I = FnStubs.begin(), E = FnStubs.end();
|
2009-07-15 01:14:44 +00:00
|
|
|
I != E; ++I) {
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(StubSection);
|
2005-12-13 04:33:58 +00:00
|
|
|
EmitAlignment(4);
|
2009-07-15 02:33:19 +00:00
|
|
|
const FnStubInfo &Info = I->second;
|
|
|
|
O << Info.Stub << ":\n";
|
|
|
|
O << "\t.indirect_symbol " << I->getKeyData() << '\n';
|
|
|
|
O << "\tlis r11,ha16(" << Info.LazyPtr << ")\n";
|
2009-07-15 02:36:21 +00:00
|
|
|
O << (isPPC64 ? "\tldu" : "\tlwzu") << " r12,lo16(";
|
2009-07-15 02:33:19 +00:00
|
|
|
O << Info.LazyPtr << ")(r11)\n";
|
2005-12-13 04:33:58 +00:00
|
|
|
O << "\tmtctr r12\n";
|
|
|
|
O << "\tbctr\n";
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(LSPSection);
|
2009-07-15 02:33:19 +00:00
|
|
|
O << Info.LazyPtr << ":\n";
|
|
|
|
O << "\t.indirect_symbol " << I->getKeyData() << '\n';
|
2009-07-15 02:36:21 +00:00
|
|
|
O << (isPPC64 ? "\t.quad" : "\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
|
|
|
|
2009-08-22 21:43:10 +00:00
|
|
|
if (MAI->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.
|
2009-06-24 19:09:55 +00:00
|
|
|
const std::vector<Function *> &Personalities = MMI->getPersonalities();
|
2007-11-20 23:24:42 +00:00
|
|
|
for (std::vector<Function *>::const_iterator I = Personalities.begin(),
|
2009-07-15 01:14:44 +00:00
|
|
|
E = Personalities.end(); I != E; ++I) {
|
|
|
|
if (*I)
|
|
|
|
GVStubs[Mang->getMangledName(*I)] =
|
2009-07-15 01:16:38 +00:00
|
|
|
Mang->getMangledName(*I, "$non_lazy_ptr", true);
|
2009-07-15 01:14:44 +00:00
|
|
|
}
|
2007-11-20 23:24:42 +00:00
|
|
|
}
|
|
|
|
|
2009-08-03 22:52:21 +00:00
|
|
|
// Output macho stubs for external and common global variables.
|
2007-10-03 19:26:29 +00:00
|
|
|
if (!GVStubs.empty()) {
|
2009-08-10 01:39:42 +00:00
|
|
|
// Switch with ".non_lazy_symbol_pointer" directive.
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection());
|
2009-08-10 17:58:51 +00:00
|
|
|
EmitAlignment(isPPC64 ? 3 : 2);
|
|
|
|
|
2009-07-15 01:14:44 +00:00
|
|
|
for (StringMap<std::string>::iterator I = GVStubs.begin(),
|
|
|
|
E = GVStubs.end(); I != E; ++I) {
|
|
|
|
O << I->second << ":\n";
|
|
|
|
O << "\t.indirect_symbol " << I->getKeyData() << '\n';
|
|
|
|
O << (isPPC64 ? "\t.quad\t0\n" : "\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()) {
|
2009-08-19 05:49:37 +00:00
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().getDataSection());
|
2009-07-15 01:14:44 +00:00
|
|
|
EmitAlignment(isPPC64 ? 3 : 2);
|
|
|
|
for (StringMap<std::string>::iterator I = HiddenGVStubs.begin(),
|
|
|
|
E = HiddenGVStubs.end(); I != E; ++I) {
|
|
|
|
O << I->second << ":\n";
|
|
|
|
O << (isPPC64 ? "\t.quad\t" : "\t.long\t") << I->getKeyData() << '\n';
|
2008-12-05 01:06:39 +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.
|
|
|
|
///
|
2009-08-13 23:48:47 +00:00
|
|
|
static AsmPrinter *createPPCAsmPrinterPass(formatted_raw_ostream &o,
|
|
|
|
TargetMachine &tm,
|
2009-08-22 20:48:53 +00:00
|
|
|
const MCAsmInfo *tai,
|
2009-08-13 23:48:47 +00:00
|
|
|
bool verbose) {
|
2006-12-21 20:26:09 +00:00
|
|
|
const PPCSubtarget *Subtarget = &tm.getSubtarget<PPCSubtarget>();
|
|
|
|
|
2009-07-21 18:38:57 +00:00
|
|
|
if (Subtarget->isDarwin())
|
2009-08-13 19:38:51 +00:00
|
|
|
return new PPCDarwinAsmPrinter(o, tm, tai, verbose);
|
|
|
|
return new PPCLinuxAsmPrinter(o, tm, tai, verbose);
|
2006-09-20 17:12:19 +00:00
|
|
|
}
|
2008-08-17 13:54:28 +00:00
|
|
|
|
2009-06-23 23:59:40 +00:00
|
|
|
// Force static initialization.
|
2009-07-15 20:24:03 +00:00
|
|
|
extern "C" void LLVMInitializePowerPCAsmPrinter() {
|
|
|
|
TargetRegistry::RegisterAsmPrinter(ThePPC32Target, createPPCAsmPrinterPass);
|
|
|
|
TargetRegistry::RegisterAsmPrinter(ThePPC64Target, createPPCAsmPrinterPass);
|
|
|
|
}
|