Migrate from using ast::Module to Program

Enforce all places where Dawn passes in or returns a ast::Module, now takes a `const Program* ` or returns a `Program`.

As the end goal of all this is to have immutable Programs, all Program inputs take a pointer instead of moving the actual object.

As consumers of a Program are now all const, we have to const_cast to work around all the places we've been incorrectly mutating a ast::Module.
These const_casts are temporary, and will be fixed in the next set of changes.

Depends on https://dawn-review.googlesource.com/c/dawn/+/38522

Bug: tint:390
Change-Id: Ie05b112b16134937d1b601e9b713ea4ec4e1c677
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/38541
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton
2021-01-26 16:57:10 +00:00
parent be610ba987
commit c40f627bea
252 changed files with 1978 additions and 2017 deletions

View File

@@ -55,9 +55,9 @@ namespace transform {
BoundArrayAccessors::BoundArrayAccessors() = default;
BoundArrayAccessors::~BoundArrayAccessors() = default;
Transform::Output BoundArrayAccessors::Run(ast::Module* in) {
Transform::Output BoundArrayAccessors::Run(const Program* in) {
Output out;
CloneContext(&out.module, in)
CloneContext(&out.program, in)
.ReplaceAll([&](CloneContext* ctx, ast::ArrayAccessorExpression* expr) {
return Transform(expr, ctx, &out.diagnostics);
})

View File

@@ -19,8 +19,8 @@
#include "src/ast/array_accessor_expression.h"
#include "src/ast/expression.h"
#include "src/ast/module.h"
#include "src/ast/statement.h"
#include "src/program.h"
#include "src/scope_stack.h"
#include "src/transform/transform.h"
@@ -38,13 +38,13 @@ class BoundArrayAccessors : public Transform {
/// Destructor
~BoundArrayAccessors() override;
/// Runs the transform on `module`, returning the transformation result.
/// Runs the transform on `program`, returning the transformation result.
/// @note Users of Tint should register the transform with transform manager
/// and invoke its Run(), instead of directly calling the transform's Run().
/// Calling Run() directly does not perform module state cleanup operations.
/// @param module the source module to transform
/// Calling Run() directly does not perform program state cleanup operations.
/// @param program the source program to transform
/// @returns the transformation result
Output Run(ast::Module* module) override;
Output Run(const Program* program) override;
private:
ast::ArrayAccessorExpression* Transform(ast::ArrayAccessorExpression* expr,

View File

@@ -38,42 +38,42 @@ const char kPointSizeVar[] = "tint_pointsize";
EmitVertexPointSize::EmitVertexPointSize() = default;
EmitVertexPointSize::~EmitVertexPointSize() = default;
Transform::Output EmitVertexPointSize::Run(ast::Module* in) {
Transform::Output EmitVertexPointSize::Run(const Program* in) {
Output out;
if (!in->Functions().HasStage(ast::PipelineStage::kVertex)) {
// If the module doesn't have any vertex stages, then there's nothing to do.
out.module = in->Clone();
out.program = in->Clone();
return out;
}
auto* f32 = out.module.create<type::F32>();
auto* f32 = out.program.create<type::F32>();
// Declare the pointsize builtin output variable.
auto* pointsize_var = out.module.create<ast::Variable>(
Source{}, // source
out.module.RegisterSymbol(kPointSizeVar), // symbol
ast::StorageClass::kOutput, // storage_class
f32, // type
false, // is_const
nullptr, // constructor
auto* pointsize_var = out.program.create<ast::Variable>(
Source{}, // source
out.program.RegisterSymbol(kPointSizeVar), // symbol
ast::StorageClass::kOutput, // storage_class
f32, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{
// decorations
out.module.create<ast::BuiltinDecoration>(Source{},
ast::Builtin::kPointSize),
out.program.create<ast::BuiltinDecoration>(Source{},
ast::Builtin::kPointSize),
});
out.module.AddGlobalVariable(pointsize_var);
out.program.AddGlobalVariable(pointsize_var);
// Build the AST expression & statement for assigning pointsize one.
auto* one = out.module.create<ast::ScalarConstructorExpression>(
Source{}, out.module.create<ast::FloatLiteral>(Source{}, f32, 1.0f));
auto* pointsize_ident = out.module.create<ast::IdentifierExpression>(
Source{}, out.module.RegisterSymbol(kPointSizeVar));
auto* pointsize_assign = out.module.create<ast::AssignmentStatement>(
auto* one = out.program.create<ast::ScalarConstructorExpression>(
Source{}, out.program.create<ast::FloatLiteral>(Source{}, f32, 1.0f));
auto* pointsize_ident = out.program.create<ast::IdentifierExpression>(
Source{}, out.program.RegisterSymbol(kPointSizeVar));
auto* pointsize_assign = out.program.create<ast::AssignmentStatement>(
Source{}, pointsize_ident, one);
// Add the pointsize assignment statement to the front of all vertex stages.
CloneContext(&out.module, in)
CloneContext(&out.program, in)
.ReplaceAll(
[&](CloneContext* ctx, ast::Function* func) -> ast::Function* {
if (func->pipeline_stage() != ast::PipelineStage::kVertex) {

View File

@@ -21,10 +21,10 @@ namespace tint {
namespace transform {
/// EmitVertexPointSize is a Transform that adds a PointSize builtin global
/// output variable to the module which is assigned 1.0 as the new first
/// output variable to the program which is assigned 1.0 as the new first
/// statement for all vertex stage entry points.
/// If the module does not contain a vertex pipeline stage entry point then then
/// this transform is a no-op.
/// If the program does not contain a vertex pipeline stage entry point then
/// then this transform is a no-op.
class EmitVertexPointSize : public Transform {
public:
/// Constructor
@@ -32,13 +32,13 @@ class EmitVertexPointSize : public Transform {
/// Destructor
~EmitVertexPointSize() override;
/// Runs the transform on `module`, returning the transformation result.
/// Runs the transform on `program`, returning the transformation result.
/// @note Users of Tint should register the transform with transform manager
/// and invoke its Run(), instead of directly calling the transform's Run().
/// Calling Run() directly does not perform module state cleanup operations.
/// @param module the source module to transform
/// Calling Run() directly does not perform program state cleanup operations.
/// @param program the source program to transform
/// @returns the transformation result
Output Run(ast::Module* module) override;
Output Run(const Program* program) override;
};
} // namespace transform

View File

@@ -81,11 +81,11 @@ FirstIndexOffset::FirstIndexOffset(uint32_t binding, uint32_t group)
FirstIndexOffset::~FirstIndexOffset() = default;
Transform::Output FirstIndexOffset::Run(ast::Module* in) {
Transform::Output FirstIndexOffset::Run(const Program* in) {
// First do a quick check to see if the transform has already been applied.
for (ast::Variable* var : in->global_variables()) {
if (auto* dec_var = var->As<ast::Variable>()) {
if (dec_var->symbol() == in->RegisterSymbol(kBufferName)) {
if (dec_var->symbol() == in->GetSymbol(kBufferName)) {
diag::Diagnostic err;
err.message = "First index offset transform has already been applied.";
err.severity = diag::Severity::Error;
@@ -99,7 +99,8 @@ Transform::Output FirstIndexOffset::Run(ast::Module* in) {
// Running TypeDeterminer as we require local_referenced_builtin_variables()
// to be populated. TODO(bclayton) - it should not be necessary to re-run the
// type determiner if semantic information is already generated. Remove.
TypeDeterminer td(in);
// TODO(https://crbug.com/tint/390): Remove this const_cast hack!
TypeDeterminer td(const_cast<Program*>(in));
if (!td.Determine()) {
diag::Diagnostic err;
err.severity = diag::Severity::Error;
@@ -115,9 +116,9 @@ Transform::Output FirstIndexOffset::Run(ast::Module* in) {
// Lazilly construct the UniformBuffer on first call to
// maybe_create_buffer_var()
ast::Variable* buffer_var = nullptr;
auto maybe_create_buffer_var = [&](ast::Module* mod) {
auto maybe_create_buffer_var = [&](Program* program) {
if (buffer_var == nullptr) {
buffer_var = AddUniformBuffer(mod);
buffer_var = AddUniformBuffer(program);
}
};
@@ -126,7 +127,7 @@ Transform::Output FirstIndexOffset::Run(ast::Module* in) {
// these builtins.
Output out;
CloneContext(&out.module, in)
CloneContext(&out.program, in)
.ReplaceAll([&](CloneContext* ctx, ast::Variable* var) -> ast::Variable* {
for (ast::VariableDecoration* dec : var->decorations()) {
if (auto* blt_dec = dec->As<ast::BuiltinDecoration>()) {
@@ -194,16 +195,16 @@ uint32_t FirstIndexOffset::GetFirstInstanceOffset() {
return instance_index_offset_;
}
ast::Variable* FirstIndexOffset::AddUniformBuffer(ast::Module* mod) {
auto* u32_type = mod->create<type::U32>();
ast::Variable* FirstIndexOffset::AddUniformBuffer(Program* dst) {
auto* u32_type = dst->create<type::U32>();
ast::StructMemberList members;
uint32_t offset = 0;
if (has_vertex_index_) {
ast::StructMemberDecorationList member_dec;
member_dec.push_back(
mod->create<ast::StructMemberOffsetDecoration>(Source{}, offset));
members.push_back(mod->create<ast::StructMember>(
Source{}, mod->RegisterSymbol(kFirstVertexName), u32_type,
dst->create<ast::StructMemberOffsetDecoration>(Source{}, offset));
members.push_back(dst->create<ast::StructMember>(
Source{}, dst->RegisterSymbol(kFirstVertexName), u32_type,
std::move(member_dec)));
vertex_index_offset_ = offset;
offset += 4;
@@ -212,36 +213,36 @@ ast::Variable* FirstIndexOffset::AddUniformBuffer(ast::Module* mod) {
if (has_instance_index_) {
ast::StructMemberDecorationList member_dec;
member_dec.push_back(
mod->create<ast::StructMemberOffsetDecoration>(Source{}, offset));
members.push_back(mod->create<ast::StructMember>(
Source{}, mod->RegisterSymbol(kFirstInstanceName), u32_type,
dst->create<ast::StructMemberOffsetDecoration>(Source{}, offset));
members.push_back(dst->create<ast::StructMember>(
Source{}, dst->RegisterSymbol(kFirstInstanceName), u32_type,
std::move(member_dec)));
instance_index_offset_ = offset;
offset += 4;
}
ast::StructDecorationList decos;
decos.push_back(mod->create<ast::StructBlockDecoration>(Source{}));
decos.push_back(dst->create<ast::StructBlockDecoration>(Source{}));
auto* struct_type = mod->create<type::Struct>(
mod->RegisterSymbol(kStructName),
mod->create<ast::Struct>(Source{}, std::move(members), std::move(decos)));
auto* struct_type = dst->create<type::Struct>(
dst->RegisterSymbol(kStructName),
dst->create<ast::Struct>(Source{}, std::move(members), std::move(decos)));
auto* idx_var = mod->create<ast::Variable>(
auto* idx_var = dst->create<ast::Variable>(
Source{}, // source
mod->RegisterSymbol(kBufferName), // symbol
dst->RegisterSymbol(kBufferName), // symbol
ast::StorageClass::kUniform, // storage_class
struct_type, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{
mod->create<ast::BindingDecoration>(Source{}, binding_),
mod->create<ast::GroupDecoration>(Source{}, group_),
dst->create<ast::BindingDecoration>(Source{}, binding_),
dst->create<ast::GroupDecoration>(Source{}, group_),
}); // decorations
mod->AddGlobalVariable(idx_var);
dst->AddGlobalVariable(idx_var);
mod->AddConstructedType(struct_type);
dst->AddConstructedType(struct_type);
return idx_var;
}
@@ -250,28 +251,28 @@ ast::VariableDeclStatement* FirstIndexOffset::CreateFirstIndexOffset(
const std::string& original_name,
const std::string& field_name,
ast::Variable* buffer_var,
ast::Module* mod) {
Program* dst) {
auto* buffer =
mod->create<ast::IdentifierExpression>(Source{}, buffer_var->symbol());
dst->create<ast::IdentifierExpression>(Source{}, buffer_var->symbol());
auto lhs_name = kIndexOffsetPrefix + original_name;
auto* constructor = mod->create<ast::BinaryExpression>(
auto* constructor = dst->create<ast::BinaryExpression>(
Source{}, ast::BinaryOp::kAdd,
mod->create<ast::IdentifierExpression>(Source{},
mod->RegisterSymbol(lhs_name)),
mod->create<ast::MemberAccessorExpression>(
dst->create<ast::IdentifierExpression>(Source{},
dst->RegisterSymbol(lhs_name)),
dst->create<ast::MemberAccessorExpression>(
Source{}, buffer,
mod->create<ast::IdentifierExpression>(
Source{}, mod->RegisterSymbol(field_name))));
dst->create<ast::IdentifierExpression>(
Source{}, dst->RegisterSymbol(field_name))));
auto* var =
mod->create<ast::Variable>(Source{}, // source
mod->RegisterSymbol(original_name), // symbol
dst->create<ast::Variable>(Source{}, // source
dst->RegisterSymbol(original_name), // symbol
ast::StorageClass::kNone, // storage_class
mod->create<type::U32>(), // type
dst->create<type::U32>(), // type
true, // is_const
constructor, // constructor
ast::VariableDecorationList{}); // decorations
return mod->create<ast::VariableDeclStatement>(Source{}, var);
return dst->create<ast::VariableDeclStatement>(Source{}, var);
}
} // namespace transform

View File

@@ -17,8 +17,8 @@
#include <string>
#include "src/ast/module.h"
#include "src/ast/variable_decl_statement.h"
#include "src/program.h"
#include "src/symbol.h"
#include "src/transform/transform.h"
@@ -68,13 +68,13 @@ class FirstIndexOffset : public Transform {
FirstIndexOffset(uint32_t binding, uint32_t group);
~FirstIndexOffset() override;
/// Runs the transform on `module`, returning the transformation result.
/// Runs the transform on `program`, returning the transformation result.
/// @note Users of Tint should register the transform with transform manager
/// and invoke its Run(), instead of directly calling the transform's Run().
/// Calling Run() directly does not perform module state cleanup operations.
/// @param module the source module to transform
/// Calling Run() directly does not perform program state cleanup operations.
/// @param program the source program to transform
/// @returns the transformation result
Output Run(ast::Module* module) override;
Output Run(const Program* program) override;
/// @returns whether shader uses vertex_index
bool HasVertexIndex();
@@ -89,19 +89,19 @@ class FirstIndexOffset : public Transform {
uint32_t GetFirstInstanceOffset();
private:
/// Adds uniform buffer with firstVertex/Instance to module
/// Adds uniform buffer with firstVertex/Instance to `program`
/// @returns variable of new uniform buffer
ast::Variable* AddUniformBuffer(ast::Module* mod);
ast::Variable* AddUniformBuffer(Program* program);
/// Adds constant with modified original_name builtin to func
/// @param original_name the name of the original builtin used in function
/// @param field_name name of field in firstVertex/Instance buffer
/// @param buffer_var variable of firstVertex/Instance buffer
/// @param module the target module to contain the new ast nodes
/// @param program the target program to contain the new ast nodes
ast::VariableDeclStatement* CreateFirstIndexOffset(
const std::string& original_name,
const std::string& field_name,
ast::Variable* buffer_var,
ast::Module* module);
Program* program);
uint32_t binding_;
uint32_t group_;

View File

@@ -22,23 +22,23 @@ namespace transform {
Manager::Manager() = default;
Manager::~Manager() = default;
Transform::Output Manager::Run(ast::Module* module) {
Transform::Output Manager::Run(const Program* program) {
Output out;
if (!transforms_.empty()) {
for (auto& transform : transforms_) {
auto res = transform->Run(module);
out.module = std::move(res.module);
auto res = transform->Run(program);
out.program = std::move(res.program);
out.diagnostics.add(std::move(res.diagnostics));
if (out.diagnostics.contains_errors()) {
return out;
}
module = &out.module;
program = &out.program;
}
} else {
out.module = module->Clone();
out.program = program->Clone();
}
TypeDeterminer td(&out.module);
TypeDeterminer td(&out.program);
if (!td.Determine()) {
diag::Diagnostic err;
err.severity = diag::Severity::Error;

View File

@@ -41,18 +41,10 @@ class Manager : public Transform {
transforms_.push_back(std::move(transform));
}
/// Runs the transforms on `module`, returning the transformation result.
/// @param module the source module to transform
/// @returns the transformed module and diagnostics
Output Run(ast::Module* module) override;
/// Runs the transform on `program`, returning the transformation result.
/// @note Users of Tint should register the transform with transform manager
/// and invoke its Run(), instead of directly calling the transform's Run().
/// Calling Run() directly does not perform program state cleanup operations.
/// Runs the transforms on `program`, returning the transformation result.
/// @param program the source program to transform
/// @returns the transformation result
Output Run(Program* program) { return Run(&program->module); }
/// @returns the transformed program and diagnostics
Output Run(const Program* program) override;
private:
std::vector<std::unique_ptr<Transform>> transforms_;

View File

@@ -46,8 +46,8 @@ class TransformTest : public testing::Test {
return "WGSL reader failed:\n" + parser.error();
}
auto module = parser.module();
TypeDeterminer td(&module);
auto program = parser.program();
TypeDeterminer td(&program);
if (!td.Determine()) {
return "Type determination failed:\n" + td.error();
}
@@ -56,7 +56,7 @@ class TransformTest : public testing::Test {
for (auto& transform : transforms) {
manager.append(std::move(transform));
}
auto result = manager.Run(&module);
auto result = manager.Run(&program);
if (result.diagnostics.contains_errors()) {
diag::Formatter::Style style;
@@ -65,10 +65,10 @@ class TransformTest : public testing::Test {
diag::Formatter(style).format(result.diagnostics);
}
// Release the source module to ensure there's no uncloned data in result
{ auto tmp = std::move(module); }
// Release the source program to ensure there's no uncloned data in result
{ auto tmp = std::move(program); }
writer::wgsl::Generator generator(std::move(result.module));
writer::wgsl::Generator generator(&result.program);
if (!generator.Generate()) {
return "WGSL writer failed:\n" + generator.error();
}

View File

@@ -23,22 +23,16 @@ namespace transform {
Transform::Output::Output() = default;
Transform::Output::Output(ast::Module&& mod) : program{std::move(mod)} {}
Transform::Output::Output(Program&& p) : program(std::move(p)) {}
Transform::Output::Output(ast::Module&& mod, diag::List&& d)
: program{std::move(mod)}, diagnostics(std::move(d)) {}
Transform::Output::Output(Program&& p, diag::List&& d)
: program(std::move(p)), diagnostics(std::move(d)) {}
Transform::Output::~Output() = default;
Transform::Output::Output(Output&& rhs)
: program(std::move(rhs.program)),
diagnostics(std::move(rhs.diagnostics)) {}
Transform::Output::Output(Output&&) = default;
Transform::Output& Transform::Output::operator=(Output&& rhs) {
program = std::move(rhs.program);
diagnostics = std::move(rhs.diagnostics);
return *this;
}
Transform::Output& Transform::Output::operator=(Output&& rhs) = default;
Transform::Transform() = default;

View File

@@ -19,14 +19,13 @@
#include <string>
#include <utility>
#include "src/ast/module.h"
#include "src/diagnostic/diagnostic.h"
#include "src/program.h"
namespace tint {
namespace transform {
/// Interface for ast::Module transforms
/// Interface for Program transforms
class Transform {
public:
/// Constructor
@@ -40,13 +39,13 @@ class Transform {
Output();
/// Constructor
/// @param module the module to move into this Output
explicit Output(ast::Module&& module);
/// @param program the program to move into this Output
explicit Output(Program&& program);
/// Constructor
/// @param module the module to move into this Output
/// @param program the program to move into this Output
/// @param diags the list of diagnostics to move into this Output
Output(ast::Module&& module, diag::List&& diags);
Output(Program&& program, diag::List&& diags);
/// Move constructor
/// @param output the output to move into this Output
@@ -64,25 +63,15 @@ class Transform {
Program program;
/// Diagnostics raised while running the Transform.
diag::List diagnostics;
/// The transformed module. May be empty on error.
ast::Module& module{program.module};
};
/// Runs the transform on `module`, returning the transformation result.
/// @note Users of Tint should register the transform with transform manager
/// and invoke its Run(), instead of directly calling the transform's Run().
/// Calling Run() directly does not perform module state cleanup operations.
/// @param module the source module to transform
/// @returns the transformation result
virtual Output Run(ast::Module* module) = 0;
/// Runs the transform on `program`, returning the transformation result.
/// @note Users of Tint should register the transform with transform manager
/// and invoke its Run(), instead of directly calling the transform's Run().
/// Calling Run() directly does not perform program state cleanup operations.
/// @param program the source program to transform
/// @returns the transformation result
Output Run(Program* program) { return Run(&program->module); }
virtual Output Run(const Program* program) = 0;
protected:
/// Clones the function `in` adding `statements` to the beginning of the

View File

@@ -73,7 +73,7 @@ void VertexPulling::SetPullingBufferBindingSet(uint32_t number) {
cfg.pulling_group = number;
}
Transform::Output VertexPulling::Run(ast::Module* in) {
Transform::Output VertexPulling::Run(const Program* in) {
// Check SetVertexState was called
if (!cfg.vertex_state_set) {
diag::Diagnostic err;
@@ -103,13 +103,13 @@ Transform::Output VertexPulling::Run(ast::Module* in) {
// following stages will pass
Output out;
State state{in, &out.module, cfg};
State state{in, &out.program, cfg};
state.FindOrInsertVertexIndexIfUsed();
state.FindOrInsertInstanceIndexIfUsed();
state.ConvertVertexInputVariablesToPrivate();
state.AddVertexStorageBuffers();
CloneContext(&out.module, in)
CloneContext(&out.program, in)
.ReplaceAll([&](CloneContext* ctx, ast::Function* f) -> ast::Function* {
if (f == func) {
return CloneWithStatementsAtStart(
@@ -126,7 +126,7 @@ VertexPulling::Config::Config() = default;
VertexPulling::Config::Config(const Config&) = default;
VertexPulling::Config::~Config() = default;
VertexPulling::State::State(ast::Module* i, ast::Module* o, const Config& c)
VertexPulling::State::State(const Program* i, Program* o, const Config& c)
: in(i), out(o), cfg(c) {}
VertexPulling::State::State(const State&) = default;
@@ -231,7 +231,8 @@ void VertexPulling::State::FindOrInsertInstanceIndexIfUsed() {
}
void VertexPulling::State::ConvertVertexInputVariablesToPrivate() {
for (auto*& v : in->global_variables()) {
// TODO(https://crbug.com/tint/390): Remove this const_cast hack!
for (auto*& v : const_cast<Program*>(in)->global_variables()) {
if (v->storage_class() != ast::StorageClass::kInput) {
continue;
}

View File

@@ -22,9 +22,9 @@
#include "src/ast/expression.h"
#include "src/ast/function.h"
#include "src/ast/module.h"
#include "src/ast/statement.h"
#include "src/ast/variable.h"
#include "src/program.h"
#include "src/transform/transform.h"
namespace tint {
@@ -114,7 +114,7 @@ struct VertexBufferLayoutDescriptor {
/// attributes
using VertexStateDescriptor = std::vector<VertexBufferLayoutDescriptor>;
/// Converts a module to use vertex pulling
/// Converts a program to use vertex pulling
///
/// Variables which accept vertex input are var<in> with a location decoration.
/// This transform will convert those to be assigned from storage buffers
@@ -159,13 +159,13 @@ class VertexPulling : public Transform {
/// @param number the group number we will use
void SetPullingBufferBindingGroup(uint32_t number);
/// Runs the transform on `module`, returning the transformation result.
/// Runs the transform on `program`, returning the transformation result.
/// @note Users of Tint should register the transform with transform manager
/// and invoke its Run(), instead of directly calling the transform's Run().
/// Calling Run() directly does not perform module state cleanup operations.
/// @param module the source module to transform
/// Calling Run() directly does not perform program state cleanup operations.
/// @param program the source program to transform
/// @returns the transformation result
Output Run(ast::Module* module) override;
Output Run(const Program* program) override;
private:
struct Config {
@@ -183,7 +183,7 @@ class VertexPulling : public Transform {
Config cfg;
struct State {
State(ast::Module* in, ast::Module* out, const Config& c);
State(const Program* in, Program* out, const Config& c);
explicit State(const State&);
~State();
@@ -263,8 +263,8 @@ class VertexPulling : public Transform {
type::Type* GetI32Type() const;
type::Type* GetF32Type() const;
ast::Module* const in;
ast::Module* const out;
const Program* const in;
Program* const out;
Config const cfg;
std::unordered_map<uint32_t, ast::Variable*> location_to_var;