179220eaeSEugene Zelenko //===- Mips16HardFloat.cpp for Mips16 Hard Float --------------------------===//
2783c7944SReed Kotler //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6783c7944SReed Kotler //
7783c7944SReed Kotler //===----------------------------------------------------------------------===//
8783c7944SReed Kotler //
9783c7944SReed Kotler // This file defines a pass needed for Mips16 Hard Float
10783c7944SReed Kotler //
11783c7944SReed Kotler //===----------------------------------------------------------------------===//
12783c7944SReed Kotler
1316132e6fSBenjamin Kramer #include "MipsTargetMachine.h"
148b61764cSFrancis Visoiu Mistrih #include "llvm/CodeGen/TargetPassConfig.h"
15783c7944SReed Kotler #include "llvm/IR/Module.h"
168a8cd2baSChandler Carruth #include "llvm/IR/Value.h"
17783c7944SReed Kotler #include "llvm/Support/Debug.h"
1816132e6fSBenjamin Kramer #include "llvm/Support/raw_ostream.h"
19d265e888SReed Kotler #include <algorithm>
20783c7944SReed Kotler #include <string>
216611eb35SVasileios Kalintiris
22a52f696eSBenjamin Kramer using namespace llvm;
23783c7944SReed Kotler
2484e68b29SChandler Carruth #define DEBUG_TYPE "mips16-hard-float"
2584e68b29SChandler Carruth
266611eb35SVasileios Kalintiris namespace {
2779220eaeSEugene Zelenko
286611eb35SVasileios Kalintiris class Mips16HardFloat : public ModulePass {
296611eb35SVasileios Kalintiris public:
306611eb35SVasileios Kalintiris static char ID;
316611eb35SVasileios Kalintiris
Mips16HardFloat()328b61764cSFrancis Visoiu Mistrih Mips16HardFloat() : ModulePass(ID) {}
336611eb35SVasileios Kalintiris
getPassName() const34117296c0SMehdi Amini StringRef getPassName() const override { return "MIPS16 Hard Float Pass"; }
352c4657d9SReed Kotler
getAnalysisUsage(AnalysisUsage & AU) const368b61764cSFrancis Visoiu Mistrih void getAnalysisUsage(AnalysisUsage &AU) const override {
378b61764cSFrancis Visoiu Mistrih AU.addRequired<TargetPassConfig>();
388b61764cSFrancis Visoiu Mistrih ModulePass::getAnalysisUsage(AU);
398b61764cSFrancis Visoiu Mistrih }
406611eb35SVasileios Kalintiris
418b61764cSFrancis Visoiu Mistrih bool runOnModule(Module &M) override;
426611eb35SVasileios Kalintiris };
432c4657d9SReed Kotler
4479220eaeSEugene Zelenko } // end anonymous namespace
456611eb35SVasileios Kalintiris
emitInlineAsm(LLVMContext & C,BasicBlock * BB,StringRef AsmText)461d49eb00SFangrui Song static void emitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
4779220eaeSEugene Zelenko std::vector<Type *> AsmArgTypes;
4879220eaeSEugene Zelenko std::vector<Value *> AsmArgs;
4979220eaeSEugene Zelenko
5079220eaeSEugene Zelenko FunctionType *AsmFTy =
5179220eaeSEugene Zelenko FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
5279220eaeSEugene Zelenko InlineAsm *IA = InlineAsm::get(AsmFTy, AsmText, "", true,
5379220eaeSEugene Zelenko /* IsAlignStack */ false, InlineAsm::AD_ATT);
546611eb35SVasileios Kalintiris CallInst::Create(IA, AsmArgs, "", BB);
556611eb35SVasileios Kalintiris }
566611eb35SVasileios Kalintiris
576611eb35SVasileios Kalintiris char Mips16HardFloat::ID = 0;
582c4657d9SReed Kotler
59783c7944SReed Kotler //
60783c7944SReed Kotler // Return types that matter for hard float are:
61783c7944SReed Kotler // float, double, complex float, and complex double
62783c7944SReed Kotler //
63783c7944SReed Kotler enum FPReturnVariant {
64783c7944SReed Kotler FRet, DRet, CFRet, CDRet, NoFPRet
65783c7944SReed Kotler };
66783c7944SReed Kotler
67783c7944SReed Kotler //
68783c7944SReed Kotler // Determine which FP return type this function has
69783c7944SReed Kotler //
whichFPReturnVariant(Type * T)70783c7944SReed Kotler static FPReturnVariant whichFPReturnVariant(Type *T) {
71783c7944SReed Kotler switch (T->getTypeID()) {
72783c7944SReed Kotler case Type::FloatTyID:
73783c7944SReed Kotler return FRet;
74783c7944SReed Kotler case Type::DoubleTyID:
75783c7944SReed Kotler return DRet;
7662df5eedSJames Y Knight case Type::StructTyID: {
7762df5eedSJames Y Knight StructType *ST = cast<StructType>(T);
7862df5eedSJames Y Knight if (ST->getNumElements() != 2)
79783c7944SReed Kotler break;
8062df5eedSJames Y Knight if ((ST->getElementType(0)->isFloatTy()) &&
8162df5eedSJames Y Knight (ST->getElementType(1)->isFloatTy()))
82783c7944SReed Kotler return CFRet;
8362df5eedSJames Y Knight if ((ST->getElementType(0)->isDoubleTy()) &&
8462df5eedSJames Y Knight (ST->getElementType(1)->isDoubleTy()))
85783c7944SReed Kotler return CDRet;
86783c7944SReed Kotler break;
8762df5eedSJames Y Knight }
88783c7944SReed Kotler default:
89783c7944SReed Kotler break;
90783c7944SReed Kotler }
91783c7944SReed Kotler return NoFPRet;
92783c7944SReed Kotler }
93783c7944SReed Kotler
942c4657d9SReed Kotler // Parameter type that matter are float, (float, float), (float, double),
952c4657d9SReed Kotler // double, (double, double), (double, float)
962c4657d9SReed Kotler enum FPParamVariant {
972c4657d9SReed Kotler FSig, FFSig, FDSig,
982c4657d9SReed Kotler DSig, DDSig, DFSig, NoSig
992c4657d9SReed Kotler };
1002c4657d9SReed Kotler
1012c4657d9SReed Kotler // which floating point parameter signature variant we are dealing with
10279220eaeSEugene Zelenko using TypeID = Type::TypeID;
1032c4657d9SReed Kotler const Type::TypeID FloatTyID = Type::FloatTyID;
1042c4657d9SReed Kotler const Type::TypeID DoubleTyID = Type::DoubleTyID;
1052c4657d9SReed Kotler
whichFPParamVariantNeeded(Function & F)1062c4657d9SReed Kotler static FPParamVariant whichFPParamVariantNeeded(Function &F) {
1072c4657d9SReed Kotler switch (F.arg_size()) {
1082c4657d9SReed Kotler case 0:
1092c4657d9SReed Kotler return NoSig;
1102c4657d9SReed Kotler case 1:{
1112c4657d9SReed Kotler TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
1122c4657d9SReed Kotler switch (ArgTypeID) {
1132c4657d9SReed Kotler case FloatTyID:
1142c4657d9SReed Kotler return FSig;
1152c4657d9SReed Kotler case DoubleTyID:
1162c4657d9SReed Kotler return DSig;
1172c4657d9SReed Kotler default:
1182c4657d9SReed Kotler return NoSig;
1192c4657d9SReed Kotler }
1202c4657d9SReed Kotler }
1212c4657d9SReed Kotler default: {
1222c4657d9SReed Kotler TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
1232c4657d9SReed Kotler TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
1242c4657d9SReed Kotler switch(ArgTypeID0) {
1252c4657d9SReed Kotler case FloatTyID: {
1262c4657d9SReed Kotler switch (ArgTypeID1) {
1272c4657d9SReed Kotler case FloatTyID:
1282c4657d9SReed Kotler return FFSig;
1292c4657d9SReed Kotler case DoubleTyID:
1302c4657d9SReed Kotler return FDSig;
1312c4657d9SReed Kotler default:
1322c4657d9SReed Kotler return FSig;
1332c4657d9SReed Kotler }
1342c4657d9SReed Kotler }
1352c4657d9SReed Kotler case DoubleTyID: {
1362c4657d9SReed Kotler switch (ArgTypeID1) {
1372c4657d9SReed Kotler case FloatTyID:
1382c4657d9SReed Kotler return DFSig;
1392c4657d9SReed Kotler case DoubleTyID:
1402c4657d9SReed Kotler return DDSig;
1412c4657d9SReed Kotler default:
1422c4657d9SReed Kotler return DSig;
1432c4657d9SReed Kotler }
1442c4657d9SReed Kotler }
1452c4657d9SReed Kotler default:
1462c4657d9SReed Kotler return NoSig;
1472c4657d9SReed Kotler }
1482c4657d9SReed Kotler }
1492c4657d9SReed Kotler }
1502c4657d9SReed Kotler llvm_unreachable("can't get here");
1512c4657d9SReed Kotler }
1522c4657d9SReed Kotler
1532c4657d9SReed Kotler // Figure out if we need float point based on the function parameters.
1542c4657d9SReed Kotler // We need to move variables in and/or out of floating point
1552c4657d9SReed Kotler // registers because of the ABI
needsFPStubFromParams(Function & F)1562c4657d9SReed Kotler static bool needsFPStubFromParams(Function &F) {
1572c4657d9SReed Kotler if (F.arg_size() >=1) {
1582c4657d9SReed Kotler Type *ArgType = F.getFunctionType()->getParamType(0);
1592c4657d9SReed Kotler switch (ArgType->getTypeID()) {
1602c4657d9SReed Kotler case Type::FloatTyID:
1612c4657d9SReed Kotler case Type::DoubleTyID:
1622c4657d9SReed Kotler return true;
1632c4657d9SReed Kotler default:
1642c4657d9SReed Kotler break;
1652c4657d9SReed Kotler }
1662c4657d9SReed Kotler }
1672c4657d9SReed Kotler return false;
1682c4657d9SReed Kotler }
1692c4657d9SReed Kotler
needsFPReturnHelper(Function & F)1702c4657d9SReed Kotler static bool needsFPReturnHelper(Function &F) {
1712c4657d9SReed Kotler Type* RetType = F.getReturnType();
1722c4657d9SReed Kotler return whichFPReturnVariant(RetType) != NoFPRet;
1732c4657d9SReed Kotler }
1742c4657d9SReed Kotler
needsFPReturnHelper(FunctionType & FT)175e3dcce97SCraig Topper static bool needsFPReturnHelper(FunctionType &FT) {
1762500bd6cSReed Kotler Type* RetType = FT.getReturnType();
1772500bd6cSReed Kotler return whichFPReturnVariant(RetType) != NoFPRet;
1782500bd6cSReed Kotler }
1792500bd6cSReed Kotler
needsFPHelperFromSig(Function & F)1802c4657d9SReed Kotler static bool needsFPHelperFromSig(Function &F) {
1812c4657d9SReed Kotler return needsFPStubFromParams(F) || needsFPReturnHelper(F);
1822c4657d9SReed Kotler }
1832c4657d9SReed Kotler
1842c4657d9SReed Kotler // We swap between FP and Integer registers to allow Mips16 and Mips32 to
1852c4657d9SReed Kotler // interoperate
swapFPIntParams(FPParamVariant PV,Module * M,bool LE,bool ToFP)186d6cf3e05SDaniel Sanders static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
187d6cf3e05SDaniel Sanders bool ToFP) {
1882c4657d9SReed Kotler std::string MI = ToFP ? "mtc1 ": "mfc1 ";
189d6cf3e05SDaniel Sanders std::string AsmText;
190d6cf3e05SDaniel Sanders
1912c4657d9SReed Kotler switch (PV) {
1922c4657d9SReed Kotler case FSig:
193d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f12\n";
1942c4657d9SReed Kotler break;
195d6cf3e05SDaniel Sanders
1962c4657d9SReed Kotler case FFSig:
197d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f12\n";
198d6cf3e05SDaniel Sanders AsmText += MI + "$$5, $$f14\n";
1992c4657d9SReed Kotler break;
200d6cf3e05SDaniel Sanders
2012c4657d9SReed Kotler case FDSig:
202d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f12\n";
2032c4657d9SReed Kotler if (LE) {
204d6cf3e05SDaniel Sanders AsmText += MI + "$$6, $$f14\n";
205d6cf3e05SDaniel Sanders AsmText += MI + "$$7, $$f15\n";
2062c4657d9SReed Kotler } else {
207d6cf3e05SDaniel Sanders AsmText += MI + "$$7, $$f14\n";
208d6cf3e05SDaniel Sanders AsmText += MI + "$$6, $$f15\n";
2092c4657d9SReed Kotler }
2102c4657d9SReed Kotler break;
211d6cf3e05SDaniel Sanders
2122c4657d9SReed Kotler case DSig:
2132c4657d9SReed Kotler if (LE) {
214d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f12\n";
215d6cf3e05SDaniel Sanders AsmText += MI + "$$5, $$f13\n";
2162c4657d9SReed Kotler } else {
217d6cf3e05SDaniel Sanders AsmText += MI + "$$5, $$f12\n";
218d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f13\n";
2192c4657d9SReed Kotler }
2202c4657d9SReed Kotler break;
221d6cf3e05SDaniel Sanders
2222c4657d9SReed Kotler case DDSig:
2232c4657d9SReed Kotler if (LE) {
224d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f12\n";
225d6cf3e05SDaniel Sanders AsmText += MI + "$$5, $$f13\n";
226d6cf3e05SDaniel Sanders AsmText += MI + "$$6, $$f14\n";
227d6cf3e05SDaniel Sanders AsmText += MI + "$$7, $$f15\n";
2282c4657d9SReed Kotler } else {
229d6cf3e05SDaniel Sanders AsmText += MI + "$$5, $$f12\n";
230d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f13\n";
231d6cf3e05SDaniel Sanders AsmText += MI + "$$7, $$f14\n";
232d6cf3e05SDaniel Sanders AsmText += MI + "$$6, $$f15\n";
2332c4657d9SReed Kotler }
2342c4657d9SReed Kotler break;
235d6cf3e05SDaniel Sanders
2362c4657d9SReed Kotler case DFSig:
2372c4657d9SReed Kotler if (LE) {
238d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f12\n";
239d6cf3e05SDaniel Sanders AsmText += MI + "$$5, $$f13\n";
2402c4657d9SReed Kotler } else {
241d6cf3e05SDaniel Sanders AsmText += MI + "$$5, $$f12\n";
242d6cf3e05SDaniel Sanders AsmText += MI + "$$4, $$f13\n";
2432c4657d9SReed Kotler }
244d6cf3e05SDaniel Sanders AsmText += MI + "$$6, $$f14\n";
2452c4657d9SReed Kotler break;
246d6cf3e05SDaniel Sanders
2472c4657d9SReed Kotler case NoSig:
248d6cf3e05SDaniel Sanders break;
2492c4657d9SReed Kotler }
250d6cf3e05SDaniel Sanders
251d6cf3e05SDaniel Sanders return AsmText;
2522c4657d9SReed Kotler }
2536611eb35SVasileios Kalintiris
2542c4657d9SReed Kotler // Make sure that we know we already need a stub for this function.
2552c4657d9SReed Kotler // Having called needsFPHelperFromSig
assureFPCallStub(Function & F,Module * M,const MipsTargetMachine & TM)256cad47f02SReed Kotler static void assureFPCallStub(Function &F, Module *M,
257d20ee0a2SEric Christopher const MipsTargetMachine &TM) {
2582c4657d9SReed Kotler // for now we only need them for static relocation
259b30e66b8SRafael Espindola if (TM.isPositionIndependent())
2602c4657d9SReed Kotler return;
2612c4657d9SReed Kotler LLVMContext &Context = M->getContext();
262d20ee0a2SEric Christopher bool LE = TM.isLittleEndian();
263adcd0268SBenjamin Kramer std::string Name(F.getName());
2642c4657d9SReed Kotler std::string SectionName = ".mips16.call.fp." + Name;
265302ae6b0SReed Kotler std::string StubName = "__call_stub_fp_" + Name;
2662c4657d9SReed Kotler //
2672c4657d9SReed Kotler // see if we already have the stub
2682c4657d9SReed Kotler //
2692c4657d9SReed Kotler Function *FStub = M->getFunction(StubName);
2702c4657d9SReed Kotler if (FStub && !FStub->isDeclaration()) return;
2712c4657d9SReed Kotler FStub = Function::Create(F.getFunctionType(),
2722c4657d9SReed Kotler Function::InternalLinkage, StubName, M);
2732c4657d9SReed Kotler FStub->addFnAttr("mips16_fp_stub");
27479220eaeSEugene Zelenko FStub->addFnAttr(Attribute::Naked);
27579220eaeSEugene Zelenko FStub->addFnAttr(Attribute::NoInline);
27679220eaeSEugene Zelenko FStub->addFnAttr(Attribute::NoUnwind);
2772c4657d9SReed Kotler FStub->addFnAttr("nomips16");
2782c4657d9SReed Kotler FStub->setSection(SectionName);
2792c4657d9SReed Kotler BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
2802c4657d9SReed Kotler FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
2812c4657d9SReed Kotler FPParamVariant PV = whichFPParamVariantNeeded(F);
282d6cf3e05SDaniel Sanders
283d6cf3e05SDaniel Sanders std::string AsmText;
284d6cf3e05SDaniel Sanders AsmText += ".set reorder\n";
285d6cf3e05SDaniel Sanders AsmText += swapFPIntParams(PV, M, LE, true);
2862c4657d9SReed Kotler if (RV != NoFPRet) {
287d6cf3e05SDaniel Sanders AsmText += "move $$18, $$31\n";
288d6cf3e05SDaniel Sanders AsmText += "jal " + Name + "\n";
2892c4657d9SReed Kotler } else {
290d6cf3e05SDaniel Sanders AsmText += "lui $$25, %hi(" + Name + ")\n";
291d6cf3e05SDaniel Sanders AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n";
2922c4657d9SReed Kotler }
293d6cf3e05SDaniel Sanders
2942c4657d9SReed Kotler switch (RV) {
2952c4657d9SReed Kotler case FRet:
296d6cf3e05SDaniel Sanders AsmText += "mfc1 $$2, $$f0\n";
2972c4657d9SReed Kotler break;
298d6cf3e05SDaniel Sanders
2992c4657d9SReed Kotler case DRet:
3002c4657d9SReed Kotler if (LE) {
301d6cf3e05SDaniel Sanders AsmText += "mfc1 $$2, $$f0\n";
302d6cf3e05SDaniel Sanders AsmText += "mfc1 $$3, $$f1\n";
3032c4657d9SReed Kotler } else {
304d6cf3e05SDaniel Sanders AsmText += "mfc1 $$3, $$f0\n";
305d6cf3e05SDaniel Sanders AsmText += "mfc1 $$2, $$f1\n";
3062c4657d9SReed Kotler }
3072c4657d9SReed Kotler break;
308d6cf3e05SDaniel Sanders
3092c4657d9SReed Kotler case CFRet:
3102c4657d9SReed Kotler if (LE) {
311d6cf3e05SDaniel Sanders AsmText += "mfc1 $$2, $$f0\n";
312d6cf3e05SDaniel Sanders AsmText += "mfc1 $$3, $$f2\n";
3132c4657d9SReed Kotler } else {
314d6cf3e05SDaniel Sanders AsmText += "mfc1 $$3, $$f0\n";
315d6cf3e05SDaniel Sanders AsmText += "mfc1 $$3, $$f2\n";
3162c4657d9SReed Kotler }
3172c4657d9SReed Kotler break;
318d6cf3e05SDaniel Sanders
3192c4657d9SReed Kotler case CDRet:
3202c4657d9SReed Kotler if (LE) {
321d6cf3e05SDaniel Sanders AsmText += "mfc1 $$4, $$f2\n";
322d6cf3e05SDaniel Sanders AsmText += "mfc1 $$5, $$f3\n";
323d6cf3e05SDaniel Sanders AsmText += "mfc1 $$2, $$f0\n";
324d6cf3e05SDaniel Sanders AsmText += "mfc1 $$3, $$f1\n";
3252c4657d9SReed Kotler
3262c4657d9SReed Kotler } else {
327d6cf3e05SDaniel Sanders AsmText += "mfc1 $$5, $$f2\n";
328d6cf3e05SDaniel Sanders AsmText += "mfc1 $$4, $$f3\n";
329d6cf3e05SDaniel Sanders AsmText += "mfc1 $$3, $$f0\n";
330d6cf3e05SDaniel Sanders AsmText += "mfc1 $$2, $$f1\n";
3312c4657d9SReed Kotler }
3322c4657d9SReed Kotler break;
333d6cf3e05SDaniel Sanders
3342c4657d9SReed Kotler case NoFPRet:
3352c4657d9SReed Kotler break;
3362c4657d9SReed Kotler }
337d6cf3e05SDaniel Sanders
3382c4657d9SReed Kotler if (RV != NoFPRet)
339d6cf3e05SDaniel Sanders AsmText += "jr $$18\n";
3402c4657d9SReed Kotler else
341d6cf3e05SDaniel Sanders AsmText += "jr $$25\n";
3421d49eb00SFangrui Song emitInlineAsm(Context, BB, AsmText);
343d6cf3e05SDaniel Sanders
3442c4657d9SReed Kotler new UnreachableInst(Context, BB);
3452c4657d9SReed Kotler }
3462c4657d9SReed Kotler
3475fdadcefSReed Kotler // Functions that are llvm intrinsics and don't need helpers.
3482626094fSCraig Topper static const char *const IntrinsicInline[] = {
3496611eb35SVasileios Kalintiris "fabs", "fabsf",
3505fdadcefSReed Kotler "llvm.ceil.f32", "llvm.ceil.f64",
3515fdadcefSReed Kotler "llvm.copysign.f32", "llvm.copysign.f64",
3525fdadcefSReed Kotler "llvm.cos.f32", "llvm.cos.f64",
3535fdadcefSReed Kotler "llvm.exp.f32", "llvm.exp.f64",
3545fdadcefSReed Kotler "llvm.exp2.f32", "llvm.exp2.f64",
3555fdadcefSReed Kotler "llvm.fabs.f32", "llvm.fabs.f64",
3565fdadcefSReed Kotler "llvm.floor.f32", "llvm.floor.f64",
3575fdadcefSReed Kotler "llvm.fma.f32", "llvm.fma.f64",
3585fdadcefSReed Kotler "llvm.log.f32", "llvm.log.f64",
3595fdadcefSReed Kotler "llvm.log10.f32", "llvm.log10.f64",
3605fdadcefSReed Kotler "llvm.nearbyint.f32", "llvm.nearbyint.f64",
3615fdadcefSReed Kotler "llvm.pow.f32", "llvm.pow.f64",
3624c7f820bSBjorn Pettersson "llvm.powi.f32.i32", "llvm.powi.f64.i32",
3635fdadcefSReed Kotler "llvm.rint.f32", "llvm.rint.f64",
3645fdadcefSReed Kotler "llvm.round.f32", "llvm.round.f64",
3655fdadcefSReed Kotler "llvm.sin.f32", "llvm.sin.f64",
3665fdadcefSReed Kotler "llvm.sqrt.f32", "llvm.sqrt.f64",
3675fdadcefSReed Kotler "llvm.trunc.f32", "llvm.trunc.f64",
3685fdadcefSReed Kotler };
369d265e888SReed Kotler
isIntrinsicInline(Function * F)370c9b7d47bSBenjamin Kramer static bool isIntrinsicInline(Function *F) {
371502b9e1dSBenjamin Kramer return std::binary_search(std::begin(IntrinsicInline),
372502b9e1dSBenjamin Kramer std::end(IntrinsicInline), F->getName());
373d265e888SReed Kotler }
37479220eaeSEugene Zelenko
375783c7944SReed Kotler // Returns of float, double and complex need to be handled with a helper
376515e9376SReed Kotler // function.
fixupFPReturnAndCall(Function & F,Module * M,const MipsTargetMachine & TM)377d20ee0a2SEric Christopher static bool fixupFPReturnAndCall(Function &F, Module *M,
378d20ee0a2SEric Christopher const MipsTargetMachine &TM) {
379783c7944SReed Kotler bool Modified = false;
380783c7944SReed Kotler LLVMContext &C = M->getContext();
381783c7944SReed Kotler Type *MyVoid = Type::getVoidTy(C);
38242db3ff4SVasileios Kalintiris for (auto &BB: F)
38342db3ff4SVasileios Kalintiris for (auto &I: BB) {
38442db3ff4SVasileios Kalintiris if (const ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
385783c7944SReed Kotler Value *RVal = RI->getReturnValue();
386783c7944SReed Kotler if (!RVal) continue;
387783c7944SReed Kotler //
388783c7944SReed Kotler // If there is a return value and it needs a helper function,
389783c7944SReed Kotler // figure out which one and add a call before the actual
390783c7944SReed Kotler // return to this helper. The purpose of the helper is to move
391783c7944SReed Kotler // floating point values from their soft float return mapping to
392783c7944SReed Kotler // where they would have been mapped to in floating point registers.
393783c7944SReed Kotler //
394783c7944SReed Kotler Type *T = RVal->getType();
395783c7944SReed Kotler FPReturnVariant RV = whichFPReturnVariant(T);
396783c7944SReed Kotler if (RV == NoFPRet) continue;
3972626094fSCraig Topper static const char *const Helper[NoFPRet] = {
3986611eb35SVasileios Kalintiris "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
3996611eb35SVasileios Kalintiris "__mips16_ret_dc"
4006611eb35SVasileios Kalintiris };
401783c7944SReed Kotler const char *Name = Helper[RV];
402b518054bSReid Kleckner AttributeList A;
403783c7944SReed Kotler Value *Params[] = {RVal};
404783c7944SReed Kotler Modified = true;
405783c7944SReed Kotler //
406783c7944SReed Kotler // These helper functions have a different calling ABI so
407783c7944SReed Kotler // this __Mips16RetHelper indicates that so that later
408783c7944SReed Kotler // during call setup, the proper call lowering to the helper
409783c7944SReed Kotler // functions will take place.
410783c7944SReed Kotler //
411de0ae9e8SArthur Eubanks A = A.addFnAttribute(C, "__Mips16RetHelper");
412de0ae9e8SArthur Eubanks A = A.addFnAttribute(C, Attribute::ReadNone);
413de0ae9e8SArthur Eubanks A = A.addFnAttribute(C, Attribute::NoInline);
41413680223SJames Y Knight FunctionCallee F = (M->getOrInsertFunction(Name, A, MyVoid, T));
41542db3ff4SVasileios Kalintiris CallInst::Create(F, Params, "", &I);
41642db3ff4SVasileios Kalintiris } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
417190577acSManuel Jacob FunctionType *FT = CI->getFunctionType();
4180ff40017SReed Kotler Function *F_ = CI->getCalledFunction();
419190577acSManuel Jacob if (needsFPReturnHelper(*FT) &&
4202500bd6cSReed Kotler !(F_ && isIntrinsicInline(F_))) {
4212500bd6cSReed Kotler Modified=true;
4222500bd6cSReed Kotler F.addFnAttr("saveS2");
4232500bd6cSReed Kotler }
4240ff40017SReed Kotler if (F_ && !isIntrinsicInline(F_)) {
4252c4657d9SReed Kotler // pic mode calls are handled by already defined
4262c4657d9SReed Kotler // helper functions
4270ff40017SReed Kotler if (needsFPReturnHelper(*F_)) {
4280ff40017SReed Kotler Modified=true;
4290ff40017SReed Kotler F.addFnAttr("saveS2");
4300ff40017SReed Kotler }
431b30e66b8SRafael Espindola if (!TM.isPositionIndependent()) {
4320ff40017SReed Kotler if (needsFPHelperFromSig(*F_)) {
433d20ee0a2SEric Christopher assureFPCallStub(*F_, M, TM);
4342c4657d9SReed Kotler Modified=true;
4352c4657d9SReed Kotler }
4362c4657d9SReed Kotler }
437783c7944SReed Kotler }
438783c7944SReed Kotler }
4390ff40017SReed Kotler }
440783c7944SReed Kotler return Modified;
441783c7944SReed Kotler }
442783c7944SReed Kotler
createFPFnStub(Function * F,Module * M,FPParamVariant PV,const MipsTargetMachine & TM)443515e9376SReed Kotler static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
444d20ee0a2SEric Christopher const MipsTargetMachine &TM) {
445b30e66b8SRafael Espindola bool PicMode = TM.isPositionIndependent();
446d20ee0a2SEric Christopher bool LE = TM.isLittleEndian();
447515e9376SReed Kotler LLVMContext &Context = M->getContext();
448adcd0268SBenjamin Kramer std::string Name(F->getName());
449515e9376SReed Kotler std::string SectionName = ".mips16.fn." + Name;
450515e9376SReed Kotler std::string StubName = "__fn_stub_" + Name;
451a6ce797fSReed Kotler std::string LocalName = "$$__fn_local_" + Name;
452515e9376SReed Kotler Function *FStub = Function::Create
453515e9376SReed Kotler (F->getFunctionType(),
454302ae6b0SReed Kotler Function::InternalLinkage, StubName, M);
455515e9376SReed Kotler FStub->addFnAttr("mips16_fp_stub");
45679220eaeSEugene Zelenko FStub->addFnAttr(Attribute::Naked);
45779220eaeSEugene Zelenko FStub->addFnAttr(Attribute::NoUnwind);
45879220eaeSEugene Zelenko FStub->addFnAttr(Attribute::NoInline);
459515e9376SReed Kotler FStub->addFnAttr("nomips16");
460515e9376SReed Kotler FStub->setSection(SectionName);
461515e9376SReed Kotler BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
462d6cf3e05SDaniel Sanders
463d6cf3e05SDaniel Sanders std::string AsmText;
464515e9376SReed Kotler if (PicMode) {
465d6cf3e05SDaniel Sanders AsmText += ".set noreorder\n";
466d6cf3e05SDaniel Sanders AsmText += ".cpload $$25\n";
467d6cf3e05SDaniel Sanders AsmText += ".set reorder\n";
468d6cf3e05SDaniel Sanders AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
469d6cf3e05SDaniel Sanders AsmText += "la $$25, " + LocalName + "\n";
470d6cf3e05SDaniel Sanders } else
471d6cf3e05SDaniel Sanders AsmText += "la $$25, " + Name + "\n";
472d6cf3e05SDaniel Sanders AsmText += swapFPIntParams(PV, M, LE, false);
473d6cf3e05SDaniel Sanders AsmText += "jr $$25\n";
474d6cf3e05SDaniel Sanders AsmText += LocalName + " = " + Name + "\n";
4751d49eb00SFangrui Song emitInlineAsm(Context, BB, AsmText);
476d6cf3e05SDaniel Sanders
477515e9376SReed Kotler new UnreachableInst(FStub->getContext(), BB);
478515e9376SReed Kotler }
479515e9376SReed Kotler
480c03807a3SReed Kotler // remove the use-soft-float attribute
removeUseSoftFloat(Function & F)481c03807a3SReed Kotler static void removeUseSoftFloat(Function &F) {
482d34e60caSNicola Zaghen LLVM_DEBUG(errs() << "removing -use-soft-float\n");
483*3b0f5a48SNikita Popov F.removeFnAttr("use-soft-float");
484c03807a3SReed Kotler if (F.hasFnAttribute("use-soft-float")) {
485d34e60caSNicola Zaghen LLVM_DEBUG(errs() << "still has -use-soft-float\n");
486c03807a3SReed Kotler }
487*3b0f5a48SNikita Popov F.addFnAttr("use-soft-float", "false");
488c03807a3SReed Kotler }
489c03807a3SReed Kotler
490783c7944SReed Kotler // This pass only makes sense when the underlying chip has floating point but
491783c7944SReed Kotler // we are compiling as mips16.
492783c7944SReed Kotler // For all mips16 functions (that are not stubs we have already generated), or
493783c7944SReed Kotler // declared via attributes as nomips16, we must:
494783c7944SReed Kotler // 1) fixup all returns of float, double, single and double complex
495783c7944SReed Kotler // by calling a helper function before the actual return.
4964cdaa7d7SReed Kotler // 2) generate helper functions (stubs) that can be called by mips32
4974cdaa7d7SReed Kotler // functions that will move parameters passed normally passed in
4984cdaa7d7SReed Kotler // floating point
499515e9376SReed Kotler // registers the soft float equivalents.
500783c7944SReed Kotler // 3) in the case of static relocation, generate helper functions so that
501783c7944SReed Kotler // mips16 functions can call extern functions of unknown type (mips16 or
502515e9376SReed Kotler // mips32).
503783c7944SReed Kotler // 4) TBD. For pic, calls to extern functions of unknown type are handled by
504783c7944SReed Kotler // predefined helper functions in libc but this work is currently done
505783c7944SReed Kotler // during call lowering but it should be moved here in the future.
runOnModule(Module & M)506783c7944SReed Kotler bool Mips16HardFloat::runOnModule(Module &M) {
5078b61764cSFrancis Visoiu Mistrih auto &TM = static_cast<const MipsTargetMachine &>(
5088b61764cSFrancis Visoiu Mistrih getAnalysis<TargetPassConfig>().getTM<TargetMachine>());
509d34e60caSNicola Zaghen LLVM_DEBUG(errs() << "Run on Module Mips16HardFloat\n");
510783c7944SReed Kotler bool Modified = false;
511783c7944SReed Kotler for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
512c03807a3SReed Kotler if (F->hasFnAttribute("nomips16") &&
513c03807a3SReed Kotler F->hasFnAttribute("use-soft-float")) {
514c03807a3SReed Kotler removeUseSoftFloat(*F);
515c03807a3SReed Kotler continue;
516c03807a3SReed Kotler }
517783c7944SReed Kotler if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
518783c7944SReed Kotler F->hasFnAttribute("nomips16")) continue;
519d20ee0a2SEric Christopher Modified |= fixupFPReturnAndCall(*F, &M, TM);
520515e9376SReed Kotler FPParamVariant V = whichFPParamVariantNeeded(*F);
521515e9376SReed Kotler if (V != NoSig) {
522515e9376SReed Kotler Modified = true;
5237869148cSDuncan P. N. Exon Smith createFPFnStub(&*F, &M, V, TM);
524515e9376SReed Kotler }
525783c7944SReed Kotler }
526783c7944SReed Kotler return Modified;
527783c7944SReed Kotler }
528783c7944SReed Kotler
createMips16HardFloatPass()5298b61764cSFrancis Visoiu Mistrih ModulePass *llvm::createMips16HardFloatPass() {
5308b61764cSFrancis Visoiu Mistrih return new Mips16HardFloat();
531783c7944SReed Kotler }
532