llvm-6502/lib/Target/MSP430/MSP430AsmPrinter.cpp
Dan Gohman 1c55fab534 Don't flush the raw_ostream between each MachineFunction. These flush
calls were originally put in place because errs() at one time was
not unbuffered, and these print routines are commonly used with errs()
for debugging. However, errs() is now properly unbuffered, so the
flush calls are no longer needed. This significantly reduces the
number of write(2) calls for regular asm printing when there are many
small functions.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78137 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 00:49:25 +00:00

253 lines
7.4 KiB
C++

//===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to the MSP430 assembly language.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "asm-printer"
#include "MSP430.h"
#include "MSP430InstrInfo.h"
#include "MSP430TargetMachine.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
STATISTIC(EmittedInsts, "Number of machine instrs printed");
namespace {
class VISIBILITY_HIDDEN MSP430AsmPrinter : public AsmPrinter {
public:
MSP430AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
const TargetAsmInfo *TAI, bool V)
: AsmPrinter(O, TM, TAI, V) {}
virtual const char *getPassName() const {
return "MSP430 Assembly Printer";
}
void printOperand(const MachineInstr *MI, int OpNum,
const char* Modifier = 0);
void printSrcMemOperand(const MachineInstr *MI, int OpNum,
const char* Modifier = 0);
void printCCOperand(const MachineInstr *MI, int OpNum);
bool printInstruction(const MachineInstr *MI); // autogenerated.
void printMachineInstruction(const MachineInstr * MI);
void emitFunctionHeader(const MachineFunction &MF);
bool runOnMachineFunction(MachineFunction &F);
virtual void PrintGlobalVariable(const GlobalVariable *GV) {
// FIXME: No support for global variables?
}
void getAnalysisUsage(AnalysisUsage &AU) const {
AsmPrinter::getAnalysisUsage(AU);
AU.setPreservesAll();
}
};
} // end of anonymous namespace
#include "MSP430GenAsmWriter.inc"
void MSP430AsmPrinter::emitFunctionHeader(const MachineFunction &MF) {
const Function *F = MF.getFunction();
SwitchToSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
unsigned FnAlign = MF.getAlignment();
EmitAlignment(FnAlign, F);
switch (F->getLinkage()) {
default: llvm_unreachable("Unknown linkage type!");
case Function::InternalLinkage: // Symbols default to internal.
case Function::PrivateLinkage:
case Function::LinkerPrivateLinkage:
break;
case Function::ExternalLinkage:
O << "\t.globl\t" << CurrentFnName << '\n';
break;
case Function::LinkOnceAnyLinkage:
case Function::LinkOnceODRLinkage:
case Function::WeakAnyLinkage:
case Function::WeakODRLinkage:
O << "\t.weak\t" << CurrentFnName << '\n';
break;
}
printVisibility(CurrentFnName, F->getVisibility());
O << "\t.type\t" << CurrentFnName << ",@function\n"
<< CurrentFnName << ":\n";
}
bool MSP430AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
SetupMachineFunction(MF);
O << "\n\n";
// Print the 'header' of function
emitFunctionHeader(MF);
// 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 (!VerboseAsm && (I->pred_empty() || I->isOnlyReachableByFallthrough())) {
// This is an entry block or a block that's only reachable via a
// fallthrough edge. In non-VerboseAsm mode, don't print the label.
} else {
printBasicBlockLabel(I, true, true, VerboseAsm);
O << '\n';
}
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
II != E; ++II)
// Print the assembly for the instruction.
printMachineInstruction(II);
}
if (TAI->hasDotTypeDotSizeDirective())
O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << '\n';
// We didn't modify anything
return false;
}
void MSP430AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
++EmittedInsts;
// Call the autogenerated instruction printer routines.
if (printInstruction(MI))
return;
llvm_unreachable("Should not happen");
}
void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
const char* Modifier) {
const MachineOperand &MO = MI->getOperand(OpNum);
switch (MO.getType()) {
case MachineOperand::MO_Register:
assert (TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
"Virtual registers should be already mapped!");
O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
return;
case MachineOperand::MO_Immediate:
if (!Modifier || strcmp(Modifier, "nohash"))
O << '#';
O << MO.getImm();
return;
case MachineOperand::MO_MachineBasicBlock:
printBasicBlockLabel(MO.getMBB());
return;
case MachineOperand::MO_GlobalAddress: {
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
bool isCallOp = Modifier && !strcmp(Modifier, "call");
std::string Name = Mang->getMangledName(MO.getGlobal());
assert(MO.getOffset() == 0 && "No offsets allowed!");
if (isCallOp)
O << '#';
else if (isMemOp)
O << '&';
O << Name;
return;
}
case MachineOperand::MO_ExternalSymbol: {
bool isCallOp = Modifier && !strcmp(Modifier, "call");
std::string Name(TAI->getGlobalPrefix());
Name += MO.getSymbolName();
if (isCallOp)
O << '#';
O << Name;
return;
}
default:
llvm_unreachable("Not implemented yet!");
}
}
void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum,
const char* Modifier) {
const MachineOperand &Base = MI->getOperand(OpNum);
const MachineOperand &Disp = MI->getOperand(OpNum+1);
if (Base.isGlobal())
printOperand(MI, OpNum, "mem");
else if (Disp.isImm() && !Base.getReg())
printOperand(MI, OpNum);
else if (Base.getReg()) {
if (Disp.getImm()) {
printOperand(MI, OpNum + 1, "nohash");
O << '(';
printOperand(MI, OpNum);
O << ')';
} else {
O << '@';
printOperand(MI, OpNum);
}
} else
llvm_unreachable("Unsupported memory operand");
}
void MSP430AsmPrinter::printCCOperand(const MachineInstr *MI, int OpNum) {
unsigned CC = MI->getOperand(OpNum).getImm();
switch (CC) {
default:
llvm_unreachable("Unsupported CC code");
break;
case MSP430::COND_E:
O << "eq";
break;
case MSP430::COND_NE:
O << "ne";
break;
case MSP430::COND_HS:
O << "hs";
break;
case MSP430::COND_LO:
O << "lo";
break;
case MSP430::COND_GE:
O << "ge";
break;
case MSP430::COND_L:
O << 'l';
break;
}
}
extern "C" void LLVMInitializeMSP430Target() {
// Register the target.
RegisterTargetMachine<MSP430TargetMachine> X(TheMSP430Target);
RegisterAsmPrinter<MSP430AsmPrinter> Y(TheMSP430Target);
}