Skip to content

Commit ac9385a

Browse files
committed
TableGen: Allow defining sets of runtime libraries
Add a way to define a SystemLibrary for a complete set of libcalls, subdivided by a predicate based on the triple. Libraries can be defined using dag set operations, and the prior default set can be subtracted from and added to (though I think eventually all targets should move to explicit opt-ins. We're still doing things like reporting ppcf128 libcalls as available dy default on all targets). Start migrating some of the easier targets to only use the new system. Targets that don't define a SystemLibrary are still manually mutating a table set to the old defaults.
1 parent b4d3283 commit ac9385a

10 files changed

+938
-448
lines changed

llvm/include/llvm/IR/RuntimeLibcalls.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ struct RuntimeLibcallsInfo {
5252
FloatABI::ABIType FloatABI = FloatABI::Default,
5353
EABI EABIVersion = EABI::Default, StringRef ABIName = "") {
5454
initSoftFloatCmpLibcallPredicates();
55-
initDefaultLibCallImpls();
5655
initLibcalls(TT, ExceptionModel, FloatABI, EABIVersion, ABIName);
5756
}
5857

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

176176
/// Generated by tablegen.
177-
void setPPCLibCallNameOverrides();
178-
179-
/// Generated by tablegen.
180-
void setZOSLibCallNameOverrides();
181-
182-
/// Generated by tablegen.
183-
void setWindowsArm64LibCallNameOverrides();
177+
void setTargetRuntimeLibcallSets(const Triple &TT);
184178

185179
void initSoftFloatCmpLibcallPredicates();
186180

llvm/include/llvm/IR/RuntimeLibcalls.td

Lines changed: 336 additions & 186 deletions
Large diffs are not rendered by default.

llvm/include/llvm/IR/RuntimeLibcallsImpl.td

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
include "llvm/TableGen/SetTheory.td"
10+
11+
// Predicate for whether a libcall exists for the target ABI. This is
12+
// a module level property that should only be computed based on the
13+
// triple.
14+
class RuntimeLibcallPredicate<code cond> {
15+
// Expression of an llvm::Triple named TT for whether a libcall
16+
// should exist.
17+
code Cond = cond;
18+
}
19+
20+
// Predicate for whether a libcall should be used for the current
21+
// function/subtarget.
22+
class LibcallLoweringPredicate<code cond> { code Cond = cond; }
23+
24+
def AlwaysAvailable : RuntimeLibcallPredicate<[{}]>;
25+
926
/// Abstract definition for functionality the compiler may need to
1027
/// emit a call to. Emits the RTLIB::Libcall enum - This enum defines
1128
/// all of the runtime library calls the backend can emit. The various
@@ -28,5 +45,24 @@ class RuntimeLibcall {
2845
class RuntimeLibcallImpl<RuntimeLibcall P, string Name = NAME> {
2946
RuntimeLibcall Provides = P;
3047
string LibCallFuncName = Name;
48+
list<LibcallLoweringPredicate> LoweringPredicates;
3149
bit IsDefault = false;
3250
}
51+
52+
class LibcallImpls<dag funcList,
53+
RuntimeLibcallPredicate Pred = AlwaysAvailable> {
54+
// Function of the triple where this applies
55+
RuntimeLibcallPredicate AvailabilityPredicate = Pred;
56+
dag MemberList = funcList;
57+
}
58+
59+
/// Convenience wrapper around LibcallImplSet to make a single libcall
60+
/// implementation conditionally conditionally available.
61+
class AvailableIf<RuntimeLibcallImpl Impl, RuntimeLibcallPredicate Pred>
62+
: LibcallImpls<(add Impl), Pred>;
63+
64+
/// Define a complete top level set of runtime libcalls for a target.
65+
class SystemRuntimeLibrary<RuntimeLibcallPredicate Pred, dag funcList> {
66+
RuntimeLibcallPredicate TriplePred = Pred;
67+
LibcallImpls MemberList = LibcallImpls<funcList>;
68+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===- SetTheory.td - DAG set operator declarations --------*- tablegen -*-===//
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// FIXME: This is not used everywhere, and different files declare
10+
// different subsets of used operators.
11+
//
12+
// It just happens TargetSelectionDAG.td defines records with the same
13+
// names as the tablegen DAG operators for SelectionDAG operators.
14+
15+
// Target.td separately declares the special set operators.
16+
17+
def add; // Forward declare
18+
def sub;
19+
def and;
20+
def shl;
21+
// def trunc; // FIXME: Name collision
22+
def rotl;
23+
def rotr;
24+
25+
def sequence;
26+
def decimate;
27+
def interleave;

llvm/lib/IR/RuntimeLibcalls.cpp

Lines changed: 6 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -12,51 +12,16 @@
1212
using namespace llvm;
1313
using namespace RTLIB;
1414

15-
#define GET_INIT_RUNTIME_LIBCALL_UTILS
1615
#define GET_INIT_RUNTIME_LIBCALL_NAMES
16+
#define GET_SET_TARGET_RUNTIME_LIBCALL_SETS
1717
#include "llvm/IR/RuntimeLibcalls.inc"
18-
#undef GET_INIT_RUNTIME_LIBCALL_UTILS
1918
#undef GET_INIT_RUNTIME_LIBCALL_NAMES
19+
#undef GET_SET_TARGET_RUNTIME_LIBCALL_SETS
2020

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

25-
static void setAArch64LibcallNames(RuntimeLibcallsInfo &Info,
26-
const Triple &TT) {
27-
#define LCALLNAMES(A, B, N) \
28-
Info.setLibcallImpl(A##N##_RELAX, B##N##_relax); \
29-
Info.setLibcallImpl(A##N##_ACQ, B##N##_acq); \
30-
Info.setLibcallImpl(A##N##_REL, B##N##_rel); \
31-
Info.setLibcallImpl(A##N##_ACQ_REL, B##N##_acq_rel);
32-
#define LCALLNAME4(A, B) \
33-
LCALLNAMES(A, B, 1) \
34-
LCALLNAMES(A, B, 2) LCALLNAMES(A, B, 4) LCALLNAMES(A, B, 8)
35-
#define LCALLNAME5(A, B) \
36-
LCALLNAMES(A, B, 1) \
37-
LCALLNAMES(A, B, 2) \
38-
LCALLNAMES(A, B, 4) LCALLNAMES(A, B, 8) LCALLNAMES(A, B, 16)
39-
40-
if (TT.isWindowsArm64EC()) {
41-
LCALLNAME5(RTLIB::OUTLINE_ATOMIC_CAS, RTLIB::arm64ec___aarch64_cas)
42-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_SWP, RTLIB::arm64ec___aarch64_swp)
43-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDADD, RTLIB::arm64ec___aarch64_ldadd)
44-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDSET, RTLIB::arm64ec___aarch64_ldset)
45-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDCLR, RTLIB::arm64ec___aarch64_ldclr)
46-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDEOR, RTLIB::arm64ec___aarch64_ldeor)
47-
} else {
48-
LCALLNAME5(RTLIB::OUTLINE_ATOMIC_CAS, RTLIB::__aarch64_cas)
49-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_SWP, RTLIB::__aarch64_swp)
50-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDADD, RTLIB::__aarch64_ldadd)
51-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDSET, RTLIB::__aarch64_ldset)
52-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDCLR, RTLIB::__aarch64_ldclr)
53-
LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDEOR, RTLIB::__aarch64_ldeor)
54-
}
55-
#undef LCALLNAMES
56-
#undef LCALLNAME4
57-
#undef LCALLNAME5
58-
}
59-
6025
static void setARMLibcallNames(RuntimeLibcallsInfo &Info, const Triple &TT,
6126
FloatABI::ABIType FloatABIType,
6227
EABI EABIVersion) {
@@ -358,6 +323,8 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
358323
ExceptionHandling ExceptionModel,
359324
FloatABI::ABIType FloatABI,
360325
EABI EABIVersion, StringRef ABIName) {
326+
setTargetRuntimeLibcallSets(TT);
327+
361328
// Use the f128 variants of math functions on x86
362329
if (TT.isX86() && TT.isGNUEnvironment())
363330
setLongDoubleIsF128Libm(*this, /*FiniteOnlyFuncs=*/true);
@@ -367,28 +334,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
367334
setLibcallImpl(RTLIB::UNWIND_RESUME, RTLIB::_Unwind_SjLj_Resume);
368335
}
369336

370-
if (TT.isPPC()) {
371-
setPPCLibCallNameOverrides();
372-
373-
// TODO: Do the finite only functions exist?
374-
setLongDoubleIsF128Libm(*this, /*FiniteOnlyFuncs=*/false);
375-
376-
// TODO: Tablegen predicate support
377-
if (TT.isOSAIX()) {
378-
if (TT.isPPC64()) {
379-
setLibcallImpl(RTLIB::MEMCPY, RTLIB::Unsupported);
380-
setLibcallImpl(RTLIB::MEMMOVE, RTLIB::___memmove64);
381-
setLibcallImpl(RTLIB::MEMSET, RTLIB::___memset64);
382-
setLibcallImpl(RTLIB::BZERO, RTLIB::___bzero64);
383-
} else {
384-
setLibcallImpl(RTLIB::MEMCPY, RTLIB::Unsupported);
385-
setLibcallImpl(RTLIB::MEMMOVE, RTLIB::___memmove);
386-
setLibcallImpl(RTLIB::MEMSET, RTLIB::___memset);
387-
setLibcallImpl(RTLIB::BZERO, RTLIB::___bzero);
388-
}
389-
}
390-
}
391-
392337
// A few names are different on particular architectures or environments.
393338
if (TT.isOSDarwin()) {
394339
// For f16/f32 conversions, Darwin uses the standard naming scheme,
@@ -453,14 +398,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
453398
setLibcallImpl(RTLIB::FREXP_PPCF128, RTLIB::Unsupported);
454399
}
455400

456-
// Disable most libcalls on AMDGPU and NVPTX.
457-
if (TT.isAMDGPU() || TT.isNVPTX()) {
458-
for (RTLIB::Libcall LC : RTLIB::libcalls()) {
459-
if (!isAtomicLibCall(LC))
460-
setLibcallImpl(LC, RTLIB::Unsupported);
461-
}
462-
}
463-
464401
if (TT.isOSMSVCRT()) {
465402
// MSVCRT doesn't have powi; fall back to pow
466403
setLibcallImpl(RTLIB::POWI_F32, RTLIB::Unsupported);
@@ -488,55 +425,14 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
488425
}
489426
}
490427

491-
if (TT.isAArch64()) {
492-
if (TT.isWindowsArm64EC()) {
493-
setWindowsArm64LibCallNameOverrides();
494-
setLibcallImpl(RTLIB::SC_MEMCPY, RTLIB::arm64ec___arm_sc_memcpy);
495-
setLibcallImpl(RTLIB::SC_MEMMOVE, RTLIB::arm64ec___arm_sc_memmove);
496-
setLibcallImpl(RTLIB::SC_MEMSET, RTLIB::arm64ec___arm_sc_memset);
497-
} else {
498-
setLibcallImpl(RTLIB::SC_MEMCPY, RTLIB::__arm_sc_memcpy);
499-
setLibcallImpl(RTLIB::SC_MEMMOVE, RTLIB::__arm_sc_memmove);
500-
setLibcallImpl(RTLIB::SC_MEMSET, RTLIB::__arm_sc_memset);
501-
}
502-
503-
setAArch64LibcallNames(*this, TT);
504-
} else if (TT.isARM() || TT.isThumb()) {
428+
if (TT.isARM() || TT.isThumb())
505429
setARMLibcallNames(*this, TT, FloatABI, EABIVersion);
506-
} else if (TT.getArch() == Triple::ArchType::avr) {
507-
// Division rtlib functions (not supported), use divmod functions instead
508-
setLibcallImpl(RTLIB::SDIV_I8, RTLIB::Unsupported);
509-
setLibcallImpl(RTLIB::SDIV_I16, RTLIB::Unsupported);
510-
setLibcallImpl(RTLIB::SDIV_I32, RTLIB::Unsupported);
511-
setLibcallImpl(RTLIB::UDIV_I8, RTLIB::Unsupported);
512-
setLibcallImpl(RTLIB::UDIV_I16, RTLIB::Unsupported);
513-
setLibcallImpl(RTLIB::UDIV_I32, RTLIB::Unsupported);
514-
515-
// Modulus rtlib functions (not supported), use divmod functions instead
516-
setLibcallImpl(RTLIB::SREM_I8, RTLIB::Unsupported);
517-
setLibcallImpl(RTLIB::SREM_I16, RTLIB::Unsupported);
518-
setLibcallImpl(RTLIB::SREM_I32, RTLIB::Unsupported);
519-
setLibcallImpl(RTLIB::UREM_I8, RTLIB::Unsupported);
520-
setLibcallImpl(RTLIB::UREM_I16, RTLIB::Unsupported);
521-
setLibcallImpl(RTLIB::UREM_I32, RTLIB::Unsupported);
522-
523-
// Division and modulus rtlib functions
524-
setLibcallImpl(RTLIB::SDIVREM_I8, RTLIB::__divmodqi4);
525-
setLibcallImpl(RTLIB::SDIVREM_I16, RTLIB::__divmodhi4);
526-
setLibcallImpl(RTLIB::SDIVREM_I32, RTLIB::__divmodsi4);
527-
setLibcallImpl(RTLIB::UDIVREM_I8, RTLIB::__udivmodqi4);
528-
setLibcallImpl(RTLIB::UDIVREM_I16, RTLIB::__udivmodhi4);
529-
setLibcallImpl(RTLIB::UDIVREM_I32, RTLIB::__udivmodsi4);
530-
430+
else if (TT.getArch() == Triple::ArchType::avr) {
531431
// Several of the runtime library functions use a special calling conv
532432
setLibcallCallingConv(RTLIB::SDIVREM_I8, CallingConv::AVR_BUILTIN);
533433
setLibcallCallingConv(RTLIB::SDIVREM_I16, CallingConv::AVR_BUILTIN);
534434
setLibcallCallingConv(RTLIB::UDIVREM_I8, CallingConv::AVR_BUILTIN);
535435
setLibcallCallingConv(RTLIB::UDIVREM_I16, CallingConv::AVR_BUILTIN);
536-
537-
// Trigonometric rtlib functions
538-
setLibcallImpl(RTLIB::SIN_F32, RTLIB::avr_sin);
539-
setLibcallImpl(RTLIB::COS_F32, RTLIB::avr_cos);
540436
}
541437

542438
if (!TT.isWasm()) {
@@ -550,11 +446,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
550446
}
551447

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

560451
if (TT.getArch() == Triple::ArchType::hexagon) {
@@ -601,12 +492,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
601492

602493
if (TT.getArch() == Triple::ArchType::msp430)
603494
setMSP430Libcalls(*this, TT);
604-
605-
if (TT.isSystemZ() && TT.isOSzOS())
606-
setZOSLibCallNameOverrides();
607-
608-
if (TT.getArch() == Triple::ArchType::xcore)
609-
setLibcallImpl(RTLIB::MEMCPY_ALIGN_4, RTLIB::__memcpy_4);
610495
}
611496

612497
bool RuntimeLibcallsInfo::darwinHasExp10(const Triple &TT) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2>&1 | FileCheck %s
2+
3+
include "llvm/IR/RuntimeLibCallsImpl.td"
4+
5+
def SOME_FUNC : RuntimeLibcall;
6+
def func_a : RuntimeLibcallImpl<SOME_FUNC>;
7+
8+
def isTargetArchA : RuntimeLibcallPredicate<[{isTargetArchA()}]>;
9+
10+
// CHECK: [[@LINE+4]]:5: error: entry for SystemLibrary is not a RuntimeLibcallImpl
11+
// CHECK-NEXT: def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA,
12+
// CHECK: note: invalid entry `SOME_FUNC`
13+
// CHECK-NEXT: def SOME_FUNC : RuntimeLibcall;
14+
def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA,
15+
(add SOME_FUNC)
16+
>;
17+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2> %t.err | FileCheck %s
2+
// RUN: FileCheck -check-prefix=ERR %s < %t.err
3+
4+
// Check behavior of libcall emission when multiple RuntimeLibcallImpl
5+
// implementations provide the same RuntimeLibcall
6+
7+
include "llvm/IR/RuntimeLibCallsImpl.td"
8+
9+
def SOME_FUNC : RuntimeLibcall;
10+
def OTHER_FUNC : RuntimeLibcall;
11+
def ANOTHER_DUP : RuntimeLibcall;
12+
13+
def isTargetArchA : RuntimeLibcallPredicate<[{isTargetArchA()}]>;
14+
def isTargetArchB : RuntimeLibcallPredicate<[{isTargetArchB()}]>;
15+
def isTargetArchC : RuntimeLibcallPredicate<[{isTargetArchC()}]>;
16+
17+
def func_a : RuntimeLibcallImpl<SOME_FUNC>;
18+
def func_b : RuntimeLibcallImpl<SOME_FUNC>;
19+
def func_c : RuntimeLibcallImpl<SOME_FUNC>;
20+
def other_func : RuntimeLibcallImpl<OTHER_FUNC>;
21+
22+
def dup0 : RuntimeLibcallImpl<ANOTHER_DUP>;
23+
def dup1 : RuntimeLibcallImpl<ANOTHER_DUP>;
24+
25+
// func_a and func_b both provide SOME_FUNC.
26+
27+
// CHECK: if (isTargetArchA()) {
28+
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
29+
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_b}, // func_b
30+
// CHECK-NEXT: };
31+
32+
// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_b, func_a
33+
def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA,
34+
(add func_b, func_a)
35+
>;
36+
37+
// CHECK: if (isTargetArchB()) {
38+
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
39+
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
40+
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a
41+
// CHECK-NEXT: };
42+
43+
// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b
44+
def TheSystemLibraryB : SystemRuntimeLibrary<isTargetArchB,
45+
(add func_a, other_func, func_b)
46+
>;
47+
48+
// CHECK: if (isTargetArchC()) {
49+
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
50+
// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::dup1}, // dup1
51+
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
52+
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a
53+
// CHECK-NEXT: };
54+
55+
// ERR: :[[@LINE+3]]:5: warning: conflicting implementations for libcall ANOTHER_DUP: dup1, dup0
56+
// ERR: :[[@LINE+2]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b
57+
// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_c
58+
def TheSystemLibraryC : SystemRuntimeLibrary<isTargetArchC,
59+
(add func_a, dup1, other_func, func_b, func_c, dup0)
60+
>;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2>&1 | FileCheck -check-prefix=ERR %s
2+
3+
include "llvm/IR/RuntimeLibCallsImpl.td"
4+
5+
def FUNC0 : RuntimeLibcall;
6+
def FUNC1 : RuntimeLibcall;
7+
8+
def isFoo : RuntimeLibcallPredicate<[{isFoo()}]>;
9+
def isBar : RuntimeLibcallPredicate<[{isBar()}]>;
10+
def isTargetArch : RuntimeLibcallPredicate<[{isTargetArch()}]>;
11+
12+
def func0 : RuntimeLibcallImpl<FUNC0>;
13+
def func1 : RuntimeLibcallImpl<FUNC1>;
14+
15+
// ERR: :[[@LINE+2]]:8: error: combining nested libcall set predicates currently unhandled
16+
def TheSystemLibrary : SystemRuntimeLibrary<isTargetArch,
17+
(add LibcallImpls<(add func0, LibcallImpls<(add func1), isBar>), isFoo>)
18+
>;

0 commit comments

Comments
 (0)