Skip to content

Commit f538409

Browse files
committed
Merge remote-tracking branch 'origin/develop'
2 parents 914d55e + 6df5ac5 commit f538409

File tree

120 files changed

+12053
-33
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+12053
-33
lines changed

bindings/python/ast.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,13 @@ void bind_proof_trace(py::module_ &m) {
426426
"function_name",
427427
&llvm_pattern_matching_failure_event::get_function_name);
428428

429+
py::class_<
430+
llvm_function_exit_event, std::shared_ptr<llvm_function_exit_event>>(
431+
proof_trace, "llvm_function_exit_event", step_event)
432+
.def_property_readonly(
433+
"rule_ordinal", &llvm_function_exit_event::get_rule_ordinal)
434+
.def_property_readonly("is_tail", &llvm_function_exit_event::is_tail);
435+
429436
py::class_<llvm_function_event, std::shared_ptr<llvm_function_event>>(
430437
proof_trace, "llvm_function_event", step_event)
431438
.def_property_readonly("name", &llvm_function_event::get_name)

docs/proof-trace.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ event ::= hook
3838
| side_cond_exit
3939
| config
4040
| pattern_matching_failure
41+
| function_exit
4142
4243
arg ::= kore_term
4344
@@ -60,6 +61,8 @@ rule ::= WORD(0x22) ordinal arity variable*
6061
side_cond_entry ::= WORD(0xEE) ordinal arity variable*
6162
side_cond_exit ::= WORD(0x33) ordinal boolean_result
6263
64+
function_exit ::= WORD(0x55) ordinal boolean_result
65+
6366
config ::= WORD(0xFF) kore_term
6467
6568
string ::= <c-style null terminated string>

include/kllvm/binary/ProofTraceParser.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ constexpr uint64_t rule_event_sentinel = detail::word(0x22);
3535
constexpr uint64_t side_condition_event_sentinel = detail::word(0xEE);
3636
constexpr uint64_t side_condition_end_sentinel = detail::word(0x33);
3737
constexpr uint64_t pattern_matching_failure_sentinel = detail::word(0x44);
38+
constexpr uint64_t function_exit_sentinel = detail::word(0x55);
3839

3940
class llvm_step_event : public std::enable_shared_from_this<llvm_step_event> {
4041
public:
@@ -172,6 +173,29 @@ class llvm_pattern_matching_failure_event : public llvm_step_event {
172173
const override;
173174
};
174175

176+
class llvm_function_exit_event : public llvm_step_event {
177+
private:
178+
uint64_t rule_ordinal_;
179+
bool is_tail_;
180+
181+
llvm_function_exit_event(uint64_t rule_ordinal, bool is_tail)
182+
: rule_ordinal_(rule_ordinal)
183+
, is_tail_(is_tail) { }
184+
185+
public:
186+
static sptr<llvm_function_exit_event>
187+
create(uint64_t rule_ordinal, bool is_tail) {
188+
return sptr<llvm_function_exit_event>(
189+
new llvm_function_exit_event(rule_ordinal, is_tail));
190+
}
191+
192+
[[nodiscard]] uint64_t get_rule_ordinal() const { return rule_ordinal_; }
193+
[[nodiscard]] bool is_tail() const { return is_tail_; }
194+
195+
void print(std::ostream &out, bool expand_terms, unsigned indent = 0U)
196+
const override;
197+
};
198+
175199
class llvm_event;
176200

177201
class llvm_function_event : public llvm_step_event {
@@ -599,6 +623,27 @@ class proof_trace_parser {
599623
return event;
600624
}
601625

626+
sptr<llvm_function_exit_event> static parse_function_exit(
627+
proof_trace_buffer &buffer) {
628+
if (!buffer.check_word(function_exit_sentinel)) {
629+
return nullptr;
630+
}
631+
632+
uint64_t ordinal = 0;
633+
if (!buffer.read_uint64(ordinal)) {
634+
return nullptr;
635+
}
636+
637+
bool is_tail = false;
638+
if (!buffer.read_bool(is_tail)) {
639+
return nullptr;
640+
}
641+
642+
auto event = llvm_function_exit_event::create(ordinal, is_tail);
643+
644+
return event;
645+
}
646+
602647
bool parse_argument(proof_trace_buffer &buffer, llvm_event &event) {
603648
if (buffer.eof() || buffer.peek() != '\x7F') {
604649
return false;
@@ -634,6 +679,8 @@ class proof_trace_parser {
634679
case pattern_matching_failure_sentinel:
635680
return parse_pattern_matching_failure(buffer);
636681

682+
case function_exit_sentinel: return parse_function_exit(buffer);
683+
637684
default: return nullptr;
638685
}
639686
}

include/kllvm/codegen/ProofEvent.h

Lines changed: 103 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
#include "kllvm/ast/AST.h"
55
#include "kllvm/codegen/Decision.h"
66
#include "kllvm/codegen/DecisionParser.h"
7+
#include "kllvm/codegen/Options.h"
78
#include "kllvm/codegen/Util.h"
89

910
#include "llvm/IR/Instructions.h"
1011

12+
#include <fmt/format.h>
13+
1114
#include <map>
1215
#include <tuple>
1316

@@ -21,27 +24,58 @@ class proof_event {
2124

2225
/*
2326
* Load the boolean flag that controls whether proof hint output is enabled or
24-
* not, then create a branch at the end of this basic block depending on the
25-
* result.
27+
* not, then create a branch at the specified location depending on the
28+
* result. The location can be before a given instruction or at the end of a
29+
* given basic block.
2630
*
2731
* Returns a pair of blocks [proof enabled, merge]; the first of these is
2832
* intended for self-contained behaviour only relevant in proof output mode,
2933
* while the second is for the continuation of the interpreter's previous
3034
* behaviour.
3135
*/
36+
template <typename Location>
3237
std::pair<llvm::BasicBlock *, llvm::BasicBlock *>
33-
proof_branch(std::string const &label, llvm::BasicBlock *insert_at_end);
38+
proof_branch(std::string const &label, Location *insert_loc);
39+
40+
/*
41+
* Return the parent function of the given location.
42+
43+
* Template specializations for llvm::Instruction and llvm::BasicBlock.
44+
*/
45+
template <typename Location>
46+
llvm::Function *get_parent_function(Location *loc);
47+
48+
/*
49+
* Return the parent basic block of the given location.
50+
51+
* Template specializations for llvm::Instruction and llvm::BasicBlock.
52+
*/
53+
template <typename Location>
54+
llvm::BasicBlock *get_parent_block(Location *loc);
55+
56+
/*
57+
* If the given location is an Instruction, this method moves the instruction
58+
* to the merge block.
59+
* If the given location is a BasicBlock, this method simply emits a no-op
60+
* instruction to the merge block.
61+
62+
* Template specializations for llvm::Instruction and llvm::BasicBlock.
63+
*/
64+
template <typename Location>
65+
void fix_insert_loc(Location *loc, llvm::BasicBlock *merge_block);
3466

3567
/*
3668
* Set up a standard event prelude by creating a pair of basic blocks for the
3769
* proof output and continuation, then loading the output filename from its
38-
* global.
70+
* global. The location for the prelude can be before a given instruction or
71+
* at the end of a given basic block.
3972
*
4073
* Returns a triple [proof enabled, merge, proof_writer]; see `proofBranch`
4174
* and `emitGetOutputFileName`.
4275
*/
76+
template <typename Location>
4377
std::tuple<llvm::BasicBlock *, llvm::BasicBlock *, llvm::Value *>
44-
event_prelude(std::string const &label, llvm::BasicBlock *insert_at_end);
78+
event_prelude(std::string const &label, Location *insert_loc);
4579

4680
/*
4781
* Set up a check of whether a new proof hint chunk should be started. The
@@ -172,6 +206,13 @@ class proof_event {
172206
llvm::Value *proof_writer, std::string const &function_name,
173207
llvm::BasicBlock *insert_at_end);
174208

209+
/*
210+
* Emit a call to the `function_exit` API of the specified `proof_writer`.
211+
*/
212+
llvm::CallInst *emit_write_function_exit(
213+
llvm::Value *proof_writer, uint64_t ordinal, bool is_tail,
214+
llvm::BasicBlock *insert_at_end);
215+
175216
/*
176217
* Emit a call to the `start_new_chunk` API of the specified `proof_writer`.
177218
*/
@@ -228,6 +269,10 @@ class proof_event {
228269
[[nodiscard]] llvm::BasicBlock *pattern_matching_failure(
229270
kore_composite_pattern const &pattern, llvm::BasicBlock *current_block);
230271

272+
template <typename Location>
273+
[[nodiscard]] llvm::BasicBlock *
274+
function_exit(uint64_t ordinal, bool is_tail, Location *insert_loc);
275+
231276
proof_event(kore_definition *definition, llvm::Module *module)
232277
: definition_(definition)
233278
, module_(module)
@@ -236,4 +281,57 @@ class proof_event {
236281

237282
} // namespace kllvm
238283

284+
//===----------------------------------------------------------------------===//
285+
// Implementation for method templates
286+
//===----------------------------------------------------------------------===//
287+
288+
template <typename Location>
289+
std::pair<llvm::BasicBlock *, llvm::BasicBlock *>
290+
kllvm::proof_event::proof_branch(
291+
std::string const &label, Location *insert_loc) {
292+
auto *i1_ty = llvm::Type::getInt1Ty(ctx_);
293+
294+
auto *proof_output_flag = module_->getOrInsertGlobal("proof_output", i1_ty);
295+
auto *proof_output = new llvm::LoadInst(
296+
i1_ty, proof_output_flag, "proof_output", insert_loc);
297+
298+
auto *f = get_parent_function(insert_loc);
299+
auto *true_block
300+
= llvm::BasicBlock::Create(ctx_, fmt::format("if_{}", label), f);
301+
auto *merge_block
302+
= llvm::BasicBlock::Create(ctx_, fmt::format("tail_{}", label), f);
303+
304+
llvm::BranchInst::Create(true_block, merge_block, proof_output, insert_loc);
305+
306+
fix_insert_loc(insert_loc, merge_block);
307+
308+
return {true_block, merge_block};
309+
}
310+
311+
template <typename Location>
312+
std::tuple<llvm::BasicBlock *, llvm::BasicBlock *, llvm::Value *>
313+
kllvm::proof_event::event_prelude(
314+
std::string const &label, Location *insert_loc) {
315+
auto [true_block, merge_block] = proof_branch(label, insert_loc);
316+
return {true_block, merge_block, emit_get_proof_trace_writer(true_block)};
317+
}
318+
319+
template <typename Location>
320+
llvm::BasicBlock *kllvm::proof_event::function_exit(
321+
uint64_t ordinal, bool is_tail, Location *insert_loc) {
322+
323+
if (!proof_hint_instrumentation) {
324+
return get_parent_block(insert_loc);
325+
}
326+
327+
auto [true_block, merge_block, proof_writer]
328+
= event_prelude("function_exit", insert_loc);
329+
330+
emit_write_function_exit(proof_writer, ordinal, is_tail, true_block);
331+
332+
llvm::BranchInst::Create(merge_block, true_block);
333+
334+
return merge_block;
335+
}
336+
239337
#endif // PROOF_EVENT_H

include/runtime/header.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ void write_side_condition_event_post_to_proof_trace(
231231
void *proof_writer, uint64_t ordinal, bool side_cond_result);
232232
void write_pattern_matching_failure_to_proof_trace(
233233
void *proof_writer, char const *function_name);
234+
void write_function_exit_to_proof_trace(
235+
void *proof_writer, uint64_t ordinal, bool is_tail);
234236
void write_configuration_to_proof_trace(
235237
void *proof_writer, block *config, bool is_initial);
236238
void start_new_chunk_in_proof_trace(void *proof_writer);

include/runtime/proof_trace_writer.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class proof_trace_writer {
3333
side_condition_event_post(uint64_t ordinal, bool side_cond_result)
3434
= 0;
3535
virtual void pattern_matching_failure(char const *function_name) = 0;
36+
virtual void function_exit(uint64_t ordinal, bool is_tail) = 0;
3637
virtual void configuration(block *config, bool is_initial) = 0;
3738
virtual void start_new_chunk() = 0;
3839
virtual void end_of_trace() = 0;
@@ -163,6 +164,12 @@ class proof_trace_file_writer : public proof_trace_writer {
163164
write_null_terminated_string(function_name);
164165
}
165166

167+
void function_exit(uint64_t ordinal, bool is_tail) override {
168+
write_uint64(kllvm::function_exit_sentinel);
169+
write_uint64(ordinal);
170+
write_bool(is_tail);
171+
}
172+
166173
void configuration(block *config, bool is_initial) override {
167174
write_uint64(kllvm::config_sentinel);
168175
serialize_configuration_to_proof_trace(file_, config, 0);
@@ -227,6 +234,15 @@ class proof_trace_callback_writer : public proof_trace_writer {
227234
, result(result) { }
228235
};
229236

237+
struct function_exit_construction {
238+
uint64_t ordinal;
239+
bool is_tail;
240+
241+
function_exit_construction(uint64_t ordinal, bool is_tail)
242+
: ordinal(ordinal)
243+
, is_tail(is_tail) { }
244+
};
245+
230246
struct call_event_construction {
231247
char const *hook_name;
232248
char const *symbol_name;
@@ -281,6 +297,8 @@ class proof_trace_callback_writer : public proof_trace_writer {
281297
side_condition_result_construction const &event) { }
282298
virtual void pattern_matching_failure_callback(
283299
pattern_matching_failure_construction const &event) { }
300+
virtual void function_exit_callback(function_exit_construction const &event) {
301+
}
284302
virtual void configuration_event_callback(
285303
kore_configuration_construction const &config, bool is_initial) { }
286304

@@ -366,6 +384,11 @@ class proof_trace_callback_writer : public proof_trace_writer {
366384
pattern_matching_failure_callback(pm_failure);
367385
}
368386

387+
void function_exit(uint64_t ordinal, bool is_tail) override {
388+
function_exit_construction function_exit(ordinal, is_tail);
389+
function_exit_callback(function_exit);
390+
}
391+
369392
void configuration(block *config, bool is_initial) override {
370393
kore_configuration_construction configuration(config);
371394
configuration_event_callback(configuration, is_initial);

lib/binary/ProofTraceParser.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ void llvm_pattern_matching_failure_event::print(
8484
"{}pattern matching failure: {}\n", indent, function_name_);
8585
}
8686

87+
void llvm_function_exit_event::print(
88+
std::ostream &out, bool expand_terms, unsigned ind) const {
89+
std::string indent(ind * indent_size, ' ');
90+
out << fmt::format(
91+
"{}function exit: {} {}\n", indent, rule_ordinal_,
92+
(is_tail_ ? "tail" : "notail"));
93+
}
94+
8795
void llvm_function_event::print(
8896
std::ostream &out, bool expand_terms, unsigned ind) const {
8997
std::string indent(ind * indent_size, ' ');

lib/codegen/CreateTerm.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,7 @@ bool can_tail_call(llvm::Type *type) {
11741174
return int_type->getBitWidth() <= 192;
11751175
}
11761176

1177+
// NOLINTNEXTLINE(*-cognitive-complexity)
11771178
bool make_function(
11781179
std::string const &name, kore_pattern *pattern, kore_definition *definition,
11791180
llvm::Module *module, bool tailcc, bool big_step, bool apply,
@@ -1276,6 +1277,10 @@ bool make_function(
12761277
call->setTailCallKind(llvm::CallInst::TCK_MustTail);
12771278
retval = call;
12781279
} else {
1280+
size_t ordinal = 0;
1281+
if (apply) {
1282+
ordinal = std::stoll(name.substr(11));
1283+
}
12791284
if (auto *call = llvm::dyn_cast<llvm::CallInst>(retval)) {
12801285
// check that musttail requirements are met:
12811286
// 1. Call is in tail position (guaranteed)
@@ -1286,6 +1291,22 @@ bool make_function(
12861291
if (call->getCallingConv() == llvm::CallingConv::Tail
12871292
&& can_tail_call(call->getType())) {
12881293
call->setTailCallKind(llvm::CallInst::TCK_MustTail);
1294+
if (apply) {
1295+
current_block
1296+
= proof_event(definition, module)
1297+
.function_exit(
1298+
ordinal, true, llvm::dyn_cast<llvm::Instruction>(call));
1299+
}
1300+
} else {
1301+
if (apply) {
1302+
current_block = proof_event(definition, module)
1303+
.function_exit(ordinal, false, current_block);
1304+
}
1305+
}
1306+
} else {
1307+
if (apply) {
1308+
current_block = proof_event(definition, module)
1309+
.function_exit(ordinal, false, current_block);
12891310
}
12901311
}
12911312
}

lib/codegen/Decision.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ void leaf_node::codegen(decision *d) {
603603
d->current_block_
604604
= proof_event(d->definition_, d->module_)
605605
.rewrite_event_pre(axiom, arity, vars, subst, d->current_block_);
606+
// maybe report here as part of the rule event whether a tail call happened
606607

607608
if (d->profile_matching_) {
608609
llvm::CallInst::Create(

0 commit comments

Comments
 (0)