mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
Run semantic3 on imported modules, and emit new symbols with
`available_externally` linkage. This allows the inliner to inline functions from other modules while telling the code generator to ignore those functions (treat them as declarations) Still generates a few extra `TypeInfo`s and strings... Disabled when generating debug info because I don't really understand it, and it doesn't like this.
This commit is contained in:
@@ -106,6 +106,11 @@ struct AggregateDeclaration : ScopeDsymbol
|
||||
#endif
|
||||
|
||||
AggregateDeclaration *isAggregateDeclaration() { return this; }
|
||||
|
||||
#if IN_LLVM
|
||||
// Aggregates that wouldn't have gotten semantic3'ed if we weren't inlining set this flag.
|
||||
bool availableExternally;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct AnonymousAggregateDeclaration : AggregateDeclaration
|
||||
|
||||
@@ -635,6 +635,8 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer
|
||||
offset2 = 0;
|
||||
|
||||
nakedUse = false;
|
||||
|
||||
availableExternally = true; // assume this unless proven otherwise
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1091,6 +1093,16 @@ void VarDeclaration::semantic2(Scope *sc)
|
||||
}
|
||||
}
|
||||
|
||||
void VarDeclaration::semantic3(Scope *sc)
|
||||
{
|
||||
// LDC
|
||||
if (!global.params.useAvailableExternally)
|
||||
availableExternally = false;
|
||||
|
||||
// Preserve call chain
|
||||
Declaration::semantic3(sc);
|
||||
}
|
||||
|
||||
const char *VarDeclaration::kind()
|
||||
{
|
||||
return "variable";
|
||||
@@ -1296,6 +1308,9 @@ Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s)
|
||||
void TypeInfoDeclaration::semantic(Scope *sc)
|
||||
{
|
||||
assert(linkage == LINKc);
|
||||
// LDC
|
||||
if (!global.params.useAvailableExternally)
|
||||
availableExternally = false;
|
||||
}
|
||||
|
||||
/***************************** TypeInfoConstDeclaration **********************/
|
||||
|
||||
@@ -300,6 +300,11 @@ struct VarDeclaration : Declaration
|
||||
/// Set during type generation.
|
||||
unsigned aggrIndex;
|
||||
|
||||
/// Variables that wouldn't have gotten semantic3'ed if we weren't inlining set this flag.
|
||||
bool availableExternally;
|
||||
/// Override added to set above flag.
|
||||
void semantic3(Scope *sc);
|
||||
|
||||
// FIXME: we're not using these anymore!
|
||||
AnonDeclaration* anonDecl;
|
||||
unsigned offset2;
|
||||
@@ -754,6 +759,9 @@ struct FuncDeclaration : Declaration
|
||||
// if this is an array operation it gets a little special attention
|
||||
bool isArrayOp;
|
||||
|
||||
// Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag.
|
||||
bool availableExternally;
|
||||
|
||||
// true if overridden with the pragma(allow_inline); stmt
|
||||
bool allowInlining;
|
||||
#endif
|
||||
|
||||
@@ -84,6 +84,8 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s
|
||||
isArrayOp = false;
|
||||
allowInlining = false;
|
||||
|
||||
availableExternally = true; // assume this unless proven otherwise
|
||||
|
||||
// function types in ldc don't merge if the context parameter differs
|
||||
// so we actually don't care about the function declaration, but only
|
||||
// what kind of context parameter it has.
|
||||
@@ -674,6 +676,10 @@ void FuncDeclaration::semantic3(Scope *sc)
|
||||
return;
|
||||
semanticRun = 3;
|
||||
|
||||
// LDC
|
||||
if (!global.params.useAvailableExternally)
|
||||
availableExternally = false;
|
||||
|
||||
if (!type || type->ty != Tfunction)
|
||||
return;
|
||||
f = (TypeFunction *)(type);
|
||||
|
||||
31
dmd/inline.c
31
dmd/inline.c
@@ -83,14 +83,17 @@ int IfStatement::inlineCost(InlineCostState *ics)
|
||||
{
|
||||
int cost;
|
||||
|
||||
#if !IN_LLVM
|
||||
/* Can't declare variables inside ?: expressions, so
|
||||
* we cannot inline if a variable is declared.
|
||||
*/
|
||||
if (arg)
|
||||
return COST_MAX;
|
||||
#endif
|
||||
|
||||
cost = condition->inlineCost(ics);
|
||||
|
||||
#if !IN_LLVM
|
||||
/* Specifically allow:
|
||||
* if (condition)
|
||||
* return exp1;
|
||||
@@ -108,6 +111,7 @@ int IfStatement::inlineCost(InlineCostState *ics)
|
||||
//printf("cost = %d\n", cost);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ics->nested += 1;
|
||||
if (ifbody)
|
||||
@@ -121,9 +125,11 @@ int IfStatement::inlineCost(InlineCostState *ics)
|
||||
|
||||
int ReturnStatement::inlineCost(InlineCostState *ics)
|
||||
{
|
||||
#if !IN_LLVM
|
||||
// Can't handle return statements nested in if's
|
||||
if (ics->nested)
|
||||
return COST_MAX;
|
||||
#endif
|
||||
return exp ? exp->inlineCost(ics) : 0;
|
||||
}
|
||||
|
||||
@@ -157,19 +163,23 @@ int VarExp::inlineCost(InlineCostState *ics)
|
||||
|
||||
int ThisExp::inlineCost(InlineCostState *ics)
|
||||
{
|
||||
#if !IN_LLVM
|
||||
FuncDeclaration *fd = ics->fd;
|
||||
if (!ics->hdrscan)
|
||||
if (fd->isNested() || !ics->hasthis)
|
||||
return COST_MAX;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SuperExp::inlineCost(InlineCostState *ics)
|
||||
{
|
||||
#if !IN_LLVM
|
||||
FuncDeclaration *fd = ics->fd;
|
||||
if (!ics->hdrscan)
|
||||
if (fd->isNested() || !ics->hasthis)
|
||||
return COST_MAX;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -195,12 +205,16 @@ int StructLiteralExp::inlineCost(InlineCostState *ics)
|
||||
|
||||
int FuncExp::inlineCost(InlineCostState *ics)
|
||||
{
|
||||
// This breaks on LDC too, since nested functions have internal linkage
|
||||
// and thus can't be referenced from other objects.
|
||||
// Right now, this makes the function be output to the .obj file twice.
|
||||
return COST_MAX;
|
||||
}
|
||||
|
||||
int DelegateExp::inlineCost(InlineCostState *ics)
|
||||
{
|
||||
// This breaks on LDC too, since nested functions have internal linkage
|
||||
// and thus can't be referenced from other objects.
|
||||
return COST_MAX;
|
||||
}
|
||||
|
||||
@@ -229,6 +243,8 @@ int DeclarationExp::inlineCost(InlineCostState *ics)
|
||||
return td->objects->dim;
|
||||
#endif
|
||||
}
|
||||
// This breaks on LDC too, since nested static variables have internal
|
||||
// linkage and thus can't be referenced from other objects.
|
||||
if (!ics->hdrscan && vd->isDataseg())
|
||||
return COST_MAX;
|
||||
cost += 1;
|
||||
@@ -246,6 +262,8 @@ int DeclarationExp::inlineCost(InlineCostState *ics)
|
||||
}
|
||||
|
||||
// These can contain functions, which when copied, get output twice.
|
||||
// These break on LDC too, since nested static variables and functions have
|
||||
// internal linkage and thus can't be referenced from other objects.
|
||||
if (declaration->isStructDeclaration() ||
|
||||
declaration->isClassDeclaration() ||
|
||||
declaration->isFuncDeclaration() ||
|
||||
@@ -1269,6 +1287,10 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan)
|
||||
if (type)
|
||||
{ assert(type->ty == Tfunction);
|
||||
TypeFunction *tf = (TypeFunction *)(type);
|
||||
#if IN_LLVM
|
||||
// LDC: Only extern(C) varargs count.
|
||||
if (tf->linkage != LINKd)
|
||||
#endif
|
||||
if (tf->varargs == 1) // no variadic parameter lists
|
||||
goto Lno;
|
||||
|
||||
@@ -1280,12 +1302,15 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan)
|
||||
!hdrscan)
|
||||
goto Lno;
|
||||
}
|
||||
#if !IN_LLVM
|
||||
// LDC: Only extern(C) varargs count, and ctors use extern(D).
|
||||
else
|
||||
{ CtorDeclaration *ctor = isCtorDeclaration();
|
||||
|
||||
if (ctor && ctor->varargs == 1)
|
||||
goto Lno;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (
|
||||
!fbody ||
|
||||
@@ -1299,17 +1324,20 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan)
|
||||
#endif
|
||||
isSynchronized() ||
|
||||
isImportedSymbol() ||
|
||||
#if !IN_LLVM
|
||||
#if DMDV2
|
||||
closureVars.dim || // no nested references to this frame
|
||||
#else
|
||||
nestedFrameRef || // no nested references to this frame
|
||||
#endif
|
||||
#endif // !IN_LLVM
|
||||
(isVirtual() && !isFinal())
|
||||
))
|
||||
{
|
||||
goto Lno;
|
||||
}
|
||||
|
||||
#if !IN_LLVM
|
||||
/* If any parameters are Tsarray's (which are passed by reference)
|
||||
* or out parameters (also passed by reference), don't do inlining.
|
||||
*/
|
||||
@@ -1322,6 +1350,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan)
|
||||
goto Lno;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&ics, 0, sizeof(ics));
|
||||
ics.hasthis = hasthis;
|
||||
@@ -1334,8 +1363,10 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan)
|
||||
if (cost >= COST_MAX)
|
||||
goto Lno;
|
||||
|
||||
#if !IN_LLVM
|
||||
if (!hdrscan) // Don't scan recursively for header content scan
|
||||
inlineScan();
|
||||
#endif
|
||||
|
||||
Lyes:
|
||||
if (!hdrscan) // Don't modify inlineStatus for header content scan
|
||||
|
||||
@@ -237,6 +237,7 @@ struct Param
|
||||
bool llvmAnnotate;
|
||||
bool useInlineAsm;
|
||||
bool verbose_cg;
|
||||
bool useAvailableExternally;
|
||||
|
||||
// target stuff
|
||||
const char* llvmArch;
|
||||
|
||||
@@ -52,6 +52,10 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
|
||||
ctor = NULL;
|
||||
defaultCtor = NULL;
|
||||
#endif
|
||||
|
||||
#if IN_LLVM
|
||||
availableExternally = true; // assume this unless proven otherwise
|
||||
#endif
|
||||
}
|
||||
|
||||
enum PROT AggregateDeclaration::prot()
|
||||
@@ -81,6 +85,10 @@ void AggregateDeclaration::semantic2(Scope *sc)
|
||||
void AggregateDeclaration::semantic3(Scope *sc)
|
||||
{ int i;
|
||||
|
||||
// LDC
|
||||
if (!global.params.useAvailableExternally)
|
||||
availableExternally = false;
|
||||
|
||||
//printf("AggregateDeclaration::semantic3(%s)\n", toChars());
|
||||
if (members)
|
||||
{
|
||||
|
||||
@@ -491,7 +491,9 @@ LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd)
|
||||
{
|
||||
Logger::cout() << "src2: " << *src << '\n';
|
||||
Logger::cout() << "index: " << field->index << '\n';
|
||||
#if 0
|
||||
Logger::cout() << "srctype: " << *src->getType() << '\n';
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
LLValue* val = DtoGEPi(src, 0, field->index);
|
||||
|
||||
@@ -9,6 +9,5 @@ enum
|
||||
LLVMva_copy,
|
||||
LLVMva_end,
|
||||
LLVMva_arg,
|
||||
LLVMldc,
|
||||
LLVMinline_asm
|
||||
};
|
||||
|
||||
@@ -1328,6 +1328,48 @@ bool mustDefineSymbol(Dsymbol* s)
|
||||
|
||||
if (fd->isArrayOp)
|
||||
return true;
|
||||
|
||||
if (global.params.useAvailableExternally && fd->availableExternally) {
|
||||
// Emit extra functions if we're inlining.
|
||||
// These will get available_externally linkage,
|
||||
// so they shouldn't end up in object code.
|
||||
|
||||
assert(fd->type->ty == Tfunction);
|
||||
TypeFunction* tf = (TypeFunction*) fd->type;
|
||||
// * If we define extra static constructors, static destructors
|
||||
// and unittests they'll get registered to run, and we won't
|
||||
// be calling them directly anyway.
|
||||
// * If it's a large function, don't emit it unnecessarily.
|
||||
// Use DMD's canInline() to determine whether it's large.
|
||||
// inlineCost() members have been changed to pay less attention
|
||||
// to DMDs limitations, but still have some issues. The most glaring
|
||||
// offenders are any kind of control flow statements other than
|
||||
// 'if' and 'return'.
|
||||
if ( !fd->isStaticCtorDeclaration()
|
||||
&& !fd->isStaticDtorDeclaration()
|
||||
&& !fd->isUnitTestDeclaration()
|
||||
&& fd->canInline(true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// This was only semantic'ed for inlining checks.
|
||||
// We won't be inlining this, so we only need to emit a declaration.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Inlining checks may create some variable and class declarations
|
||||
// we don't need to emit.
|
||||
if (global.params.useAvailableExternally)
|
||||
{
|
||||
if (VarDeclaration* vd = s->isVarDeclaration())
|
||||
if (vd->availableExternally)
|
||||
return false;
|
||||
|
||||
if (ClassDeclaration* cd = s->isClassDeclaration())
|
||||
if (cd->availableExternally)
|
||||
return false;
|
||||
}
|
||||
|
||||
TemplateInstance* tinst = DtoIsTemplateInstance(s);
|
||||
|
||||
15
gen/main.cpp
15
gen/main.cpp
@@ -35,6 +35,7 @@
|
||||
#include "gen/logger.h"
|
||||
#include "gen/linker.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/optimizer.h"
|
||||
#include "gen/toobj.h"
|
||||
#include "gen/metadata.h"
|
||||
#include "gen/passes/Passes.h"
|
||||
@@ -811,6 +812,17 @@ int main(int argc, char** argv)
|
||||
* not be found at link time.
|
||||
*/
|
||||
if (!global.params.useArrayBounds && !global.params.useAssert)
|
||||
#elif LLVM_REV >= 68940
|
||||
// This doesn't play nice with debug info at the moment
|
||||
if (!global.params.symdebug && willInline())
|
||||
{
|
||||
global.params.useAvailableExternally = true;
|
||||
Logger::println("Running some extra semantic3's for inlining purposes");
|
||||
#else
|
||||
// IN_LLVM, but available_externally not available yet.
|
||||
if (false)
|
||||
{
|
||||
#endif
|
||||
{
|
||||
// Do pass 3 semantic analysis on all imported modules,
|
||||
// since otherwise functions in them cannot be inlined
|
||||
@@ -825,6 +837,7 @@ int main(int argc, char** argv)
|
||||
fatal();
|
||||
}
|
||||
|
||||
#if !IN_LLVM
|
||||
for (int i = 0; i < modules.dim; i++)
|
||||
{
|
||||
m = (Module *)modules.data[i];
|
||||
@@ -832,10 +845,10 @@ int main(int argc, char** argv)
|
||||
printf("inline scan %s\n", m->toChars());
|
||||
m->inlineScan();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (global.errors)
|
||||
fatal();
|
||||
#endif
|
||||
|
||||
// write module dependencies to file if requested
|
||||
if (global.params.moduleDepsFile != NULL)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "llvm/Support/PassNameParser.h"
|
||||
|
||||
#include "root.h" // error()
|
||||
#include <cstring> // strcmp();
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@@ -78,6 +79,19 @@ bool doInline() {
|
||||
|| (enableInlining == cl::BOU_UNSET && optimizeLevel >= 3);
|
||||
}
|
||||
|
||||
// Determine whether the inliner will be run.
|
||||
bool willInline() {
|
||||
if (doInline())
|
||||
return true;
|
||||
// It may also have been specified explicitly on the command line as an explicit pass
|
||||
typedef cl::list<const PassInfo*, bool, PassNameParser> PL;
|
||||
for (PL::iterator I = passList.begin(), E = passList.end(); I != E; ++I) {
|
||||
if (!std::strcmp((*I)->getPassArgument(), "inline"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Some extra accessors for the linker: (llvm-ld version only, currently unused?)
|
||||
int optLevel() {
|
||||
return optimizeLevel;
|
||||
@@ -108,7 +122,6 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||
else
|
||||
addPass(pm, createScalarReplAggregatesPass());
|
||||
addPass(pm, createGlobalOptimizerPass());
|
||||
addPass(pm, createGlobalDCEPass());
|
||||
}
|
||||
|
||||
// -O2
|
||||
@@ -208,6 +221,10 @@ static void addPassesForOptLevel(PassManager& pm) {
|
||||
addPass(pm, createConstantMergePass());
|
||||
}
|
||||
|
||||
if (optimizeLevel >= 1) {
|
||||
addPass(pm, createGlobalDCEPass());
|
||||
}
|
||||
|
||||
// level -O4 and -O5 are linktime optimizations
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@ namespace llvm { class Module; }
|
||||
|
||||
bool ldc_optimize_module(llvm::Module* m);
|
||||
|
||||
// Determines whether the inliner will run in the -O<N> list of passes
|
||||
bool doInline();
|
||||
// Determines whether the inliner will be run at all.
|
||||
bool willInline();
|
||||
|
||||
int optLevel();
|
||||
|
||||
|
||||
@@ -241,6 +241,13 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||
// global variable
|
||||
if (VarDeclaration* vd = sym->isVarDeclaration())
|
||||
{
|
||||
if (mustDefineSymbol(vd))
|
||||
Logger::println("Variable %savailable externally: %s", (vd->availableExternally ? "" : "not "), vd->toChars());
|
||||
#if LLVM_REV >= 68940
|
||||
// generated by inlining semantics run
|
||||
if (vd->availableExternally && mustDefineSymbol(sym))
|
||||
return llvm::GlobalValue::AvailableExternallyLinkage;
|
||||
#endif
|
||||
// template
|
||||
if (needsTemplateLinkage(sym))
|
||||
return TEMPLATE_LINKAGE_TYPE;
|
||||
@@ -248,15 +255,22 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||
// function
|
||||
else if (FuncDeclaration* fdecl = sym->isFuncDeclaration())
|
||||
{
|
||||
if (mustDefineSymbol(fdecl))
|
||||
Logger::println("Function %savailable externally: %s", (fdecl->availableExternally ? "" : "not "), fdecl->toChars());
|
||||
assert(fdecl->type->ty == Tfunction);
|
||||
TypeFunction* ft = (TypeFunction*)fdecl->type;
|
||||
|
||||
// array operations are always template linkage
|
||||
if (fdecl->isArrayOp)
|
||||
return TEMPLATE_LINKAGE_TYPE;
|
||||
// intrinsics are always external
|
||||
if (fdecl->llvmInternal == LLVMintrinsic)
|
||||
return llvm::GlobalValue::ExternalLinkage;
|
||||
#if LLVM_REV >= 68940
|
||||
// generated by inlining semantics run
|
||||
if (fdecl->availableExternally && mustDefineSymbol(sym))
|
||||
return llvm::GlobalValue::AvailableExternallyLinkage;
|
||||
#endif
|
||||
// array operations are always template linkage
|
||||
if (fdecl->isArrayOp)
|
||||
return TEMPLATE_LINKAGE_TYPE;
|
||||
// template instances should have weak linkage
|
||||
// but only if there's a body, and it's not naked
|
||||
// otherwise we make it external
|
||||
@@ -269,6 +283,13 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||
// class
|
||||
else if (ClassDeclaration* cd = sym->isClassDeclaration())
|
||||
{
|
||||
if (mustDefineSymbol(cd))
|
||||
Logger::println("Class %savailable externally: %s", (cd->availableExternally ? "" : "not "), vd->toChars());
|
||||
#if LLVM_REV >= 68940
|
||||
// generated by inlining semantics run
|
||||
if (cd->availableExternally && mustDefineSymbol(sym))
|
||||
return llvm::GlobalValue::AvailableExternallyLinkage;
|
||||
#endif
|
||||
// template
|
||||
if (needsTemplateLinkage(cd))
|
||||
return TEMPLATE_LINKAGE_TYPE;
|
||||
@@ -278,8 +299,8 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||
assert(0 && "not global/function");
|
||||
}
|
||||
|
||||
// The following breaks for nested naked functions, so check for that.
|
||||
bool skipNestedCheck = false;
|
||||
// The following breaks for nested naked functions and other declarations, so check for that.
|
||||
bool skipNestedCheck = !mustDefineSymbol(sym);
|
||||
if (FuncDeclaration* fd = sym->isFuncDeclaration())
|
||||
skipNestedCheck = (fd->naked != 0);
|
||||
|
||||
@@ -306,16 +327,36 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
|
||||
return llvm::GlobalValue::ExternalLinkage;
|
||||
}
|
||||
|
||||
static bool isAvailableExternally(Dsymbol* sym)
|
||||
{
|
||||
if (VarDeclaration* vd = sym->isVarDeclaration())
|
||||
return vd->availableExternally;
|
||||
if (FuncDeclaration* fd = sym->isFuncDeclaration())
|
||||
return fd->availableExternally;
|
||||
if (AggregateDeclaration* ad = sym->isAggregateDeclaration())
|
||||
return ad->availableExternally;
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::GlobalValue::LinkageTypes DtoInternalLinkage(Dsymbol* sym)
|
||||
{
|
||||
if (needsTemplateLinkage(sym))
|
||||
if (needsTemplateLinkage(sym)) {
|
||||
#if LLVM_REV >= 68940
|
||||
if (isAvailableExternally(sym) && mustDefineSymbol(sym))
|
||||
return llvm::GlobalValue::AvailableExternallyLinkage;
|
||||
#endif
|
||||
return TEMPLATE_LINKAGE_TYPE;
|
||||
}
|
||||
else
|
||||
return llvm::GlobalValue::InternalLinkage;
|
||||
}
|
||||
|
||||
llvm::GlobalValue::LinkageTypes DtoExternalLinkage(Dsymbol* sym)
|
||||
{
|
||||
#if LLVM_REV >= 68940
|
||||
if (isAvailableExternally(sym) && mustDefineSymbol(sym))
|
||||
return llvm::GlobalValue::AvailableExternallyLinkage;
|
||||
#endif
|
||||
if (needsTemplateLinkage(sym))
|
||||
return TEMPLATE_LINKAGE_TYPE;
|
||||
else
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "gen/linkage.h"
|
||||
#include "gen/metadata.h"
|
||||
#include "gen/rttibuilder.h"
|
||||
#include "gen/llvm-version.h"
|
||||
|
||||
#include "ir/irvar.h"
|
||||
#include "ir/irtype.h"
|
||||
|
||||
Reference in New Issue
Block a user