Skip to content
Open
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
7 changes: 6 additions & 1 deletion dmd/main.d
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ import dmd.vsoptions;

version (IN_LLVM)
{
import gen.semantic : extraLDCSpecificSemanticAnalysis;
import gen.semantic : extraLDCSpecificPreSemanticAnalysis, extraLDCSpecificSemanticAnalysis;
extern (C++):

// in driver/main.cpp
Expand Down Expand Up @@ -709,6 +709,11 @@ version (IN_LLVM) {} else
backend_init(params, driverParams, target);
}

version (IN_LLVM)
{
extraLDCSpecificPreSemanticAnalysis(modules);
}

// Do semantic analysis
foreach (m; modules)
{
Expand Down
31 changes: 24 additions & 7 deletions driver/plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,15 @@ cl::list<std::string> pluginFiles("plugin", cl::CommaSeparated,

struct SemaPlugin {
llvm::sys::DynamicLibrary library;
void (*runPreSemanticAnalysis)(Module *);
void (*runSemanticAnalysis)(Module *);

SemaPlugin(const llvm::sys::DynamicLibrary &library,
void (*runPreSemanticAnalysis)(Module *),
void (*runSemanticAnalysis)(Module *))
: library(library), runSemanticAnalysis(runSemanticAnalysis) {}
: library(library),
runPreSemanticAnalysis(runPreSemanticAnalysis),
runSemanticAnalysis(runSemanticAnalysis) {}
};

llvm::SmallVector<SemaPlugin, 1> sema_plugins;
Expand All @@ -66,16 +70,21 @@ bool loadSemanticAnalysisPlugin(const std::string &filename) {
return true; // No success, but no need to try loading again as LLVM plugin.
}

// SemanticAnalysis plugins need to export the `runSemanticAnalysis` function.
// SemanticAnalysis plugins export `runSemanticAnalysis` (called after
// semantic3) and/or `runPreSemanticAnalysis` (called before dsymbolSemantic).
void *runSemanticAnalysisFnPtr =
library.getAddressOfSymbol("runSemanticAnalysis");
void *runPreSemanticAnalysisFnPtr =
library.getAddressOfSymbol("runPreSemanticAnalysis");

// If the symbol isn't found, this is probably an LLVM plugin.
if (!runSemanticAnalysisFnPtr)
// If neither symbol is found, this is probably an LLVM plugin.
if (!runSemanticAnalysisFnPtr && !runPreSemanticAnalysisFnPtr)
return false;

sema_plugins.emplace_back(
library, reinterpret_cast<void (*)(Module *)>(runSemanticAnalysisFnPtr));
library,
reinterpret_cast<void (*)(Module *)>(runPreSemanticAnalysisFnPtr),
reinterpret_cast<void (*)(Module *)>(runSemanticAnalysisFnPtr));
return true;
}

Expand Down Expand Up @@ -117,10 +126,17 @@ void registerAllPluginsWithPassBuilder(llvm::PassBuilder &PB) {
}
}

void runAllPreSemanticAnalysisPlugins(Module *m) {
for (auto &plugin : sema_plugins) {
if (plugin.runPreSemanticAnalysis)
plugin.runPreSemanticAnalysis(m);
}
}

void runAllSemanticAnalysisPlugins(Module *m) {
for (auto &plugin : sema_plugins) {
assert(plugin.runSemanticAnalysis);
plugin.runSemanticAnalysis(m);
if (plugin.runSemanticAnalysis)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: cleaner to early exit when this is null?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is to optionally require those functions in the plugin, as now we have multiple of them, but I guess we can keep the old behavior and only make runPreSemanticAnalysis optional.

What if a user only wants to have a plugin for runPreSemanticAnalysis? I can check for both in both places (if they have at least one).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not what i meant. I agree with the change that both are optional.

I just meant hoisting the if-statement out of the loop :)

plugin.runSemanticAnalysis(m);
}
}

Expand All @@ -130,6 +146,7 @@ class Module;

void loadAllPlugins() {}
void registerAllPluginsWithPassBuilder(llvm::PassBuilder &) {}
void runAllPreSemanticAnalysisPlugins(Module *m) {}
void runAllSemanticAnalysisPlugins(Module *m) {}

#endif // LDC_ENABLE_PLUGINS
9 changes: 9 additions & 0 deletions gen/semantic.d
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ import dmd.dmodule;

extern(C++) void dcomputeSemanticAnalysis(Module m);
extern(C) int hasComputeAttr(Dsymbol m);
extern(C++) void runAllPreSemanticAnalysisPlugins(Module m);
extern(C++) void runAllSemanticAnalysisPlugins(Module m);

extern(C++) void extraLDCSpecificPreSemanticAnalysis(ref Modules modules)
{
foreach(m; modules[])
{
runAllPreSemanticAnalysisPlugins(m);
}
}

extern(C++) void extraLDCSpecificSemanticAnalysis(ref Modules modules)
{
// First finish DCompute SemA for all modules, before calling plugins.
Expand Down
23 changes: 23 additions & 0 deletions tests/plugins/basic_presema_plugin.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// REQUIRES: Plugins

// RUN: split-file %s %t --leading-lines
// RUN: %buildplugin %t/plugin.d -of=%t/plugin%so --buildDir=%t/build
// RUN: %ldc -wi -c -o- --plugin=%t/plugin%so %t/testcase.d 2>&1 | FileCheck %t/testcase.d

//--- plugin.d
import dmd.dmodule : Module;
import dmd.errors;
import dmd.location;

extern(C) void runPreSemanticAnalysis(Module m) {
if (m.md) {
warning(m.md.loc, "Pre-sema hook fired!");
}
}

//--- testcase.d
// CHECK: testcase.d([[@LINE+1]]): Warning: Pre-sema hook fired!
module testcase;
int testfunction(int i) {
return i * 2;
}
30 changes: 30 additions & 0 deletions tests/plugins/pre_and_post_sema_plugin.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// REQUIRES: Plugins

// RUN: split-file %s %t --leading-lines
// RUN: %buildplugin %t/plugin.d -of=%t/plugin%so --buildDir=%t/build
// RUN: %ldc -wi -c -o- --plugin=%t/plugin%so %t/testcase.d 2>&1 | FileCheck %t/testcase.d

//--- plugin.d
import dmd.dmodule : Module;
import dmd.errors;
import dmd.location;

extern(C) void runPreSemanticAnalysis(Module m) {
if (m.md) {
warning(m.md.loc, "pre-sema");
}
}

extern(C) void runSemanticAnalysis(Module m) {
if (m.md) {
warning(m.md.loc, "post-sema");
}
}

//--- testcase.d
// CHECK: testcase.d([[@LINE+2]]): Warning: pre-sema
// CHECK: testcase.d([[@LINE+1]]): Warning: post-sema
module testcase;
int testfunction(int i) {
return i * 2;
}
Loading