1//===----------------------------------------------------------------------===//
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#include "RuntimeLibcalls.h"
10#include "PredicateExpanderDag.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/Support/raw_ostream.h"
13#include "llvm/TableGen/Error.h"
14
15using namespace llvm;
16
17std::string AvailabilityPredicate::lowerCondDag(const Record *Owner,
18 const Init *Val,
19 bool ParenIfBinOp) {
20 // Leaf: a LibcallPredicate whose Cond is a C++ boolean over `TT`.
21 auto EmitLeaf = [&](const Init &Leaf, raw_ostream &OS) -> bool {
22 const auto *DI = dyn_cast<DefInit>(Val: &Leaf);
23 if (!DI || !DI->getDef()->isSubClassOf(Name: "LibcallPredicate"))
24 PrintFatalError(Rec: Owner, Msg: "predicate dag leaf '" + Leaf.getAsString() +
25 "' is not a LibcallPredicate");
26 OS << DI->getDef()->getValueAsString(FieldName: "Cond");
27 return false;
28 };
29
30 std::string Result;
31 raw_string_ostream OS(Result);
32 emitPredicateDag(Owner, Val: *Val, ParenIfBinOp, OS, EmitLeaf);
33 return Result;
34}
35
36RuntimeLibcalls::RuntimeLibcalls(const RecordKeeper &Records) {
37 ArrayRef<const Record *> AllRuntimeLibcalls =
38 Records.getAllDerivedDefinitions(ClassName: "RuntimeLibcall");
39
40 RuntimeLibcallDefList.reserve(n: AllRuntimeLibcalls.size());
41
42 size_t CallTypeEnumVal = 0;
43 for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) {
44 RuntimeLibcallDefList.emplace_back(args&: RuntimeLibcallDef, args: CallTypeEnumVal++);
45 Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back();
46 }
47
48 for (RuntimeLibcall &LibCall : RuntimeLibcallDefList)
49 Def2RuntimeLibcall[LibCall.getDef()] = &LibCall;
50
51 ArrayRef<const Record *> AllRuntimeLibcallImplsRaw =
52 Records.getAllDerivedDefinitions(ClassName: "RuntimeLibcallImpl");
53
54 SmallVector<const Record *, 1024> AllRuntimeLibcallImpls(
55 AllRuntimeLibcallImplsRaw);
56
57 // Sort by libcall impl name and secondarily by the enum name.
58 sort(C&: AllRuntimeLibcallImpls, Comp: [](const Record *A, const Record *B) {
59 return std::pair(A->getValueAsString(FieldName: "LibCallFuncName"), A->getName()) <
60 std::pair(B->getValueAsString(FieldName: "LibCallFuncName"), B->getName());
61 });
62
63 RuntimeLibcallImplDefList.reserve(n: AllRuntimeLibcallImpls.size());
64
65 size_t LibCallImplEnumVal = 1;
66 for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) {
67 RuntimeLibcallImplDefList.emplace_back(args&: LibCallImplDef, args&: Def2RuntimeLibcall,
68 args: LibCallImplEnumVal++);
69
70 const RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back();
71 Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl;
72
73 if (LibCallImpl.isDefault()) {
74 const RuntimeLibcall *Provides = LibCallImpl.getProvides();
75 if (!Provides)
76 PrintFatalError(ErrorLoc: LibCallImplDef->getLoc(),
77 Msg: "default implementations must provide a libcall");
78 LibCallToDefaultImpl[Provides] = &LibCallImpl;
79 }
80 }
81}
82
83void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def,
84 SetTheory::RecSet &Elts) {
85 assert(Def->isSubClassOf("LibcallImpls"));
86
87 SetTheory::RecSet TmpElts;
88
89 ST.evaluate(Expr: Def->getValueInit(FieldName: "MemberList"), Elts&: TmpElts, Loc: Def->getLoc());
90
91 Elts.insert(Start: TmpElts.begin(), End: TmpElts.end());
92
93 AvailabilityPredicate AP(Def->getValueAsDef(FieldName: "AvailabilityPredicate"));
94 const Record *CCClass = Def->getValueAsOptionalDef(FieldName: "CallingConv");
95
96 // This is assuming we aren't conditionally applying a calling convention to
97 // some subsets, and not another, but this doesn't appear to be used.
98
99 for (const Record *LibcallImplDef : TmpElts) {
100 const RuntimeLibcallImpl *LibcallImpl =
101 Libcalls.getRuntimeLibcallImpl(Def: LibcallImplDef);
102 if (!AP.isAlwaysAvailable() || CCClass) {
103 auto [It, Inserted] = Func2Preds.insert(KV: {LibcallImpl, {{}, CCClass}});
104 if (!Inserted) {
105 PrintError(
106 Rec: Def,
107 Msg: "combining nested libcall set predicates currently unhandled: '" +
108 LibcallImpl->getLibcallFuncName() + "'");
109 }
110
111 It->second.first.push_back(x: AP.getDef());
112 It->second.second = CCClass;
113 }
114 }
115}
116