"llvm/git@repo.hca.bsc.es:rferrer/llvm-epi-0.8.git" did not exist on "7e6d4a12b510b32a4ac98aaf296ef73d70d7d306"
Newer
Older
//===-- MipsAsmPrinter.cpp - Mips 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 GAS-format MIPS assembly language.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mips-asm-printer"
#include "Mips.h"
#include "MipsSubtarget.h"
#include "MipsInstrInfo.h"
#include "MipsTargetMachine.h"
#include "MipsMachineFunction.h"
#include "llvm/BasicBlock.h"
#include "llvm/Instructions.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetData.h"
Bruno Cardoso Lopes
committed
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
Nick Lewycky
committed
class MipsAsmPrinter : public AsmPrinter {
const MipsSubtarget *Subtarget;
Bill Wendling
committed
public:
explicit MipsAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
: AsmPrinter(TM, Streamer) {
Subtarget = &TM.getSubtarget<MipsSubtarget>();
}
virtual const char *getPassName() const {
return "Mips Assembly Printer";
}
Bruno Cardoso Lopes
committed
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O);
void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
void printUnsignedImm(const MachineInstr *MI, int opNum, raw_ostream &O);
Bruno Cardoso Lopes
committed
void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
Bruno Cardoso Lopes
committed
void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
Bruno Cardoso Lopes
committed
const char *Modifier = 0);
void printSavedRegsBitmask(raw_ostream &O);
void printHex32(unsigned int Value, raw_ostream &O);
const char *getCurrentABIString() const;
void emitFrameDirective();
void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen'd.
void EmitInstruction(const MachineInstr *MI) {
SmallString<128> Str;
raw_svector_ostream OS(Str);
printInstruction(MI, OS);
OutStreamer.EmitRawText(OS.str());
virtual void EmitFunctionBodyStart();
virtual void EmitFunctionBodyEnd();
virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const;
static const char *getRegisterName(unsigned RegNo);
virtual void EmitFunctionEntryLabel();
void EmitStartOfAsmFile(Module &M);
};
} // end of anonymous namespace
#include "MipsGenAsmWriter.inc"
//===----------------------------------------------------------------------===//
//
// Mips Asm Directives
//
// -- Frame directive "frame Stackpointer, Stacksize, RARegister"
// Describe the stack frame.
//
Bruno Cardoso Lopes
committed
// -- Mask directives "(f)mask bitmask, offset"
// Tells the assembler which registers are saved and where.
Bruno Cardoso Lopes
committed
// bitmask - contain a little endian bitset indicating which registers are
// saved on function prologue (e.g. with a 0x80000000 mask, the
// assembler knows the register 31 (RA) is saved at prologue.
Bruno Cardoso Lopes
committed
// offset - the position before stack pointer subtraction indicating where
// the first saved register on prologue is located. (e.g. with a
//
// Consider the following function prologue:
//
// .frame $fp,48,$ra
// .mask 0xc0000000,-8
// addiu $sp, $sp, -48
// sw $ra, 40($sp)
// sw $fp, 36($sp)
Bruno Cardoso Lopes
committed
// With a 0xc0000000 mask, the assembler knows the register 31 (RA) and
// 30 (FP) are saved at prologue. As the save order on prologue is from
// left to right, RA is saved first. A -8 offset means that after the
// stack pointer subtration, the first register in the mask (RA) will be
// saved at address 48-8=40.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Mask directives
//===----------------------------------------------------------------------===//
Bruno Cardoso Lopes
committed
// Create a bitmask with all callee saved registers for CPU or Floating Point
// registers. For CPU registers consider RA, GP and FP for saving if necessary.
void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) {
Anton Korobeynikov
committed
const TargetFrameLowering *TFI = TM.getFrameLowering();
const TargetRegisterInfo *RI = TM.getRegisterInfo();
const MipsFunctionInfo *MipsFI = MF->getInfo<MipsFunctionInfo>();
// CPU and FPU Saved Registers Bitmasks
unsigned int CPUBitmask = 0;
unsigned int FPUBitmask = 0;
// Set the CPU and FPU Bitmasks
const MachineFrameInfo *MFI = MF->getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
unsigned Reg = CSI[i].getReg();
unsigned RegNum = MipsRegisterInfo::getRegisterNumbering(Reg);
if (Mips::CPURegsRegisterClass->contains(Reg))
CPUBitmask |= (1 << RegNum);
else
FPUBitmask |= (1 << RegNum);
}
// Return Address and Frame registers must also be set in CPUBitmask.
Anton Korobeynikov
committed
// FIXME: Do we really need hasFP() call here? When no FP is present SP is
// just returned -- will it be ok?
if (TFI->hasFP(*MF))
CPUBitmask |= (1 << MipsRegisterInfo::
getRegisterNumbering(RI->getFrameRegister(*MF)));
if (MFI->adjustsStack())
CPUBitmask |= (1 << MipsRegisterInfo::
getRegisterNumbering(RI->getRARegister()));
O << "\t.mask \t"; printHex32(CPUBitmask, O);
O << ',' << MipsFI->getCPUTopSavedRegOff() << '\n';
// Print FPUBitmask
O << "\t.fmask\t"; printHex32(FPUBitmask, O); O << ","
<< MipsFI->getFPUTopSavedRegOff() << '\n';
}
// Print a 32 bit hex number with all numbers.
void MipsAsmPrinter::printHex32(unsigned Value, raw_ostream &O) {
Bruno Cardoso Lopes
committed
for (int i = 7; i >= 0; i--)
O << utohexstr((Value & (0xF << (i*4))) >> (i*4));
//===----------------------------------------------------------------------===//
// Frame and Set directives
//===----------------------------------------------------------------------===//
/// Frame Directive
void MipsAsmPrinter::emitFrameDirective() {
const TargetRegisterInfo &RI = *TM.getRegisterInfo();
unsigned stackReg = RI.getFrameRegister(*MF);
unsigned returnReg = RI.getRARegister();
unsigned stackSize = MF->getFrameInfo()->getStackSize();
OutStreamer.EmitRawText("\t.frame\t$" +
Twine(LowercaseString(getRegisterName(stackReg))) +
"," + Twine(stackSize) + ",$" +
Twine(LowercaseString(getRegisterName(returnReg))));
}
/// Emit Set directives.
Bruno Cardoso Lopes
committed
const char *MipsAsmPrinter::getCurrentABIString() const {
switch (Subtarget->getTargetABI()) {
Bruno Cardoso Lopes
committed
case MipsSubtarget::O32: return "abi32";
case MipsSubtarget::O64: return "abiO64";
case MipsSubtarget::N32: return "abiN32";
case MipsSubtarget::N64: return "abi64";
case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64
default: break;
llvm_unreachable("Unknown Mips ABI");
Bruno Cardoso Lopes
committed
}
void MipsAsmPrinter::EmitFunctionEntryLabel() {
OutStreamer.EmitRawText("\t.ent\t" + Twine(CurrentFnSym->getName()));
OutStreamer.EmitLabel(CurrentFnSym);
}
/// EmitFunctionBodyStart - Targets can override this to emit stuff before
/// the first basic block in the function.
void MipsAsmPrinter::EmitFunctionBodyStart() {
emitFrameDirective();
Bruno Cardoso Lopes
committed
SmallString<128> Str;
raw_svector_ostream OS(Str);
printSavedRegsBitmask(OS);
OutStreamer.EmitRawText(OS.str());
/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
/// the last basic block in the function.
void MipsAsmPrinter::EmitFunctionBodyEnd() {
// There are instruction for this macros, but they must
// always be at the function end, and we can't emit and
Bruno Cardoso Lopes
committed
// break with BB logic.
OutStreamer.EmitRawText(StringRef("\t.set\tmacro"));
OutStreamer.EmitRawText(StringRef("\t.set\treorder"));
OutStreamer.EmitRawText("\t.end\t" + Twine(CurrentFnSym->getName()));
/// isBlockOnlyReachableByFallthough - Return true if the basic block has
/// exactly one predecessor and the control transfer mechanism between
/// the predecessor and this block is a fall-through.
Bruno Cardoso Lopes
committed
bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
const {
// The predecessor has to be immediately before this block.
const MachineBasicBlock *Pred = *MBB->pred_begin();
// If the predecessor is a switch statement, assume a jump table
// implementation, so it is not a fall through.
if (const BasicBlock *bb = Pred->getBasicBlock())
if (isa<SwitchInst>(bb->getTerminator()))
return false;
Bruno Cardoso Lopes
committed
Akira Hatanaka
committed
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// If this is a landing pad, it isn't a fall through. If it has no preds,
// then nothing falls through to it.
if (MBB->isLandingPad() || MBB->pred_empty())
return false;
// If there isn't exactly one predecessor, it can't be a fall through.
MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI;
++PI2;
if (PI2 != MBB->pred_end())
return false;
// The predecessor has to be immediately before this block.
if (!Pred->isLayoutSuccessor(MBB))
return false;
// If the block is completely empty, then it definitely does fall through.
if (Pred->empty())
return true;
// Otherwise, check the last instruction.
// Check if the last terminator is an unconditional branch.
MachineBasicBlock::const_iterator I = Pred->end();
while (I != Pred->begin() && !(--I)->getDesc().isTerminator());
return !I->getDesc().isBarrier();
// Print out an operand for an inline asm expression.
Bruno Cardoso Lopes
committed
bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,const char *ExtraCode,
raw_ostream &O) {
// Does this asm operand have a single letter operand modifier?
Bruno Cardoso Lopes
committed
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier.
printOperand(MI, OpNo, O);
void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
raw_ostream &O) {
const MachineOperand &MO = MI->getOperand(opNum);
bool closeP = false;
closeP = true;
switch(MO.getTargetFlags()) {
case MipsII::MO_GPREL: O << "%gp_rel("; break;
case MipsII::MO_GOT_CALL: O << "%call16("; break;
case MipsII::MO_GOT: {
const MachineOperand &LastMO = MI->getOperand(opNum-1);
bool LastMOIsGP = LastMO.getType() == MachineOperand::MO_Register
&& LastMO.getReg() == Mips::GP;
if (MI->getOpcode() == Mips::LW || LastMOIsGP)
O << "%lo(";
case MipsII::MO_ABS_HILO:
if (MI->getOpcode() == Mips::LUi)
O << "%hi(";
else
Bruno Cardoso Lopes
committed
O << "%lo(";
switch (MO.getType()) {
case MachineOperand::MO_Register:
O << '$' << LowercaseString(getRegisterName(MO.getReg()));
break;
case MachineOperand::MO_Immediate:
Bruno Cardoso Lopes
committed
O << (short int)MO.getImm();
break;
case MachineOperand::MO_MachineBasicBlock:
O << *MO.getMBB()->getSymbol();
return;
case MachineOperand::MO_GlobalAddress:
O << *Mang->getSymbol(MO.getGlobal());
Bruno Cardoso Lopes
committed
case MachineOperand::MO_BlockAddress: {
MCSymbol* BA = GetBlockAddressSymbol(MO.getBlockAddress());
O << BA->getName();
break;
}
case MachineOperand::MO_ExternalSymbol:
O << *GetExternalSymbolSymbol(MO.getSymbolName());
O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
<< '_' << MO.getIndex();
case MachineOperand::MO_ConstantPoolIndex:
O << MAI->getPrivateGlobalPrefix() << "CPI"
<< getFunctionNumber() << "_" << MO.getIndex();
if (MO.getOffset())
O << "+" << MO.getOffset();
Bruno Cardoso Lopes
committed
llvm_unreachable("<unknown operand type>");
}
if (closeP) O << ")";
}
void MipsAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum,
raw_ostream &O) {
Bruno Cardoso Lopes
committed
const MachineOperand &MO = MI->getOperand(opNum);
Bruno Cardoso Lopes
committed
O << (unsigned short int)MO.getImm();
Bruno Cardoso Lopes
committed
else
printOperand(MI, opNum, O);
Bruno Cardoso Lopes
committed
}
printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
const char *Modifier) {
// when using stack locations for not load/store instructions
// print the same way as all normal 3 operand instructions.
if (Modifier && !strcmp(Modifier, "stackloc")) {
printOperand(MI, opNum+1, O);
O << ", ";
printOperand(MI, opNum, O);
return;
}
Bruno Cardoso Lopes
committed
// Load/Store memory operands -- imm($reg)
// If PIC target the target is loaded as the
// pattern lw $25,%call16($28)
printOperand(MI, opNum, O);
printOperand(MI, opNum+1, O);
Bruno Cardoso Lopes
committed
void MipsAsmPrinter::
printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
const char *Modifier) {
Bruno Cardoso Lopes
committed
const MachineOperand& MO = MI->getOperand(opNum);
Bruno Cardoso Lopes
committed
O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
Bruno Cardoso Lopes
committed
}
void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
// FIXME: Use SwitchSection.
Bruno Cardoso Lopes
committed
// Tell the assembler which ABI we are using
OutStreamer.EmitRawText("\t.section .mdebug." + Twine(getCurrentABIString()));
// TODO: handle O64 ABI
if (Subtarget->isGP32bit())
OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long32"));
else
OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long64"));
// return to previous section
Bruno Cardoso Lopes
committed
OutStreamer.EmitRawText(StringRef("\t.previous"));
// Force static initialization.
Bruno Cardoso Lopes
committed
extern "C" void LLVMInitializeMipsAsmPrinter() {
RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget);
RegisterAsmPrinter<MipsAsmPrinter> Y(TheMipselTarget);