Skip to content

TableGen: Allow defining sets of runtime libraries #144978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: users/arsenm/aarch64/add-libcall-impl-for-sc-mem-functions
Choose a base branch
from
Open
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
10 changes: 2 additions & 8 deletions llvm/include/llvm/IR/RuntimeLibcalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ struct RuntimeLibcallsInfo {
FloatABI::ABIType FloatABI = FloatABI::Default,
EABI EABIVersion = EABI::Default) {
initSoftFloatCmpLibcallPredicates();
initDefaultLibCallImpls();
initLibcalls(TT, ExceptionModel, FloatABI, EABIVersion);
}

Expand Down Expand Up @@ -97,6 +96,7 @@ struct RuntimeLibcallsInfo {
/// Get the comparison predicate that's to be used to test the result of the
/// comparison libcall against zero. This should only be used with
/// floating-point compare libcalls.
// FIXME: This should be a function of RTLIB::LibcallImpl
CmpInst::Predicate
getSoftFloatCmpLibcallPredicate(RTLIB::Libcall Call) const {
return SoftFloatCompareLibcallPredicates[Call];
Expand Down Expand Up @@ -172,13 +172,7 @@ struct RuntimeLibcallsInfo {
void initDefaultLibCallImpls();

/// Generated by tablegen.
void setPPCLibCallNameOverrides();

/// Generated by tablegen.
void setZOSLibCallNameOverrides();

/// Generated by tablegen.
void setWindowsArm64LibCallNameOverrides();
void setTargetRuntimeLibcallSets(const Triple &TT);

void initSoftFloatCmpLibcallPredicates();

Expand Down
493 changes: 309 additions & 184 deletions llvm/include/llvm/IR/RuntimeLibcalls.td

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions llvm/include/llvm/IR/RuntimeLibcallsImpl.td
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@
//
//===----------------------------------------------------------------------===//

include "llvm/TableGen/SetTheory.td"

// Predicate for whether a libcall exists for the target ABI. This is
// a module level property that should only be computed based on the
// triple.
class RuntimeLibcallPredicate<code cond> {
// Expression of an llvm::Triple named TT for whether a libcall
// should exist.
code Cond = cond;
}

// Predicate for whether a libcall should be used for the current
// function/subtarget.
class LibcallLoweringPredicate<code cond> { code Cond = cond; }

def AlwaysAvailable : RuntimeLibcallPredicate<[{}]>;

/// Abstract definition for functionality the compiler may need to
/// emit a call to. Emits the RTLIB::Libcall enum - This enum defines
/// all of the runtime library calls the backend can emit. The various
Expand All @@ -28,5 +45,24 @@ class RuntimeLibcall {
class RuntimeLibcallImpl<RuntimeLibcall P, string Name = NAME> {
RuntimeLibcall Provides = P;
string LibCallFuncName = Name;
list<LibcallLoweringPredicate> LoweringPredicates;
bit IsDefault = false;
}

class LibcallImpls<dag funcList,
RuntimeLibcallPredicate Pred = AlwaysAvailable> {
// Function of the triple where this applies
RuntimeLibcallPredicate AvailabilityPredicate = Pred;
dag MemberList = funcList;
}

/// Convenience wrapper around LibcallImplSet to make a single libcall
/// implementation conditionally conditionally available.
class AvailableIf<RuntimeLibcallImpl Impl, RuntimeLibcallPredicate Pred>
: LibcallImpls<(add Impl), Pred>;

/// Define a complete top level set of runtime libcalls for a target.
class SystemRuntimeLibrary<RuntimeLibcallPredicate Pred, dag funcList> {
RuntimeLibcallPredicate TriplePred = Pred;
LibcallImpls MemberList = LibcallImpls<funcList>;
}
27 changes: 27 additions & 0 deletions llvm/include/llvm/TableGen/SetTheory.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===- SetTheory.td - DAG set operator declarations --------*- tablegen -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

// FIXME: This is not used everywhere, and different files declare
// different subsets of used operators.
//
// It just happens TargetSelectionDAG.td defines records with the same
// names as the tablegen DAG operators for SelectionDAG operators.

// Target.td separately declares the special set operators.

def add; // Forward declare
def sub;
def and;
def shl;
// def trunc; // FIXME: Name collision
def rotl;
def rotr;

def sequence;
def decimate;
def interleave;
127 changes: 6 additions & 121 deletions llvm/lib/IR/RuntimeLibcalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,16 @@
using namespace llvm;
using namespace RTLIB;

#define GET_INIT_RUNTIME_LIBCALL_UTILS
#define GET_INIT_RUNTIME_LIBCALL_NAMES
#define GET_SET_TARGET_RUNTIME_LIBCALL_SETS
#include "llvm/IR/RuntimeLibcalls.inc"
#undef GET_INIT_RUNTIME_LIBCALL_UTILS
#undef GET_INIT_RUNTIME_LIBCALL_NAMES
#undef GET_SET_TARGET_RUNTIME_LIBCALL_SETS

static cl::opt<bool>
HexagonEnableFastMathRuntimeCalls("hexagon-fast-math", cl::Hidden,
cl::desc("Enable Fast Math processing"));

static void setAArch64LibcallNames(RuntimeLibcallsInfo &Info,
const Triple &TT) {
#define LCALLNAMES(A, B, N) \
Info.setLibcallImpl(A##N##_RELAX, B##N##_relax); \
Info.setLibcallImpl(A##N##_ACQ, B##N##_acq); \
Info.setLibcallImpl(A##N##_REL, B##N##_rel); \
Info.setLibcallImpl(A##N##_ACQ_REL, B##N##_acq_rel);
#define LCALLNAME4(A, B) \
LCALLNAMES(A, B, 1) \
LCALLNAMES(A, B, 2) LCALLNAMES(A, B, 4) LCALLNAMES(A, B, 8)
#define LCALLNAME5(A, B) \
LCALLNAMES(A, B, 1) \
LCALLNAMES(A, B, 2) \
LCALLNAMES(A, B, 4) LCALLNAMES(A, B, 8) LCALLNAMES(A, B, 16)

if (TT.isWindowsArm64EC()) {
LCALLNAME5(RTLIB::OUTLINE_ATOMIC_CAS, RTLIB::arm64ec___aarch64_cas)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_SWP, RTLIB::arm64ec___aarch64_swp)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDADD, RTLIB::arm64ec___aarch64_ldadd)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDSET, RTLIB::arm64ec___aarch64_ldset)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDCLR, RTLIB::arm64ec___aarch64_ldclr)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDEOR, RTLIB::arm64ec___aarch64_ldeor)
} else {
LCALLNAME5(RTLIB::OUTLINE_ATOMIC_CAS, RTLIB::__aarch64_cas)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_SWP, RTLIB::__aarch64_swp)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDADD, RTLIB::__aarch64_ldadd)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDSET, RTLIB::__aarch64_ldset)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDCLR, RTLIB::__aarch64_ldclr)
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDEOR, RTLIB::__aarch64_ldeor)
}
#undef LCALLNAMES
#undef LCALLNAME4
#undef LCALLNAME5
}

static void setARMLibcallNames(RuntimeLibcallsInfo &Info, const Triple &TT,
FloatABI::ABIType FloatABIType,
EABI EABIVersion) {
Expand Down Expand Up @@ -358,6 +323,8 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
ExceptionHandling ExceptionModel,
FloatABI::ABIType FloatABI,
EABI EABIVersion) {
setTargetRuntimeLibcallSets(TT);

// Use the f128 variants of math functions on x86
if (TT.isX86() && TT.isGNUEnvironment())
setLongDoubleIsF128Libm(*this, /*FiniteOnlyFuncs=*/true);
Expand All @@ -367,28 +334,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
setLibcallImpl(RTLIB::UNWIND_RESUME, RTLIB::_Unwind_SjLj_Resume);
}

if (TT.isPPC()) {
setPPCLibCallNameOverrides();

// TODO: Do the finite only functions exist?
setLongDoubleIsF128Libm(*this, /*FiniteOnlyFuncs=*/false);

// TODO: Tablegen predicate support
if (TT.isOSAIX()) {
if (TT.isPPC64()) {
setLibcallImpl(RTLIB::MEMCPY, RTLIB::Unsupported);
setLibcallImpl(RTLIB::MEMMOVE, RTLIB::___memmove64);
setLibcallImpl(RTLIB::MEMSET, RTLIB::___memset64);
setLibcallImpl(RTLIB::BZERO, RTLIB::___bzero64);
} else {
setLibcallImpl(RTLIB::MEMCPY, RTLIB::Unsupported);
setLibcallImpl(RTLIB::MEMMOVE, RTLIB::___memmove);
setLibcallImpl(RTLIB::MEMSET, RTLIB::___memset);
setLibcallImpl(RTLIB::BZERO, RTLIB::___bzero);
}
}
}

// A few names are different on particular architectures or environments.
if (TT.isOSDarwin()) {
// For f16/f32 conversions, Darwin uses the standard naming scheme,
Expand Down Expand Up @@ -485,14 +430,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
setLibcallImpl(RTLIB::FREXP_PPCF128, RTLIB::Unsupported);
}

// Disable most libcalls on AMDGPU and NVPTX.
if (TT.isAMDGPU() || TT.isNVPTX()) {
for (RTLIB::Libcall LC : RTLIB::libcalls()) {
if (!isAtomicLibCall(LC))
setLibcallImpl(LC, RTLIB::Unsupported);
}
}

if (TT.isOSMSVCRT()) {
// MSVCRT doesn't have powi; fall back to pow
setLibcallImpl(RTLIB::POWI_F32, RTLIB::Unsupported);
Expand Down Expand Up @@ -520,55 +457,14 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
}
}

if (TT.isAArch64()) {
if (TT.isWindowsArm64EC()) {
setWindowsArm64LibCallNameOverrides();
setLibcallImpl(RTLIB::SC_MEMCPY, RTLIB::arm64ec___arm_sc_memcpy);
setLibcallImpl(RTLIB::SC_MEMMOVE, RTLIB::arm64ec___arm_sc_memmove);
setLibcallImpl(RTLIB::SC_MEMSET, RTLIB::arm64ec___arm_sc_memset);
} else {
setLibcallImpl(RTLIB::SC_MEMCPY, RTLIB::__arm_sc_memcpy);
setLibcallImpl(RTLIB::SC_MEMMOVE, RTLIB::__arm_sc_memmove);
setLibcallImpl(RTLIB::SC_MEMSET, RTLIB::__arm_sc_memset);
}

setAArch64LibcallNames(*this, TT);
} else if (TT.isARM() || TT.isThumb()) {
if (TT.isARM() || TT.isThumb())
setARMLibcallNames(*this, TT, FloatABI, EABIVersion);
} else if (TT.getArch() == Triple::ArchType::avr) {
// Division rtlib functions (not supported), use divmod functions instead
setLibcallImpl(RTLIB::SDIV_I8, RTLIB::Unsupported);
setLibcallImpl(RTLIB::SDIV_I16, RTLIB::Unsupported);
setLibcallImpl(RTLIB::SDIV_I32, RTLIB::Unsupported);
setLibcallImpl(RTLIB::UDIV_I8, RTLIB::Unsupported);
setLibcallImpl(RTLIB::UDIV_I16, RTLIB::Unsupported);
setLibcallImpl(RTLIB::UDIV_I32, RTLIB::Unsupported);

// Modulus rtlib functions (not supported), use divmod functions instead
setLibcallImpl(RTLIB::SREM_I8, RTLIB::Unsupported);
setLibcallImpl(RTLIB::SREM_I16, RTLIB::Unsupported);
setLibcallImpl(RTLIB::SREM_I32, RTLIB::Unsupported);
setLibcallImpl(RTLIB::UREM_I8, RTLIB::Unsupported);
setLibcallImpl(RTLIB::UREM_I16, RTLIB::Unsupported);
setLibcallImpl(RTLIB::UREM_I32, RTLIB::Unsupported);

// Division and modulus rtlib functions
setLibcallImpl(RTLIB::SDIVREM_I8, RTLIB::__divmodqi4);
setLibcallImpl(RTLIB::SDIVREM_I16, RTLIB::__divmodhi4);
setLibcallImpl(RTLIB::SDIVREM_I32, RTLIB::__divmodsi4);
setLibcallImpl(RTLIB::UDIVREM_I8, RTLIB::__udivmodqi4);
setLibcallImpl(RTLIB::UDIVREM_I16, RTLIB::__udivmodhi4);
setLibcallImpl(RTLIB::UDIVREM_I32, RTLIB::__udivmodsi4);

else if (TT.getArch() == Triple::ArchType::avr) {
// Several of the runtime library functions use a special calling conv
setLibcallCallingConv(RTLIB::SDIVREM_I8, CallingConv::AVR_BUILTIN);
setLibcallCallingConv(RTLIB::SDIVREM_I16, CallingConv::AVR_BUILTIN);
setLibcallCallingConv(RTLIB::UDIVREM_I8, CallingConv::AVR_BUILTIN);
setLibcallCallingConv(RTLIB::UDIVREM_I16, CallingConv::AVR_BUILTIN);

// Trigonometric rtlib functions
setLibcallImpl(RTLIB::SIN_F32, RTLIB::avr_sin);
setLibcallImpl(RTLIB::COS_F32, RTLIB::avr_cos);
}

if (!TT.isWasm()) {
Expand All @@ -582,11 +478,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
}

setLibcallImpl(RTLIB::MULO_I128, RTLIB::Unsupported);
} else {
// Define the emscripten name for return address helper.
// TODO: when implementing other Wasm backends, make this generic or only do
// this on emscripten depending on what they end up doing.
setLibcallImpl(RTLIB::RETURN_ADDRESS, RTLIB::emscripten_return_address);
}

if (TT.getArch() == Triple::ArchType::hexagon) {
Expand Down Expand Up @@ -633,10 +524,4 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,

if (TT.getArch() == Triple::ArchType::msp430)
setMSP430Libcalls(*this, TT);

if (TT.isSystemZ() && TT.isOSzOS())
setZOSLibCallNameOverrides();

if (TT.getArch() == Triple::ArchType::xcore)
setLibcallImpl(RTLIB::MEMCPY_ALIGN_4, RTLIB::__memcpy_4);
}
60 changes: 60 additions & 0 deletions llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2> %t.err | FileCheck %s
// RUN: FileCheck -check-prefix=ERR %s < %t.err

// Check behavior of libcall emission when multiple RuntimeLibcallImpl
// implementations provide the same RuntimeLibcall

include "llvm/IR/RuntimeLibCallsImpl.td"

def SOME_FUNC : RuntimeLibcall;
def OTHER_FUNC : RuntimeLibcall;
def ANOTHER_DUP : RuntimeLibcall;

def isTargetArchA : RuntimeLibcallPredicate<[{isTargetArchA()}]>;
def isTargetArchB : RuntimeLibcallPredicate<[{isTargetArchB()}]>;
def isTargetArchC : RuntimeLibcallPredicate<[{isTargetArchC()}]>;

def func_a : RuntimeLibcallImpl<SOME_FUNC>;
def func_b : RuntimeLibcallImpl<SOME_FUNC>;
def func_c : RuntimeLibcallImpl<SOME_FUNC>;
def other_func : RuntimeLibcallImpl<OTHER_FUNC>;

def dup0 : RuntimeLibcallImpl<ANOTHER_DUP>;
def dup1 : RuntimeLibcallImpl<ANOTHER_DUP>;

// func_a and func_b both provide SOME_FUNC.

// CHECK: if (isTargetArchA()) {
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_b}, // func_b
// CHECK-NEXT: };

// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_b, func_a
def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA,
(add func_b, func_a)
>;

// CHECK: if (isTargetArchB()) {
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a
// CHECK-NEXT: };

// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b
def TheSystemLibraryB : SystemRuntimeLibrary<isTargetArchB,
(add func_a, other_func, func_b)
>;

// CHECK: if (isTargetArchC()) {
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::dup1}, // dup1
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a
// CHECK-NEXT: };

// ERR: :[[@LINE+3]]:5: warning: conflicting implementations for libcall ANOTHER_DUP: dup1, dup0
// ERR: :[[@LINE+2]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b
// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_c
def TheSystemLibraryC : SystemRuntimeLibrary<isTargetArchC,
(add func_a, dup1, other_func, func_b, func_c, dup0)
>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2>&1 | FileCheck -check-prefix=ERR %s

include "llvm/IR/RuntimeLibCallsImpl.td"

def FUNC0 : RuntimeLibcall;
def FUNC1 : RuntimeLibcall;

def isFoo : RuntimeLibcallPredicate<[{isFoo()}]>;
def isBar : RuntimeLibcallPredicate<[{isBar()}]>;
def isTargetArch : RuntimeLibcallPredicate<[{isTargetArch()}]>;

def func0 : RuntimeLibcallImpl<FUNC0>;
def func1 : RuntimeLibcallImpl<FUNC1>;

// ERR: :[[@LINE+2]]:8: error: combining nested libcall set predicates currently unhandled
def TheSystemLibrary : SystemRuntimeLibrary<isTargetArch,
(add LibcallImpls<(add func0, LibcallImpls<(add func1), isBar>), isFoo>)
>;
Loading
Loading