Jlm
Loading...
Searching...
No Matches
instrument-ref.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 David Metz <david.c.metz@ntnu.no>
3 * See COPYING for terms of redistribution.
4 */
5
14#include <jlm/rvsdg/gamma.hpp>
16
17#include <cmath>
18
19namespace jlm::hls
20{
21
22rvsdg::LambdaNode *
23change_function_name(rvsdg::LambdaNode * ln, const std::string & name)
24{
25 const auto & op = dynamic_cast<llvm::LlvmLambdaOperation &>(ln->GetOperation());
26 auto lambda = rvsdg::LambdaNode::Create(
27 *ln->region(),
29 op.Type(),
30 name,
31 op.linkage(),
32 op.callingConvention(),
33 op.attributes()));
34
35 /* add context variables */
37 for (const auto & cv : ln->GetContextVars())
38 {
39 auto origin = cv.input->origin();
40 auto newcv = lambda->AddContextVar(*origin);
41 subregionmap.insert(cv.inner, newcv.inner);
42 }
43 /* collect function arguments */
44 auto args = ln->GetFunctionArguments();
45 auto newArgs = lambda->GetFunctionArguments();
46 JLM_ASSERT(args.size() == newArgs.size());
47 for (std::size_t n = 0; n < args.size(); ++n)
48 {
49 subregionmap.insert(args[n], newArgs[n]);
50 }
51
52 /* copy subregion */
53 ln->subregion()->copy(lambda->subregion(), subregionmap);
54
55 /* collect function results */
56 std::vector<jlm::rvsdg::Output *> results;
57 for (auto result : ln->GetFunctionResults())
58 results.push_back(&subregionmap.lookup(*result->origin()));
59
60 /* finalize lambda */
61 lambda->finalize(results);
62
63 divert_users(ln, outputs(lambda));
65
66 return lambda;
67}
68
69void
71{
72 auto & graph = rm.Rvsdg();
73 auto root = &graph.GetRootRegion();
74 auto lambda = dynamic_cast<rvsdg::LambdaNode *>(root->Nodes().begin().ptr());
75
76 auto newLambda = change_function_name(lambda, "instrumented_ref");
77
78 auto functionType = newLambda->GetOperation().type();
79 auto numArguments = functionType.NumArguments();
80 if (numArguments == 0)
81 {
82 // The lambda has no arguments so it shouldn't have any memory operations
83 return;
84 }
85
88 {
89 // The lambda has no memory state so it shouldn't have any memory operations
90 return;
91 }
92 // The function should always have an IO state if it has a memory state
95
96 // addr, width, memstate
104 graph,
106 "reference_load",
110 graph,
112 "reference_store",
115 // addr, size, memstate
123 graph,
125 "reference_alloca",
128
130 root,
131 newLambda->subregion()->argument(ioStateArgumentIndex),
138}
139
140void
142 rvsdg::Region * region,
145 const std::shared_ptr<const jlm::rvsdg::FunctionType> & loadFunctionType,
147 const std::shared_ptr<const jlm::rvsdg::FunctionType> & storeFunctionType,
149 const std::shared_ptr<const jlm::rvsdg::FunctionType> & allocaFunctionType)
150{
155 for (auto & node : rvsdg::TopDownTraverser(region))
156 {
157 if (auto structnode = dynamic_cast<rvsdg::StructuralNode *>(node))
158 {
159 for (size_t n = 0; n < structnode->nsubregions(); n++)
160 {
161 auto subregion = structnode->subregion(n);
162 auto ioStateRouted = &rvsdg::RouteToRegion(*ioState, *subregion);
164 subregion,
166 load_func,
172 }
173 }
174 else if (
175 auto loadOp =
176 dynamic_cast<const jlm::llvm::LoadNonVolatileOperation *>(&(node->GetOperation())))
177 {
178 auto addr = node->input(0)->origin();
180 size_t bitWidth = BaseHLS::JlmSize(&*loadOp->GetLoadedType());
181 int log2Bytes = log2(bitWidth / 8);
183
184 // Does this IF make sense now when the void_ptr doesn't have a type?
185 if (*addr->Type() != *void_ptr)
186 {
188 }
189 auto memstate = node->input(1)->origin();
191 load_func,
193 { addr, widthNode.output(0), ioState, memstate });
194 // Divert the memory state of the load to the new memstate from the call operation
195 node->input(1)->divert_to(callOp[1]);
196 }
197 else if (auto ao = dynamic_cast<const jlm::llvm::AllocaOperation *>(&(node->GetOperation())))
198 {
199 // ensure that the size is one
200 JLM_ASSERT(node->ninputs() == 1);
201 auto constant_output = dynamic_cast<rvsdg::NodeOutput *>(node->input(0)->origin());
203 auto constant_operation = dynamic_cast<const llvm::IntegerConstantOperation *>(
204 &constant_output->node()->GetOperation());
206 JLM_ASSERT(constant_operation->Representation().to_uint() == 1);
207 jlm::rvsdg::Output * addr = node->output(0);
208 // ensure that the alloca is an array type
210 auto at = dynamic_cast<const llvm::ArrayType *>(ao->allocatedType().get());
211 JLM_ASSERT(at);
212 auto & sizeNode =
214
215 // Does this IF make sense now when the void_ptr doesn't have a type?
216 if (*addr->Type() != *void_ptr)
217 {
219 }
220 std::vector<jlm::rvsdg::Input *> old_users;
221 for (auto & user : node->output(1)->Users())
222 old_users.push_back(&user);
223 auto memstate = node->output(1);
227 { addr, sizeNode.output(0), ioState, memstate });
228 for (auto ou : old_users)
229 {
230 // Divert the memory state of the load to the new memstate from the call operation
231 ou->divert_to(callOp[1]);
232 }
233 }
234 else if (
235 auto so =
236 dynamic_cast<const jlm::llvm::StoreNonVolatileOperation *>(&(node->GetOperation())))
237 {
238 auto addr = node->input(0)->origin();
240 auto bitWidth = JlmSize(&so->GetStoredType());
241 int log2Bytes = log2(bitWidth / 8);
243
244 // Does this IF make sense now when the void_ptr doesn't have a type?
245 if (*addr->Type() != *void_ptr)
246 {
248 }
249 auto memstate = node->output(0);
250 std::vector<jlm::rvsdg::Input *> oldUsers;
251 for (auto & user : memstate->Users())
252 oldUsers.push_back(&user);
256 { addr, widthNode.output(0), ioState, memstate });
257 // Divert the memory state after the store to the new memstate from the call operation
258 for (auto user : oldUsers)
259 {
260 user->divert_to(callOp[1]);
261 }
262 }
263 }
264}
265
266} // namespace jlm::hls
static int JlmSize(const jlm::rvsdg::Type *type)
Definition base-hls.cpp:110
static jlm::rvsdg::Output * create(jlm::rvsdg::Output *operand, std::shared_ptr< const jlm::rvsdg::Type > rtype)
static std::vector< rvsdg::Output * > Create(rvsdg::Output *function, std::shared_ptr< const rvsdg::FunctionType > functionType, const std::vector< rvsdg::Output * > &arguments)
Definition call.hpp:464
static std::shared_ptr< const IOStateType > Create()
Definition types.cpp:343
static rvsdg::Node & Create(rvsdg::Region &region, IntegerValueRepresentation representation)
static LlvmGraphImport & createFunctionImport(rvsdg::Graph &graph, std::shared_ptr< const rvsdg::FunctionType > functionType, std::string name, Linkage linkage, CallingConvention callingConvention)
static std::unique_ptr< LlvmLambdaOperation > Create(std::shared_ptr< const jlm::rvsdg::FunctionType > type, std::string name, const jlm::llvm::Linkage &linkage, jlm::llvm::CallingConvention callingConvention, jlm::llvm::AttributeSet attributes)
Definition lambda.hpp:84
static std::shared_ptr< const MemoryStateType > Create()
Definition types.cpp:379
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition type.cpp:45
static std::shared_ptr< const FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type > > argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type > > resultTypes)
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
void insert(const Output *original, Output *substitute)
#define JLM_ASSERT(x)
Definition common.hpp:16
rvsdg::LambdaNode * change_function_name(rvsdg::LambdaNode *ln, const std::string &name)
int JlmSize(const jlm::rvsdg::Type *type)
Definition hls.cpp:344
static void divert_users(jlm::rvsdg::Output *output, Context &ctx)
Definition cne.cpp:504
void instrument_ref(llvm::LlvmRvsdgModule &rm)
static void remove(Node *node)
Definition region.hpp:1035
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition node.hpp:1058
Output & RouteToRegion(Output &output, Region &region)
Definition node.cpp:381
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
detail::TopDownTraverserGeneric< false > TopDownTraverser
Traverser for visiting every node in a region in a top down order.