1*9880d681SAndroid Build Coastguard Worker //===---- Mips16HardFloat.cpp for Mips16 Hard Float --------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This file defines a pass needed for Mips16 Hard Float
11*9880d681SAndroid Build Coastguard Worker //
12*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
13*9880d681SAndroid Build Coastguard Worker
14*9880d681SAndroid Build Coastguard Worker #include "MipsTargetMachine.h"
15*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Module.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Value.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Debug.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/raw_ostream.h"
19*9880d681SAndroid Build Coastguard Worker #include <algorithm>
20*9880d681SAndroid Build Coastguard Worker #include <string>
21*9880d681SAndroid Build Coastguard Worker
22*9880d681SAndroid Build Coastguard Worker using namespace llvm;
23*9880d681SAndroid Build Coastguard Worker
24*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "mips16-hard-float"
25*9880d681SAndroid Build Coastguard Worker
26*9880d681SAndroid Build Coastguard Worker namespace {
27*9880d681SAndroid Build Coastguard Worker class Mips16HardFloat : public ModulePass {
28*9880d681SAndroid Build Coastguard Worker public:
29*9880d681SAndroid Build Coastguard Worker static char ID;
30*9880d681SAndroid Build Coastguard Worker
Mips16HardFloat(MipsTargetMachine & TM_)31*9880d681SAndroid Build Coastguard Worker Mips16HardFloat(MipsTargetMachine &TM_) : ModulePass(ID), TM(TM_) {}
32*9880d681SAndroid Build Coastguard Worker
getPassName() const33*9880d681SAndroid Build Coastguard Worker const char *getPassName() const override {
34*9880d681SAndroid Build Coastguard Worker return "MIPS16 Hard Float Pass";
35*9880d681SAndroid Build Coastguard Worker }
36*9880d681SAndroid Build Coastguard Worker
37*9880d681SAndroid Build Coastguard Worker bool runOnModule(Module &M) override;
38*9880d681SAndroid Build Coastguard Worker
39*9880d681SAndroid Build Coastguard Worker protected:
40*9880d681SAndroid Build Coastguard Worker const MipsTargetMachine &TM;
41*9880d681SAndroid Build Coastguard Worker };
42*9880d681SAndroid Build Coastguard Worker
EmitInlineAsm(LLVMContext & C,BasicBlock * BB,StringRef AsmText)43*9880d681SAndroid Build Coastguard Worker static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
44*9880d681SAndroid Build Coastguard Worker std::vector<llvm::Type *> AsmArgTypes;
45*9880d681SAndroid Build Coastguard Worker std::vector<llvm::Value *> AsmArgs;
46*9880d681SAndroid Build Coastguard Worker
47*9880d681SAndroid Build Coastguard Worker llvm::FunctionType *AsmFTy =
48*9880d681SAndroid Build Coastguard Worker llvm::FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
49*9880d681SAndroid Build Coastguard Worker llvm::InlineAsm *IA =
50*9880d681SAndroid Build Coastguard Worker llvm::InlineAsm::get(AsmFTy, AsmText, "", true,
51*9880d681SAndroid Build Coastguard Worker /* IsAlignStack */ false, llvm::InlineAsm::AD_ATT);
52*9880d681SAndroid Build Coastguard Worker CallInst::Create(IA, AsmArgs, "", BB);
53*9880d681SAndroid Build Coastguard Worker }
54*9880d681SAndroid Build Coastguard Worker
55*9880d681SAndroid Build Coastguard Worker char Mips16HardFloat::ID = 0;
56*9880d681SAndroid Build Coastguard Worker }
57*9880d681SAndroid Build Coastguard Worker
58*9880d681SAndroid Build Coastguard Worker //
59*9880d681SAndroid Build Coastguard Worker // Return types that matter for hard float are:
60*9880d681SAndroid Build Coastguard Worker // float, double, complex float, and complex double
61*9880d681SAndroid Build Coastguard Worker //
62*9880d681SAndroid Build Coastguard Worker enum FPReturnVariant {
63*9880d681SAndroid Build Coastguard Worker FRet, DRet, CFRet, CDRet, NoFPRet
64*9880d681SAndroid Build Coastguard Worker };
65*9880d681SAndroid Build Coastguard Worker
66*9880d681SAndroid Build Coastguard Worker //
67*9880d681SAndroid Build Coastguard Worker // Determine which FP return type this function has
68*9880d681SAndroid Build Coastguard Worker //
whichFPReturnVariant(Type * T)69*9880d681SAndroid Build Coastguard Worker static FPReturnVariant whichFPReturnVariant(Type *T) {
70*9880d681SAndroid Build Coastguard Worker switch (T->getTypeID()) {
71*9880d681SAndroid Build Coastguard Worker case Type::FloatTyID:
72*9880d681SAndroid Build Coastguard Worker return FRet;
73*9880d681SAndroid Build Coastguard Worker case Type::DoubleTyID:
74*9880d681SAndroid Build Coastguard Worker return DRet;
75*9880d681SAndroid Build Coastguard Worker case Type::StructTyID:
76*9880d681SAndroid Build Coastguard Worker if (T->getStructNumElements() != 2)
77*9880d681SAndroid Build Coastguard Worker break;
78*9880d681SAndroid Build Coastguard Worker if ((T->getContainedType(0)->isFloatTy()) &&
79*9880d681SAndroid Build Coastguard Worker (T->getContainedType(1)->isFloatTy()))
80*9880d681SAndroid Build Coastguard Worker return CFRet;
81*9880d681SAndroid Build Coastguard Worker if ((T->getContainedType(0)->isDoubleTy()) &&
82*9880d681SAndroid Build Coastguard Worker (T->getContainedType(1)->isDoubleTy()))
83*9880d681SAndroid Build Coastguard Worker return CDRet;
84*9880d681SAndroid Build Coastguard Worker break;
85*9880d681SAndroid Build Coastguard Worker default:
86*9880d681SAndroid Build Coastguard Worker break;
87*9880d681SAndroid Build Coastguard Worker }
88*9880d681SAndroid Build Coastguard Worker return NoFPRet;
89*9880d681SAndroid Build Coastguard Worker }
90*9880d681SAndroid Build Coastguard Worker
91*9880d681SAndroid Build Coastguard Worker //
92*9880d681SAndroid Build Coastguard Worker // Parameter type that matter are float, (float, float), (float, double),
93*9880d681SAndroid Build Coastguard Worker // double, (double, double), (double, float)
94*9880d681SAndroid Build Coastguard Worker //
95*9880d681SAndroid Build Coastguard Worker enum FPParamVariant {
96*9880d681SAndroid Build Coastguard Worker FSig, FFSig, FDSig,
97*9880d681SAndroid Build Coastguard Worker DSig, DDSig, DFSig, NoSig
98*9880d681SAndroid Build Coastguard Worker };
99*9880d681SAndroid Build Coastguard Worker
100*9880d681SAndroid Build Coastguard Worker // which floating point parameter signature variant we are dealing with
101*9880d681SAndroid Build Coastguard Worker //
102*9880d681SAndroid Build Coastguard Worker typedef Type::TypeID TypeID;
103*9880d681SAndroid Build Coastguard Worker const Type::TypeID FloatTyID = Type::FloatTyID;
104*9880d681SAndroid Build Coastguard Worker const Type::TypeID DoubleTyID = Type::DoubleTyID;
105*9880d681SAndroid Build Coastguard Worker
whichFPParamVariantNeeded(Function & F)106*9880d681SAndroid Build Coastguard Worker static FPParamVariant whichFPParamVariantNeeded(Function &F) {
107*9880d681SAndroid Build Coastguard Worker switch (F.arg_size()) {
108*9880d681SAndroid Build Coastguard Worker case 0:
109*9880d681SAndroid Build Coastguard Worker return NoSig;
110*9880d681SAndroid Build Coastguard Worker case 1:{
111*9880d681SAndroid Build Coastguard Worker TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
112*9880d681SAndroid Build Coastguard Worker switch (ArgTypeID) {
113*9880d681SAndroid Build Coastguard Worker case FloatTyID:
114*9880d681SAndroid Build Coastguard Worker return FSig;
115*9880d681SAndroid Build Coastguard Worker case DoubleTyID:
116*9880d681SAndroid Build Coastguard Worker return DSig;
117*9880d681SAndroid Build Coastguard Worker default:
118*9880d681SAndroid Build Coastguard Worker return NoSig;
119*9880d681SAndroid Build Coastguard Worker }
120*9880d681SAndroid Build Coastguard Worker }
121*9880d681SAndroid Build Coastguard Worker default: {
122*9880d681SAndroid Build Coastguard Worker TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
123*9880d681SAndroid Build Coastguard Worker TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
124*9880d681SAndroid Build Coastguard Worker switch(ArgTypeID0) {
125*9880d681SAndroid Build Coastguard Worker case FloatTyID: {
126*9880d681SAndroid Build Coastguard Worker switch (ArgTypeID1) {
127*9880d681SAndroid Build Coastguard Worker case FloatTyID:
128*9880d681SAndroid Build Coastguard Worker return FFSig;
129*9880d681SAndroid Build Coastguard Worker case DoubleTyID:
130*9880d681SAndroid Build Coastguard Worker return FDSig;
131*9880d681SAndroid Build Coastguard Worker default:
132*9880d681SAndroid Build Coastguard Worker return FSig;
133*9880d681SAndroid Build Coastguard Worker }
134*9880d681SAndroid Build Coastguard Worker }
135*9880d681SAndroid Build Coastguard Worker case DoubleTyID: {
136*9880d681SAndroid Build Coastguard Worker switch (ArgTypeID1) {
137*9880d681SAndroid Build Coastguard Worker case FloatTyID:
138*9880d681SAndroid Build Coastguard Worker return DFSig;
139*9880d681SAndroid Build Coastguard Worker case DoubleTyID:
140*9880d681SAndroid Build Coastguard Worker return DDSig;
141*9880d681SAndroid Build Coastguard Worker default:
142*9880d681SAndroid Build Coastguard Worker return DSig;
143*9880d681SAndroid Build Coastguard Worker }
144*9880d681SAndroid Build Coastguard Worker }
145*9880d681SAndroid Build Coastguard Worker default:
146*9880d681SAndroid Build Coastguard Worker return NoSig;
147*9880d681SAndroid Build Coastguard Worker }
148*9880d681SAndroid Build Coastguard Worker }
149*9880d681SAndroid Build Coastguard Worker }
150*9880d681SAndroid Build Coastguard Worker llvm_unreachable("can't get here");
151*9880d681SAndroid Build Coastguard Worker }
152*9880d681SAndroid Build Coastguard Worker
153*9880d681SAndroid Build Coastguard Worker // Figure out if we need float point based on the function parameters.
154*9880d681SAndroid Build Coastguard Worker // We need to move variables in and/or out of floating point
155*9880d681SAndroid Build Coastguard Worker // registers because of the ABI
156*9880d681SAndroid Build Coastguard Worker //
needsFPStubFromParams(Function & F)157*9880d681SAndroid Build Coastguard Worker static bool needsFPStubFromParams(Function &F) {
158*9880d681SAndroid Build Coastguard Worker if (F.arg_size() >=1) {
159*9880d681SAndroid Build Coastguard Worker Type *ArgType = F.getFunctionType()->getParamType(0);
160*9880d681SAndroid Build Coastguard Worker switch (ArgType->getTypeID()) {
161*9880d681SAndroid Build Coastguard Worker case Type::FloatTyID:
162*9880d681SAndroid Build Coastguard Worker case Type::DoubleTyID:
163*9880d681SAndroid Build Coastguard Worker return true;
164*9880d681SAndroid Build Coastguard Worker default:
165*9880d681SAndroid Build Coastguard Worker break;
166*9880d681SAndroid Build Coastguard Worker }
167*9880d681SAndroid Build Coastguard Worker }
168*9880d681SAndroid Build Coastguard Worker return false;
169*9880d681SAndroid Build Coastguard Worker }
170*9880d681SAndroid Build Coastguard Worker
needsFPReturnHelper(Function & F)171*9880d681SAndroid Build Coastguard Worker static bool needsFPReturnHelper(Function &F) {
172*9880d681SAndroid Build Coastguard Worker Type* RetType = F.getReturnType();
173*9880d681SAndroid Build Coastguard Worker return whichFPReturnVariant(RetType) != NoFPRet;
174*9880d681SAndroid Build Coastguard Worker }
175*9880d681SAndroid Build Coastguard Worker
needsFPReturnHelper(FunctionType & FT)176*9880d681SAndroid Build Coastguard Worker static bool needsFPReturnHelper(FunctionType &FT) {
177*9880d681SAndroid Build Coastguard Worker Type* RetType = FT.getReturnType();
178*9880d681SAndroid Build Coastguard Worker return whichFPReturnVariant(RetType) != NoFPRet;
179*9880d681SAndroid Build Coastguard Worker }
180*9880d681SAndroid Build Coastguard Worker
needsFPHelperFromSig(Function & F)181*9880d681SAndroid Build Coastguard Worker static bool needsFPHelperFromSig(Function &F) {
182*9880d681SAndroid Build Coastguard Worker return needsFPStubFromParams(F) || needsFPReturnHelper(F);
183*9880d681SAndroid Build Coastguard Worker }
184*9880d681SAndroid Build Coastguard Worker
185*9880d681SAndroid Build Coastguard Worker //
186*9880d681SAndroid Build Coastguard Worker // We swap between FP and Integer registers to allow Mips16 and Mips32 to
187*9880d681SAndroid Build Coastguard Worker // interoperate
188*9880d681SAndroid Build Coastguard Worker //
swapFPIntParams(FPParamVariant PV,Module * M,bool LE,bool ToFP)189*9880d681SAndroid Build Coastguard Worker static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
190*9880d681SAndroid Build Coastguard Worker bool ToFP) {
191*9880d681SAndroid Build Coastguard Worker std::string MI = ToFP ? "mtc1 ": "mfc1 ";
192*9880d681SAndroid Build Coastguard Worker std::string AsmText;
193*9880d681SAndroid Build Coastguard Worker
194*9880d681SAndroid Build Coastguard Worker switch (PV) {
195*9880d681SAndroid Build Coastguard Worker case FSig:
196*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f12\n";
197*9880d681SAndroid Build Coastguard Worker break;
198*9880d681SAndroid Build Coastguard Worker
199*9880d681SAndroid Build Coastguard Worker case FFSig:
200*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f12\n";
201*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$5, $$f14\n";
202*9880d681SAndroid Build Coastguard Worker break;
203*9880d681SAndroid Build Coastguard Worker
204*9880d681SAndroid Build Coastguard Worker case FDSig:
205*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f12\n";
206*9880d681SAndroid Build Coastguard Worker if (LE) {
207*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$6, $$f14\n";
208*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$7, $$f15\n";
209*9880d681SAndroid Build Coastguard Worker } else {
210*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$7, $$f14\n";
211*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$6, $$f15\n";
212*9880d681SAndroid Build Coastguard Worker }
213*9880d681SAndroid Build Coastguard Worker break;
214*9880d681SAndroid Build Coastguard Worker
215*9880d681SAndroid Build Coastguard Worker case DSig:
216*9880d681SAndroid Build Coastguard Worker if (LE) {
217*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f12\n";
218*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$5, $$f13\n";
219*9880d681SAndroid Build Coastguard Worker } else {
220*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$5, $$f12\n";
221*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f13\n";
222*9880d681SAndroid Build Coastguard Worker }
223*9880d681SAndroid Build Coastguard Worker break;
224*9880d681SAndroid Build Coastguard Worker
225*9880d681SAndroid Build Coastguard Worker case DDSig:
226*9880d681SAndroid Build Coastguard Worker if (LE) {
227*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f12\n";
228*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$5, $$f13\n";
229*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$6, $$f14\n";
230*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$7, $$f15\n";
231*9880d681SAndroid Build Coastguard Worker } else {
232*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$5, $$f12\n";
233*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f13\n";
234*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$7, $$f14\n";
235*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$6, $$f15\n";
236*9880d681SAndroid Build Coastguard Worker }
237*9880d681SAndroid Build Coastguard Worker break;
238*9880d681SAndroid Build Coastguard Worker
239*9880d681SAndroid Build Coastguard Worker case DFSig:
240*9880d681SAndroid Build Coastguard Worker if (LE) {
241*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f12\n";
242*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$5, $$f13\n";
243*9880d681SAndroid Build Coastguard Worker } else {
244*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$5, $$f12\n";
245*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$4, $$f13\n";
246*9880d681SAndroid Build Coastguard Worker }
247*9880d681SAndroid Build Coastguard Worker AsmText += MI + "$$6, $$f14\n";
248*9880d681SAndroid Build Coastguard Worker break;
249*9880d681SAndroid Build Coastguard Worker
250*9880d681SAndroid Build Coastguard Worker case NoSig:
251*9880d681SAndroid Build Coastguard Worker break;
252*9880d681SAndroid Build Coastguard Worker }
253*9880d681SAndroid Build Coastguard Worker
254*9880d681SAndroid Build Coastguard Worker return AsmText;
255*9880d681SAndroid Build Coastguard Worker }
256*9880d681SAndroid Build Coastguard Worker
257*9880d681SAndroid Build Coastguard Worker //
258*9880d681SAndroid Build Coastguard Worker // Make sure that we know we already need a stub for this function.
259*9880d681SAndroid Build Coastguard Worker // Having called needsFPHelperFromSig
260*9880d681SAndroid Build Coastguard Worker //
assureFPCallStub(Function & F,Module * M,const MipsTargetMachine & TM)261*9880d681SAndroid Build Coastguard Worker static void assureFPCallStub(Function &F, Module *M,
262*9880d681SAndroid Build Coastguard Worker const MipsTargetMachine &TM) {
263*9880d681SAndroid Build Coastguard Worker // for now we only need them for static relocation
264*9880d681SAndroid Build Coastguard Worker if (TM.isPositionIndependent())
265*9880d681SAndroid Build Coastguard Worker return;
266*9880d681SAndroid Build Coastguard Worker LLVMContext &Context = M->getContext();
267*9880d681SAndroid Build Coastguard Worker bool LE = TM.isLittleEndian();
268*9880d681SAndroid Build Coastguard Worker std::string Name = F.getName();
269*9880d681SAndroid Build Coastguard Worker std::string SectionName = ".mips16.call.fp." + Name;
270*9880d681SAndroid Build Coastguard Worker std::string StubName = "__call_stub_fp_" + Name;
271*9880d681SAndroid Build Coastguard Worker //
272*9880d681SAndroid Build Coastguard Worker // see if we already have the stub
273*9880d681SAndroid Build Coastguard Worker //
274*9880d681SAndroid Build Coastguard Worker Function *FStub = M->getFunction(StubName);
275*9880d681SAndroid Build Coastguard Worker if (FStub && !FStub->isDeclaration()) return;
276*9880d681SAndroid Build Coastguard Worker FStub = Function::Create(F.getFunctionType(),
277*9880d681SAndroid Build Coastguard Worker Function::InternalLinkage, StubName, M);
278*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr("mips16_fp_stub");
279*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr(llvm::Attribute::Naked);
280*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr(llvm::Attribute::NoInline);
281*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr(llvm::Attribute::NoUnwind);
282*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr("nomips16");
283*9880d681SAndroid Build Coastguard Worker FStub->setSection(SectionName);
284*9880d681SAndroid Build Coastguard Worker BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
285*9880d681SAndroid Build Coastguard Worker FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
286*9880d681SAndroid Build Coastguard Worker FPParamVariant PV = whichFPParamVariantNeeded(F);
287*9880d681SAndroid Build Coastguard Worker
288*9880d681SAndroid Build Coastguard Worker std::string AsmText;
289*9880d681SAndroid Build Coastguard Worker AsmText += ".set reorder\n";
290*9880d681SAndroid Build Coastguard Worker AsmText += swapFPIntParams(PV, M, LE, true);
291*9880d681SAndroid Build Coastguard Worker if (RV != NoFPRet) {
292*9880d681SAndroid Build Coastguard Worker AsmText += "move $$18, $$31\n";
293*9880d681SAndroid Build Coastguard Worker AsmText += "jal " + Name + "\n";
294*9880d681SAndroid Build Coastguard Worker } else {
295*9880d681SAndroid Build Coastguard Worker AsmText += "lui $$25, %hi(" + Name + ")\n";
296*9880d681SAndroid Build Coastguard Worker AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n";
297*9880d681SAndroid Build Coastguard Worker }
298*9880d681SAndroid Build Coastguard Worker
299*9880d681SAndroid Build Coastguard Worker switch (RV) {
300*9880d681SAndroid Build Coastguard Worker case FRet:
301*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$2, $$f0\n";
302*9880d681SAndroid Build Coastguard Worker break;
303*9880d681SAndroid Build Coastguard Worker
304*9880d681SAndroid Build Coastguard Worker case DRet:
305*9880d681SAndroid Build Coastguard Worker if (LE) {
306*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$2, $$f0\n";
307*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$3, $$f1\n";
308*9880d681SAndroid Build Coastguard Worker } else {
309*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$3, $$f0\n";
310*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$2, $$f1\n";
311*9880d681SAndroid Build Coastguard Worker }
312*9880d681SAndroid Build Coastguard Worker break;
313*9880d681SAndroid Build Coastguard Worker
314*9880d681SAndroid Build Coastguard Worker case CFRet:
315*9880d681SAndroid Build Coastguard Worker if (LE) {
316*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$2, $$f0\n";
317*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$3, $$f2\n";
318*9880d681SAndroid Build Coastguard Worker } else {
319*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$3, $$f0\n";
320*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$3, $$f2\n";
321*9880d681SAndroid Build Coastguard Worker }
322*9880d681SAndroid Build Coastguard Worker break;
323*9880d681SAndroid Build Coastguard Worker
324*9880d681SAndroid Build Coastguard Worker case CDRet:
325*9880d681SAndroid Build Coastguard Worker if (LE) {
326*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$4, $$f2\n";
327*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$5, $$f3\n";
328*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$2, $$f0\n";
329*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$3, $$f1\n";
330*9880d681SAndroid Build Coastguard Worker
331*9880d681SAndroid Build Coastguard Worker } else {
332*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$5, $$f2\n";
333*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$4, $$f3\n";
334*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$3, $$f0\n";
335*9880d681SAndroid Build Coastguard Worker AsmText += "mfc1 $$2, $$f1\n";
336*9880d681SAndroid Build Coastguard Worker }
337*9880d681SAndroid Build Coastguard Worker break;
338*9880d681SAndroid Build Coastguard Worker
339*9880d681SAndroid Build Coastguard Worker case NoFPRet:
340*9880d681SAndroid Build Coastguard Worker break;
341*9880d681SAndroid Build Coastguard Worker }
342*9880d681SAndroid Build Coastguard Worker
343*9880d681SAndroid Build Coastguard Worker if (RV != NoFPRet)
344*9880d681SAndroid Build Coastguard Worker AsmText += "jr $$18\n";
345*9880d681SAndroid Build Coastguard Worker else
346*9880d681SAndroid Build Coastguard Worker AsmText += "jr $$25\n";
347*9880d681SAndroid Build Coastguard Worker EmitInlineAsm(Context, BB, AsmText);
348*9880d681SAndroid Build Coastguard Worker
349*9880d681SAndroid Build Coastguard Worker new UnreachableInst(Context, BB);
350*9880d681SAndroid Build Coastguard Worker }
351*9880d681SAndroid Build Coastguard Worker
352*9880d681SAndroid Build Coastguard Worker //
353*9880d681SAndroid Build Coastguard Worker // Functions that are llvm intrinsics and don't need helpers.
354*9880d681SAndroid Build Coastguard Worker //
355*9880d681SAndroid Build Coastguard Worker static const char *const IntrinsicInline[] = {
356*9880d681SAndroid Build Coastguard Worker "fabs", "fabsf",
357*9880d681SAndroid Build Coastguard Worker "llvm.ceil.f32", "llvm.ceil.f64",
358*9880d681SAndroid Build Coastguard Worker "llvm.copysign.f32", "llvm.copysign.f64",
359*9880d681SAndroid Build Coastguard Worker "llvm.cos.f32", "llvm.cos.f64",
360*9880d681SAndroid Build Coastguard Worker "llvm.exp.f32", "llvm.exp.f64",
361*9880d681SAndroid Build Coastguard Worker "llvm.exp2.f32", "llvm.exp2.f64",
362*9880d681SAndroid Build Coastguard Worker "llvm.fabs.f32", "llvm.fabs.f64",
363*9880d681SAndroid Build Coastguard Worker "llvm.floor.f32", "llvm.floor.f64",
364*9880d681SAndroid Build Coastguard Worker "llvm.fma.f32", "llvm.fma.f64",
365*9880d681SAndroid Build Coastguard Worker "llvm.log.f32", "llvm.log.f64",
366*9880d681SAndroid Build Coastguard Worker "llvm.log10.f32", "llvm.log10.f64",
367*9880d681SAndroid Build Coastguard Worker "llvm.nearbyint.f32", "llvm.nearbyint.f64",
368*9880d681SAndroid Build Coastguard Worker "llvm.pow.f32", "llvm.pow.f64",
369*9880d681SAndroid Build Coastguard Worker "llvm.powi.f32", "llvm.powi.f64",
370*9880d681SAndroid Build Coastguard Worker "llvm.rint.f32", "llvm.rint.f64",
371*9880d681SAndroid Build Coastguard Worker "llvm.round.f32", "llvm.round.f64",
372*9880d681SAndroid Build Coastguard Worker "llvm.sin.f32", "llvm.sin.f64",
373*9880d681SAndroid Build Coastguard Worker "llvm.sqrt.f32", "llvm.sqrt.f64",
374*9880d681SAndroid Build Coastguard Worker "llvm.trunc.f32", "llvm.trunc.f64",
375*9880d681SAndroid Build Coastguard Worker };
376*9880d681SAndroid Build Coastguard Worker
isIntrinsicInline(Function * F)377*9880d681SAndroid Build Coastguard Worker static bool isIntrinsicInline(Function *F) {
378*9880d681SAndroid Build Coastguard Worker return std::binary_search(std::begin(IntrinsicInline),
379*9880d681SAndroid Build Coastguard Worker std::end(IntrinsicInline), F->getName());
380*9880d681SAndroid Build Coastguard Worker }
381*9880d681SAndroid Build Coastguard Worker //
382*9880d681SAndroid Build Coastguard Worker // Returns of float, double and complex need to be handled with a helper
383*9880d681SAndroid Build Coastguard Worker // function.
384*9880d681SAndroid Build Coastguard Worker //
fixupFPReturnAndCall(Function & F,Module * M,const MipsTargetMachine & TM)385*9880d681SAndroid Build Coastguard Worker static bool fixupFPReturnAndCall(Function &F, Module *M,
386*9880d681SAndroid Build Coastguard Worker const MipsTargetMachine &TM) {
387*9880d681SAndroid Build Coastguard Worker bool Modified = false;
388*9880d681SAndroid Build Coastguard Worker LLVMContext &C = M->getContext();
389*9880d681SAndroid Build Coastguard Worker Type *MyVoid = Type::getVoidTy(C);
390*9880d681SAndroid Build Coastguard Worker for (auto &BB: F)
391*9880d681SAndroid Build Coastguard Worker for (auto &I: BB) {
392*9880d681SAndroid Build Coastguard Worker if (const ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
393*9880d681SAndroid Build Coastguard Worker Value *RVal = RI->getReturnValue();
394*9880d681SAndroid Build Coastguard Worker if (!RVal) continue;
395*9880d681SAndroid Build Coastguard Worker //
396*9880d681SAndroid Build Coastguard Worker // If there is a return value and it needs a helper function,
397*9880d681SAndroid Build Coastguard Worker // figure out which one and add a call before the actual
398*9880d681SAndroid Build Coastguard Worker // return to this helper. The purpose of the helper is to move
399*9880d681SAndroid Build Coastguard Worker // floating point values from their soft float return mapping to
400*9880d681SAndroid Build Coastguard Worker // where they would have been mapped to in floating point registers.
401*9880d681SAndroid Build Coastguard Worker //
402*9880d681SAndroid Build Coastguard Worker Type *T = RVal->getType();
403*9880d681SAndroid Build Coastguard Worker FPReturnVariant RV = whichFPReturnVariant(T);
404*9880d681SAndroid Build Coastguard Worker if (RV == NoFPRet) continue;
405*9880d681SAndroid Build Coastguard Worker static const char *const Helper[NoFPRet] = {
406*9880d681SAndroid Build Coastguard Worker "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
407*9880d681SAndroid Build Coastguard Worker "__mips16_ret_dc"
408*9880d681SAndroid Build Coastguard Worker };
409*9880d681SAndroid Build Coastguard Worker const char *Name = Helper[RV];
410*9880d681SAndroid Build Coastguard Worker AttributeSet A;
411*9880d681SAndroid Build Coastguard Worker Value *Params[] = {RVal};
412*9880d681SAndroid Build Coastguard Worker Modified = true;
413*9880d681SAndroid Build Coastguard Worker //
414*9880d681SAndroid Build Coastguard Worker // These helper functions have a different calling ABI so
415*9880d681SAndroid Build Coastguard Worker // this __Mips16RetHelper indicates that so that later
416*9880d681SAndroid Build Coastguard Worker // during call setup, the proper call lowering to the helper
417*9880d681SAndroid Build Coastguard Worker // functions will take place.
418*9880d681SAndroid Build Coastguard Worker //
419*9880d681SAndroid Build Coastguard Worker A = A.addAttribute(C, AttributeSet::FunctionIndex,
420*9880d681SAndroid Build Coastguard Worker "__Mips16RetHelper");
421*9880d681SAndroid Build Coastguard Worker A = A.addAttribute(C, AttributeSet::FunctionIndex,
422*9880d681SAndroid Build Coastguard Worker Attribute::ReadNone);
423*9880d681SAndroid Build Coastguard Worker A = A.addAttribute(C, AttributeSet::FunctionIndex,
424*9880d681SAndroid Build Coastguard Worker Attribute::NoInline);
425*9880d681SAndroid Build Coastguard Worker Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, nullptr));
426*9880d681SAndroid Build Coastguard Worker CallInst::Create(F, Params, "", &I);
427*9880d681SAndroid Build Coastguard Worker } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
428*9880d681SAndroid Build Coastguard Worker FunctionType *FT = CI->getFunctionType();
429*9880d681SAndroid Build Coastguard Worker Function *F_ = CI->getCalledFunction();
430*9880d681SAndroid Build Coastguard Worker if (needsFPReturnHelper(*FT) &&
431*9880d681SAndroid Build Coastguard Worker !(F_ && isIntrinsicInline(F_))) {
432*9880d681SAndroid Build Coastguard Worker Modified=true;
433*9880d681SAndroid Build Coastguard Worker F.addFnAttr("saveS2");
434*9880d681SAndroid Build Coastguard Worker }
435*9880d681SAndroid Build Coastguard Worker if (F_ && !isIntrinsicInline(F_)) {
436*9880d681SAndroid Build Coastguard Worker // pic mode calls are handled by already defined
437*9880d681SAndroid Build Coastguard Worker // helper functions
438*9880d681SAndroid Build Coastguard Worker if (needsFPReturnHelper(*F_)) {
439*9880d681SAndroid Build Coastguard Worker Modified=true;
440*9880d681SAndroid Build Coastguard Worker F.addFnAttr("saveS2");
441*9880d681SAndroid Build Coastguard Worker }
442*9880d681SAndroid Build Coastguard Worker if (!TM.isPositionIndependent()) {
443*9880d681SAndroid Build Coastguard Worker if (needsFPHelperFromSig(*F_)) {
444*9880d681SAndroid Build Coastguard Worker assureFPCallStub(*F_, M, TM);
445*9880d681SAndroid Build Coastguard Worker Modified=true;
446*9880d681SAndroid Build Coastguard Worker }
447*9880d681SAndroid Build Coastguard Worker }
448*9880d681SAndroid Build Coastguard Worker }
449*9880d681SAndroid Build Coastguard Worker }
450*9880d681SAndroid Build Coastguard Worker }
451*9880d681SAndroid Build Coastguard Worker return Modified;
452*9880d681SAndroid Build Coastguard Worker }
453*9880d681SAndroid Build Coastguard Worker
createFPFnStub(Function * F,Module * M,FPParamVariant PV,const MipsTargetMachine & TM)454*9880d681SAndroid Build Coastguard Worker static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
455*9880d681SAndroid Build Coastguard Worker const MipsTargetMachine &TM) {
456*9880d681SAndroid Build Coastguard Worker bool PicMode = TM.isPositionIndependent();
457*9880d681SAndroid Build Coastguard Worker bool LE = TM.isLittleEndian();
458*9880d681SAndroid Build Coastguard Worker LLVMContext &Context = M->getContext();
459*9880d681SAndroid Build Coastguard Worker std::string Name = F->getName();
460*9880d681SAndroid Build Coastguard Worker std::string SectionName = ".mips16.fn." + Name;
461*9880d681SAndroid Build Coastguard Worker std::string StubName = "__fn_stub_" + Name;
462*9880d681SAndroid Build Coastguard Worker std::string LocalName = "$$__fn_local_" + Name;
463*9880d681SAndroid Build Coastguard Worker Function *FStub = Function::Create
464*9880d681SAndroid Build Coastguard Worker (F->getFunctionType(),
465*9880d681SAndroid Build Coastguard Worker Function::InternalLinkage, StubName, M);
466*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr("mips16_fp_stub");
467*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr(llvm::Attribute::Naked);
468*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr(llvm::Attribute::NoUnwind);
469*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr(llvm::Attribute::NoInline);
470*9880d681SAndroid Build Coastguard Worker FStub->addFnAttr("nomips16");
471*9880d681SAndroid Build Coastguard Worker FStub->setSection(SectionName);
472*9880d681SAndroid Build Coastguard Worker BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
473*9880d681SAndroid Build Coastguard Worker
474*9880d681SAndroid Build Coastguard Worker std::string AsmText;
475*9880d681SAndroid Build Coastguard Worker if (PicMode) {
476*9880d681SAndroid Build Coastguard Worker AsmText += ".set noreorder\n";
477*9880d681SAndroid Build Coastguard Worker AsmText += ".cpload $$25\n";
478*9880d681SAndroid Build Coastguard Worker AsmText += ".set reorder\n";
479*9880d681SAndroid Build Coastguard Worker AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
480*9880d681SAndroid Build Coastguard Worker AsmText += "la $$25, " + LocalName + "\n";
481*9880d681SAndroid Build Coastguard Worker } else
482*9880d681SAndroid Build Coastguard Worker AsmText += "la $$25, " + Name + "\n";
483*9880d681SAndroid Build Coastguard Worker AsmText += swapFPIntParams(PV, M, LE, false);
484*9880d681SAndroid Build Coastguard Worker AsmText += "jr $$25\n";
485*9880d681SAndroid Build Coastguard Worker AsmText += LocalName + " = " + Name + "\n";
486*9880d681SAndroid Build Coastguard Worker EmitInlineAsm(Context, BB, AsmText);
487*9880d681SAndroid Build Coastguard Worker
488*9880d681SAndroid Build Coastguard Worker new UnreachableInst(FStub->getContext(), BB);
489*9880d681SAndroid Build Coastguard Worker }
490*9880d681SAndroid Build Coastguard Worker
491*9880d681SAndroid Build Coastguard Worker //
492*9880d681SAndroid Build Coastguard Worker // remove the use-soft-float attribute
493*9880d681SAndroid Build Coastguard Worker //
removeUseSoftFloat(Function & F)494*9880d681SAndroid Build Coastguard Worker static void removeUseSoftFloat(Function &F) {
495*9880d681SAndroid Build Coastguard Worker AttributeSet A;
496*9880d681SAndroid Build Coastguard Worker DEBUG(errs() << "removing -use-soft-float\n");
497*9880d681SAndroid Build Coastguard Worker A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex,
498*9880d681SAndroid Build Coastguard Worker "use-soft-float", "false");
499*9880d681SAndroid Build Coastguard Worker F.removeAttributes(AttributeSet::FunctionIndex, A);
500*9880d681SAndroid Build Coastguard Worker if (F.hasFnAttribute("use-soft-float")) {
501*9880d681SAndroid Build Coastguard Worker DEBUG(errs() << "still has -use-soft-float\n");
502*9880d681SAndroid Build Coastguard Worker }
503*9880d681SAndroid Build Coastguard Worker F.addAttributes(AttributeSet::FunctionIndex, A);
504*9880d681SAndroid Build Coastguard Worker }
505*9880d681SAndroid Build Coastguard Worker
506*9880d681SAndroid Build Coastguard Worker
507*9880d681SAndroid Build Coastguard Worker //
508*9880d681SAndroid Build Coastguard Worker // This pass only makes sense when the underlying chip has floating point but
509*9880d681SAndroid Build Coastguard Worker // we are compiling as mips16.
510*9880d681SAndroid Build Coastguard Worker // For all mips16 functions (that are not stubs we have already generated), or
511*9880d681SAndroid Build Coastguard Worker // declared via attributes as nomips16, we must:
512*9880d681SAndroid Build Coastguard Worker // 1) fixup all returns of float, double, single and double complex
513*9880d681SAndroid Build Coastguard Worker // by calling a helper function before the actual return.
514*9880d681SAndroid Build Coastguard Worker // 2) generate helper functions (stubs) that can be called by mips32
515*9880d681SAndroid Build Coastguard Worker // functions that will move parameters passed normally passed in
516*9880d681SAndroid Build Coastguard Worker // floating point
517*9880d681SAndroid Build Coastguard Worker // registers the soft float equivalents.
518*9880d681SAndroid Build Coastguard Worker // 3) in the case of static relocation, generate helper functions so that
519*9880d681SAndroid Build Coastguard Worker // mips16 functions can call extern functions of unknown type (mips16 or
520*9880d681SAndroid Build Coastguard Worker // mips32).
521*9880d681SAndroid Build Coastguard Worker // 4) TBD. For pic, calls to extern functions of unknown type are handled by
522*9880d681SAndroid Build Coastguard Worker // predefined helper functions in libc but this work is currently done
523*9880d681SAndroid Build Coastguard Worker // during call lowering but it should be moved here in the future.
524*9880d681SAndroid Build Coastguard Worker //
runOnModule(Module & M)525*9880d681SAndroid Build Coastguard Worker bool Mips16HardFloat::runOnModule(Module &M) {
526*9880d681SAndroid Build Coastguard Worker DEBUG(errs() << "Run on Module Mips16HardFloat\n");
527*9880d681SAndroid Build Coastguard Worker bool Modified = false;
528*9880d681SAndroid Build Coastguard Worker for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
529*9880d681SAndroid Build Coastguard Worker if (F->hasFnAttribute("nomips16") &&
530*9880d681SAndroid Build Coastguard Worker F->hasFnAttribute("use-soft-float")) {
531*9880d681SAndroid Build Coastguard Worker removeUseSoftFloat(*F);
532*9880d681SAndroid Build Coastguard Worker continue;
533*9880d681SAndroid Build Coastguard Worker }
534*9880d681SAndroid Build Coastguard Worker if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
535*9880d681SAndroid Build Coastguard Worker F->hasFnAttribute("nomips16")) continue;
536*9880d681SAndroid Build Coastguard Worker Modified |= fixupFPReturnAndCall(*F, &M, TM);
537*9880d681SAndroid Build Coastguard Worker FPParamVariant V = whichFPParamVariantNeeded(*F);
538*9880d681SAndroid Build Coastguard Worker if (V != NoSig) {
539*9880d681SAndroid Build Coastguard Worker Modified = true;
540*9880d681SAndroid Build Coastguard Worker createFPFnStub(&*F, &M, V, TM);
541*9880d681SAndroid Build Coastguard Worker }
542*9880d681SAndroid Build Coastguard Worker }
543*9880d681SAndroid Build Coastguard Worker return Modified;
544*9880d681SAndroid Build Coastguard Worker }
545*9880d681SAndroid Build Coastguard Worker
546*9880d681SAndroid Build Coastguard Worker
createMips16HardFloatPass(MipsTargetMachine & TM)547*9880d681SAndroid Build Coastguard Worker ModulePass *llvm::createMips16HardFloatPass(MipsTargetMachine &TM) {
548*9880d681SAndroid Build Coastguard Worker return new Mips16HardFloat(TM);
549*9880d681SAndroid Build Coastguard Worker }
550