mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 15:40:55 +03:00
Fix inlining problem: reverse order in which module array is codegenned.
This commit is contained in:
parent
2e9b196c09
commit
a3f0678283
4 changed files with 67 additions and 53 deletions
|
@ -1393,7 +1393,15 @@ int cppmain(int argc, char **argv) {
|
|||
if (global.params.obj && !modules.empty()) {
|
||||
ldc::CodeGenerator cg(getGlobalContext(), singleObj);
|
||||
|
||||
for (unsigned i = 0; i < modules.dim; i++) {
|
||||
// When inlining is enabled, we are calling semantic3 on function
|
||||
// declarations, which may _add_ members to the first module in the modules
|
||||
// array. These added functions must be codegenned, because these functions
|
||||
// may be "alwaysinline" and linker problems arise otherwise with templates
|
||||
// that have __FILE__ as parameters (which must be `pragma(inline, true);`)
|
||||
// Therefore, codegen is done in reverse order with members[0] last, to make
|
||||
// sure these functions (added to members[0] by members[x>0]) are
|
||||
// codegenned.
|
||||
for (d_size_t i = modules.dim; i-- > 0;) {
|
||||
Module *const m = modules[i];
|
||||
if (global.params.verbose) {
|
||||
fprintf(global.stdmsg, "code %s\n", m->toChars());
|
||||
|
|
|
@ -79,49 +79,69 @@ bool defineAsExternallyAvailable(FuncDeclaration &fdecl) {
|
|||
IF_LOG Logger::println("Enter defineAsExternallyAvailable");
|
||||
LOG_SCOPE
|
||||
|
||||
// Try to do cheap checks first.
|
||||
// Implementation note: try to do cheap checks first.
|
||||
|
||||
if (fdecl.neverInline || fdecl.inlining == PINLINEnever)
|
||||
if (fdecl.neverInline || fdecl.inlining == PINLINEnever) {
|
||||
IF_LOG Logger::println("pragma(inline, false) specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
// pragma(inline, true) functions will be inlined even at -O0
|
||||
if (!willInline() && (fdecl.inlining != PINLINEalways))
|
||||
if (!willInline() && (fdecl.inlining != PINLINEalways)) {
|
||||
IF_LOG Logger::println("Commandline flags indicate no inlining");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fdecl.isUnitTestDeclaration())
|
||||
if (fdecl.isUnitTestDeclaration()) {
|
||||
IF_LOG Logger::println("isUnitTestDeclaration() == true");
|
||||
return false;
|
||||
if (fdecl.isFuncAliasDeclaration())
|
||||
}
|
||||
if (fdecl.isFuncAliasDeclaration()) {
|
||||
IF_LOG Logger::println("isFuncAliasDeclaration() == true");
|
||||
return false;
|
||||
if (!fdecl.fbody)
|
||||
}
|
||||
if (!fdecl.fbody) {
|
||||
IF_LOG Logger::println("No function body available for inlining");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable inlining functions from object.d because of TypeInfo related issue
|
||||
if (fdecl.getModule()->ident == Id::object)
|
||||
// Disable inlining functions from object.d because of TypeInfo related
|
||||
// issue
|
||||
if (fdecl.getModule()->ident == Id::object) {
|
||||
IF_LOG Logger::println("Inlining of object.d functions is disabled");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alreadyOrWillBeDefined(fdecl))
|
||||
if (alreadyOrWillBeDefined(fdecl)) {
|
||||
IF_LOG Logger::println("Function will be defined later.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Weak-linkage functions can not be inlined.
|
||||
if (hasWeakUDA(&fdecl))
|
||||
if (hasWeakUDA(&fdecl)) {
|
||||
IF_LOG Logger::println("@weak functions cannot be inlined.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isInlineCandidate(fdecl))
|
||||
return false;
|
||||
|
||||
IF_LOG Logger::println("Potential inlining candidate");
|
||||
|
||||
// If semantic analysis is already complete, the function will be codegenned
|
||||
// elsewhere.
|
||||
if (fdecl.semanticRun >= PASSsemantic3)
|
||||
if (fdecl.semanticRun >= PASSsemantic3) {
|
||||
// If semantic analysis has come this far, the function will be defined
|
||||
// elsewhere and should not get the available_externally attribute from
|
||||
// here.
|
||||
IF_LOG Logger::println("Semantic analysis already completed");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
IF_LOG Logger::println("Do semantic analysis");
|
||||
LOG_SCOPE
|
||||
|
||||
// The inlining is aggressive and may give semantic errors that are forward
|
||||
// referencing errors. Simply avoid those cases for inlining.
|
||||
// The inlining is aggressive and may give semantic errors that are
|
||||
// forward referencing errors. Simply avoid those cases for inlining.
|
||||
uint errors = global.startGagging();
|
||||
global.gaggedForInlining = true;
|
||||
|
||||
|
@ -144,9 +164,8 @@ bool defineAsExternallyAvailable(FuncDeclaration &fdecl) {
|
|||
// For naked functions (inline assembly), we emit the assembly directly as
|
||||
// globals in the text section. Emitting them during this inline pass will
|
||||
// therefore result in multiple definitions. Solution: don't try to inline
|
||||
// them.
|
||||
// These naked functions don't appear to be inlined anyway, so it is pointless
|
||||
// at this moment to try.
|
||||
// them. These naked functions don't appear to be inlined anyway, so it is
|
||||
// pointless at this moment to try.
|
||||
// FuncDeclaration::naked is set by the AsmParser during semantic analysis.
|
||||
if (fdecl.naked) {
|
||||
IF_LOG Logger::println("Naked asm functions cannot be inlined.");
|
||||
|
@ -912,22 +931,11 @@ void DtoDefineFunction(FuncDeclaration *fd, bool availableExternally) {
|
|||
}
|
||||
|
||||
if (!availableExternally) {
|
||||
// Check whether the frontend knows that the function is already defined
|
||||
// in some other module (see DMD's FuncDeclaration::toObjFile).
|
||||
for (FuncDeclaration *f = fd; f;) {
|
||||
if (!f->isInstantiated() && f->inNonRoot()) {
|
||||
if (!alreadyOrWillBeDefined(*fd)) {
|
||||
IF_LOG Logger::println("Skipping '%s'.", fd->toPrettyChars());
|
||||
// TODO: Emit as available_externally for inlining purposes instead
|
||||
// (see #673).
|
||||
fd->ir->setDefined();
|
||||
return;
|
||||
}
|
||||
if (f->isNested()) {
|
||||
f = f->toParent2()->isFuncDeclaration();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DtoDeclareFunction(fd);
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
|
||||
// RUN: %ldc %s -I%S -c -output-ll -release -enable-inlining -O0 -of=%t.O0.ll && FileCheck %s < %t.O0.ll
|
||||
|
||||
// Test linking too (separate compilation)
|
||||
// RUN: %ldc -singleobj %S/inputs/inlinables.d %s -I%S -c -output-ll -release -enable-inlining -O0 -of=%t.singleobj.O0.ll && FileCheck %s < %t.singleobj.O0.ll
|
||||
|
||||
// Test linking too.
|
||||
// Separate compilation
|
||||
// RUN: %ldc -c -enable-inlining %S/inputs/inlinables.d -of=%t.inlinables%obj \
|
||||
// RUN: && %ldc -I%S -enable-inlining %t.inlinables%obj %s -of=%t%exe
|
||||
// Singleobj compilation
|
||||
// RUN: %ldc -I%S -enable-inlining -singleobj %S/inputs/inlinables.d %s -of=%t2%exe
|
||||
|
||||
import inputs.inlinables;
|
||||
import std.stdio;
|
||||
|
@ -15,9 +20,6 @@ int foo(int i)
|
|||
{
|
||||
return call_template_foo(i);
|
||||
}
|
||||
// CHECK-NOT: declare{{.*}}D6inputs10inlinables20__T12template_fooTiZ12template_fooUNaNbNiNfiZi
|
||||
// CHECK: define{{.*}}D6inputs10inlinables20__T12template_fooTiZ12template_fooUNaNbNiNfiZi
|
||||
// CHECK-SAME: #[[ATTR1:[0-9]+]]
|
||||
|
||||
// stdio.File.flush contains a call to errnoException, which contains __FILE__ as default template parameter.
|
||||
// Make sure the symbol is inlined/defined and not declared (which will lead to linker errors if the location
|
||||
|
@ -27,18 +29,15 @@ void ggg(ref File f)
|
|||
f.flush();
|
||||
}
|
||||
|
||||
// CHECK-NOT: declare{{.*}}D3std9exception{{[0-9]+}}__T12errnoEnforce
|
||||
// CHECK: define{{.*}}D3std9exception{{[0-9]+}}__T12errnoEnforce
|
||||
// CHECK-SAME: #[[ATTR2:[0-9]+]]
|
||||
|
||||
void hhh()
|
||||
{
|
||||
auto f = File("filename","r");
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
}
|
||||
|
||||
// CHECK-NOT: declare{{.*}}D6inputs10inlinables20__T12template_fooTiZ12template_foo
|
||||
// CHECK-NOT: declare{{.*}}D3std9exception{{[0-9]+}}__T12errnoEnforce
|
||||
|
||||
// CHECK-DAG: define{{.*}}D6inputs10inlinables20__T12template_fooTiZ12template_foo{{.*}}) #[[ATTR1:[0-9]+]]
|
||||
// CHECK-DAG: define{{.*}}D3std9exception{{[0-9]+}}__T12errnoEnforce{{.*}}) #[[ATTR2:[0-9]+]]
|
||||
|
||||
// CHECK-DAG: attributes #[[ATTR1]] ={{.*}} alwaysinline
|
||||
// CHECK-DAG: attributes #[[ATTR2]] ={{.*}} alwaysinline
|
||||
|
|
|
@ -102,13 +102,12 @@ pragma(inline, true) extern (C) void naked_asm_func()
|
|||
}
|
||||
}
|
||||
|
||||
pragma(inline, true)
|
||||
int call_template_foo(int i) {
|
||||
pragma(inline, true) int call_template_foo(int i)
|
||||
{
|
||||
return template_foo(i);
|
||||
}
|
||||
|
||||
pragma(inline, true)
|
||||
T template_foo(T)(T i)
|
||||
pragma(inline, true) T template_foo(T)(T i)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue