mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 11:36:07 +00:00

This also fixes some missing implicit uses on call instructions, adds missing G_ASSERT_SEXT/ZEXT annotations, and some missing outgoing sext/zexts. This also fixes not respecting tablegen requested type promotions. This starts treating f64 passed in i32 GPRs as a type of custom assignment, which restores some previously XFAILed tests. This is due to getNumRegistersForCallingConv returns a static value, but in this case it is context dependent on other arguments. Most of the ugliness is reproducing a hack CC_MipsO32 uses in SelectionDAG. CC_MipsO32 depends on a bunch of vectors populated from the original IR argument types in MipsCCState. The way this ends up working in GlobalISel is it only ends up inspecting the most recently added vector element. I'm pretty sure there are cleaner ways to do this, but this seemed easier than fixing up the current DAG handling. This is another case where it would be easier of the CCAssignFns were passed the original type instead of only the pre-legalized ones. There's still a lot of junk here that shouldn't be necessary. This also likely breaks big endian handling, but it wasn't complete/tested anyway since the IRTranslator gives up on big endian targets.
209 lines
8.1 KiB
C++
209 lines
8.1 KiB
C++
//===---- MipsCCState.cpp - CCState with Mips specific extensions ---------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MipsCCState.h"
|
|
#include "MipsSubtarget.h"
|
|
#include "llvm/IR/Module.h"
|
|
|
|
using namespace llvm;
|
|
|
|
bool MipsCCState::isF128SoftLibCall(const char *CallSym) {
|
|
const char *const LibCalls[] = {
|
|
"__addtf3", "__divtf3", "__eqtf2", "__extenddftf2",
|
|
"__extendsftf2", "__fixtfdi", "__fixtfsi", "__fixtfti",
|
|
"__fixunstfdi", "__fixunstfsi", "__fixunstfti", "__floatditf",
|
|
"__floatsitf", "__floattitf", "__floatunditf", "__floatunsitf",
|
|
"__floatuntitf", "__getf2", "__gttf2", "__letf2",
|
|
"__lttf2", "__multf3", "__netf2", "__powitf2",
|
|
"__subtf3", "__trunctfdf2", "__trunctfsf2", "__unordtf2",
|
|
"ceill", "copysignl", "cosl", "exp2l",
|
|
"expl", "floorl", "fmal", "fmaxl",
|
|
"fmodl", "log10l", "log2l", "logl",
|
|
"nearbyintl", "powl", "rintl", "roundl",
|
|
"sinl", "sqrtl", "truncl"};
|
|
|
|
// Check that LibCalls is sorted alphabetically.
|
|
auto Comp = [](const char *S1, const char *S2) { return strcmp(S1, S2) < 0; };
|
|
assert(llvm::is_sorted(LibCalls, Comp));
|
|
return std::binary_search(std::begin(LibCalls), std::end(LibCalls), CallSym,
|
|
Comp);
|
|
}
|
|
|
|
/// This function returns true if Ty is fp128, {f128} or i128 which was
|
|
/// originally a fp128.
|
|
bool MipsCCState::originalTypeIsF128(const Type *Ty, const char *Func) {
|
|
if (Ty->isFP128Ty())
|
|
return true;
|
|
|
|
if (Ty->isStructTy() && Ty->getStructNumElements() == 1 &&
|
|
Ty->getStructElementType(0)->isFP128Ty())
|
|
return true;
|
|
|
|
// If the Ty is i128 and the function being called is a long double emulation
|
|
// routine, then the original type is f128.
|
|
// FIXME: This is unsound because these functions could be indirectly called
|
|
return (Func && Ty->isIntegerTy(128) && isF128SoftLibCall(Func));
|
|
}
|
|
|
|
/// Return true if the original type was vXfXX.
|
|
bool MipsCCState::originalEVTTypeIsVectorFloat(EVT Ty) {
|
|
if (Ty.isVector() && Ty.getVectorElementType().isFloatingPoint())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Return true if the original type was vXfXX / vXfXX.
|
|
bool MipsCCState::originalTypeIsVectorFloat(const Type *Ty) {
|
|
if (Ty->isVectorTy() && Ty->isFPOrFPVectorTy())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
MipsCCState::SpecialCallingConvType
|
|
MipsCCState::getSpecialCallingConvForCallee(const SDNode *Callee,
|
|
const MipsSubtarget &Subtarget) {
|
|
MipsCCState::SpecialCallingConvType SpecialCallingConv = NoSpecialCallingConv;
|
|
if (Subtarget.inMips16HardFloat()) {
|
|
if (const GlobalAddressSDNode *G =
|
|
dyn_cast<const GlobalAddressSDNode>(Callee)) {
|
|
llvm::StringRef Sym = G->getGlobal()->getName();
|
|
Function *F = G->getGlobal()->getParent()->getFunction(Sym);
|
|
if (F && F->hasFnAttribute("__Mips16RetHelper")) {
|
|
SpecialCallingConv = Mips16RetHelperConv;
|
|
}
|
|
}
|
|
}
|
|
return SpecialCallingConv;
|
|
}
|
|
|
|
void MipsCCState::PreAnalyzeCallResultForF128(
|
|
const SmallVectorImpl<ISD::InputArg> &Ins,
|
|
const Type *RetTy, const char *Call) {
|
|
for (unsigned i = 0; i < Ins.size(); ++i) {
|
|
OriginalArgWasF128.push_back(
|
|
originalTypeIsF128(RetTy, Call));
|
|
OriginalArgWasFloat.push_back(RetTy->isFloatingPointTy());
|
|
}
|
|
}
|
|
|
|
/// Identify lowered values that originated from f128 or float arguments and
|
|
/// record this for use by RetCC_MipsN.
|
|
void MipsCCState::PreAnalyzeReturnForF128(
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs) {
|
|
const MachineFunction &MF = getMachineFunction();
|
|
for (unsigned i = 0; i < Outs.size(); ++i) {
|
|
OriginalArgWasF128.push_back(
|
|
originalTypeIsF128(MF.getFunction().getReturnType(), nullptr));
|
|
OriginalArgWasFloat.push_back(
|
|
MF.getFunction().getReturnType()->isFloatingPointTy());
|
|
}
|
|
}
|
|
|
|
/// Identify lower values that originated from vXfXX and record
|
|
/// this.
|
|
void MipsCCState::PreAnalyzeCallResultForVectorFloat(
|
|
const SmallVectorImpl<ISD::InputArg> &Ins, const Type *RetTy) {
|
|
for (unsigned i = 0; i < Ins.size(); ++i) {
|
|
OriginalRetWasFloatVector.push_back(originalTypeIsVectorFloat(RetTy));
|
|
}
|
|
}
|
|
|
|
/// Identify lowered values that originated from vXfXX arguments and record
|
|
/// this.
|
|
void MipsCCState::PreAnalyzeReturnForVectorFloat(
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs) {
|
|
for (unsigned i = 0; i < Outs.size(); ++i) {
|
|
ISD::OutputArg Out = Outs[i];
|
|
OriginalRetWasFloatVector.push_back(
|
|
originalEVTTypeIsVectorFloat(Out.ArgVT));
|
|
}
|
|
}
|
|
|
|
void MipsCCState::PreAnalyzeReturnValue(EVT ArgVT) {
|
|
OriginalRetWasFloatVector.push_back(originalEVTTypeIsVectorFloat(ArgVT));
|
|
}
|
|
|
|
void MipsCCState::PreAnalyzeCallOperand(const Type *ArgTy, bool IsFixed,
|
|
const char *Func) {
|
|
OriginalArgWasF128.push_back(originalTypeIsF128(ArgTy, Func));
|
|
OriginalArgWasFloat.push_back(ArgTy->isFloatingPointTy());
|
|
OriginalArgWasFloatVector.push_back(ArgTy->isVectorTy());
|
|
CallOperandIsFixed.push_back(IsFixed);
|
|
}
|
|
|
|
/// Identify lowered values that originated from f128, float and sret to vXfXX
|
|
/// arguments and record this.
|
|
void MipsCCState::PreAnalyzeCallOperands(
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
std::vector<TargetLowering::ArgListEntry> &FuncArgs,
|
|
const char *Func) {
|
|
for (unsigned i = 0; i < Outs.size(); ++i) {
|
|
TargetLowering::ArgListEntry FuncArg = FuncArgs[Outs[i].OrigArgIndex];
|
|
|
|
OriginalArgWasF128.push_back(originalTypeIsF128(FuncArg.Ty, Func));
|
|
OriginalArgWasFloat.push_back(FuncArg.Ty->isFloatingPointTy());
|
|
OriginalArgWasFloatVector.push_back(FuncArg.Ty->isVectorTy());
|
|
CallOperandIsFixed.push_back(Outs[i].IsFixed);
|
|
}
|
|
}
|
|
|
|
void MipsCCState::PreAnalyzeFormalArgument(const Type *ArgTy,
|
|
ISD::ArgFlagsTy Flags) {
|
|
// SRet arguments cannot originate from f128 or {f128} returns so we just
|
|
// push false. We have to handle this specially since SRet arguments
|
|
// aren't mapped to an original argument.
|
|
if (Flags.isSRet()) {
|
|
OriginalArgWasF128.push_back(false);
|
|
OriginalArgWasFloat.push_back(false);
|
|
OriginalArgWasFloatVector.push_back(false);
|
|
return;
|
|
}
|
|
|
|
OriginalArgWasF128.push_back(originalTypeIsF128(ArgTy, nullptr));
|
|
OriginalArgWasFloat.push_back(ArgTy->isFloatingPointTy());
|
|
|
|
// The MIPS vector ABI exhibits a corner case of sorts or quirk; if the
|
|
// first argument is actually an SRet pointer to a vector, then the next
|
|
// argument slot is $a2.
|
|
OriginalArgWasFloatVector.push_back(ArgTy->isVectorTy());
|
|
}
|
|
|
|
/// Identify lowered values that originated from f128, float and vXfXX arguments
|
|
/// and record this.
|
|
void MipsCCState::PreAnalyzeFormalArgumentsForF128(
|
|
const SmallVectorImpl<ISD::InputArg> &Ins) {
|
|
const MachineFunction &MF = getMachineFunction();
|
|
for (unsigned i = 0; i < Ins.size(); ++i) {
|
|
Function::const_arg_iterator FuncArg = MF.getFunction().arg_begin();
|
|
|
|
// SRet arguments cannot originate from f128 or {f128} returns so we just
|
|
// push false. We have to handle this specially since SRet arguments
|
|
// aren't mapped to an original argument.
|
|
if (Ins[i].Flags.isSRet()) {
|
|
OriginalArgWasF128.push_back(false);
|
|
OriginalArgWasFloat.push_back(false);
|
|
OriginalArgWasFloatVector.push_back(false);
|
|
continue;
|
|
}
|
|
|
|
assert(Ins[i].getOrigArgIndex() < MF.getFunction().arg_size());
|
|
std::advance(FuncArg, Ins[i].getOrigArgIndex());
|
|
|
|
OriginalArgWasF128.push_back(
|
|
originalTypeIsF128(FuncArg->getType(), nullptr));
|
|
OriginalArgWasFloat.push_back(FuncArg->getType()->isFloatingPointTy());
|
|
|
|
// The MIPS vector ABI exhibits a corner case of sorts or quirk; if the
|
|
// first argument is actually an SRet pointer to a vector, then the next
|
|
// argument slot is $a2.
|
|
OriginalArgWasFloatVector.push_back(FuncArg->getType()->isVectorTy());
|
|
}
|
|
}
|