forked from OSchip/llvm-project
This patch has two main functions:
1) Fix a specific bug when certain conversion functions are called in a program compiled as mips16 with hard float and the program is linked as c++. There are two libraries that are reversed in the link order with gcc/g++ and clang/clang++ for mips16 in this case and the proper stubs will then not be called. These stubs are normally handled in the Mips16HardFloat pass but in this case we don't know at that time that we need to generate the stubs. This must all be handled later in code generation and we have moved this functionality to MipsAsmPrinter. When linked as C (gcc or clang) the proper stubs are linked in from libc. 2) Set up the infrastructure to handle 90% of what is in the Mips16HardFloat pass in this new area of MipsAsmPrinter. This is a more logical place to handle this and we have known for some time that we needed to move the code later and not implement it using inline asm as we do now but it was not clear exactly where to do this and what mechanism should be used. Now it's clear to us how to do this and this patch contains the infrastructure to move most of this to MipsAsmPrinter but the actual moving will be done in a follow on patch. The same infrastructure is used to fix this current bug as described in #1. This change was requested by the list during the original putback of the Mips16HardFloat pass but was not practical for us do at that time. llvm-svn: 201426
This commit is contained in:
parent
8eee97ddce
commit
4cdaa7d778
|
@ -16,6 +16,7 @@ add_public_tablegen_target(MipsCommonTableGen)
|
|||
add_llvm_target(MipsCodeGen
|
||||
Mips16FrameLowering.cpp
|
||||
Mips16HardFloat.cpp
|
||||
Mips16HardFloatInfo.cpp
|
||||
Mips16InstrInfo.cpp
|
||||
Mips16ISelDAGToDAG.cpp
|
||||
Mips16ISelLowering.cpp
|
||||
|
|
|
@ -245,8 +245,8 @@ static void swapFPIntParams
|
|||
// Make sure that we know we already need a stub for this function.
|
||||
// Having called needsFPHelperFromSig
|
||||
//
|
||||
static void assureFPCallStub(Function &F, Module *M,
|
||||
const MipsSubtarget &Subtarget){
|
||||
static void assureFPCallStub(Function &F, Module *M,
|
||||
const MipsSubtarget &Subtarget) {
|
||||
// for now we only need them for static relocation
|
||||
if (Subtarget.getRelocationModel() == Reloc::PIC_)
|
||||
return;
|
||||
|
@ -500,8 +500,9 @@ namespace llvm {
|
|||
// declared via attributes as nomips16, we must:
|
||||
// 1) fixup all returns of float, double, single and double complex
|
||||
// by calling a helper function before the actual return.
|
||||
// 2) generate helper functions (stubs) that can be called by mips32 functions
|
||||
// that will move parameters passed normally passed in floating point
|
||||
// 2) generate helper functions (stubs) that can be called by mips32
|
||||
// functions that will move parameters passed normally passed in
|
||||
// floating point
|
||||
// registers the soft float equivalents.
|
||||
// 3) in the case of static relocation, generate helper functions so that
|
||||
// mips16 functions can call extern functions of unknown type (mips16 or
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
//===---- Mips16HardFloatInfo.cpp for Mips16 Hard Float -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the Mips16 implementation of Mips16HardFloatInfo
|
||||
// namespace.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <string.h>
|
||||
#include "Mips16HardFloatInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace Mips16HardFloatInfo {
|
||||
|
||||
const FuncNameSignature PredefinedFuncs[] = {
|
||||
{ "__floatdidf", { NoSig, DRet } },
|
||||
{ "__floatdisf", { NoSig, FRet } },
|
||||
{ "__floatundidf", { NoSig, DRet } },
|
||||
{ "__fixsfdi", { FSig, NoFPRet } },
|
||||
{ "__fixunsdfsi", { DSig, NoFPRet } },
|
||||
{ "__fixunsdfdi", { DSig, NoFPRet } },
|
||||
{ "__fixdfdi", { DSig, NoFPRet } },
|
||||
{ "__fixunssfsi", { FSig, NoFPRet } },
|
||||
{ "__fixunssfdi", { FSig, NoFPRet } },
|
||||
{ "__floatundisf", { NoSig, FRet } },
|
||||
{ 0, { NoSig, NoFPRet } }
|
||||
};
|
||||
|
||||
// just do a search for now. there are very few of these special cases.
|
||||
//
|
||||
extern FuncSignature const *findFuncSignature(const char *name) {
|
||||
const char *name_;
|
||||
int i = 0;
|
||||
while (PredefinedFuncs[i].Name) {
|
||||
name_ = PredefinedFuncs[i].Name;
|
||||
if (strcmp(name, name_) == 0)
|
||||
return &PredefinedFuncs[i].Signature;
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
//===---- Mips16HardFloatInfo.h for Mips16 Hard Float --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines some data structures relevant to the implementation of
|
||||
// Mips16 hard float.
|
||||
//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MIPS16HARDFLOATINFO_H
|
||||
#define MIPS16HARDFLOATINFO_H
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace Mips16HardFloatInfo {
|
||||
|
||||
// Return types that matter for hard float are:
|
||||
// float, double, complex float, and complex double
|
||||
//
|
||||
enum FPReturnVariant { FRet, DRet, CFRet, CDRet, NoFPRet };
|
||||
|
||||
//
|
||||
// Parameter type that matter are float, (float, float), (float, double),
|
||||
// double, (double, double), (double, float)
|
||||
//
|
||||
enum FPParamVariant { FSig, FFSig, FDSig, DSig, DDSig, DFSig, NoSig };
|
||||
|
||||
struct FuncSignature {
|
||||
FPParamVariant ParamSig;
|
||||
FPReturnVariant RetSig;
|
||||
};
|
||||
|
||||
struct FuncNameSignature {
|
||||
const char *Name;
|
||||
FuncSignature Signature;
|
||||
};
|
||||
|
||||
extern const FuncNameSignature PredefinedFuncs[];
|
||||
|
||||
extern FuncSignature const *findFuncSignature(const char *name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -11,10 +11,12 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#define DEBUG_TYPE "mips-lower"
|
||||
#include <string>
|
||||
#include "Mips16ISelLowering.h"
|
||||
#include "MCTargetDesc/MipsBaseInfo.h"
|
||||
#include "MipsRegisterInfo.h"
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
|
@ -445,7 +447,29 @@ getOpndList(SmallVectorImpl<SDValue> &Ops,
|
|||
Find))
|
||||
LookupHelper = false;
|
||||
else {
|
||||
Mips16IntrinsicHelperType IntrinsicFind = {S->getSymbol(), ""};
|
||||
const char *Symbol = S->getSymbol();
|
||||
Mips16IntrinsicHelperType IntrinsicFind = { Symbol, "" };
|
||||
const Mips16HardFloatInfo::FuncSignature *Signature =
|
||||
Mips16HardFloatInfo::findFuncSignature(Symbol);
|
||||
if (!IsPICCall && (Signature && (FuncInfo->StubsNeeded.find(Symbol) ==
|
||||
FuncInfo->StubsNeeded.end()))) {
|
||||
FuncInfo->StubsNeeded[Symbol] = Signature;
|
||||
//
|
||||
// S2 is normally saved if the stub is for a function which
|
||||
// returns a float or double value and is not otherwise. This is
|
||||
// because more work is required after the function the stub
|
||||
// is calling completes, and so the stub cannot directly return
|
||||
// and the stub has no stack space to store the return address so
|
||||
// S2 is used for that purpose.
|
||||
// In order to take advantage of not saving S2, we need to also
|
||||
// optimize the call in the stub and this requires some further
|
||||
// functionality in MipsAsmPrinter which we don't have yet.
|
||||
// So for now we always save S2. The optimization will be done
|
||||
// in a follow-on patch.
|
||||
//
|
||||
if (Signature->RetSig != Mips16HardFloatInfo::NoFPRet || 1)
|
||||
FuncInfo->setSaveS2();
|
||||
}
|
||||
// one more look at list of intrinsics
|
||||
if (std::binary_search(Mips16IntrinsicHelper,
|
||||
array_endof(Mips16IntrinsicHelper),
|
||||
|
@ -748,8 +772,8 @@ MachineBasicBlock *Mips16TargetLowering::emitFEXT_CCRX16_ins(
|
|||
unsigned CC = MI->getOperand(0).getReg();
|
||||
unsigned regX = MI->getOperand(1).getReg();
|
||||
unsigned regY = MI->getOperand(2).getReg();
|
||||
BuildMI(*BB, MI, MI->getDebugLoc(),
|
||||
TII->get(SltOpc)).addReg(regX).addReg(regY);
|
||||
BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(SltOpc)).addReg(regX).addReg(
|
||||
regY);
|
||||
BuildMI(*BB, MI, MI->getDebugLoc(),
|
||||
TII->get(Mips::MoveR3216), CC).addReg(Mips::T8);
|
||||
MI->eraseFromParent(); // The pseudo instruction is gone now.
|
||||
|
|
|
@ -36,7 +36,9 @@
|
|||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCELFStreamer.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCSection.h"
|
||||
#include "llvm/MC/MCSectionELF.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
|
@ -44,6 +46,7 @@
|
|||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetLoweringObjectFile.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include <string>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
|
@ -57,6 +60,17 @@ bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
|||
const_cast<TargetLoweringObjectFile&>(getObjFileLowering())
|
||||
.Initialize(OutContext, TM);
|
||||
MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
if (Subtarget->inMips16Mode())
|
||||
for (std::map<
|
||||
const char *,
|
||||
const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator
|
||||
it = MipsFI->StubsNeeded.begin();
|
||||
it != MipsFI->StubsNeeded.end(); ++it) {
|
||||
const char *Symbol = it->first;
|
||||
const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second;
|
||||
if (StubsNeeded.find(Symbol) == StubsNeeded.end())
|
||||
StubsNeeded[Symbol] = Signature;
|
||||
}
|
||||
MCP = MF.getConstantPool();
|
||||
AsmPrinter::runOnMachineFunction(MF);
|
||||
return true;
|
||||
|
@ -616,7 +630,273 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
|
|||
OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0,
|
||||
SectionKind::getDataRel()));
|
||||
}
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) {
|
||||
MCInst I;
|
||||
I.setOpcode(Mips::JAL);
|
||||
I.addOperand(
|
||||
MCOperand::CreateExpr(MCSymbolRefExpr::Create(Symbol, OutContext)));
|
||||
OutStreamer.EmitInstruction(I, getSubtargetInfo());
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitInstrReg(unsigned Opcode, unsigned Reg) {
|
||||
MCInst I;
|
||||
I.setOpcode(Opcode);
|
||||
I.addOperand(MCOperand::CreateReg(Reg));
|
||||
OutStreamer.EmitInstruction(I, getSubtargetInfo());
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitInstrRegReg(unsigned Opcode, unsigned Reg1,
|
||||
unsigned Reg2) {
|
||||
MCInst I;
|
||||
//
|
||||
// Because of the current td files for Mips32, the operands for MTC1
|
||||
// appear backwards from their normal assembly order. It's not a trivial
|
||||
// change to fix this in the td file so we adjust for it here.
|
||||
//
|
||||
if (Opcode == Mips::MTC1) {
|
||||
unsigned Temp = Reg1;
|
||||
Reg1 = Reg2;
|
||||
Reg2 = Temp;
|
||||
}
|
||||
I.setOpcode(Opcode);
|
||||
I.addOperand(MCOperand::CreateReg(Reg1));
|
||||
I.addOperand(MCOperand::CreateReg(Reg2));
|
||||
OutStreamer.EmitInstruction(I, getSubtargetInfo());
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitInstrRegRegReg(unsigned Opcode, unsigned Reg1,
|
||||
unsigned Reg2, unsigned Reg3) {
|
||||
MCInst I;
|
||||
I.setOpcode(Opcode);
|
||||
I.addOperand(MCOperand::CreateReg(Reg1));
|
||||
I.addOperand(MCOperand::CreateReg(Reg2));
|
||||
I.addOperand(MCOperand::CreateReg(Reg3));
|
||||
OutStreamer.EmitInstruction(I, getSubtargetInfo());
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitMovFPIntPair(unsigned MovOpc, unsigned Reg1,
|
||||
unsigned Reg2, unsigned FPReg1,
|
||||
unsigned FPReg2, bool LE) {
|
||||
if (!LE) {
|
||||
unsigned temp = Reg1;
|
||||
Reg1 = Reg2;
|
||||
Reg2 = temp;
|
||||
}
|
||||
EmitInstrRegReg(MovOpc, Reg1, FPReg1);
|
||||
EmitInstrRegReg(MovOpc, Reg2, FPReg2);
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitSwapFPIntParams(Mips16HardFloatInfo::FPParamVariant PV,
|
||||
bool LE, bool ToFP) {
|
||||
using namespace Mips16HardFloatInfo;
|
||||
unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1;
|
||||
switch (PV) {
|
||||
case FSig:
|
||||
EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12);
|
||||
break;
|
||||
case FFSig:
|
||||
EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE);
|
||||
break;
|
||||
case FDSig:
|
||||
EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12);
|
||||
EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
|
||||
break;
|
||||
case DSig:
|
||||
EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
|
||||
break;
|
||||
case DDSig:
|
||||
EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
|
||||
EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
|
||||
break;
|
||||
case DFSig:
|
||||
EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
|
||||
EmitInstrRegReg(MovOpc, Mips::A2, Mips::F14);
|
||||
break;
|
||||
case NoSig:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MipsAsmPrinter::EmitSwapFPIntRetval(Mips16HardFloatInfo::FPReturnVariant RV,
|
||||
bool LE) {
|
||||
using namespace Mips16HardFloatInfo;
|
||||
unsigned MovOpc = Mips::MFC1;
|
||||
switch (RV) {
|
||||
case FRet:
|
||||
EmitInstrRegReg(MovOpc, Mips::V0, Mips::F0);
|
||||
break;
|
||||
case DRet:
|
||||
EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
|
||||
break;
|
||||
case CFRet:
|
||||
EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
|
||||
break;
|
||||
case CDRet:
|
||||
EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
|
||||
EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE);
|
||||
break;
|
||||
case NoFPRet:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitFPCallStub(
|
||||
const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) {
|
||||
MCSymbol *MSymbol = OutContext.GetOrCreateSymbol(StringRef(Symbol));
|
||||
using namespace Mips16HardFloatInfo;
|
||||
bool LE = Subtarget->isLittle();
|
||||
//
|
||||
// .global xxxx
|
||||
//
|
||||
OutStreamer.EmitSymbolAttribute(MSymbol, MCSA_Global);
|
||||
const char *RetType;
|
||||
//
|
||||
// make the comment field identifying the return and parameter
|
||||
// types of the floating point stub
|
||||
// # Stub function to call rettype xxxx (params)
|
||||
//
|
||||
switch (Signature->RetSig) {
|
||||
case FRet:
|
||||
RetType = "float";
|
||||
break;
|
||||
case DRet:
|
||||
RetType = "double";
|
||||
break;
|
||||
case CFRet:
|
||||
RetType = "complex";
|
||||
break;
|
||||
case CDRet:
|
||||
RetType = "double complex";
|
||||
break;
|
||||
case NoFPRet:
|
||||
RetType = "";
|
||||
break;
|
||||
}
|
||||
const char *Parms;
|
||||
switch (Signature->ParamSig) {
|
||||
case FSig:
|
||||
Parms = "float";
|
||||
break;
|
||||
case FFSig:
|
||||
Parms = "float, float";
|
||||
break;
|
||||
case FDSig:
|
||||
Parms = "float, double";
|
||||
break;
|
||||
case DSig:
|
||||
Parms = "double";
|
||||
break;
|
||||
case DDSig:
|
||||
Parms = "double, double";
|
||||
break;
|
||||
case DFSig:
|
||||
Parms = "double, float";
|
||||
break;
|
||||
case NoSig:
|
||||
Parms = "";
|
||||
break;
|
||||
}
|
||||
OutStreamer.AddComment("\t# Stub function to call " + Twine(RetType) + " " +
|
||||
Twine(Symbol) + " (" + Twine(Parms) + ")");
|
||||
//
|
||||
// probably not necessary but we save and restore the current section state
|
||||
//
|
||||
OutStreamer.PushSection();
|
||||
//
|
||||
// .section mips16.call.fpxxxx,"ax",@progbits
|
||||
//
|
||||
const MCSectionELF *M = OutContext.getELFSection(
|
||||
".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS,
|
||||
ELF::SHF_ALLOC | ELF::SHF_EXECINSTR, SectionKind::getText());
|
||||
OutStreamer.SwitchSection(M, 0);
|
||||
//
|
||||
// .align 2
|
||||
//
|
||||
OutStreamer.EmitValueToAlignment(4);
|
||||
MipsTargetStreamer &TS = getTargetStreamer();
|
||||
//
|
||||
// .set nomips16
|
||||
// .set nomicromips
|
||||
//
|
||||
TS.emitDirectiveSetNoMips16();
|
||||
TS.emitDirectiveSetNoMicroMips();
|
||||
//
|
||||
// .ent __call_stub_fp_xxxx
|
||||
// .type __call_stub_fp_xxxx,@function
|
||||
// __call_stub_fp_xxxx:
|
||||
//
|
||||
std::string x = "__call_stub_fp_" + std::string(Symbol);
|
||||
MCSymbol *Stub = OutContext.GetOrCreateSymbol(StringRef(x));
|
||||
TS.emitDirectiveEnt(*Stub);
|
||||
MCSymbol *MType =
|
||||
OutContext.GetOrCreateSymbol("__call_stub_fp_" + Twine(Symbol));
|
||||
OutStreamer.EmitSymbolAttribute(MType, MCSA_ELF_TypeFunction);
|
||||
OutStreamer.EmitLabel(Stub);
|
||||
//
|
||||
// we just handle non pic for now. these function will not be
|
||||
// called otherwise. when the full stub generation is moved here
|
||||
// we need to deal with pic.
|
||||
//
|
||||
if (Subtarget->getRelocationModel() == Reloc::PIC_)
|
||||
llvm_unreachable("should not be here if we are compiling pic");
|
||||
TS.emitDirectiveSetReorder();
|
||||
//
|
||||
// We need to add a MipsMCExpr class to MCTargetDesc to fully implement
|
||||
// stubs without raw text but this current patch is for compiler generated
|
||||
// functions and they all return some value.
|
||||
// The calling sequence for non pic is different in that case and we need
|
||||
// to implement %lo and %hi in order to handle the case of no return value
|
||||
// See the corresponding method in Mips16HardFloat for details.
|
||||
//
|
||||
// mov the return address to S2.
|
||||
// we have no stack space to store it and we are about to make another call.
|
||||
// We need to make sure that the enclosing function knows to save S2
|
||||
// This should have already been handled.
|
||||
//
|
||||
// Mov $18, $31
|
||||
|
||||
EmitInstrRegRegReg(Mips::ADDu, Mips::S2, Mips::RA, Mips::ZERO);
|
||||
|
||||
EmitSwapFPIntParams(Signature->ParamSig, LE, true);
|
||||
|
||||
// Jal xxxx
|
||||
//
|
||||
EmitJal(MSymbol);
|
||||
|
||||
// fix return values
|
||||
EmitSwapFPIntRetval(Signature->RetSig, LE);
|
||||
//
|
||||
// do the return
|
||||
// if (Signature->RetSig == NoFPRet)
|
||||
// llvm_unreachable("should not be any stubs here with no return value");
|
||||
// else
|
||||
EmitInstrReg(Mips::JR, Mips::S2);
|
||||
|
||||
MCSymbol *Tmp = OutContext.CreateTempSymbol();
|
||||
OutStreamer.EmitLabel(Tmp);
|
||||
const MCSymbolRefExpr *E = MCSymbolRefExpr::Create(Stub, OutContext);
|
||||
const MCSymbolRefExpr *T = MCSymbolRefExpr::Create(Tmp, OutContext);
|
||||
const MCExpr *T_min_E = MCBinaryExpr::CreateSub(T, E, OutContext);
|
||||
OutStreamer.EmitELFSize(Stub, T_min_E);
|
||||
TS.emitDirectiveEnd(x);
|
||||
OutStreamer.PopSection();
|
||||
}
|
||||
|
||||
void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
||||
// Emit needed stubs
|
||||
//
|
||||
for (std::map<
|
||||
const char *,
|
||||
const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator
|
||||
it = StubsNeeded.begin();
|
||||
it != StubsNeeded.end(); ++it) {
|
||||
const char *Symbol = it->first;
|
||||
const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second;
|
||||
EmitFPCallStub(Symbol, Signature);
|
||||
}
|
||||
// return to the text section
|
||||
OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection());
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef MIPSASMPRINTER_H
|
||||
#define MIPSASMPRINTER_H
|
||||
|
||||
#include "Mips16HardFloatInfo.h"
|
||||
#include "MipsMCInstLower.h"
|
||||
#include "MipsMachineFunction.h"
|
||||
#include "MipsSubtarget.h"
|
||||
|
@ -50,6 +51,27 @@ private:
|
|||
/// pool entries so we can properly mark them as data regions.
|
||||
bool InConstantPool;
|
||||
|
||||
std::map<const char *, const llvm::Mips16HardFloatInfo::FuncSignature *>
|
||||
StubsNeeded;
|
||||
|
||||
void EmitJal(MCSymbol *Symbol);
|
||||
|
||||
void EmitInstrReg(unsigned Opcode, unsigned Reg);
|
||||
|
||||
void EmitInstrRegReg(unsigned Opcode, unsigned Reg1, unsigned Reg2);
|
||||
|
||||
void EmitInstrRegRegReg(unsigned Opcode, unsigned Reg1, unsigned Reg2,
|
||||
unsigned Reg3);
|
||||
|
||||
void EmitMovFPIntPair(unsigned MovOpc, unsigned Reg1, unsigned Reg2,
|
||||
unsigned FPReg1, unsigned FPReg2, bool LE);
|
||||
|
||||
void EmitSwapFPIntParams(Mips16HardFloatInfo::FPParamVariant, bool LE,
|
||||
bool ToFP);
|
||||
|
||||
void EmitSwapFPIntRetval(Mips16HardFloatInfo::FPReturnVariant, bool LE);
|
||||
|
||||
void EmitFPCallStub(const char *, const Mips16HardFloatInfo::FuncSignature *);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -100,6 +122,7 @@ public:
|
|||
void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
|
||||
const char *Modifier = 0);
|
||||
void EmitStartOfAsmFile(Module &M);
|
||||
void EmitEndOfAsmFile(Module &M);
|
||||
void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef MIPS_MACHINE_FUNCTION_INFO_H
|
||||
#define MIPS_MACHINE_FUNCTION_INFO_H
|
||||
|
||||
#include "Mips16HardFloatInfo.h"
|
||||
#include "MipsSubtarget.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/ValueMap.h"
|
||||
|
@ -24,6 +25,8 @@
|
|||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
@ -50,10 +53,9 @@ private:
|
|||
/// Mips target-specific information for each MachineFunction.
|
||||
class MipsFunctionInfo : public MachineFunctionInfo {
|
||||
public:
|
||||
MipsFunctionInfo(MachineFunction& MF)
|
||||
: MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0),
|
||||
VarArgsFrameIndex(0), CallsEhReturn(false)
|
||||
{}
|
||||
MipsFunctionInfo(MachineFunction &MF)
|
||||
: MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0),
|
||||
VarArgsFrameIndex(0), CallsEhReturn(false), SaveS2(false) {}
|
||||
|
||||
~MipsFunctionInfo();
|
||||
|
||||
|
@ -92,6 +94,12 @@ public:
|
|||
/// representing a GOT entry for a global function.
|
||||
MachinePointerInfo callPtrInfo(const GlobalValue *Val);
|
||||
|
||||
void setSaveS2() { SaveS2 = true; }
|
||||
bool hasSaveS2() const { return SaveS2; }
|
||||
|
||||
std::map<const char *, const llvm::Mips16HardFloatInfo::FuncSignature *>
|
||||
StubsNeeded;
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
|
||||
|
@ -126,6 +134,9 @@ private:
|
|||
/// Frame objects for spilling eh data registers.
|
||||
int EhDataRegFI[4];
|
||||
|
||||
// saveS2
|
||||
bool SaveS2;
|
||||
|
||||
/// MipsCallEntry maps.
|
||||
StringMap<const MipsCallEntry *> ExternalCallEntries;
|
||||
ValueMap<const GlobalValue *, const MipsCallEntry *> GlobalCallEntries;
|
||||
|
|
|
@ -187,11 +187,12 @@ getReservedRegs(const MachineFunction &MF) const {
|
|||
|
||||
// Reserve RA if in mips16 mode.
|
||||
if (Subtarget.inMips16Mode()) {
|
||||
const MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
Reserved.set(Mips::RA);
|
||||
Reserved.set(Mips::RA_64);
|
||||
Reserved.set(Mips::T0);
|
||||
Reserved.set(Mips::T1);
|
||||
if (MF.getFunction()->hasFnAttribute("saveS2"))
|
||||
if (MF.getFunction()->hasFnAttribute("saveS2") || MipsFI->hasSaveS2())
|
||||
Reserved.set(Mips::S2);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixunsdfsi
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___floatdidf
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___floatdisf
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___floatundidf
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixsfdi
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixunsdfdi
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixdfdi
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixunssfsi
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___fixunssfdi
|
||||
|
||||
; RUN: llc -mtriple=mipsel-linux-gnu -march=mipsel -mcpu=mips16 -soft-float -mips16-hard-float -relocation-model=static < %s | FileCheck %s -check-prefix=__call_stub_fp___floatundisf
|
||||
|
||||
@ll1 = global i64 0, align 8
|
||||
@ll2 = global i64 0, align 8
|
||||
@ll3 = global i64 0, align 8
|
||||
@l1 = global i32 0, align 4
|
||||
@l2 = global i32 0, align 4
|
||||
@l3 = global i32 0, align 4
|
||||
@ull1 = global i64 0, align 8
|
||||
@ull2 = global i64 0, align 8
|
||||
@ull3 = global i64 0, align 8
|
||||
@ul1 = global i32 0, align 4
|
||||
@ul2 = global i32 0, align 4
|
||||
@ul3 = global i32 0, align 4
|
||||
@d1 = global double 0.000000e+00, align 8
|
||||
@d2 = global double 0.000000e+00, align 8
|
||||
@d3 = global double 0.000000e+00, align 8
|
||||
@d4 = global double 0.000000e+00, align 8
|
||||
@f1 = global float 0.000000e+00, align 4
|
||||
@f2 = global float 0.000000e+00, align 4
|
||||
@f3 = global float 0.000000e+00, align 4
|
||||
@f4 = global float 0.000000e+00, align 4
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @_Z3foov() #0 {
|
||||
entry:
|
||||
%0 = load double* @d1, align 8
|
||||
%conv = fptosi double %0 to i64
|
||||
store i64 %conv, i64* @ll1, align 8
|
||||
%1 = load double* @d2, align 8
|
||||
%conv1 = fptoui double %1 to i64
|
||||
store i64 %conv1, i64* @ull1, align 8
|
||||
%2 = load float* @f1, align 4
|
||||
%conv2 = fptosi float %2 to i64
|
||||
store i64 %conv2, i64* @ll2, align 8
|
||||
%3 = load float* @f2, align 4
|
||||
%conv3 = fptoui float %3 to i64
|
||||
store i64 %conv3, i64* @ull2, align 8
|
||||
%4 = load double* @d3, align 8
|
||||
%conv4 = fptosi double %4 to i32
|
||||
store i32 %conv4, i32* @l1, align 4
|
||||
%5 = load double* @d4, align 8
|
||||
%conv5 = fptoui double %5 to i32
|
||||
store i32 %conv5, i32* @ul1, align 4
|
||||
%6 = load float* @f3, align 4
|
||||
%conv6 = fptosi float %6 to i32
|
||||
store i32 %conv6, i32* @l2, align 4
|
||||
%7 = load float* @f4, align 4
|
||||
%conv7 = fptoui float %7 to i32
|
||||
store i32 %conv7, i32* @ul2, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @_Z3goov() #0 {
|
||||
entry:
|
||||
%0 = load i64* @ll1, align 8
|
||||
%conv = sitofp i64 %0 to double
|
||||
store double %conv, double* @d1, align 8
|
||||
%1 = load i64* @ull1, align 8
|
||||
%conv1 = uitofp i64 %1 to double
|
||||
store double %conv1, double* @d2, align 8
|
||||
%2 = load i64* @ll2, align 8
|
||||
%conv2 = sitofp i64 %2 to float
|
||||
store float %conv2, float* @f1, align 4
|
||||
%3 = load i64* @ull2, align 8
|
||||
%conv3 = uitofp i64 %3 to float
|
||||
store float %conv3, float* @f2, align 4
|
||||
%4 = load i32* @l1, align 4
|
||||
%conv4 = sitofp i32 %4 to double
|
||||
store double %conv4, double* @d3, align 8
|
||||
%5 = load i32* @ul1, align 4
|
||||
%conv5 = uitofp i32 %5 to double
|
||||
store double %conv5, double* @d4, align 8
|
||||
%6 = load i32* @l2, align 4
|
||||
%conv6 = sitofp i32 %6 to float
|
||||
store float %conv6, float* @f3, align 4
|
||||
%7 = load i32* @ul2, align 4
|
||||
%conv7 = uitofp i32 %7 to float
|
||||
store float %conv7, float* @f4, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
|
||||
; __call_stub_fp___fixunsdfsi: __call_stub_fp___fixunsdfsi:
|
||||
; __call_stub_fp___floatdidf: __call_stub_fp___floatdidf:
|
||||
; __call_stub_fp___floatdisf: __call_stub_fp___floatdisf:
|
||||
; __call_stub_fp___floatundidf: __call_stub_fp___floatundidf:
|
||||
; __call_stub_fp___fixsfdi: __call_stub_fp___fixsfdi:
|
||||
; __call_stub_fp___fixunsdfdi: __call_stub_fp___fixunsdfdi:
|
||||
; __call_stub_fp___fixdfdi: __call_stub_fp___fixdfdi:
|
||||
; __call_stub_fp___fixunssfsi: __call_stub_fp___fixunssfsi:
|
||||
; __call_stub_fp___fixunssfdi: __call_stub_fp___fixunssfdi:
|
||||
; __call_stub_fp___floatundisf: __call_stub_fp___floatundisf:
|
||||
|
Loading…
Reference in New Issue