Skip to content

Commit feb291b

Browse files
authored
Refactor k-rule-apply tool (#1110)
This PR is a preparatory refactoring that will enable me to fix a problematic bug in the Kasmer project; I've factored out the changes here because they include other related cleanups not directly relevant to the bug I'm fixing in the subsequent PR. Currently, the `k-rule-apply` tool is explicitly linked against the KORE AST library in order for it to be able to parse a KORE definition and search for an axiom with a particular label. This works fine, but on changing the way that the LLVM backend is linked on macOS, this AST linkage caused a subtle bug to manifest because of the way that `k-rule-apply` uses `dlopen` to inspect a shared library compiled by the backend.[^1] The fix here is to remove the explicit dependency of this tool on the AST + Parser libraries, and instead push all the required behaviour of the tool into the C bindings so that it can be used fully with `dlopen`. The changes in this PR are as follows: - Reorganise the existing code in the `k-rule-apply` tool to be more hygienic in its usage of header files etc. - Push calls to the KORE parser library and references to the KORE AST structures out in favour of C-linkage calls to the bindings module, which is available and compiled into the same shared library as we're already `dlopen`ing. - Extract the one non-trivial usage of the AST library (mapping rule labels to matching function names via their axiom) into the core C bindings. - Remove the dependency of this tool on the AST and Parser libraries, finally enabling the downstream bugfix that motivated this change in the first place. [^1]: I have a full writeup of this on the way; in the context of this PR the specifics aren't important.
1 parent 71a5f9e commit feb291b

File tree

11 files changed

+206
-135
lines changed

11 files changed

+206
-135
lines changed

bindings/c/include/kllvm-c/kllvm-c.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,18 @@ void kllvm_free_all_memory(void);
162162

163163
bool kllvm_mutable_bytes_enabled(void);
164164

165+
/* Definitions */
166+
167+
/**
168+
* Parse the given KORE definition, then if any of its axioms have a `label`
169+
* attribute that matches the supplied label, return the name of the function
170+
* symbol that attempts matching a pattern against that axiom (and will
171+
* therefore populate the backend's global matching log).
172+
*
173+
* If no such axiom exists, return `nullptr`.
174+
*/
175+
char *kore_match_function_name(char const *defn_path, char const *label);
176+
165177
#ifdef __cplusplus
166178
}
167179
#endif

bindings/c/lib.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,17 @@ void kllvm_free_all_memory(void) {
434434
bool kllvm_mutable_bytes_enabled(void) {
435435
return hook_BYTES_mutableBytesEnabled();
436436
}
437+
438+
/* Definitions */
439+
440+
char *kore_match_function_name(char const *defn_path, char const *label) {
441+
auto result = kllvm::bindings::get_match_function_name(defn_path, label);
442+
if (!result) {
443+
return nullptr;
444+
}
445+
446+
return get_c_string(*result);
447+
}
437448
}
438449

439450
namespace {

bindings/core/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ add_library(BindingsCore
33
)
44

55
target_link_libraries(BindingsCore
6-
PUBLIC AST fmt::fmt-header-only
6+
PUBLIC AST Parser fmt::fmt-header-only
77
)
88

99
install(

bindings/core/src/core.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <kllvm/bindings/core/core.h>
2+
#include <kllvm/parser/KOREParser.h>
23

34
using namespace kllvm;
45

@@ -116,4 +117,25 @@ bool is_sort_k(std::shared_ptr<kore_sort> const &sort) {
116117
return false;
117118
}
118119

120+
std::optional<std::string> get_match_function_name(
121+
std::string const &definition_path, std::string const &label) {
122+
// Parse the definition.kore to get the AST.
123+
parser::kore_parser parser(definition_path);
124+
auto kore_ast = parser.definition();
125+
kore_ast->preprocess();
126+
127+
// Iterate through axioms and return the one with the give rulen label if exits.
128+
for (auto *axiom : kore_ast.get()->get_axioms()) {
129+
// Check if the current axiom has the attribute label.
130+
if (axiom->attributes().contains(attribute_set::key::Label)) {
131+
// Compare the axiom's label with the given rule label.
132+
if (label == axiom->attributes().get_string(attribute_set::key::Label)) {
133+
return "intern_match_" + std::to_string(axiom->get_ordinal());
134+
}
135+
}
136+
}
137+
138+
return std::nullopt;
139+
}
140+
119141
} // namespace kllvm::bindings

include/kllvm/ast/AST.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,8 @@ class kore_definition {
10341034
}
10351035
kore_symbol *get_inj_symbol() { return inj_symbol_; }
10361036

1037-
std::vector<kore_composite_sort *> const &get_all_sorts() const {
1037+
[[nodiscard]] std::vector<kore_composite_sort *> const &
1038+
get_all_sorts() const {
10381039
return all_sorts_;
10391040
}
10401041
};

include/kllvm/bindings/core/core.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <kllvm/ast/AST.h>
55

66
#include <memory>
7+
#include <optional>
78

89
// These headers need to be included last because they pollute a number of macro
910
// definitions into the global namespace.
@@ -41,6 +42,13 @@ bool is_sort_k(std::shared_ptr<kllvm::kore_sort> const &sort);
4142
std::shared_ptr<kore_pattern>
4243
evaluate_function(std::shared_ptr<kore_composite_pattern> const &term);
4344

45+
/**
46+
* Get the name of the LLVM function that attempts matching on the rule with
47+
* this label by parsing a KORE definition and examining its axioms.
48+
*/
49+
std::optional<std::string> get_match_function_name(
50+
std::string const &definition_path, std::string const &label);
51+
4452
} // namespace kllvm::bindings
4553

4654
#endif

tools/k-rule-apply/CMakeLists.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
kllvm_add_tool(k-rule-apply
22
main.cpp
3-
)
4-
5-
target_link_libraries(k-rule-apply
6-
PUBLIC Parser AST gmp gmpxx
3+
shims.cpp
74
)
85

96
install(

tools/k-rule-apply/auxiliar.h

Lines changed: 0 additions & 83 deletions
This file was deleted.

tools/k-rule-apply/main.cpp

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
#include "auxiliar.h"
1+
#include "shims.h"
2+
3+
#include <llvm/Support/CommandLine.h>
4+
5+
#include <cstdlib>
6+
#include <dlfcn.h>
7+
#include <fstream>
8+
#include <iostream>
9+
#include <optional>
10+
11+
#include "runtime/header.h"
212

313
using namespace llvm;
414
using namespace kllvm;
@@ -20,43 +30,10 @@ cl::opt<std::string> kore_pattern_filename(
2030
cl::opt<std::string> shared_lib_path(
2131
cl::Positional, cl::desc("<path_to_shared_lib>"), cl::cat(k_rule_cat));
2232

23-
std::optional<std::string> get_match_function_name() {
24-
auto definition = kompiled_dir + "/definition.kore";
25-
// Parse the definition.kore to get the AST.
26-
parser::kore_parser parser(definition);
27-
auto kore_ast = parser.definition();
28-
kore_ast->preprocess();
29-
30-
// Iterate through axioms and return the one with the give rulen label if exits.
31-
for (auto *axiom : kore_ast.get()->get_axioms()) {
32-
// Check if the current axiom has the attribute label.
33-
if (axiom->attributes().contains(attribute_set::key::Label)) {
34-
// Compare the axiom's label with the given rule label.
35-
if (rule_label
36-
== axiom->attributes().get_string(attribute_set::key::Label)) {
37-
return "intern_match_" + std::to_string(axiom->get_ordinal());
38-
}
39-
}
40-
}
41-
std::cerr << rule_label << "\n";
42-
return std::nullopt;
43-
}
44-
4533
int main(int argc, char **argv) {
4634
cl::HideUnrelatedOptions({&k_rule_cat});
4735
cl::ParseCommandLineOptions(argc, argv);
4836

49-
// Parse the given KORE Pattern and get the block* to use as input for the
50-
// match function.
51-
parser::kore_parser parser(kore_pattern_filename.getValue());
52-
auto initial_configuration = parser.pattern();
53-
54-
auto match_function_name = get_match_function_name();
55-
if (!match_function_name.has_value()) {
56-
std::cerr << "Rule with label " << rule_label << " does not exist.\n";
57-
return EXIT_FAILURE;
58-
}
59-
6037
// Open the shared library that contains the llvm match functions.
6138
auto *handle = dlopen(shared_lib_path.c_str(), RTLD_LAZY);
6239

@@ -66,30 +43,36 @@ int main(int argc, char **argv) {
6643
return EXIT_FAILURE;
6744
}
6845

46+
auto *match_function_name = get_match_function_name(
47+
kompiled_dir + "/definition.kore", rule_label, handle);
48+
if (!match_function_name) {
49+
std::cerr << "Rule with label " << rule_label << " does not exist.\n";
50+
return EXIT_FAILURE;
51+
}
52+
6953
// Get util function from the shared lib, cast it to its right type, and call
7054
// with its appropriate argument if any.
71-
void *match_function_ptr = dlsym(handle, match_function_name->c_str());
72-
if (match_function_ptr == nullptr) {
55+
auto *match_function
56+
= reinterpret_cast<void (*)(block *)>(dlsym(handle, match_function_name));
57+
if (!match_function) {
7358
std::cerr << "Error: " << dlerror() << "\n";
7459
dlclose(handle);
7560
return EXIT_FAILURE;
7661
}
7762

78-
// NOLINTNEXTLINE(*-reinterpret-cast)
79-
auto match_function = reinterpret_cast<void (*)(block *)>(match_function_ptr);
80-
81-
reset_match_reason(handle);
8263
init_static_objects(handle);
83-
auto *b
84-
= construct_initial_configuration(initial_configuration.get(), handle);
85-
if (b == nullptr) {
64+
reset_match_reason(handle);
65+
66+
auto *b = parse_initial_configuration(kore_pattern_filename, handle);
67+
if (!b) {
8668
std::cerr << "Error: " << dlerror() << "\n";
8769
return EXIT_FAILURE;
8870
}
8971

90-
match_function((block *)b);
72+
match_function(b);
73+
9174
auto *log = getmatch_log(handle);
92-
if (log == nullptr) {
75+
if (!log) {
9376
std::cerr << "Error: " << dlerror() << "\n";
9477
return EXIT_FAILURE;
9578
}
@@ -101,7 +84,8 @@ int main(int argc, char **argv) {
10184
}
10285

10386
print_match_result(
104-
std::cout, (match_log *)log, log_size, kompiled_dir, handle);
87+
std::cout, reinterpret_cast<match_log *>(log), log_size, kompiled_dir,
88+
handle);
10589

10690
dlclose(handle);
10791
return 0;

0 commit comments

Comments
 (0)