CIRCT 24.0.0git
Loading...
Searching...
No Matches
BMCTrace.cpp
Go to the documentation of this file.
1//===- BMCTrace.cpp -------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/SmallString.h"
13#include <cassert>
14
15circt::bmc::BMCTrace::BMCTrace(llvm::StringRef topName) : topName(topName) {}
16
17size_t circt::bmc::BMCTrace::addSignal(llvm::StringRef name, unsigned width) {
18 assert(!signalIndices.contains(name) && "duplicate trace signal");
19 signalIndices.try_emplace(name, signals.size());
20 signals.push_back({name.str(), width});
21 for (auto &step : recorded)
22 step.resize(signals.size());
23 return signals.size() - 1;
24}
25
27 if (step >= recorded.size())
28 recorded.resize(step + 1, Step(signals.size()));
29}
30
31void circt::bmc::BMCTrace::record(size_t step, size_t signal, Handle handle) {
32 assert(signal < signals.size() && "signal index out of range");
33 ensureStep(step);
34 recorded[step][signal] = handle;
35}
36
37void circt::bmc::BMCTrace::record(size_t step, llvm::StringRef name,
38 unsigned width, Handle handle) {
39 auto it = signalIndices.find(name);
40 size_t signal;
41 if (it == signalIndices.end()) {
42 signal = addSignal(name, width);
43 } else {
44 signal = it->second;
45 assert(signals[signal].width == width && "trace signal width changed");
46 }
47 record(step, signal, handle);
48}
49
50std::optional<circt::bmc::BMCTrace::Handle>
51circt::bmc::BMCTrace::lookup(size_t step, size_t signal) const {
52 if (step >= recorded.size() || signal >= signals.size())
53 return std::nullopt;
54 return recorded[step][signal];
55}
56
57bool circt::bmc::BMCTrace::printTextTrace(llvm::raw_ostream &os,
58 Evaluator evaluate) const {
59 os << "counterexample for " << topName << ":\n";
60 for (size_t step = 0, e = recorded.size(); step != e; ++step) {
61 os << "cycle " << step << ":\n";
62 for (size_t signal = 0, numSignals = signals.size(); signal != numSignals;
63 ++signal) {
64 auto handle = recorded[step][signal];
65 if (!handle)
66 return false;
67 auto value = evaluate(*handle, signals[signal].width);
68 if (!value || value->getBitWidth() != signals[signal].width)
69 return false;
70 llvm::SmallString<40> str;
71 value->toString(str, /*Radix=*/16, /*Signed=*/false,
72 /*formatAsCLiteral=*/false, /*UpperCase=*/false);
73 os << " " << signals[signal].name << " = 0x" << str << "\n";
74 }
75 }
76 return true;
77}
78
80 llvm::raw_ostream &os, Handle context, Handle model, ModelEval modelEval,
81 GetNumeralBinaryString getNumeralBinaryString) const {
82 if (!context || !model || !modelEval || !getNumeralBinaryString)
83 return false;
84
85 return printTextTrace(
86 os, [&](Handle expression, unsigned width) -> std::optional<llvm::APInt> {
87 // Z3 does not represent zero-width bit-vectors. Preserve the runtime's
88 // i0 behavior without asking Z3 to evaluate such a value.
89 if (width == 0)
90 return llvm::APInt(0, uint64_t{0});
91
92 Handle value = nullptr;
93 if (!modelEval(context, model, expression, /*modelCompletion=*/true,
94 &value) ||
95 !value)
96 return std::nullopt;
97
98 const char *binaryString = getNumeralBinaryString(context, value);
99 if (!binaryString)
100 return std::nullopt;
101 llvm::StringRef digits(binaryString);
102 digits.consume_front("#b");
103 if (digits.empty() || digits.size() > width ||
104 llvm::any_of(digits, [](char digit) {
105 return digit != '0' && digit != '1';
106 }))
107 return std::nullopt;
108 return llvm::APInt(width, digits, 2);
109 });
110}
111
113 uint32_t step,
114 const char *name,
115 uint32_t width,
116 BMCTrace::Handle handle) {
117 if (!trace)
118 return;
119 trace->record(step, name, width, handle);
120}
121
124 BMCTrace::ModelEval modelEval,
125 BMCTrace::GetNumeralBinaryString getNumeralBinaryString) {
126 if (!trace)
127 return false;
128 if (!trace->printTextTrace(llvm::outs(), context, model, modelEval,
129 getNumeralBinaryString)) {
130 llvm::errs() << "failed to evaluate BMC counterexample trace\n";
131 return false;
132 }
133 return true;
134}
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
bool printTextTrace(llvm::raw_ostream &os, Evaluator evaluate) const
Render the trace as cycle-by-cycle text using the provided evaluator to materialize values from recor...
Definition BMCTrace.cpp:57
const char *(*)(Handle context, Handle value) GetNumeralBinaryString
Definition BMCTrace.h:44
void ensureStep(size_t step)
Definition BMCTrace.cpp:26
BMCTrace(llvm::StringRef topName="bmc")
Create an empty trace for the given top-level design/module name.
Definition BMCTrace.cpp:15
const void * Handle
Opaque per-signal value reference recorded for a specific cycle.
Definition BMCTrace.h:33
size_t addSignal(llvm::StringRef name, unsigned width)
Register a signal to be tracked and return its stable index.
Definition BMCTrace.cpp:17
std::vector< std::optional< Handle > > Step
Per-cycle storage for all tracked signals.
Definition BMCTrace.h:81
llvm::function_ref< std::optional< llvm::APInt >(Handle, unsigned width)> Evaluator
Callback used to materialize a recorded handle into a concrete value when formatting a trace.
Definition BMCTrace.h:38
void record(size_t step, size_t signal, Handle handle)
Record the value handle for a tracked signal at the given cycle.
Definition BMCTrace.cpp:31
std::optional< Handle > lookup(size_t step, size_t signal) const
Return the recorded handle for a signal at a given cycle, if present.
Definition BMCTrace.cpp:51
bool(*)(Handle context, Handle model, Handle expression, bool modelCompletion, Handle *value) ModelEval
Z3 API callbacks passed in by JIT-compiled code.
Definition BMCTrace.h:43
bool circt_bmc_print_trace(BMCTrace *trace, BMCTrace::Handle context, BMCTrace::Handle model, BMCTrace::ModelEval modelEval, BMCTrace::GetNumeralBinaryString getNumeralBinaryString)
Runtime entry point called on the SAT path while the Z3 context and model are still alive.
Definition BMCTrace.cpp:122
void circt_bmc_record_trace(BMCTrace *trace, uint32_t step, const char *name, uint32_t width, BMCTrace::Handle handle)
Runtime entry point called by JIT-compiled BMC code.
Definition BMCTrace.cpp:112