Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions llvm/include/llvm/IR/RuntimeLibcalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,13 @@ struct RuntimeLibcallsInfo {
return RTLIB::Unsupported;
}

/// \returns the function type and attributes for the \p LibcallImpl,
/// depending on the target \p TT. If the function has incomplete type
/// information, return nullptr for the function type.
std::pair<FunctionType *, AttributeList>
getFunctionTy(LLVMContext &Ctx, const Triple &TT, const DataLayout &DL,
RTLIB::LibcallImpl LibcallImpl) const;

private:
LLVM_ABI static iota_range<RTLIB::LibcallImpl>
lookupLibcallImplNameImpl(StringRef Name);
Expand Down
109 changes: 109 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ class SelectionDAGLegalize {
RTLIB::Libcall CallI128);
void ExpandDivRemLibCall(SDNode *Node, SmallVectorImpl<SDValue> &Results);

SDValue ExpandSincosStretLibCall(SDNode *Node) const;

SDValue EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT,
const SDLoc &dl);
SDValue EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT,
Expand Down Expand Up @@ -2423,6 +2425,101 @@ static bool useSinCos(SDNode *Node) {
return false;
}

SDValue SelectionDAGLegalize::ExpandSincosStretLibCall(SDNode *Node) const {
// For iOS, we want to call an alternative entry point: __sincos_stret,
// which returns the values in two S / D registers.
SDLoc dl(Node);
SDValue Arg = Node->getOperand(0);
EVT ArgVT = Arg.getValueType();
RTLIB::Libcall LC = RTLIB::getSINCOS_STRET(ArgVT);
RTLIB::LibcallImpl SincosStret = TLI.getLibcallImpl(LC);
if (SincosStret == RTLIB::Unsupported)
return SDValue();

/// There are 3 different ABI cases to handle:
/// - Direct return of separate fields in registers
/// - Single return as vector elements
/// - sret struct

const RTLIB::RuntimeLibcallsInfo &CallsInfo = TLI.getRuntimeLibcallsInfo();

const DataLayout &DL = DAG.getDataLayout();

auto [FuncTy, FuncAttrs] = CallsInfo.getFunctionTy(
*DAG.getContext(), TM.getTargetTriple(), DL, SincosStret);

Type *SincosStretRetTy = FuncTy->getReturnType();
CallingConv::ID CallConv = CallsInfo.getLibcallImplCallingConv(SincosStret);
StringRef LibcallImplName = CallsInfo.getLibcallImplName(SincosStret);

SDValue Callee = DAG.getExternalSymbol(LibcallImplName.data(),
TLI.getProgramPointerTy(DL));

TargetLowering::ArgListTy Args;
SDValue SRet;

int FrameIdx;
if (FuncTy->getParamType(0)->isPointerTy()) {
// Uses sret
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();

AttributeSet PtrAttrs = FuncAttrs.getParamAttrs(0);
Type *StructTy = PtrAttrs.getStructRetType();
const uint64_t ByteSize = DL.getTypeAllocSize(StructTy);
const Align StackAlign = DL.getPrefTypeAlign(StructTy);

FrameIdx = MFI.CreateStackObject(ByteSize, StackAlign, false);
SRet = DAG.getFrameIndex(FrameIdx, TLI.getFrameIndexTy(DL));

TargetLowering::ArgListEntry Entry(SRet, FuncTy->getParamType(0));
Entry.IsSRet = true;
Entry.IndirectType = StructTy;
Entry.Alignment = StackAlign;

Args.push_back(Entry);
Args.emplace_back(Arg, FuncTy->getParamType(1));
} else {
Args.emplace_back(Arg, FuncTy->getParamType(0));
}

TargetLowering::CallLoweringInfo CLI(DAG);
CLI.setDebugLoc(dl)
.setChain(DAG.getEntryNode())
.setLibCallee(CallConv, SincosStretRetTy, Callee, std::move(Args))
.setIsPostTypeLegalization();

std::pair<SDValue, SDValue> CallResult = TLI.LowerCallTo(CLI);

if (SRet) {
MachinePointerInfo PtrInfo =
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FrameIdx);
SDValue LoadSin = DAG.getLoad(ArgVT, dl, CallResult.second, SRet, PtrInfo);

TypeSize StoreSize = ArgVT.getStoreSize();

// Address of cos field.
SDValue Add = DAG.getObjectPtrOffset(dl, SRet, StoreSize);
SDValue LoadCos = DAG.getLoad(ArgVT, dl, LoadSin.getValue(1), Add,
PtrInfo.getWithOffset(StoreSize));

SDVTList Tys = DAG.getVTList(ArgVT, ArgVT);
return DAG.getNode(ISD::MERGE_VALUES, dl, Tys, LoadSin.getValue(0),
LoadCos.getValue(0));
}

if (!CallResult.first.getValueType().isVector())
return CallResult.first;

SDValue SinVal =
DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, ArgVT, CallResult.first,
DAG.getVectorIdxConstant(0, dl));
SDValue CosVal =
DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, ArgVT, CallResult.first,
DAG.getVectorIdxConstant(1, dl));
SDVTList Tys = DAG.getVTList(ArgVT, ArgVT);
return DAG.getNode(ISD::MERGE_VALUES, dl, Tys, SinVal, CosVal);
}

SDValue SelectionDAGLegalize::expandLdexp(SDNode *Node) const {
SDLoc dl(Node);
EVT VT = Node->getValueType(0);
Expand Down Expand Up @@ -4730,6 +4827,18 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
case ISD::FSINCOS:
case ISD::FSINCOSPI: {
EVT VT = Node->getValueType(0);

if (Node->getOpcode() == ISD::FSINCOS) {
RTLIB::Libcall SincosStret = RTLIB::getSINCOS_STRET(VT);
if (SincosStret != RTLIB::UNKNOWN_LIBCALL) {
if (SDValue Expanded = ExpandSincosStretLibCall(Node)) {
Results.push_back(Expanded);
Results.push_back(Expanded.getValue(1));
break;
}
}
}

RTLIB::Libcall LC = Node->getOpcode() == ISD::FSINCOS
? RTLIB::getSINCOS(VT)
: RTLIB::getSINCOSPI(VT);
Expand Down
79 changes: 79 additions & 0 deletions llvm/lib/IR/RuntimeLibcalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//

#include "llvm/IR/RuntimeLibcalls.h"
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/ADT/StringTable.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/xxhash.h"
#include "llvm/TargetParser/ARMTargetParser.h"
Expand Down Expand Up @@ -72,3 +74,80 @@ bool RuntimeLibcallsInfo::darwinHasExp10(const Triple &TT) {
return false;
}
}

std::pair<FunctionType *, AttributeList>
RuntimeLibcallsInfo::getFunctionTy(LLVMContext &Ctx, const Triple &TT,
const DataLayout &DL,
RTLIB::LibcallImpl LibcallImpl) const {
static constexpr Attribute::AttrKind CommonFnAttrs[] = {
Attribute::NoCallback, Attribute::NoFree, Attribute::NoSync,
Attribute::NoUnwind, Attribute::WillReturn};

switch (LibcallImpl) {
case RTLIB::impl___sincos_stret:
case RTLIB::impl___sincosf_stret: {
if (!darwinHasSinCosStret(TT)) // Non-darwin currently unexpected
return {};

Type *ScalarTy = LibcallImpl == RTLIB::impl___sincosf_stret
? Type::getFloatTy(Ctx)
: Type::getDoubleTy(Ctx);

AttrBuilder FuncAttrBuilder(Ctx);
for (Attribute::AttrKind Attr : CommonFnAttrs)
FuncAttrBuilder.addAttribute(Attr);

const bool UseSret =
TT.isX86_32() || ((TT.isARM() || TT.isThumb()) &&
ARM::computeTargetABI(TT) == ARM::ARM_ABI_APCS);

FuncAttrBuilder.addMemoryAttr(MemoryEffects::argumentOrErrnoMemOnly(
UseSret ? ModRefInfo::Mod : ModRefInfo::NoModRef, ModRefInfo::Mod));

AttributeList Attrs;
Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder);

if (UseSret) {
AttrBuilder AttrBuilder(Ctx);
StructType *StructTy = StructType::get(ScalarTy, ScalarTy);
AttrBuilder.addStructRetAttr(StructTy);
AttrBuilder.addAlignmentAttr(DL.getABITypeAlign(StructTy));
FunctionType *FuncTy = FunctionType::get(
Type::getVoidTy(Ctx), {DL.getAllocaPtrType(Ctx), ScalarTy}, false);

return {FuncTy, Attrs.addParamAttributes(Ctx, 0, AttrBuilder)};
}

Type *RetTy =
LibcallImpl == RTLIB::impl___sincosf_stret && TT.isX86_64()
? static_cast<Type *>(FixedVectorType::get(ScalarTy, 2))
: static_cast<Type *>(StructType::get(ScalarTy, ScalarTy));

return {FunctionType::get(RetTy, {ScalarTy}, false), Attrs};
}
case RTLIB::impl_sqrtf:
case RTLIB::impl_sqrt: {
AttrBuilder FuncAttrBuilder(Ctx);

for (Attribute::AttrKind Attr : CommonFnAttrs)
FuncAttrBuilder.addAttribute(Attr);
FuncAttrBuilder.addMemoryAttr(MemoryEffects::errnoMemOnly(ModRefInfo::Mod));

AttributeList Attrs;
Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder);

Type *ScalarTy = LibcallImpl == RTLIB::impl_sqrtf ? Type::getFloatTy(Ctx)
: Type::getDoubleTy(Ctx);
FunctionType *FuncTy = FunctionType::get(ScalarTy, {ScalarTy}, false);

Attrs = Attrs.addRetAttribute(
Ctx, Attribute::getWithNoFPClass(Ctx, fcNegInf | fcNegSubnormal |
fcNegNormal));
return {FuncTy, Attrs};
}
default:
return {};
}

return {};
}
43 changes: 3 additions & 40 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1052,15 +1052,9 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
// Lower READCYCLECOUNTER using an mrs from CNTVCT_EL0.
setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Legal);

if (getLibcallName(RTLIB::SINCOS_STRET_F32) != nullptr &&
getLibcallName(RTLIB::SINCOS_STRET_F64) != nullptr) {
// Issue __sincos_stret if available.
setOperationAction(ISD::FSINCOS, MVT::f64, Custom);
setOperationAction(ISD::FSINCOS, MVT::f32, Custom);
} else {
setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
}
// Issue __sincos_stret if available.
setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
setOperationAction(ISD::FSINCOS, MVT::f32, Expand);

// Make floating-point constants legal for the large code model, so they don't
// become loads from the constant pool.
Expand Down Expand Up @@ -5346,35 +5340,6 @@ SDValue AArch64TargetLowering::LowerINT_TO_FP(SDValue Op,
return SDValue();
}

SDValue AArch64TargetLowering::LowerFSINCOS(SDValue Op,
SelectionDAG &DAG) const {
// For iOS, we want to call an alternative entry point: __sincos_stret,
// which returns the values in two S / D registers.
SDLoc DL(Op);
SDValue Arg = Op.getOperand(0);
EVT ArgVT = Arg.getValueType();
Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext());

ArgListTy Args;
Args.emplace_back(Arg, ArgTy);

RTLIB::Libcall LC = ArgVT == MVT::f64 ? RTLIB::SINCOS_STRET_F64
: RTLIB::SINCOS_STRET_F32;
const char *LibcallName = getLibcallName(LC);
SDValue Callee =
DAG.getExternalSymbol(LibcallName, getPointerTy(DAG.getDataLayout()));

StructType *RetTy = StructType::get(ArgTy, ArgTy);
TargetLowering::CallLoweringInfo CLI(DAG);
CallingConv::ID CC = getLibcallCallingConv(LC);
CLI.setDebugLoc(DL)
.setChain(DAG.getEntryNode())
.setLibCallee(CC, RetTy, Callee, std::move(Args));

std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI);
return CallResult.first;
}

static MVT getSVEContainerType(EVT ContentTy);

SDValue
Expand Down Expand Up @@ -7723,8 +7688,6 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
case ISD::FP_TO_SINT_SAT:
case ISD::FP_TO_UINT_SAT:
return LowerFP_TO_INT_SAT(Op, DAG);
case ISD::FSINCOS:
return LowerFSINCOS(Op, DAG);
case ISD::GET_ROUNDING:
return LowerGET_ROUNDING(Op, DAG);
case ISD::SET_ROUNDING:
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Target/AArch64/AArch64ISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,6 @@ class AArch64TargetLowering : public TargetLowering {
SDValue LowerVectorOR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerXOR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFSINCOS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerLOOP_DEPENDENCE_MASK(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBITCAST(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVSCALE(SDValue Op, SelectionDAG &DAG) const;
Expand Down
Loading
Loading