2012-02-17 16:55:11 +08:00
|
|
|
//===-- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer -------------------===//
|
2007-06-06 15:42:06 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 04:36:04 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-06-06 15:42:06 +08:00
|
|
|
//
|
2011-04-16 05:51:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2007-06-06 15:42:06 +08:00
|
|
|
//
|
|
|
|
// This file contains a printer that converts from our internal representation
|
|
|
|
// of machine-dependent LLVM code to GAS-format MIPS assembly language.
|
|
|
|
//
|
2011-04-16 05:51:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2007-06-06 15:42:06 +08:00
|
|
|
|
|
|
|
#define DEBUG_TYPE "mips-asm-printer"
|
2011-07-08 07:56:50 +08:00
|
|
|
#include "InstPrinter/MipsInstPrinter.h"
|
2011-11-12 06:58:42 +08:00
|
|
|
#include "MCTargetDesc/MipsBaseInfo.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "Mips.h"
|
2013-01-19 05:20:38 +08:00
|
|
|
#include "MipsAsmPrinter.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "MipsInstrInfo.h"
|
|
|
|
#include "MipsMCInstLower.h"
|
2013-10-08 21:08:17 +08:00
|
|
|
#include "MipsTargetStreamer.h"
|
2011-11-09 06:26:47 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
#include "llvm/ADT/Twine.h"
|
2007-06-06 15:42:06 +08:00
|
|
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
2007-07-12 07:24:41 +08:00
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
2012-07-06 07:58:21 +08:00
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
2007-06-06 15:42:06 +08:00
|
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
2011-08-13 05:30:06 +08:00
|
|
|
#include "llvm/CodeGen/MachineMemOperand.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/DataLayout.h"
|
|
|
|
#include "llvm/IR/InlineAsm.h"
|
|
|
|
#include "llvm/IR/Instructions.h"
|
2014-01-08 05:19:40 +08:00
|
|
|
#include "llvm/IR/Mangler.h"
|
2009-08-23 04:48:53 +08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2014-01-27 09:33:33 +08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2013-10-06 00:42:21 +08:00
|
|
|
#include "llvm/MC/MCELFStreamer.h"
|
2011-07-08 07:56:50 +08:00
|
|
|
#include "llvm/MC/MCInst.h"
|
2014-01-27 09:33:33 +08:00
|
|
|
#include "llvm/MC/MCSectionELF.h"
|
2009-09-14 01:14:04 +08:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2013-02-20 06:04:37 +08:00
|
|
|
#include "llvm/Support/ELF.h"
|
2012-07-06 07:58:21 +08:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2011-03-05 01:51:39 +08:00
|
|
|
#include "llvm/Target/TargetLoweringObjectFile.h"
|
2007-11-13 03:49:57 +08:00
|
|
|
#include "llvm/Target/TargetOptions.h"
|
2011-07-01 09:04:43 +08:00
|
|
|
|
2007-06-06 15:42:06 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2013-10-08 21:08:17 +08:00
|
|
|
MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() {
|
2014-01-14 09:21:46 +08:00
|
|
|
return static_cast<MipsTargetStreamer &>(*OutStreamer.getTargetStreamer());
|
2013-10-08 21:08:17 +08:00
|
|
|
}
|
|
|
|
|
2012-03-28 08:22:50 +08:00
|
|
|
bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
2013-04-10 03:46:01 +08:00
|
|
|
// Initialize TargetLoweringObjectFile.
|
|
|
|
if (Subtarget->allowMixed16_32())
|
|
|
|
const_cast<TargetLoweringObjectFile&>(getObjFileLowering())
|
|
|
|
.Initialize(OutContext, TM);
|
2012-03-28 08:22:50 +08:00
|
|
|
MipsFI = MF.getInfo<MipsFunctionInfo>();
|
2013-10-28 05:57:36 +08:00
|
|
|
MCP = MF.getConstantPool();
|
2012-03-28 08:22:50 +08:00
|
|
|
AsmPrinter::runOnMachineFunction(MF);
|
|
|
|
return true;
|
2011-11-09 06:26:47 +08:00
|
|
|
}
|
|
|
|
|
2012-09-27 09:59:07 +08:00
|
|
|
bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
|
|
|
|
MCOp = MCInstLowering.LowerOperand(MO);
|
|
|
|
return MCOp.isValid();
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "MipsGenMCPseudoLowering.inc"
|
|
|
|
|
2011-07-08 04:10:52 +08:00
|
|
|
void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
|
|
|
if (MI->isDebugValue()) {
|
2011-12-31 05:09:41 +08:00
|
|
|
SmallString<128> Str;
|
|
|
|
raw_svector_ostream OS(Str);
|
|
|
|
|
2011-07-08 04:10:52 +08:00
|
|
|
PrintDebugValueComment(MI, OS);
|
|
|
|
return;
|
|
|
|
}
|
2007-06-06 15:42:06 +08:00
|
|
|
|
2013-10-28 05:57:36 +08:00
|
|
|
// If we just ended a constant pool, mark it as such.
|
|
|
|
if (InConstantPool && MI->getOpcode() != Mips::CONSTPOOL_ENTRY) {
|
|
|
|
OutStreamer.EmitDataRegion(MCDR_DataRegionEnd);
|
|
|
|
InConstantPool = false;
|
|
|
|
}
|
|
|
|
if (MI->getOpcode() == Mips::CONSTPOOL_ENTRY) {
|
|
|
|
// CONSTPOOL_ENTRY - This instruction represents a floating
|
|
|
|
//constant pool in the function. The first operand is the ID#
|
|
|
|
// for this instruction, the second is the index into the
|
|
|
|
// MachineConstantPool that this is, the third is the size in
|
|
|
|
// bytes of this constant pool entry.
|
|
|
|
// The required alignment is specified on the basic block holding this MI.
|
|
|
|
//
|
|
|
|
unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
|
|
|
|
unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
|
|
|
|
|
|
|
|
// If this is the first entry of the pool, mark it.
|
|
|
|
if (!InConstantPool) {
|
|
|
|
OutStreamer.EmitDataRegion(MCDR_DataRegion);
|
|
|
|
InConstantPool = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
OutStreamer.EmitLabel(GetCPISymbol(LabelId));
|
|
|
|
|
|
|
|
const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
|
|
|
|
if (MCPE.isMachineConstantPoolEntry())
|
|
|
|
EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
|
|
|
|
else
|
|
|
|
EmitGlobalConstant(MCPE.Val.ConstVal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-25 23:06:56 +08:00
|
|
|
|
2012-06-14 07:25:52 +08:00
|
|
|
MachineBasicBlock::const_instr_iterator I = MI;
|
|
|
|
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
|
|
|
|
|
|
|
|
do {
|
2013-02-07 05:50:15 +08:00
|
|
|
// Do any auto-generated pseudo lowerings.
|
|
|
|
if (emitPseudoExpansionLowering(OutStreamer, &*I))
|
|
|
|
continue;
|
2012-08-29 03:07:39 +08:00
|
|
|
|
2013-02-16 05:05:58 +08:00
|
|
|
// The inMips16Mode() test is not permanent.
|
|
|
|
// Some instructions are marked as pseudo right now which
|
|
|
|
// would make the test fail for the wrong reason but
|
|
|
|
// that will be fixed soon. We need this here because we are
|
|
|
|
// removing another test for this situation downstream in the
|
|
|
|
// callchain.
|
|
|
|
//
|
|
|
|
if (I->isPseudo() && !Subtarget->inMips16Mode())
|
|
|
|
llvm_unreachable("Pseudo opcode found in EmitInstruction()");
|
|
|
|
|
2013-02-07 05:50:15 +08:00
|
|
|
MCInst TmpInst0;
|
|
|
|
MCInstLowering.Lower(I, TmpInst0);
|
2012-06-14 07:25:52 +08:00
|
|
|
OutStreamer.EmitInstruction(TmpInst0);
|
2013-02-07 05:50:15 +08:00
|
|
|
} while ((++I != E) && I->isInsideBundle()); // Delay slot check
|
2011-07-08 04:10:52 +08:00
|
|
|
}
|
2007-06-06 15:42:06 +08:00
|
|
|
|
2011-04-16 05:51:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2007-08-28 13:06:17 +08:00
|
|
|
//
|
|
|
|
// Mips Asm Directives
|
|
|
|
//
|
|
|
|
// -- Frame directive "frame Stackpointer, Stacksize, RARegister"
|
|
|
|
// Describe the stack frame.
|
|
|
|
//
|
2011-03-05 01:51:39 +08:00
|
|
|
// -- Mask directives "(f)mask bitmask, offset"
|
2007-08-28 13:06:17 +08:00
|
|
|
// Tells the assembler which registers are saved and where.
|
2011-03-05 01:51:39 +08:00
|
|
|
// bitmask - contain a little endian bitset indicating which registers are
|
|
|
|
// saved on function prologue (e.g. with a 0x80000000 mask, the
|
2007-08-28 13:06:17 +08:00
|
|
|
// assembler knows the register 31 (RA) is saved at prologue.
|
2011-03-05 01:51:39 +08:00
|
|
|
// offset - the position before stack pointer subtraction indicating where
|
2007-08-28 13:06:17 +08:00
|
|
|
// the first saved register on prologue is located. (e.g. with a
|
|
|
|
//
|
|
|
|
// Consider the following function prologue:
|
|
|
|
//
|
2008-02-27 14:33:05 +08:00
|
|
|
// .frame $fp,48,$ra
|
|
|
|
// .mask 0xc0000000,-8
|
|
|
|
// addiu $sp, $sp, -48
|
|
|
|
// sw $ra, 40($sp)
|
|
|
|
// sw $fp, 36($sp)
|
2007-08-28 13:06:17 +08:00
|
|
|
//
|
2011-03-05 01:51:39 +08:00
|
|
|
// 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
|
2007-08-28 13:06:17 +08:00
|
|
|
// stack pointer subtration, the first register in the mask (RA) will be
|
|
|
|
// saved at address 48-8=40.
|
|
|
|
//
|
2011-04-16 05:51:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2007-07-12 07:24:41 +08:00
|
|
|
|
2011-04-16 05:51:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-07-14 22:42:54 +08:00
|
|
|
// Mask directives
|
2011-04-16 05:51:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-07-14 22:42:54 +08:00
|
|
|
|
2011-03-05 01:51:39 +08:00
|
|
|
// Create a bitmask with all callee saved registers for CPU or Floating Point
|
2008-08-06 14:14:43 +08:00
|
|
|
// registers. For CPU registers consider RA, GP and FP for saving if necessary.
|
2010-04-04 12:47:45 +08:00
|
|
|
void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) {
|
2008-08-06 14:14:43 +08:00
|
|
|
// CPU and FPU Saved Registers Bitmasks
|
2011-05-24 04:34:30 +08:00
|
|
|
unsigned CPUBitmask = 0, FPUBitmask = 0;
|
|
|
|
int CPUTopSavedRegOff, FPUTopSavedRegOff;
|
2007-08-28 13:06:17 +08:00
|
|
|
|
2008-08-06 14:14:43 +08:00
|
|
|
// Set the CPU and FPU Bitmasks
|
2010-01-28 14:22:43 +08:00
|
|
|
const MachineFrameInfo *MFI = MF->getFrameInfo();
|
2007-08-28 13:06:17 +08:00
|
|
|
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
|
2011-05-24 04:34:30 +08:00
|
|
|
// size of stack area to which FP callee-saved regs are saved.
|
2013-08-07 07:08:38 +08:00
|
|
|
unsigned CPURegSize = Mips::GPR32RegClass.getSize();
|
2012-04-20 15:30:17 +08:00
|
|
|
unsigned FGR32RegSize = Mips::FGR32RegClass.getSize();
|
|
|
|
unsigned AFGR64RegSize = Mips::AFGR64RegClass.getSize();
|
2011-05-24 04:34:30 +08:00
|
|
|
bool HasAFGR64Reg = false;
|
|
|
|
unsigned CSFPRegsSize = 0;
|
|
|
|
unsigned i, e = CSI.size();
|
|
|
|
|
|
|
|
// Set FPU Bitmask.
|
|
|
|
for (i = 0; i != e; ++i) {
|
2010-06-03 04:02:30 +08:00
|
|
|
unsigned Reg = CSI[i].getReg();
|
2013-08-07 07:08:38 +08:00
|
|
|
if (Mips::GPR32RegClass.contains(Reg))
|
2011-05-24 04:34:30 +08:00
|
|
|
break;
|
|
|
|
|
2012-12-11 04:04:40 +08:00
|
|
|
unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg);
|
2012-04-20 15:30:17 +08:00
|
|
|
if (Mips::AFGR64RegClass.contains(Reg)) {
|
2011-05-24 04:34:30 +08:00
|
|
|
FPUBitmask |= (3 << RegNum);
|
|
|
|
CSFPRegsSize += AFGR64RegSize;
|
|
|
|
HasAFGR64Reg = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
FPUBitmask |= (1 << RegNum);
|
|
|
|
CSFPRegsSize += FGR32RegSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set CPU Bitmask.
|
|
|
|
for (; i != e; ++i) {
|
|
|
|
unsigned Reg = CSI[i].getReg();
|
2012-12-11 04:04:40 +08:00
|
|
|
unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg);
|
2011-05-24 04:34:30 +08:00
|
|
|
CPUBitmask |= (1 << RegNum);
|
2008-08-06 14:14:43 +08:00
|
|
|
}
|
2007-08-28 13:06:17 +08:00
|
|
|
|
2011-05-24 04:34:30 +08:00
|
|
|
// FP Regs are saved right below where the virtual frame pointer points to.
|
|
|
|
FPUTopSavedRegOff = FPUBitmask ?
|
|
|
|
(HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0;
|
2010-11-19 05:19:35 +08:00
|
|
|
|
2011-05-24 04:34:30 +08:00
|
|
|
// CPU Regs are saved below FP Regs.
|
|
|
|
CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0;
|
2007-08-28 13:06:17 +08:00
|
|
|
|
2008-08-06 14:14:43 +08:00
|
|
|
// Print CPUBitmask
|
2010-04-04 12:47:45 +08:00
|
|
|
O << "\t.mask \t"; printHex32(CPUBitmask, O);
|
2011-05-24 04:34:30 +08:00
|
|
|
O << ',' << CPUTopSavedRegOff << '\n';
|
2008-08-06 14:14:43 +08:00
|
|
|
|
|
|
|
// Print FPUBitmask
|
2011-05-24 04:34:30 +08:00
|
|
|
O << "\t.fmask\t"; printHex32(FPUBitmask, O);
|
|
|
|
O << "," << FPUTopSavedRegOff << '\n';
|
2007-08-28 13:06:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Print a 32 bit hex number with all numbers.
|
2010-04-04 12:47:45 +08:00
|
|
|
void MipsAsmPrinter::printHex32(unsigned Value, raw_ostream &O) {
|
2008-08-21 08:14:44 +08:00
|
|
|
O << "0x";
|
2011-03-05 01:51:39 +08:00
|
|
|
for (int i = 7; i >= 0; i--)
|
2011-11-07 04:37:06 +08:00
|
|
|
O.write_hex((Value & (0xF << (i*4))) >> (i*4));
|
2007-07-12 07:24:41 +08:00
|
|
|
}
|
|
|
|
|
2011-04-16 05:51:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-07-14 22:42:54 +08:00
|
|
|
// Frame and Set directives
|
2011-04-16 05:51:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-07-14 22:42:54 +08:00
|
|
|
|
|
|
|
/// Frame Directive
|
2010-04-04 15:05:53 +08:00
|
|
|
void MipsAsmPrinter::emitFrameDirective() {
|
2008-07-14 22:42:54 +08:00
|
|
|
const TargetRegisterInfo &RI = *TM.getRegisterInfo();
|
|
|
|
|
2010-01-28 14:22:43 +08:00
|
|
|
unsigned stackReg = RI.getFrameRegister(*MF);
|
2008-07-14 22:42:54 +08:00
|
|
|
unsigned returnReg = RI.getRARegister();
|
2010-01-28 14:22:43 +08:00
|
|
|
unsigned stackSize = MF->getFrameInfo()->getStackSize();
|
2008-07-14 22:42:54 +08:00
|
|
|
|
2014-01-27 11:53:56 +08:00
|
|
|
getTargetStreamer().emitFrame(stackReg, stackSize, returnReg);
|
2008-07-14 22:42:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit Set directives.
|
2011-03-05 01:51:39 +08:00
|
|
|
const char *MipsAsmPrinter::getCurrentABIString() const {
|
2010-04-04 15:05:53 +08:00
|
|
|
switch (Subtarget->getTargetABI()) {
|
2011-03-05 01:51:39 +08:00
|
|
|
case MipsSubtarget::O32: return "abi32";
|
2010-04-04 15:05:53 +08:00
|
|
|
case MipsSubtarget::N32: return "abiN32";
|
|
|
|
case MipsSubtarget::N64: return "abi64";
|
|
|
|
case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64
|
2012-09-11 05:26:47 +08:00
|
|
|
default: llvm_unreachable("Unknown Mips ABI");
|
2008-07-14 22:42:54 +08:00
|
|
|
}
|
2011-03-05 01:51:39 +08:00
|
|
|
}
|
2008-07-14 22:42:54 +08:00
|
|
|
|
2010-01-28 07:23:58 +08:00
|
|
|
void MipsAsmPrinter::EmitFunctionEntryLabel() {
|
2014-01-15 02:57:12 +08:00
|
|
|
MipsTargetStreamer &TS = getTargetStreamer();
|
2014-01-14 12:25:13 +08:00
|
|
|
if (Subtarget->inMicroMipsMode())
|
2014-01-15 02:57:12 +08:00
|
|
|
TS.emitDirectiveSetMicroMips();
|
|
|
|
// leave out until FSF available gas has micromips changes
|
|
|
|
// else
|
|
|
|
// TS.emitDirectiveSetNoMicroMips();
|
2014-01-14 12:25:13 +08:00
|
|
|
|
2014-01-15 02:57:12 +08:00
|
|
|
if (Subtarget->inMips16Mode())
|
|
|
|
TS.emitDirectiveSetMips16();
|
|
|
|
else
|
|
|
|
TS.emitDirectiveSetNoMips16();
|
2013-02-20 06:04:37 +08:00
|
|
|
|
2014-01-15 02:57:12 +08:00
|
|
|
TS.emitDirectiveEnt(*CurrentFnSym);
|
2010-01-28 07:23:58 +08:00
|
|
|
OutStreamer.EmitLabel(CurrentFnSym);
|
|
|
|
}
|
|
|
|
|
2010-01-28 14:22:43 +08:00
|
|
|
/// EmitFunctionBodyStart - Targets can override this to emit stuff before
|
|
|
|
/// the first basic block in the function.
|
|
|
|
void MipsAsmPrinter::EmitFunctionBodyStart() {
|
2014-01-26 13:06:48 +08:00
|
|
|
MipsTargetStreamer &TS = getTargetStreamer();
|
|
|
|
|
2013-10-30 00:24:21 +08:00
|
|
|
MCInstLowering.Initialize(&MF->getContext());
|
2012-03-28 08:22:50 +08:00
|
|
|
|
2013-05-04 07:17:24 +08:00
|
|
|
bool IsNakedFunction =
|
|
|
|
MF->getFunction()->
|
|
|
|
getAttributes().hasAttribute(AttributeSet::FunctionIndex,
|
|
|
|
Attribute::Naked);
|
|
|
|
if (!IsNakedFunction)
|
|
|
|
emitFrameDirective();
|
2011-03-05 01:51:39 +08:00
|
|
|
|
2011-11-09 06:26:47 +08:00
|
|
|
if (OutStreamer.hasRawTextSupport()) {
|
|
|
|
SmallString<128> Str;
|
|
|
|
raw_svector_ostream OS(Str);
|
2013-05-04 07:17:24 +08:00
|
|
|
if (!IsNakedFunction)
|
|
|
|
printSavedRegsBitmask(OS);
|
2011-11-09 06:26:47 +08:00
|
|
|
OutStreamer.EmitRawText(OS.str());
|
2014-01-26 13:06:48 +08:00
|
|
|
}
|
|
|
|
if (!Subtarget->inMips16Mode()) {
|
|
|
|
TS.emitDirectiveSetNoReorder();
|
|
|
|
TS.emitDirectiveSetNoMacro();
|
|
|
|
TS.emitDirectiveSetNoAt();
|
2012-05-12 08:48:43 +08:00
|
|
|
}
|
2010-01-28 14:22:43 +08:00
|
|
|
}
|
2007-06-06 15:42:06 +08:00
|
|
|
|
2010-01-28 14:22:43 +08:00
|
|
|
/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
|
|
|
|
/// the last basic block in the function.
|
|
|
|
void MipsAsmPrinter::EmitFunctionBodyEnd() {
|
2014-01-26 13:06:48 +08:00
|
|
|
MipsTargetStreamer &TS = getTargetStreamer();
|
|
|
|
|
2010-01-28 09:48:52 +08:00
|
|
|
// There are instruction for this macros, but they must
|
|
|
|
// always be at the function end, and we can't emit and
|
2011-03-05 01:51:39 +08:00
|
|
|
// break with BB logic.
|
2014-01-26 13:06:48 +08:00
|
|
|
if (!Subtarget->inMips16Mode()) {
|
|
|
|
TS.emitDirectiveSetAt();
|
|
|
|
TS.emitDirectiveSetMacro();
|
|
|
|
TS.emitDirectiveSetReorder();
|
2011-11-09 06:26:47 +08:00
|
|
|
}
|
2014-01-26 13:06:48 +08:00
|
|
|
TS.emitDirectiveEnd(CurrentFnSym->getName());
|
2013-10-28 05:57:36 +08:00
|
|
|
// Make sure to terminate any constant pools that were at the end
|
|
|
|
// of the function.
|
|
|
|
if (!InConstantPool)
|
|
|
|
return;
|
|
|
|
InConstantPool = false;
|
|
|
|
OutStreamer.EmitDataRegion(MCDR_DataRegionEnd);
|
2007-06-06 15:42:06 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 16:37:04 +08:00
|
|
|
/// 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.
|
2011-04-16 05:51:11 +08:00
|
|
|
bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock*
|
|
|
|
MBB) const {
|
2010-07-20 16:37:04 +08:00
|
|
|
// 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;
|
2011-03-05 01:51:39 +08:00
|
|
|
|
2011-04-02 02:57:38 +08:00
|
|
|
// 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;
|
2012-02-28 15:46:26 +08:00
|
|
|
|
2011-04-02 02:57:38 +08:00
|
|
|
if (PI2 != MBB->pred_end())
|
2012-02-28 15:46:26 +08:00
|
|
|
return false;
|
2011-04-02 02:57:38 +08:00
|
|
|
|
|
|
|
// The predecessor has to be immediately before this block.
|
|
|
|
if (!Pred->isLayoutSuccessor(MBB))
|
|
|
|
return false;
|
2012-02-28 15:46:26 +08:00
|
|
|
|
2011-04-02 02:57:38 +08:00
|
|
|
// If the block is completely empty, then it definitely does fall through.
|
|
|
|
if (Pred->empty())
|
|
|
|
return true;
|
2012-02-28 15:46:26 +08:00
|
|
|
|
2011-04-02 02:57:38 +08:00
|
|
|
// Otherwise, check the last instruction.
|
|
|
|
// Check if the last terminator is an unconditional branch.
|
|
|
|
MachineBasicBlock::const_iterator I = Pred->end();
|
2011-12-07 15:15:52 +08:00
|
|
|
while (I != Pred->begin() && !(--I)->isTerminator()) ;
|
2011-04-02 02:57:38 +08:00
|
|
|
|
2011-12-07 15:15:52 +08:00
|
|
|
return !I->isBarrier();
|
2010-07-20 16:37:04 +08:00
|
|
|
}
|
|
|
|
|
2008-08-03 03:42:36 +08:00
|
|
|
// Print out an operand for an inline asm expression.
|
2012-05-11 05:48:22 +08:00
|
|
|
bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
|
2010-04-04 13:29:35 +08:00
|
|
|
unsigned AsmVariant,const char *ExtraCode,
|
|
|
|
raw_ostream &O) {
|
2008-08-03 03:42:36 +08:00
|
|
|
// Does this asm operand have a single letter operand modifier?
|
2012-05-11 05:48:22 +08:00
|
|
|
if (ExtraCode && ExtraCode[0]) {
|
|
|
|
if (ExtraCode[1] != 0) return true; // Unknown modifier.
|
|
|
|
|
|
|
|
const MachineOperand &MO = MI->getOperand(OpNum);
|
|
|
|
switch (ExtraCode[0]) {
|
2012-05-19 08:51:56 +08:00
|
|
|
default:
|
2012-06-22 01:14:46 +08:00
|
|
|
// See if this is a generic print operand
|
|
|
|
return AsmPrinter::PrintAsmOperand(MI,OpNum,AsmVariant,ExtraCode,O);
|
2012-05-19 08:51:56 +08:00
|
|
|
case 'X': // hex const int
|
|
|
|
if ((MO.getType()) != MachineOperand::MO_Immediate)
|
|
|
|
return true;
|
|
|
|
O << "0x" << StringRef(utohexstr(MO.getImm())).lower();
|
|
|
|
return false;
|
|
|
|
case 'x': // hex const int (low 16 bits)
|
|
|
|
if ((MO.getType()) != MachineOperand::MO_Immediate)
|
|
|
|
return true;
|
|
|
|
O << "0x" << StringRef(utohexstr(MO.getImm() & 0xffff)).lower();
|
|
|
|
return false;
|
|
|
|
case 'd': // decimal const int
|
|
|
|
if ((MO.getType()) != MachineOperand::MO_Immediate)
|
|
|
|
return true;
|
|
|
|
O << MO.getImm();
|
|
|
|
return false;
|
2012-05-31 03:05:19 +08:00
|
|
|
case 'm': // decimal const int minus 1
|
|
|
|
if ((MO.getType()) != MachineOperand::MO_Immediate)
|
|
|
|
return true;
|
|
|
|
O << MO.getImm() - 1;
|
|
|
|
return false;
|
2012-06-29 04:46:26 +08:00
|
|
|
case 'z': {
|
|
|
|
// $0 if zero, regular printing otherwise
|
2012-06-28 09:33:40 +08:00
|
|
|
if (MO.getType() != MachineOperand::MO_Immediate)
|
|
|
|
return true;
|
|
|
|
int64_t Val = MO.getImm();
|
|
|
|
if (Val)
|
|
|
|
O << Val;
|
|
|
|
else
|
|
|
|
O << "$0";
|
|
|
|
return false;
|
|
|
|
}
|
Mips specific inline asm operand modifier 'L'.
Low order register of a double word register operand. Operands
are defined by the name of the variable they are marked with in
the inline assembler code. This is a way to specify that the
operand just refers to the low order register for that variable.
It is the opposite of modifier 'D' which specifies the high order
register.
Example:
main()
{
long long ll_input = 0x1111222233334444LL;
long long ll_val = 3;
int i_result = 0;
__asm__ __volatile__(
"or %0, %L1, %2"
: "=r" (i_result)
: "r" (ll_input), "r" (ll_val));
}
Which results in:
lui $2, %hi(_gp_disp)
addiu $2, $2, %lo(_gp_disp)
addiu $sp, $sp, -8
addu $2, $2, $25
sw $2, 0($sp)
lui $2, 13107
ori $3, $2, 17476 <-- Low 32 bits of ll_input
lui $2, 4369
ori $4, $2, 8738 <-- High 32 bits of ll_input
addiu $5, $zero, 3 <-- Low 32 bits of ll_val
addiu $2, $zero, 0 <-- High 32 bits of ll_val
#APP
or $3, $4, $5 <-- or i_result, high 32 ll_input, low 32 of ll_val
#NO_APP
addiu $sp, $sp, 8
jr $ra
If not direction is done for the long long for 32 bit variables results
in using the low 32 bits as ll_val shows.
There is an existing bug if 'L' or 'D' is used for the destination register
for 32 bit long longs in that the target value will be updated incorrectly
for the non-specified part unless explicitly set within the inline asm code.
llvm-svn: 160028
2012-07-11 06:41:20 +08:00
|
|
|
case 'D': // Second part of a double word register operand
|
|
|
|
case 'L': // Low order register of a double word register operand
|
2012-07-18 14:41:36 +08:00
|
|
|
case 'M': // High order register of a double word register operand
|
Mips specific inline asm operand modifier 'L'.
Low order register of a double word register operand. Operands
are defined by the name of the variable they are marked with in
the inline assembler code. This is a way to specify that the
operand just refers to the low order register for that variable.
It is the opposite of modifier 'D' which specifies the high order
register.
Example:
main()
{
long long ll_input = 0x1111222233334444LL;
long long ll_val = 3;
int i_result = 0;
__asm__ __volatile__(
"or %0, %L1, %2"
: "=r" (i_result)
: "r" (ll_input), "r" (ll_val));
}
Which results in:
lui $2, %hi(_gp_disp)
addiu $2, $2, %lo(_gp_disp)
addiu $sp, $sp, -8
addu $2, $2, $25
sw $2, 0($sp)
lui $2, 13107
ori $3, $2, 17476 <-- Low 32 bits of ll_input
lui $2, 4369
ori $4, $2, 8738 <-- High 32 bits of ll_input
addiu $5, $zero, 3 <-- Low 32 bits of ll_val
addiu $2, $zero, 0 <-- High 32 bits of ll_val
#APP
or $3, $4, $5 <-- or i_result, high 32 ll_input, low 32 of ll_val
#NO_APP
addiu $sp, $sp, 8
jr $ra
If not direction is done for the long long for 32 bit variables results
in using the low 32 bits as ll_val shows.
There is an existing bug if 'L' or 'D' is used for the destination register
for 32 bit long longs in that the target value will be updated incorrectly
for the non-specified part unless explicitly set within the inline asm code.
llvm-svn: 160028
2012-07-11 06:41:20 +08:00
|
|
|
{
|
2012-07-06 07:58:21 +08:00
|
|
|
if (OpNum == 0)
|
|
|
|
return true;
|
|
|
|
const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1);
|
|
|
|
if (!FlagsOP.isImm())
|
|
|
|
return true;
|
|
|
|
unsigned Flags = FlagsOP.getImm();
|
|
|
|
unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
|
2012-07-06 10:44:22 +08:00
|
|
|
// Number of registers represented by this operand. We are looking
|
|
|
|
// for 2 for 32 bit mode and 1 for 64 bit mode.
|
2012-07-06 07:58:21 +08:00
|
|
|
if (NumVals != 2) {
|
2012-07-06 10:44:22 +08:00
|
|
|
if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) {
|
2012-07-06 07:58:21 +08:00
|
|
|
unsigned Reg = MO.getReg();
|
|
|
|
O << '$' << MipsInstPrinter::getRegisterName(Reg);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2012-07-12 05:41:49 +08:00
|
|
|
|
|
|
|
unsigned RegOp = OpNum;
|
|
|
|
if (!Subtarget->isGP64bit()){
|
Mips specific inline asm operand modifier 'L'.
Low order register of a double word register operand. Operands
are defined by the name of the variable they are marked with in
the inline assembler code. This is a way to specify that the
operand just refers to the low order register for that variable.
It is the opposite of modifier 'D' which specifies the high order
register.
Example:
main()
{
long long ll_input = 0x1111222233334444LL;
long long ll_val = 3;
int i_result = 0;
__asm__ __volatile__(
"or %0, %L1, %2"
: "=r" (i_result)
: "r" (ll_input), "r" (ll_val));
}
Which results in:
lui $2, %hi(_gp_disp)
addiu $2, $2, %lo(_gp_disp)
addiu $sp, $sp, -8
addu $2, $2, $25
sw $2, 0($sp)
lui $2, 13107
ori $3, $2, 17476 <-- Low 32 bits of ll_input
lui $2, 4369
ori $4, $2, 8738 <-- High 32 bits of ll_input
addiu $5, $zero, 3 <-- Low 32 bits of ll_val
addiu $2, $zero, 0 <-- High 32 bits of ll_val
#APP
or $3, $4, $5 <-- or i_result, high 32 ll_input, low 32 of ll_val
#NO_APP
addiu $sp, $sp, 8
jr $ra
If not direction is done for the long long for 32 bit variables results
in using the low 32 bits as ll_val shows.
There is an existing bug if 'L' or 'D' is used for the destination register
for 32 bit long longs in that the target value will be updated incorrectly
for the non-specified part unless explicitly set within the inline asm code.
llvm-svn: 160028
2012-07-11 06:41:20 +08:00
|
|
|
// Endianess reverses which register holds the high or low value
|
2012-07-18 14:41:36 +08:00
|
|
|
// between M and L.
|
Mips specific inline asm operand modifier 'L'.
Low order register of a double word register operand. Operands
are defined by the name of the variable they are marked with in
the inline assembler code. This is a way to specify that the
operand just refers to the low order register for that variable.
It is the opposite of modifier 'D' which specifies the high order
register.
Example:
main()
{
long long ll_input = 0x1111222233334444LL;
long long ll_val = 3;
int i_result = 0;
__asm__ __volatile__(
"or %0, %L1, %2"
: "=r" (i_result)
: "r" (ll_input), "r" (ll_val));
}
Which results in:
lui $2, %hi(_gp_disp)
addiu $2, $2, %lo(_gp_disp)
addiu $sp, $sp, -8
addu $2, $2, $25
sw $2, 0($sp)
lui $2, 13107
ori $3, $2, 17476 <-- Low 32 bits of ll_input
lui $2, 4369
ori $4, $2, 8738 <-- High 32 bits of ll_input
addiu $5, $zero, 3 <-- Low 32 bits of ll_val
addiu $2, $zero, 0 <-- High 32 bits of ll_val
#APP
or $3, $4, $5 <-- or i_result, high 32 ll_input, low 32 of ll_val
#NO_APP
addiu $sp, $sp, 8
jr $ra
If not direction is done for the long long for 32 bit variables results
in using the low 32 bits as ll_val shows.
There is an existing bug if 'L' or 'D' is used for the destination register
for 32 bit long longs in that the target value will be updated incorrectly
for the non-specified part unless explicitly set within the inline asm code.
llvm-svn: 160028
2012-07-11 06:41:20 +08:00
|
|
|
switch(ExtraCode[0]) {
|
2012-07-18 14:41:36 +08:00
|
|
|
case 'M':
|
|
|
|
RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum;
|
Mips specific inline asm operand modifier 'L'.
Low order register of a double word register operand. Operands
are defined by the name of the variable they are marked with in
the inline assembler code. This is a way to specify that the
operand just refers to the low order register for that variable.
It is the opposite of modifier 'D' which specifies the high order
register.
Example:
main()
{
long long ll_input = 0x1111222233334444LL;
long long ll_val = 3;
int i_result = 0;
__asm__ __volatile__(
"or %0, %L1, %2"
: "=r" (i_result)
: "r" (ll_input), "r" (ll_val));
}
Which results in:
lui $2, %hi(_gp_disp)
addiu $2, $2, %lo(_gp_disp)
addiu $sp, $sp, -8
addu $2, $2, $25
sw $2, 0($sp)
lui $2, 13107
ori $3, $2, 17476 <-- Low 32 bits of ll_input
lui $2, 4369
ori $4, $2, 8738 <-- High 32 bits of ll_input
addiu $5, $zero, 3 <-- Low 32 bits of ll_val
addiu $2, $zero, 0 <-- High 32 bits of ll_val
#APP
or $3, $4, $5 <-- or i_result, high 32 ll_input, low 32 of ll_val
#NO_APP
addiu $sp, $sp, 8
jr $ra
If not direction is done for the long long for 32 bit variables results
in using the low 32 bits as ll_val shows.
There is an existing bug if 'L' or 'D' is used for the destination register
for 32 bit long longs in that the target value will be updated incorrectly
for the non-specified part unless explicitly set within the inline asm code.
llvm-svn: 160028
2012-07-11 06:41:20 +08:00
|
|
|
break;
|
|
|
|
case 'L':
|
2012-07-18 14:41:36 +08:00
|
|
|
RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1;
|
|
|
|
break;
|
|
|
|
case 'D': // Always the second part
|
|
|
|
RegOp = OpNum + 1;
|
Mips specific inline asm operand modifier 'L'.
Low order register of a double word register operand. Operands
are defined by the name of the variable they are marked with in
the inline assembler code. This is a way to specify that the
operand just refers to the low order register for that variable.
It is the opposite of modifier 'D' which specifies the high order
register.
Example:
main()
{
long long ll_input = 0x1111222233334444LL;
long long ll_val = 3;
int i_result = 0;
__asm__ __volatile__(
"or %0, %L1, %2"
: "=r" (i_result)
: "r" (ll_input), "r" (ll_val));
}
Which results in:
lui $2, %hi(_gp_disp)
addiu $2, $2, %lo(_gp_disp)
addiu $sp, $sp, -8
addu $2, $2, $25
sw $2, 0($sp)
lui $2, 13107
ori $3, $2, 17476 <-- Low 32 bits of ll_input
lui $2, 4369
ori $4, $2, 8738 <-- High 32 bits of ll_input
addiu $5, $zero, 3 <-- Low 32 bits of ll_val
addiu $2, $zero, 0 <-- High 32 bits of ll_val
#APP
or $3, $4, $5 <-- or i_result, high 32 ll_input, low 32 of ll_val
#NO_APP
addiu $sp, $sp, 8
jr $ra
If not direction is done for the long long for 32 bit variables results
in using the low 32 bits as ll_val shows.
There is an existing bug if 'L' or 'D' is used for the destination register
for 32 bit long longs in that the target value will be updated incorrectly
for the non-specified part unless explicitly set within the inline asm code.
llvm-svn: 160028
2012-07-11 06:41:20 +08:00
|
|
|
}
|
|
|
|
if (RegOp >= MI->getNumOperands())
|
|
|
|
return true;
|
|
|
|
const MachineOperand &MO = MI->getOperand(RegOp);
|
|
|
|
if (!MO.isReg())
|
|
|
|
return true;
|
|
|
|
unsigned Reg = MO.getReg();
|
|
|
|
O << '$' << MipsInstPrinter::getRegisterName(Reg);
|
|
|
|
return false;
|
2012-07-06 07:58:21 +08:00
|
|
|
}
|
2012-05-11 05:48:22 +08:00
|
|
|
}
|
2013-11-12 20:56:01 +08:00
|
|
|
case 'w':
|
|
|
|
// Print MSA registers for the 'f' constraint
|
|
|
|
// In LLVM, the 'w' modifier doesn't need to do anything.
|
|
|
|
// We can just call printOperand as normal.
|
|
|
|
break;
|
2012-07-06 10:44:22 +08:00
|
|
|
}
|
|
|
|
}
|
2008-08-03 03:42:36 +08:00
|
|
|
|
2012-05-11 05:48:22 +08:00
|
|
|
printOperand(MI, OpNum, O);
|
2008-08-03 03:42:36 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-06-21 08:40:49 +08:00
|
|
|
bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
|
|
|
|
unsigned OpNum, unsigned AsmVariant,
|
|
|
|
const char *ExtraCode,
|
|
|
|
raw_ostream &O) {
|
Mips specific inline asm operand modifier 'D'
Modifier 'D' is to use the second word of a double integer.
We had previously implemented the pure register varient of
the modifier and this patch implements the memory reference.
#include "stdio.h"
int b[8] = {0,1,2,3,4,5,6,7};
void main()
{
int i;
// The first word. Notice, no 'D'
{asm (
"lw %0,%1;"
: "=r" (i)
: "m" (*(b+4))
);}
printf("%d\n",i);
// The second word
{asm (
"lw %0,%D1;"
: "=r" (i)
: "m" (*(b+4))
);}
printf("%d\n",i);
}
llvm-svn: 179135
2013-04-10 07:19:50 +08:00
|
|
|
int Offset = 0;
|
|
|
|
// Currently we are expecting either no ExtraCode or 'D'
|
|
|
|
if (ExtraCode) {
|
|
|
|
if (ExtraCode[0] == 'D')
|
|
|
|
Offset = 4;
|
|
|
|
else
|
|
|
|
return true; // Unknown modifier.
|
|
|
|
}
|
2012-02-28 15:46:26 +08:00
|
|
|
|
2011-06-21 08:40:49 +08:00
|
|
|
const MachineOperand &MO = MI->getOperand(OpNum);
|
|
|
|
assert(MO.isReg() && "unexpected inline asm memory operand");
|
Mips specific inline asm operand modifier 'D'
Modifier 'D' is to use the second word of a double integer.
We had previously implemented the pure register varient of
the modifier and this patch implements the memory reference.
#include "stdio.h"
int b[8] = {0,1,2,3,4,5,6,7};
void main()
{
int i;
// The first word. Notice, no 'D'
{asm (
"lw %0,%1;"
: "=r" (i)
: "m" (*(b+4))
);}
printf("%d\n",i);
// The second word
{asm (
"lw %0,%D1;"
: "=r" (i)
: "m" (*(b+4))
);}
printf("%d\n",i);
}
llvm-svn: 179135
2013-04-10 07:19:50 +08:00
|
|
|
O << Offset << "($" << MipsInstPrinter::getRegisterName(MO.getReg()) << ")";
|
2012-06-28 09:33:40 +08:00
|
|
|
|
2011-06-21 08:40:49 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-04-04 12:47:45 +08:00
|
|
|
void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
|
|
|
|
raw_ostream &O) {
|
2014-01-04 03:21:54 +08:00
|
|
|
const DataLayout *DL = TM.getDataLayout();
|
2007-06-06 15:42:06 +08:00
|
|
|
const MachineOperand &MO = MI->getOperand(opNum);
|
2007-11-05 11:02:32 +08:00
|
|
|
bool closeP = false;
|
2009-09-02 01:27:58 +08:00
|
|
|
|
|
|
|
if (MO.getTargetFlags())
|
2009-08-28 03:57:56 +08:00
|
|
|
closeP = true;
|
2009-09-02 01:27:58 +08:00
|
|
|
|
|
|
|
switch(MO.getTargetFlags()) {
|
|
|
|
case MipsII::MO_GPREL: O << "%gp_rel("; break;
|
|
|
|
case MipsII::MO_GOT_CALL: O << "%call16("; break;
|
2011-04-02 05:41:06 +08:00
|
|
|
case MipsII::MO_GOT: O << "%got("; break;
|
|
|
|
case MipsII::MO_ABS_HI: O << "%hi("; break;
|
|
|
|
case MipsII::MO_ABS_LO: O << "%lo("; break;
|
2011-05-31 10:53:58 +08:00
|
|
|
case MipsII::MO_TLSGD: O << "%tlsgd("; break;
|
|
|
|
case MipsII::MO_GOTTPREL: O << "%gottprel("; break;
|
|
|
|
case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break;
|
|
|
|
case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break;
|
2011-09-22 11:09:07 +08:00
|
|
|
case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break;
|
|
|
|
case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break;
|
|
|
|
case MipsII::MO_GOT_DISP: O << "%got_disp("; break;
|
|
|
|
case MipsII::MO_GOT_PAGE: O << "%got_page("; break;
|
|
|
|
case MipsII::MO_GOT_OFST: O << "%got_ofst("; break;
|
2007-06-06 15:42:06 +08:00
|
|
|
}
|
2009-09-02 01:27:58 +08:00
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
switch (MO.getType()) {
|
2007-06-06 15:42:06 +08:00
|
|
|
case MachineOperand::MO_Register:
|
2011-07-08 07:56:50 +08:00
|
|
|
O << '$'
|
2011-11-07 04:37:06 +08:00
|
|
|
<< StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower();
|
2007-06-06 15:42:06 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MachineOperand::MO_Immediate:
|
2011-05-25 05:22:21 +08:00
|
|
|
O << MO.getImm();
|
2007-06-06 15:42:06 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MachineOperand::MO_MachineBasicBlock:
|
2010-03-14 05:04:28 +08:00
|
|
|
O << *MO.getMBB()->getSymbol();
|
2007-06-06 15:42:06 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case MachineOperand::MO_GlobalAddress:
|
2013-10-30 01:07:16 +08:00
|
|
|
O << *getSymbol(MO.getGlobal());
|
2007-06-06 15:42:06 +08:00
|
|
|
break;
|
|
|
|
|
2011-03-05 04:01:52 +08:00
|
|
|
case MachineOperand::MO_BlockAddress: {
|
2012-06-15 05:10:56 +08:00
|
|
|
MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
|
2011-03-05 04:01:52 +08:00
|
|
|
O << BA->getName();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-06-06 15:42:06 +08:00
|
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
2014-01-04 03:21:54 +08:00
|
|
|
O << DL->getPrivateGlobalPrefix() << "CPI"
|
2007-12-31 07:10:15 +08:00
|
|
|
<< getFunctionNumber() << "_" << MO.getIndex();
|
2009-11-19 14:06:13 +08:00
|
|
|
if (MO.getOffset())
|
|
|
|
O << "+" << MO.getOffset();
|
2007-06-06 15:42:06 +08:00
|
|
|
break;
|
2011-03-05 01:51:39 +08:00
|
|
|
|
2007-06-06 15:42:06 +08:00
|
|
|
default:
|
2009-07-15 00:55:14 +08:00
|
|
|
llvm_unreachable("<unknown operand type>");
|
2007-06-06 15:42:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (closeP) O << ")";
|
|
|
|
}
|
|
|
|
|
2010-04-04 12:47:45 +08:00
|
|
|
void MipsAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum,
|
|
|
|
raw_ostream &O) {
|
2008-08-13 15:13:40 +08:00
|
|
|
const MachineOperand &MO = MI->getOperand(opNum);
|
2010-04-28 06:24:37 +08:00
|
|
|
if (MO.isImm())
|
2008-08-13 15:13:40 +08:00
|
|
|
O << (unsigned short int)MO.getImm();
|
2011-03-05 01:51:39 +08:00
|
|
|
else
|
2010-04-04 12:47:45 +08:00
|
|
|
printOperand(MI, opNum, O);
|
2008-08-13 15:13:40 +08:00
|
|
|
}
|
|
|
|
|
2013-11-12 18:45:18 +08:00
|
|
|
void MipsAsmPrinter::printUnsignedImm8(const MachineInstr *MI, int opNum,
|
|
|
|
raw_ostream &O) {
|
|
|
|
const MachineOperand &MO = MI->getOperand(opNum);
|
|
|
|
if (MO.isImm())
|
|
|
|
O << (unsigned short int)(unsigned char)MO.getImm();
|
|
|
|
else
|
|
|
|
printOperand(MI, opNum, O);
|
|
|
|
}
|
|
|
|
|
2007-06-06 15:42:06 +08:00
|
|
|
void MipsAsmPrinter::
|
2011-07-08 04:54:20 +08:00
|
|
|
printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) {
|
2011-03-05 01:51:39 +08:00
|
|
|
// Load/Store memory operands -- imm($reg)
|
|
|
|
// If PIC target the target is loaded as the
|
2007-11-05 11:02:32 +08:00
|
|
|
// pattern lw $25,%call16($28)
|
2010-04-04 12:47:45 +08:00
|
|
|
printOperand(MI, opNum+1, O);
|
2011-07-08 02:57:00 +08:00
|
|
|
O << "(";
|
|
|
|
printOperand(MI, opNum, O);
|
2007-06-06 15:42:06 +08:00
|
|
|
O << ")";
|
|
|
|
}
|
|
|
|
|
2011-07-08 04:54:20 +08:00
|
|
|
void MipsAsmPrinter::
|
|
|
|
printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) {
|
|
|
|
// when using stack locations for not load/store instructions
|
|
|
|
// print the same way as all normal 3 operand instructions.
|
|
|
|
printOperand(MI, opNum, O);
|
|
|
|
O << ", ";
|
|
|
|
printOperand(MI, opNum+1, O);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Several changes to Mips backend, experimental fp support being the most
important.
- Cleanup in the Subtarget info with addition of new features, not all support
yet, but they allow the future inclusion of features easier. Among new features,
we have : Arch family info (mips1, mips2, ...), ABI info (o32, eabi), 64-bit
integer
and float registers, allegrex vector FPU (VFPU), single float only support.
- TargetMachine now detects allegrex core.
- Added allegrex (Mips32r2) sext_inreg instructions.
- *Added Float Point Instructions*, handling single float only, and
aliased accesses for 32-bit FPUs.
- Some cleanup in FP instruction formats and FP register classes.
- Calling conventions improved to support mips 32-bit EABI.
- Added Asm Printer support for fp cond codes.
- Added support for sret copy to a return register.
- EABI support added into LowerCALL and FORMAL_ARGS.
- MipsFunctionInfo now keeps a virtual register per function to track the
sret on function entry until function ret.
- MipsInstrInfo FP support into methods (isMoveInstr, isLoadFromStackSlot, ...),
FP cond codes mapping and initial FP Branch Analysis.
- Two new Mips SDNode to handle fp branch and compare instructions : FPBrcond,
FPCmp
- MipsTargetLowering : handling different FP classes, Allegrex support, sret
return copy, no homing location within EABI, non 32-bit stack objects
arguments, and asm constraint for float.
llvm-svn: 53146
2008-07-06 03:05:21 +08:00
|
|
|
void MipsAsmPrinter::
|
2010-04-04 12:47:45 +08:00
|
|
|
printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
|
|
|
|
const char *Modifier) {
|
2012-06-15 05:10:56 +08:00
|
|
|
const MachineOperand &MO = MI->getOperand(opNum);
|
2011-03-05 01:51:39 +08:00
|
|
|
O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
|
Several changes to Mips backend, experimental fp support being the most
important.
- Cleanup in the Subtarget info with addition of new features, not all support
yet, but they allow the future inclusion of features easier. Among new features,
we have : Arch family info (mips1, mips2, ...), ABI info (o32, eabi), 64-bit
integer
and float registers, allegrex vector FPU (VFPU), single float only support.
- TargetMachine now detects allegrex core.
- Added allegrex (Mips32r2) sext_inreg instructions.
- *Added Float Point Instructions*, handling single float only, and
aliased accesses for 32-bit FPUs.
- Some cleanup in FP instruction formats and FP register classes.
- Calling conventions improved to support mips 32-bit EABI.
- Added Asm Printer support for fp cond codes.
- Added support for sret copy to a return register.
- EABI support added into LowerCALL and FORMAL_ARGS.
- MipsFunctionInfo now keeps a virtual register per function to track the
sret on function entry until function ret.
- MipsInstrInfo FP support into methods (isMoveInstr, isLoadFromStackSlot, ...),
FP cond codes mapping and initial FP Branch Analysis.
- Two new Mips SDNode to handle fp branch and compare instructions : FPBrcond,
FPCmp
- MipsTargetLowering : handling different FP classes, Allegrex support, sret
return copy, no homing location within EABI, non 32-bit stack objects
arguments, and asm constraint for float.
llvm-svn: 53146
2008-07-06 03:05:21 +08:00
|
|
|
}
|
|
|
|
|
2009-10-01 06:06:26 +08:00
|
|
|
void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
|
2013-06-19 03:47:15 +08:00
|
|
|
// TODO: Need to add -mabicalls and -mno-abicalls flags.
|
|
|
|
// Currently we assume that -mabicalls is the default.
|
2014-01-07 07:27:31 +08:00
|
|
|
getTargetStreamer().emitDirectiveAbiCalls();
|
|
|
|
Reloc::Model RM = Subtarget->getRelocationModel();
|
|
|
|
if (RM == Reloc::Static && !Subtarget->hasMips64())
|
|
|
|
getTargetStreamer().emitDirectiveOptionPic0();
|
2013-06-19 03:47:15 +08:00
|
|
|
|
2008-07-14 22:42:54 +08:00
|
|
|
// Tell the assembler which ABI we are using
|
2014-01-27 09:33:33 +08:00
|
|
|
std::string SectionName = std::string(".mdebug.") + getCurrentABIString();
|
|
|
|
OutStreamer.SwitchSection(OutContext.getELFSection(
|
|
|
|
SectionName, ELF::SHT_PROGBITS, 0, SectionKind::getDataRel()));
|
2008-07-14 22:42:54 +08:00
|
|
|
|
|
|
|
// TODO: handle O64 ABI
|
|
|
|
|
2014-01-27 09:33:33 +08:00
|
|
|
if (Subtarget->isABI_EABI()) {
|
|
|
|
if (Subtarget->isGP32bit())
|
|
|
|
OutStreamer.SwitchSection(
|
|
|
|
OutContext.getELFSection(".gcc_compiled_long32", ELF::SHT_PROGBITS, 0,
|
|
|
|
SectionKind::getDataRel()));
|
|
|
|
else
|
|
|
|
OutStreamer.SwitchSection(
|
|
|
|
OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0,
|
|
|
|
SectionKind::getDataRel()));
|
|
|
|
}
|
2013-01-19 05:20:38 +08:00
|
|
|
|
2014-01-27 09:33:33 +08:00
|
|
|
// return to the text section
|
|
|
|
OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection());
|
2013-01-19 05:20:38 +08:00
|
|
|
}
|
|
|
|
|
2013-10-06 00:42:21 +08:00
|
|
|
void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
2013-01-19 05:20:38 +08:00
|
|
|
// Emit Mips ELF register info
|
|
|
|
Subtarget->getMReginfo().emitMipsReginfoSectionCG(
|
|
|
|
OutStreamer, getObjFileLowering(), *Subtarget);
|
2007-06-06 15:42:06 +08:00
|
|
|
}
|
|
|
|
|
2011-07-01 09:04:43 +08:00
|
|
|
void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
// TODO: implement
|
|
|
|
}
|
|
|
|
|
2009-06-24 07:59:40 +08:00
|
|
|
// Force static initialization.
|
2011-03-05 01:51:39 +08:00
|
|
|
extern "C" void LLVMInitializeMipsAsmPrinter() {
|
2009-07-25 14:49:55 +08:00
|
|
|
RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget);
|
|
|
|
RegisterAsmPrinter<MipsAsmPrinter> Y(TheMipselTarget);
|
2011-09-21 11:00:58 +08:00
|
|
|
RegisterAsmPrinter<MipsAsmPrinter> A(TheMips64Target);
|
|
|
|
RegisterAsmPrinter<MipsAsmPrinter> B(TheMips64elTarget);
|
2009-07-16 04:24:03 +08:00
|
|
|
}
|