summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/Mips
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/Mips')
-rw-r--r--llvm/lib/Target/Mips/MipsISelLowering.cpp275
-rw-r--r--llvm/lib/Target/Mips/MipsISelLowering.h7
2 files changed, 246 insertions, 36 deletions
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index e148da139a6..a23ffd7288a 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -11,8 +11,8 @@
// selection DAG.
//
//===----------------------------------------------------------------------===//
-
#define DEBUG_TYPE "mips-lower"
+#include <set>
#include "MipsISelLowering.h"
#include "InstPrinter/MipsInstPrinter.h"
#include "MCTargetDesc/MipsBaseInfo.h"
@@ -205,39 +205,64 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const {
}
}
+namespace {
+ struct eqstr {
+ bool operator()(const char *s1, const char *s2) const
+ {
+ return strcmp(s1, s2) == 0;
+ }
+ };
+
+ std::set<const char*, eqstr> noHelperNeeded;
+
+ const char* addToNoHelperNeeded(const char* s) {
+ noHelperNeeded.insert(s);
+ return s;
+ }
+
+}
+
void MipsTargetLowering::setMips16HardFloatLibCalls() {
- setLibcallName(RTLIB::ADD_F32, "__mips16_addsf3");
- setLibcallName(RTLIB::ADD_F64, "__mips16_adddf3");
- setLibcallName(RTLIB::SUB_F32, "__mips16_subsf3");
- setLibcallName(RTLIB::SUB_F64, "__mips16_subdf3");
- setLibcallName(RTLIB::MUL_F32, "__mips16_mulsf3");
- setLibcallName(RTLIB::MUL_F64, "__mips16_muldf3");
- setLibcallName(RTLIB::DIV_F32, "__mips16_divsf3");
- setLibcallName(RTLIB::DIV_F64, "__mips16_divdf3");
- setLibcallName(RTLIB::FPEXT_F32_F64, "__mips16_extendsfdf2");
- setLibcallName(RTLIB::FPROUND_F64_F32, "__mips16_truncdfsf2");
- setLibcallName(RTLIB::FPTOSINT_F32_I32, "__mips16_fix_truncsfsi");
- setLibcallName(RTLIB::FPTOSINT_F64_I32, "__mips16_fix_truncdfsi");
- setLibcallName(RTLIB::SINTTOFP_I32_F32, "__mips16_floatsisf");
- setLibcallName(RTLIB::SINTTOFP_I32_F64, "__mips16_floatsidf");
- setLibcallName(RTLIB::UINTTOFP_I32_F32, "__mips16_floatunsisf");
- setLibcallName(RTLIB::UINTTOFP_I32_F64, "__mips16_floatunsidf");
- setLibcallName(RTLIB::OEQ_F32, "__mips16_eqsf2");
- setLibcallName(RTLIB::OEQ_F64, "__mips16_eqdf2");
- setLibcallName(RTLIB::UNE_F32, "__mips16_nesf2");
- setLibcallName(RTLIB::UNE_F64, "__mips16_nedf2");
- setLibcallName(RTLIB::OGE_F32, "__mips16_gesf2");
- setLibcallName(RTLIB::OGE_F64, "__mips16_gedf2");
- setLibcallName(RTLIB::OLT_F32, "__mips16_ltsf2");
- setLibcallName(RTLIB::OLT_F64, "__mips16_ltdf2");
- setLibcallName(RTLIB::OLE_F32, "__mips16_lesf2");
- setLibcallName(RTLIB::OLE_F64, "__mips16_ledf2");
- setLibcallName(RTLIB::OGT_F32, "__mips16_gtsf2");
- setLibcallName(RTLIB::OGT_F64, "__mips16_gtdf2");
- setLibcallName(RTLIB::UO_F32, "__mips16_unordsf2");
- setLibcallName(RTLIB::UO_F64, "__mips16_unorddf2");
- setLibcallName(RTLIB::O_F32, "__mips16_unordsf2");
- setLibcallName(RTLIB::O_F64, "__mips16_unorddf2");
+ setLibcallName(RTLIB::ADD_F32, addToNoHelperNeeded("__mips16_addsf3"));
+ setLibcallName(RTLIB::ADD_F64, addToNoHelperNeeded("__mips16_adddf3"));
+ setLibcallName(RTLIB::SUB_F32, addToNoHelperNeeded("__mips16_subsf3"));
+ setLibcallName(RTLIB::SUB_F64, addToNoHelperNeeded("__mips16_subdf3"));
+ setLibcallName(RTLIB::MUL_F32, addToNoHelperNeeded("__mips16_mulsf3"));
+ setLibcallName(RTLIB::MUL_F64, addToNoHelperNeeded("__mips16_muldf3"));
+ setLibcallName(RTLIB::DIV_F32, addToNoHelperNeeded("__mips16_divsf3"));
+ setLibcallName(RTLIB::DIV_F64, addToNoHelperNeeded("__mips16_divdf3"));
+ setLibcallName(RTLIB::FPEXT_F32_F64,
+ addToNoHelperNeeded("__mips16_extendsfdf2"));
+ setLibcallName(RTLIB::FPROUND_F64_F32,
+ addToNoHelperNeeded("__mips16_truncdfsf2"));
+ setLibcallName(RTLIB::FPTOSINT_F32_I32,
+ addToNoHelperNeeded("__mips16_fix_truncsfsi"));
+ setLibcallName(RTLIB::FPTOSINT_F64_I32,
+ addToNoHelperNeeded("__mips16_fix_truncdfsi"));
+ setLibcallName(RTLIB::SINTTOFP_I32_F32,
+ addToNoHelperNeeded("__mips16_floatsisf"));
+ setLibcallName(RTLIB::SINTTOFP_I32_F64,
+ addToNoHelperNeeded("__mips16_floatsidf"));
+ setLibcallName(RTLIB::UINTTOFP_I32_F32,
+ addToNoHelperNeeded("__mips16_floatunsisf"));
+ setLibcallName(RTLIB::UINTTOFP_I32_F64,
+ addToNoHelperNeeded("__mips16_floatunsidf"));
+ setLibcallName(RTLIB::OEQ_F32, addToNoHelperNeeded("__mips16_eqsf2"));
+ setLibcallName(RTLIB::OEQ_F64, addToNoHelperNeeded("__mips16_eqdf2"));
+ setLibcallName(RTLIB::UNE_F32, addToNoHelperNeeded("__mips16_nesf2"));
+ setLibcallName(RTLIB::UNE_F64, addToNoHelperNeeded("__mips16_nedf2"));
+ setLibcallName(RTLIB::OGE_F32, addToNoHelperNeeded("__mips16_gesf2"));
+ setLibcallName(RTLIB::OGE_F64, addToNoHelperNeeded("__mips16_gedf2"));
+ setLibcallName(RTLIB::OLT_F32, addToNoHelperNeeded("__mips16_ltsf2"));
+ setLibcallName(RTLIB::OLT_F64, addToNoHelperNeeded("__mips16_ltdf2"));
+ setLibcallName(RTLIB::OLE_F32, addToNoHelperNeeded("__mips16_lesf2"));
+ setLibcallName(RTLIB::OLE_F64, addToNoHelperNeeded("__mips16_ledf2"));
+ setLibcallName(RTLIB::OGT_F32, addToNoHelperNeeded("__mips16_gtsf2"));
+ setLibcallName(RTLIB::OGT_F64, addToNoHelperNeeded("__mips16_gtdf2"));
+ setLibcallName(RTLIB::UO_F32, addToNoHelperNeeded("__mips16_unordsf2"));
+ setLibcallName(RTLIB::UO_F64, addToNoHelperNeeded("__mips16_unorddf2"));
+ setLibcallName(RTLIB::O_F32, addToNoHelperNeeded("__mips16_unordsf2"));
+ setLibcallName(RTLIB::O_F64, addToNoHelperNeeded("__mips16_unorddf2"));
}
MipsTargetLowering::
@@ -2754,6 +2779,155 @@ MipsTargetLowering::passArgOnStack(SDValue StackPtr, unsigned Offset,
/*isVolatile=*/ true, false, 0);
}
+//
+// The Mips16 hard float is a crazy quilt inherited from gcc. I have a much
+// cleaner way to do all of this but it will have to wait until the traditional
+// gcc mechanism is completed.
+//
+// For Pic, in order for Mips16 code to call Mips32 code which according the abi
+// have either arguments or returned values placed in floating point registers,
+// we use a set of helper functions. (This includes functions which return type
+// complex which on Mips are returned in a pair of floating point registers).
+//
+// This is an encoding that we inherited from gcc.
+// In Mips traditional O32, N32 ABI, floating point numbers are passed in
+// floating point argument registers 1,2 only when the first and optionally
+// the second arguments are float (sf) or double (df).
+// For Mips16 we are only concerned with the situations where floating point
+// arguments are being passed in floating point registers by the ABI, because
+// Mips16 mode code cannot execute floating point instructions to load those
+// values and hence helper functions are needed.
+// The possibilities are (), (sf), (sf, sf), (sf, df), (df), (df, sf), (df, df)
+// the helper function suffixs for these are:
+// 0, 1, 5, 9, 2, 6, 10
+// this suffix can then be calculated as follows:
+// for a given argument Arg:
+// Arg1x, Arg2x = 1 : Arg is sf
+// 2 : Arg is df
+// 0: Arg is neither sf or df
+// So this stub is the string for number Arg1x + Arg2x*4.
+// However not all numbers between 0 and 10 are possible, we check anyway and
+// assert if the impossible exists.
+//
+
+unsigned int MipsTargetLowering::getMips16HelperFunctionStubNumber
+ (ArgListTy &Args) const {
+ unsigned int resultNum = 0;
+ if (Args.size() >= 1) {
+ Type *t = Args[0].Ty;
+ if (t->isFloatTy()) {
+ resultNum = 1;
+ }
+ else if (t->isDoubleTy()) {
+ resultNum = 2;
+ }
+ }
+ if (resultNum) {
+ if (Args.size() >=2) {
+ Type *t = Args[1].Ty;
+ if (t->isFloatTy()) {
+ resultNum += 4;
+ }
+ else if (t->isDoubleTy()) {
+ resultNum += 8;
+ }
+ }
+ }
+ return resultNum;
+}
+
+//
+// prefixs are attached to stub numbers depending on the return type .
+// return type: float sf_
+// double df_
+// single complex sc_
+// double complext dc_
+// others NO PREFIX
+//
+//
+// The full name of a helper function is__mips16_call_stub +
+// return type dependent prefix + stub number
+//
+//
+// This is something that probably should be in a different source file and
+// perhaps done differently but my main purpose is to not waste runtime
+// on something that we can enumerate in the source. Another possibility is
+// to have a python script to generate these mapping tables. This will do
+// for now. There are a whole series of helper function mapping arrays, one
+// for each return type class as outlined above. There there are 11 possible
+// entries. Ones with 0 are ones which should never be selected
+//
+// All the arrays are similar except for ones which return neither
+// sf, df, sc, dc, in which only care about ones which have sf or df as a
+// first parameter.
+//
+#define P_ "__mips16_call_stub_"
+#define MAX_STUB_NUMBER 10
+#define T1 P "1", P "2", 0, 0, P "5", P "6", 0, 0, P "9", P "10"
+#define T P "0" , T1
+#define P P_
+static char const * vMips16Helper[MAX_STUB_NUMBER+1] =
+ {0, T1 };
+#undef P
+#define P P_ "sf_"
+static char const * sfMips16Helper[MAX_STUB_NUMBER+1] =
+ { T };
+#undef P
+#define P P_ "df_"
+static char const * dfMips16Helper[MAX_STUB_NUMBER+1] =
+ { T };
+#undef P
+#define P P_ "sc_"
+static char const * scMips16Helper[MAX_STUB_NUMBER+1] =
+ { T };
+#undef P
+#define P P_ "dc_"
+static char const * dcMips16Helper[MAX_STUB_NUMBER+1] =
+ { T };
+#undef P
+#undef P_
+
+
+const char* MipsTargetLowering::
+ getMips16HelperFunction
+ (Type* RetTy, ArgListTy &Args, bool &needHelper) const {
+ const unsigned int maxStubNum = 10;
+ const bool validStubNum[maxStubNum+1] =
+ {true, true, true, false, false, true, true, false, false, true, true};
+ const unsigned int stubNum = getMips16HelperFunctionStubNumber(Args);
+ assert(stubNum <= maxStubNum);
+ assert (validStubNum[stubNum]);
+ const char *result;
+ if (RetTy->isFloatTy()) {
+ result = sfMips16Helper[stubNum];
+ }
+ else if (RetTy ->isDoubleTy()) {
+ result = dfMips16Helper[stubNum];
+ }
+ else if (RetTy->isStructTy()) {
+ // check if it's complex
+ if (RetTy->getNumContainedTypes() == 2) {
+ if ((RetTy->getContainedType(0)->isFloatTy()) &&
+ (RetTy->getContainedType(1)->isFloatTy())) {
+ result = scMips16Helper[stubNum];
+ }
+ else if ((RetTy->getContainedType(0)->isDoubleTy()) &&
+ (RetTy->getContainedType(1)->isDoubleTy())) {
+ result = dcMips16Helper[stubNum];
+ }
+ }
+ }
+ else {
+ if (stubNum == 0) {
+ needHelper = false;
+ return "";
+ }
+ result = vMips16Helper[stubNum];
+ }
+ needHelper = true;
+ return result;
+}
+
/// LowerCall - functions arguments are copied from virtual regs to
/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted.
SDValue
@@ -2770,6 +2944,26 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
CallingConv::ID CallConv = CLI.CallConv;
bool isVarArg = CLI.IsVarArg;
+ const char* mips16HelperFunction = 0;
+ bool needMips16Helper = false;
+
+ if (Subtarget->inMips16Mode() && getTargetMachine().Options.UseSoftFloat &&
+ Mips16HardFloat) {
+ //
+ // currently we don't have symbols tagged with the mips16 or mips32
+ // qualifier so we will assume that we don't know what kind it is.
+ // and generate the helper
+ //
+ bool lookupHelper = true;
+ if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ if (noHelperNeeded.find(S->getSymbol()) != noHelperNeeded.end()) {
+ lookupHelper = false;
+ }
+ }
+ if (lookupHelper) mips16HelperFunction =
+ getMips16HelperFunction(CLI.RetTy, CLI.Args, needMips16Helper);
+
+ }
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
const TargetFrameLowering *TFL = MF.getTarget().getFrameLowering();
@@ -2934,10 +3128,19 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// -reloction-model=pic or it is an indirect call.
if (IsPICCall || !GlobalOrExternal) {
unsigned T9Reg = IsN64 ? Mips::T9_64 : Mips::T9;
- RegsToPass.push_front(std::make_pair(T9Reg, Callee));
+ unsigned V0Reg = Mips::V0;
+ if (needMips16Helper) {
+ RegsToPass.push_front(std::make_pair(V0Reg, Callee));
+ JumpTarget = DAG.getExternalSymbol(
+ mips16HelperFunction, getPointerTy());
+ JumpTarget = getAddrGlobal(JumpTarget, DAG, MipsII::MO_GOT);
+ }
+ else {
+ RegsToPass.push_front(std::make_pair(T9Reg, Callee));
- if (!Subtarget->inMips16Mode())
- JumpTarget = SDValue();
+ if (!Subtarget->inMips16Mode())
+ JumpTarget = SDValue();
+ }
}
// Insert node "GP copy globalreg" before call to function.
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index deb6ad04634..c682c89f87c 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -21,6 +21,7 @@
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/Target/TargetLowering.h"
#include <deque>
+#include <string>
namespace llvm {
namespace MipsISD {
@@ -177,6 +178,12 @@ namespace llvm {
void setMips16HardFloatLibCalls();
+ unsigned int
+ getMips16HelperFunctionStubNumber(ArgListTy &Args) const;
+
+ const char *getMips16HelperFunction
+ (Type* RetTy, ArgListTy &Args, bool &needHelper) const;
+
/// ByValArgInfo - Byval argument information.
struct ByValArgInfo {
unsigned FirstIdx; // Index of the first register used.
OpenPOWER on IntegriCloud