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
1 change: 1 addition & 0 deletions llvm/utils/TableGen/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ add_llvm_library(LLVMTableGenBasic OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_LINK_LLV
IntrinsicEmitter.cpp
RISCVTargetDefEmitter.cpp
RuntimeLibcallsEmitter.cpp
RuntimeLibcalls.cpp
SDNodeProperties.cpp
TableGen.cpp
TargetFeaturesEmitter.cpp
Expand Down
93 changes: 93 additions & 0 deletions llvm/utils/TableGen/Basic/RuntimeLibcalls.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//===----------------------------------------------------------------------===//
//
// 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 "RuntimeLibcalls.h"
#include "llvm/TableGen/Error.h"

using namespace llvm;

RuntimeLibcalls::RuntimeLibcalls(const RecordKeeper &Records) {
ArrayRef<const Record *> AllRuntimeLibcalls =
Records.getAllDerivedDefinitions("RuntimeLibcall");

RuntimeLibcallDefList.reserve(AllRuntimeLibcalls.size());

size_t CallTypeEnumVal = 0;
for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) {
RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef, CallTypeEnumVal++);
Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back();
}

for (RuntimeLibcall &LibCall : RuntimeLibcallDefList)
Def2RuntimeLibcall[LibCall.getDef()] = &LibCall;

ArrayRef<const Record *> AllRuntimeLibcallImplsRaw =
Records.getAllDerivedDefinitions("RuntimeLibcallImpl");

SmallVector<const Record *, 1024> AllRuntimeLibcallImpls(
AllRuntimeLibcallImplsRaw);

// Sort by libcall impl name and secondarily by the enum name.
sort(AllRuntimeLibcallImpls, [](const Record *A, const Record *B) {
return std::pair(A->getValueAsString("LibCallFuncName"), A->getName()) <
std::pair(B->getValueAsString("LibCallFuncName"), B->getName());
});

RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size());

size_t LibCallImplEnumVal = 1;
for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) {
RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, Def2RuntimeLibcall,
LibCallImplEnumVal++);

const RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back();
Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl;

if (LibCallImpl.isDefault()) {
const RuntimeLibcall *Provides = LibCallImpl.getProvides();
if (!Provides)
PrintFatalError(LibCallImplDef->getLoc(),
"default implementations must provide a libcall");
LibCallToDefaultImpl[Provides] = &LibCallImpl;
}
}
}

void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def,
SetTheory::RecSet &Elts) {
assert(Def->isSubClassOf("LibcallImpls"));

SetTheory::RecSet TmpElts;

ST.evaluate(Def->getValueInit("MemberList"), TmpElts, Def->getLoc());

Elts.insert(TmpElts.begin(), TmpElts.end());

AvailabilityPredicate AP(Def->getValueAsDef("AvailabilityPredicate"));
const Record *CCClass = Def->getValueAsOptionalDef("CallingConv");

// This is assuming we aren't conditionally applying a calling convention to
// some subsets, and not another, but this doesn't appear to be used.

for (const Record *LibcallImplDef : TmpElts) {
const RuntimeLibcallImpl *LibcallImpl =
Libcalls.getRuntimeLibcallImpl(LibcallImplDef);
if (!AP.isAlwaysAvailable() || CCClass) {
auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {{}, CCClass}});
if (!Inserted) {
PrintError(
Def,
"combining nested libcall set predicates currently unhandled: '" +
LibcallImpl->getLibcallFuncName() + "'");
}

It->second.first.push_back(AP.getDef());
It->second.second = CCClass;
}
}
}
189 changes: 189 additions & 0 deletions llvm/utils/TableGen/Basic/RuntimeLibcalls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
//===------------------------------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H
#define LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/SetTheory.h"

namespace llvm {

class AvailabilityPredicate {
const Record *TheDef;
StringRef PredicateString;

public:
AvailabilityPredicate(const Record *Def) : TheDef(Def) {
if (TheDef)
PredicateString = TheDef->getValueAsString("Cond");
}

const Record *getDef() const { return TheDef; }

bool isAlwaysAvailable() const { return PredicateString.empty(); }

void emitIf(raw_ostream &OS) const {
OS << "if (" << PredicateString << ") {\n";
}

void emitEndIf(raw_ostream &OS) const { OS << "}\n"; }

void emitTableVariableNameSuffix(raw_ostream &OS) const {
if (TheDef)
OS << '_' << TheDef->getName();
}
};

class RuntimeLibcalls;
class RuntimeLibcallImpl;

/// Used to apply predicates to nested sets of libcalls.
struct LibcallPredicateExpander : SetTheory::Expander {
const RuntimeLibcalls &Libcalls;
DenseMap<const RuntimeLibcallImpl *,
std::pair<std::vector<const Record *>, const Record *>> &Func2Preds;

LibcallPredicateExpander(
const RuntimeLibcalls &Libcalls,
DenseMap<const RuntimeLibcallImpl *,
std::pair<std::vector<const Record *>, const Record *>>
&Func2Preds)
: Libcalls(Libcalls), Func2Preds(Func2Preds) {}

void expand(SetTheory &ST, const Record *Def,
SetTheory::RecSet &Elts) override;
};

class RuntimeLibcall {
const Record *TheDef = nullptr;
const size_t EnumVal;

public:
RuntimeLibcall() = delete;
RuntimeLibcall(const Record *Def, size_t EnumVal)
: TheDef(Def), EnumVal(EnumVal) {
assert(Def);
}

~RuntimeLibcall() { assert(TheDef); }

const Record *getDef() const { return TheDef; }

StringRef getName() const { return TheDef->getName(); }

size_t getEnumVal() const { return EnumVal; }

void emitEnumEntry(raw_ostream &OS) const {
OS << "RTLIB::" << TheDef->getValueAsString("Name");
}
};

class RuntimeLibcallImpl {
const Record *TheDef;
const RuntimeLibcall *Provides = nullptr;
const size_t EnumVal;

public:
RuntimeLibcallImpl(
const Record *Def,
const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap,
size_t EnumVal)
: TheDef(Def), EnumVal(EnumVal) {
if (const Record *ProvidesDef = Def->getValueAsDef("Provides"))
Provides = ProvideMap.lookup(ProvidesDef);
}

~RuntimeLibcallImpl() = default;

const Record *getDef() const { return TheDef; }

StringRef getName() const { return TheDef->getName(); }

size_t getEnumVal() const { return EnumVal; }

const RuntimeLibcall *getProvides() const { return Provides; }

StringRef getLibcallFuncName() const {
return TheDef->getValueAsString("LibCallFuncName");
}

const Record *getCallingConv() const {
return TheDef->getValueAsOptionalDef("CallingConv");
}

void emitQuotedLibcallFuncName(raw_ostream &OS) const {
OS << '\"' << getLibcallFuncName() << '\"';
}

bool isDefault() const { return TheDef->getValueAsBit("IsDefault"); }

void emitEnumEntry(raw_ostream &OS) const {
OS << "RTLIB::impl_" << this->getName();
}

void emitSetImplCall(raw_ostream &OS) const {
OS << "setLibcallImpl(";
Provides->emitEnumEntry(OS);
OS << ", ";
emitEnumEntry(OS);
OS << "); // " << getLibcallFuncName() << '\n';
}

void emitTableEntry(raw_ostream &OS) const {
OS << '{';
Provides->emitEnumEntry(OS);
OS << ", ";
emitEnumEntry(OS);
OS << "}, // " << getLibcallFuncName() << '\n';
}

void emitSetCallingConv(raw_ostream &OS) const {}
};

struct LibcallsWithCC {
std::vector<const RuntimeLibcallImpl *> LibcallImpls;
const Record *CallingConv = nullptr;
};

class RuntimeLibcalls {
private:
DenseMap<const Record *, const RuntimeLibcall *> Def2RuntimeLibcall;
DenseMap<const Record *, const RuntimeLibcallImpl *> Def2RuntimeLibcallImpl;

std::vector<RuntimeLibcall> RuntimeLibcallDefList;
std::vector<RuntimeLibcallImpl> RuntimeLibcallImplDefList;

DenseMap<const RuntimeLibcall *, const RuntimeLibcallImpl *>
LibCallToDefaultImpl;

public:
RuntimeLibcalls(const RecordKeeper &Records);

ArrayRef<RuntimeLibcall> getRuntimeLibcallDefList() const {
return RuntimeLibcallDefList;
}

ArrayRef<RuntimeLibcallImpl> getRuntimeLibcallImplDefList() const {
return RuntimeLibcallImplDefList;
}

const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const {
return Def2RuntimeLibcall.lookup(Def);
}

const RuntimeLibcallImpl *getRuntimeLibcallImpl(const Record *Def) const {
return Def2RuntimeLibcallImpl.lookup(Def);
}
};

} // namespace llvm

#endif // LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H
Loading