brintos

brintos / llvm-project-archived public Read only

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