[tint][ir] Use 'const' on non-mutating IR consumers
Change-Id: Ieee80631de6c522c7679ca7816726a408b30682d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/161012
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index 6147550..e505e1f 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -87,11 +87,11 @@
} // namespace
-std::string Disassemble(Module& mod) {
+std::string Disassemble(const Module& mod) {
return Disassembler{mod}.Disassemble();
}
-Disassembler::Disassembler(Module& mod) : mod_(mod) {}
+Disassembler::Disassembler(const Module& mod) : mod_(mod) {}
Disassembler::~Disassembler() = default;
@@ -108,12 +108,12 @@
current_output_start_pos_ = out_.tellp();
}
-size_t Disassembler::IdOf(Block* node) {
+size_t Disassembler::IdOf(const Block* node) {
TINT_ASSERT(node);
return block_ids_.GetOrCreate(node, [&] { return block_ids_.Count(); });
}
-std::string Disassembler::IdOf(Value* value) {
+std::string Disassembler::IdOf(const Value* value) {
TINT_ASSERT(value);
return value_ids_.GetOrCreate(value, [&] {
if (auto sym = mod_.NameOf(value)) {
@@ -132,7 +132,7 @@
});
}
-std::string Disassembler::NameOf(If* inst) {
+std::string Disassembler::NameOf(const If* inst) {
if (!inst) {
return "undef";
}
@@ -140,7 +140,7 @@
return if_names_.GetOrCreate(inst, [&] { return "if_" + std::to_string(if_names_.Count()); });
}
-std::string Disassembler::NameOf(Loop* inst) {
+std::string Disassembler::NameOf(const Loop* inst) {
if (!inst) {
return "undef";
}
@@ -149,7 +149,7 @@
[&] { return "loop_" + std::to_string(loop_names_.Count()); });
}
-std::string Disassembler::NameOf(Switch* inst) {
+std::string Disassembler::NameOf(const Switch* inst) {
if (!inst) {
return "undef";
}
@@ -180,7 +180,7 @@
return out_.str();
}
-void Disassembler::EmitBlock(Block* blk, std::string_view comment /* = "" */) {
+void Disassembler::EmitBlock(const Block* blk, std::string_view comment /* = "" */) {
Indent();
SourceMarker sm(this);
@@ -229,7 +229,7 @@
}
}
-void Disassembler::EmitParamAttributes(FunctionParam* p) {
+void Disassembler::EmitParamAttributes(const FunctionParam* p) {
if (!p->Invariant() && !p->Location().has_value() && !p->BindingPoint().has_value() &&
!p->Builtin().has_value()) {
return;
@@ -266,7 +266,7 @@
out_ << "]";
}
-void Disassembler::EmitReturnAttributes(Function* func) {
+void Disassembler::EmitReturnAttributes(const Function* func) {
if (!func->ReturnInvariant() && !func->ReturnLocation().has_value() &&
!func->ReturnBuiltin().has_value()) {
return;
@@ -298,7 +298,7 @@
out_ << "]";
}
-void Disassembler::EmitFunction(Function* func) {
+void Disassembler::EmitFunction(const Function* func) {
in_function_ = true;
std::string fn_id = IdOf(func);
@@ -358,17 +358,17 @@
EmitLine();
}
-void Disassembler::EmitValueWithType(Instruction* val) {
+void Disassembler::EmitValueWithType(const Instruction* val) {
SourceMarker sm(this);
if (val->Result(0)) {
EmitValueWithType(val->Result(0));
} else {
out_ << "undef";
}
- sm.StoreResult(Usage{val, 0});
+ sm.StoreResult(IndexedValue{val, 0});
}
-void Disassembler::EmitValueWithType(Value* val) {
+void Disassembler::EmitValueWithType(const Value* val) {
if (!val) {
out_ << "undef";
return;
@@ -378,10 +378,10 @@
out_ << ":" << val->Type()->FriendlyName();
}
-void Disassembler::EmitValue(Value* val) {
+void Disassembler::EmitValue(const Value* val) {
tint::Switch(
val,
- [&](ir::Constant* constant) {
+ [&](const ir::Constant* constant) {
std::function<void(const core::constant::Value*)> emit =
[&](const core::constant::Value* c) {
tint::Switch(
@@ -427,10 +427,12 @@
};
emit(constant->Value());
},
- [&](ir::InstructionResult* rv) { out_ << "%" << IdOf(rv); },
- [&](ir::BlockParam* p) { out_ << "%" << IdOf(p) << ":" << p->Type()->FriendlyName(); },
- [&](ir::FunctionParam* p) { out_ << "%" << IdOf(p); },
- [&](ir::Function* f) { out_ << "%" << IdOf(f); },
+ [&](const ir::InstructionResult* rv) { out_ << "%" << IdOf(rv); },
+ [&](const ir::BlockParam* p) {
+ out_ << "%" << IdOf(p) << ":" << p->Type()->FriendlyName();
+ },
+ [&](const ir::FunctionParam* p) { out_ << "%" << IdOf(p); },
+ [&](const ir::Function* f) { out_ << "%" << IdOf(f); },
[&](Default) {
if (val == nullptr) {
out_ << "undef";
@@ -440,13 +442,13 @@
});
}
-void Disassembler::EmitInstructionName(Instruction* inst) {
+void Disassembler::EmitInstructionName(const Instruction* inst) {
SourceMarker sm(this);
out_ << inst->FriendlyName();
sm.Store(inst);
}
-void Disassembler::EmitInstruction(Instruction* inst) {
+void Disassembler::EmitInstruction(const Instruction* inst) {
TINT_DEFER(EmitLine());
if (!inst->Alive()) {
@@ -456,26 +458,26 @@
return;
}
tint::Switch(
- inst, //
- [&](Switch* s) { EmitSwitch(s); }, //
- [&](If* i) { EmitIf(i); }, //
- [&](Loop* l) { EmitLoop(l); }, //
- [&](Binary* b) { EmitBinary(b); }, //
- [&](Unary* u) { EmitUnary(u); }, //
- [&](Discard* d) { EmitInstructionName(d); },
- [&](Store* s) {
+ inst, //
+ [&](const Switch* s) { EmitSwitch(s); }, //
+ [&](const If* i) { EmitIf(i); }, //
+ [&](const Loop* l) { EmitLoop(l); }, //
+ [&](const Binary* b) { EmitBinary(b); }, //
+ [&](const Unary* u) { EmitUnary(u); }, //
+ [&](const Discard* d) { EmitInstructionName(d); },
+ [&](const Store* s) {
EmitInstructionName(s);
out_ << " ";
EmitOperand(s, Store::kToOperandOffset);
out_ << ", ";
EmitOperand(s, Store::kFromOperandOffset);
},
- [&](StoreVectorElement* s) {
+ [&](const StoreVectorElement* s) {
EmitInstructionName(s);
out_ << " ";
EmitOperandList(s);
},
- [&](UserCall* uc) {
+ [&](const UserCall* uc) {
EmitValueWithType(uc);
out_ << " = ";
EmitInstructionName(uc);
@@ -486,7 +488,7 @@
}
EmitOperandList(uc, UserCall::kArgsOperandOffset);
},
- [&](Var* v) {
+ [&](const Var* v) {
EmitValueWithType(v);
out_ << " = ";
EmitInstructionName(v);
@@ -519,7 +521,7 @@
out_ << " @builtin(" << v->Attributes().builtin.value() << ")";
}
},
- [&](Swizzle* s) {
+ [&](const Swizzle* s) {
EmitValueWithType(s);
out_ << " = ";
EmitInstructionName(s);
@@ -543,7 +545,7 @@
}
}
},
- [&](Terminator* b) { EmitTerminator(b); },
+ [&](const Terminator* b) { EmitTerminator(b); },
[&](Default) {
EmitValueWithType(inst);
out_ << " = ";
@@ -572,13 +574,13 @@
}
}
-void Disassembler::EmitOperand(Instruction* inst, size_t index) {
+void Disassembler::EmitOperand(const Instruction* inst, size_t index) {
SourceMarker marker(this);
EmitValue(inst->Operands()[index]);
- marker.Store(Usage{inst, static_cast<uint32_t>(index)});
+ marker.Store(IndexedValue{inst, static_cast<uint32_t>(index)});
}
-void Disassembler::EmitOperandList(Instruction* inst, size_t start_index /* = 0 */) {
+void Disassembler::EmitOperandList(const Instruction* inst, size_t start_index /* = 0 */) {
for (size_t i = start_index, n = inst->Operands().Length(); i < n; i++) {
if (i != start_index) {
out_ << ", ";
@@ -587,7 +589,7 @@
}
}
-void Disassembler::EmitIf(If* if_) {
+void Disassembler::EmitIf(const If* if_) {
SourceMarker sm(this);
if (auto results = if_->Results(); !results.IsEmpty()) {
for (size_t i = 0; i < results.Length(); ++i) {
@@ -596,7 +598,7 @@
}
SourceMarker rs(this);
EmitValueWithType(results[i]);
- rs.StoreResult(Usage{if_, i});
+ rs.StoreResult(IndexedValue{if_, i});
}
out_ << " = ";
}
@@ -638,7 +640,7 @@
out_ << "}";
}
-void Disassembler::EmitLoop(Loop* l) {
+void Disassembler::EmitLoop(const Loop* l) {
Vector<std::string, 3> parts;
if (!l->Initializer()->IsEmpty()) {
parts.Push("i: %b" + std::to_string(IdOf(l->Initializer())));
@@ -656,7 +658,7 @@
}
SourceMarker rs(this);
EmitValueWithType(results[i]);
- rs.StoreResult(Usage{l, i});
+ rs.StoreResult(IndexedValue{l, i});
}
out_ << " = ";
}
@@ -686,7 +688,7 @@
out_ << "}";
}
-void Disassembler::EmitSwitch(Switch* s) {
+void Disassembler::EmitSwitch(const Switch* s) {
SourceMarker sm(this);
if (auto results = s->Results(); !results.IsEmpty()) {
for (size_t i = 0; i < results.Length(); ++i) {
@@ -695,7 +697,7 @@
}
SourceMarker rs(this);
EmitValueWithType(results[i]);
- rs.StoreResult(Usage{s, i});
+ rs.StoreResult(IndexedValue{s, i});
}
out_ << " = ";
}
@@ -735,43 +737,43 @@
out_ << "}";
}
-void Disassembler::EmitTerminator(Terminator* b) {
+void Disassembler::EmitTerminator(const Terminator* b) {
SourceMarker sm(this);
size_t args_offset = 0;
tint::Switch(
b,
- [&](ir::Return*) {
+ [&](const ir::Return*) {
out_ << "ret";
args_offset = ir::Return::kArgsOperandOffset;
},
- [&](ir::Continue* cont) {
+ [&](const ir::Continue* cont) {
out_ << "continue %b" << IdOf(cont->Loop()->Continuing());
args_offset = ir::Continue::kArgsOperandOffset;
},
- [&](ir::ExitIf*) {
+ [&](const ir::ExitIf*) {
out_ << "exit_if";
args_offset = ir::ExitIf::kArgsOperandOffset;
},
- [&](ir::ExitSwitch*) {
+ [&](const ir::ExitSwitch*) {
out_ << "exit_switch";
args_offset = ir::ExitSwitch::kArgsOperandOffset;
},
- [&](ir::ExitLoop*) {
+ [&](const ir::ExitLoop*) {
out_ << "exit_loop";
args_offset = ir::ExitLoop::kArgsOperandOffset;
},
- [&](ir::NextIteration* ni) {
+ [&](const ir::NextIteration* ni) {
out_ << "next_iteration %b" << IdOf(ni->Loop()->Body());
args_offset = ir::NextIteration::kArgsOperandOffset;
},
- [&](ir::Unreachable*) { out_ << "unreachable"; },
- [&](ir::BreakIf* bi) {
+ [&](const ir::Unreachable*) { out_ << "unreachable"; },
+ [&](const ir::BreakIf* bi) {
out_ << "break_if ";
EmitValue(bi->Condition());
out_ << " %b" << IdOf(bi->Loop()->Body());
args_offset = ir::BreakIf::kArgsOperandOffset;
},
- [&](ir::TerminateInvocation*) { out_ << "terminate_invocation"; },
+ [&](const ir::TerminateInvocation*) { out_ << "terminate_invocation"; },
[&](Default) { out_ << "unknown terminator " << b->TypeInfo().name; });
if (!b->Args().IsEmpty()) {
@@ -781,14 +783,14 @@
sm.Store(b);
tint::Switch(
- b, //
- [&](ir::ExitIf* e) { out_ << " # " << NameOf(e->If()); }, //
- [&](ir::ExitSwitch* e) { out_ << " # " << NameOf(e->Switch()); }, //
- [&](ir::ExitLoop* e) { out_ << " # " << NameOf(e->Loop()); } //
+ b, //
+ [&](const ir::ExitIf* e) { out_ << " # " << NameOf(e->If()); }, //
+ [&](const ir::ExitSwitch* e) { out_ << " # " << NameOf(e->Switch()); }, //
+ [&](const ir::ExitLoop* e) { out_ << " # " << NameOf(e->Loop()); } //
);
}
-void Disassembler::EmitValueList(tint::Slice<Value* const> values) {
+void Disassembler::EmitValueList(tint::Slice<const Value* const> values) {
for (size_t i = 0, n = values.Length(); i < n; i++) {
if (i > 0) {
out_ << ", ";
@@ -797,7 +799,7 @@
}
}
-void Disassembler::EmitBinary(Binary* b) {
+void Disassembler::EmitBinary(const Binary* b) {
SourceMarker sm(this);
EmitValueWithType(b);
out_ << " = ";
@@ -857,7 +859,7 @@
sm.Store(b);
}
-void Disassembler::EmitUnary(Unary* u) {
+void Disassembler::EmitUnary(const Unary* u) {
SourceMarker sm(this);
EmitValueWithType(u);
out_ << " = ";
diff --git a/src/tint/lang/core/ir/disassembler.h b/src/tint/lang/core/ir/disassembler.h
index a22182d..8f15e95 100644
--- a/src/tint/lang/core/ir/disassembler.h
+++ b/src/tint/lang/core/ir/disassembler.h
@@ -51,14 +51,32 @@
/// @returns the disassembly for the module @p mod
/// @param mod the module to disassemble
-std::string Disassemble(Module& mod);
+std::string Disassemble(const Module& mod);
/// Helper class to disassemble the IR
class Disassembler {
public:
+ /// A reference to an instruction's operand or result.
+ struct IndexedValue {
+ /// The instruction that is using the value;
+ const Instruction* instruction = nullptr;
+ /// The index of the operand that is the value being used.
+ size_t index = 0u;
+
+ /// @returns the hash code of the IndexedValue
+ size_t HashCode() const { return Hash(instruction, index); }
+
+ /// An equality helper for IndexedValue.
+ /// @param other the IndexedValue to compare against
+ /// @returns true if the two IndexedValues are equal
+ bool operator==(const IndexedValue& other) const {
+ return instruction == other.instruction && index == other.index;
+ }
+ };
+
/// Constructor
/// @param mod the module
- explicit Disassembler(Module& mod);
+ explicit Disassembler(const Module& mod);
~Disassembler();
/// Returns the module as a string
@@ -70,41 +88,45 @@
/// @param inst the instruction to retrieve
/// @returns the source for the instruction
- Source InstructionSource(Instruction* inst) {
+ Source InstructionSource(const Instruction* inst) {
return instruction_to_src_.Get(inst).value_or(Source{});
}
/// @param operand the operand to retrieve
/// @returns the source for the operand
- Source OperandSource(Usage operand) { return operand_to_src_.Get(operand).value_or(Source{}); }
+ Source OperandSource(IndexedValue operand) {
+ return operand_to_src_.Get(operand).value_or(Source{});
+ }
/// @param result the result to retrieve
/// @returns the source for the result
- Source ResultSource(Usage result) { return result_to_src_.Get(result).value_or(Source{}); }
+ Source ResultSource(IndexedValue result) {
+ return result_to_src_.Get(result).value_or(Source{});
+ }
/// @param blk teh block to retrieve
/// @returns the source for the block
- Source BlockSource(Block* blk) { return block_to_src_.Get(blk).value_or(Source{}); }
+ Source BlockSource(const Block* blk) { return block_to_src_.Get(blk).value_or(Source{}); }
/// Stores the given @p src location for @p inst instruction
/// @param inst the instruction to store
/// @param src the source location
- void SetSource(Instruction* inst, Source src) { instruction_to_src_.Add(inst, src); }
+ void SetSource(const Instruction* inst, Source src) { instruction_to_src_.Add(inst, src); }
/// Stores the given @p src location for @p blk block
/// @param blk the block to store
/// @param src the source location
- void SetSource(Block* blk, Source src) { block_to_src_.Add(blk, src); }
+ void SetSource(const Block* blk, Source src) { block_to_src_.Add(blk, src); }
/// Stores the given @p src location for @p op operand
/// @param op the operand to store
/// @param src the source location
- void SetSource(Usage op, Source src) { operand_to_src_.Add(op, src); }
+ void SetSource(IndexedValue op, Source src) { operand_to_src_.Add(op, src); }
/// Stores the given @p src location for @p result
/// @param result the result to store
/// @param src the source location
- void SetResultSource(Usage result, Source src) { result_to_src_.Add(result, src); }
+ void SetResultSource(IndexedValue result, Source src) { result_to_src_.Add(result, src); }
/// @returns the source location for the current emission location
Source::Location MakeCurrentLocation();
@@ -115,13 +137,13 @@
explicit SourceMarker(Disassembler* d) : dis_(d), begin_(dis_->MakeCurrentLocation()) {}
~SourceMarker() = default;
- void Store(Instruction* inst) { dis_->SetSource(inst, MakeSource()); }
+ void Store(const Instruction* inst) { dis_->SetSource(inst, MakeSource()); }
- void Store(Block* blk) { dis_->SetSource(blk, MakeSource()); }
+ void Store(const Block* blk) { dis_->SetSource(blk, MakeSource()); }
- void Store(Usage operand) { dis_->SetSource(operand, MakeSource()); }
+ void Store(IndexedValue operand) { dis_->SetSource(operand, MakeSource()); }
- void StoreResult(Usage result) { dis_->SetResultSource(result, MakeSource()); }
+ void StoreResult(IndexedValue result) { dis_->SetResultSource(result, MakeSource()); }
Source MakeSource() const {
return Source(Source::Range(begin_, dis_->MakeCurrentLocation()));
@@ -134,39 +156,39 @@
StringStream& Indent();
- size_t IdOf(Block* blk);
- std::string IdOf(Value* node);
- std::string NameOf(If* inst);
- std::string NameOf(Loop* inst);
- std::string NameOf(Switch* inst);
+ size_t IdOf(const Block* blk);
+ std::string IdOf(const Value* node);
+ std::string NameOf(const If* inst);
+ std::string NameOf(const Loop* inst);
+ std::string NameOf(const Switch* inst);
- void EmitBlock(Block* blk, std::string_view comment = "");
- void EmitFunction(Function* func);
- void EmitParamAttributes(FunctionParam* p);
- void EmitReturnAttributes(Function* func);
+ void EmitBlock(const Block* blk, std::string_view comment = "");
+ void EmitFunction(const Function* func);
+ void EmitParamAttributes(const FunctionParam* p);
+ void EmitReturnAttributes(const Function* func);
void EmitBindingPoint(BindingPoint p);
void EmitLocation(Location loc);
- void EmitInstruction(Instruction* inst);
- void EmitValueWithType(Instruction* val);
- void EmitValueWithType(Value* val);
- void EmitValue(Value* val);
- void EmitValueList(tint::Slice<ir::Value* const> values);
- void EmitBinary(Binary* b);
- void EmitUnary(Unary* b);
- void EmitTerminator(Terminator* b);
- void EmitSwitch(Switch* s);
- void EmitLoop(Loop* l);
- void EmitIf(If* i);
+ void EmitInstruction(const Instruction* inst);
+ void EmitValueWithType(const Instruction* val);
+ void EmitValueWithType(const Value* val);
+ void EmitValue(const Value* val);
+ void EmitValueList(tint::Slice<const ir::Value* const> values);
+ void EmitBinary(const Binary* b);
+ void EmitUnary(const Unary* b);
+ void EmitTerminator(const Terminator* b);
+ void EmitSwitch(const Switch* s);
+ void EmitLoop(const Loop* l);
+ void EmitIf(const If* i);
void EmitStructDecl(const core::type::Struct* str);
void EmitLine();
- void EmitOperand(Instruction* inst, size_t index);
- void EmitOperandList(Instruction* inst, size_t start_index = 0);
- void EmitInstructionName(Instruction* inst);
+ void EmitOperand(const Instruction* inst, size_t index);
+ void EmitOperandList(const Instruction* inst, size_t start_index = 0);
+ void EmitInstructionName(const Instruction* inst);
- Module& mod_;
+ const Module& mod_;
StringStream out_;
- Hashmap<Block*, size_t, 32> block_ids_;
- Hashmap<Value*, std::string, 32> value_ids_;
+ Hashmap<const Block*, size_t, 32> block_ids_;
+ Hashmap<const Value*, std::string, 32> value_ids_;
Hashset<std::string, 32> ids_;
uint32_t indent_size_ = 0;
bool in_function_ = false;
@@ -174,13 +196,13 @@
uint32_t current_output_line_ = 1;
uint32_t current_output_start_pos_ = 0;
- Hashmap<Block*, Source, 8> block_to_src_;
- Hashmap<Instruction*, Source, 8> instruction_to_src_;
- Hashmap<Usage, Source, 8> operand_to_src_;
- Hashmap<Usage, Source, 8> result_to_src_;
- Hashmap<If*, std::string, 8> if_names_;
- Hashmap<Loop*, std::string, 8> loop_names_;
- Hashmap<Switch*, std::string, 8> switch_names_;
+ Hashmap<const Block*, Source, 8> block_to_src_;
+ Hashmap<const Instruction*, Source, 8> instruction_to_src_;
+ Hashmap<IndexedValue, Source, 8> operand_to_src_;
+ Hashmap<IndexedValue, Source, 8> result_to_src_;
+ Hashmap<const If*, std::string, 8> if_names_;
+ Hashmap<const Loop*, std::string, 8> loop_names_;
+ Hashmap<const Switch*, std::string, 8> switch_names_;
};
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 02f6d98..f149306 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -90,7 +90,7 @@
public:
/// Create a core validator
/// @param mod the module to be validated
- explicit Validator(Module& mod);
+ explicit Validator(const Module& mod);
/// Destructor
~Validator();
@@ -103,47 +103,47 @@
/// @param inst the instruction
/// @param err the error message
/// @returns a string with the instruction name name and error message formatted
- std::string InstError(Instruction* inst, std::string err);
+ std::string InstError(const Instruction* inst, std::string err);
/// Adds an error for the @p inst and highlights the instruction in the disassembly
/// @param inst the instruction
/// @param err the error string
- void AddError(Instruction* inst, std::string err);
+ void AddError(const Instruction* inst, std::string err);
/// Adds an error for the @p inst operand at @p idx and highlights the operand in the
/// disassembly
/// @param inst the instaruction
/// @param idx the operand index
/// @param err the error string
- void AddError(Instruction* inst, size_t idx, std::string err);
+ void AddError(const Instruction* inst, size_t idx, std::string err);
/// Adds an error for the @p inst result at @p idx and highlgihts the result in the disassembly
/// @param inst the instruction
/// @param idx the result index
/// @param err the error string
- void AddResultError(Instruction* inst, size_t idx, std::string err);
+ void AddResultError(const Instruction* inst, size_t idx, std::string err);
/// Adds an error the @p block and highlights the block header in the disassembly
/// @param blk the block
/// @param err the error string
- void AddError(Block* blk, std::string err);
+ void AddError(const Block* blk, std::string err);
/// Adds a note to @p inst and highlights the instruction in the disassembly
/// @param inst the instruction
/// @param err the message to emit
- void AddNote(Instruction* inst, std::string err);
+ void AddNote(const Instruction* inst, std::string err);
/// Adds a note to @p inst for operand @p idx and highlights the operand in the
/// disassembly
/// @param inst the instruction
/// @param idx the operand index
/// @param err the message string
- void AddNote(Instruction* inst, size_t idx, std::string err);
+ void AddNote(const Instruction* inst, size_t idx, std::string err);
/// Adds a note to @p blk and highlights the block in the disassembly
/// @param blk the block
/// @param err the message to emit
- void AddNote(Block* blk, std::string err);
+ void AddNote(const Block* blk, std::string err);
/// Adds an error to the diagnostics
/// @param err the message to emit
@@ -157,141 +157,143 @@
/// @param v the value to get the name for
/// @returns the name for the given value
- std::string Name(Value* v);
+ std::string Name(const Value* v);
/// Checks the given operand is not null
/// @param inst the instruction
/// @param operand the operand
/// @param idx the operand index
- void CheckOperandNotNull(ir::Instruction* inst, ir::Value* operand, size_t idx);
+ void CheckOperandNotNull(const ir::Instruction* inst, const ir::Value* operand, size_t idx);
/// Checks all operands in the given range (inclusive) for @p inst are not null
/// @param inst the instruction
/// @param start_operand the first operand to check
/// @param end_operand the last operand to check
- void CheckOperandsNotNull(ir::Instruction* inst, size_t start_operand, size_t end_operand);
+ void CheckOperandsNotNull(const ir::Instruction* inst,
+ size_t start_operand,
+ size_t end_operand);
/// Validates the root block
/// @param blk the block
- void CheckRootBlock(Block* blk);
+ void CheckRootBlock(const Block* blk);
/// Validates the given function
/// @param func the function validate
- void CheckFunction(Function* func);
+ void CheckFunction(const Function* func);
/// Validates the given block
/// @param blk the block to validate
- void CheckBlock(Block* blk);
+ void CheckBlock(const Block* blk);
/// Validates the given instruction
/// @param inst the instruction to validate
- void CheckInstruction(Instruction* inst);
+ void CheckInstruction(const Instruction* inst);
/// Validates the given var
/// @param var the var to validate
- void CheckVar(Var* var);
+ void CheckVar(const Var* var);
/// Validates the given let
/// @param let the let to validate
- void CheckLet(Let* let);
+ void CheckLet(const Let* let);
/// Validates the given call
/// @param call the call to validate
- void CheckCall(Call* call);
+ void CheckCall(const Call* call);
/// Validates the given builtin call
/// @param call the call to validate
- void CheckBuiltinCall(BuiltinCall* call);
+ void CheckBuiltinCall(const BuiltinCall* call);
/// Validates the given user call
/// @param call the call to validate
- void CheckUserCall(UserCall* call);
+ void CheckUserCall(const UserCall* call);
/// Validates the given access
/// @param a the access to validate
- void CheckAccess(Access* a);
+ void CheckAccess(const Access* a);
/// Validates the given binary
/// @param b the binary to validate
- void CheckBinary(Binary* b);
+ void CheckBinary(const Binary* b);
/// Validates the given unary
/// @param u the unary to validate
- void CheckUnary(Unary* u);
+ void CheckUnary(const Unary* u);
/// Validates the given if
/// @param if_ the if to validate
- void CheckIf(If* if_);
+ void CheckIf(const If* if_);
/// Validates the given loop
/// @param l the loop to validate
- void CheckLoop(Loop* l);
+ void CheckLoop(const Loop* l);
/// Validates the given switch
/// @param s the switch to validate
- void CheckSwitch(Switch* s);
+ void CheckSwitch(const Switch* s);
/// Validates the given terminator
/// @param b the terminator to validate
- void CheckTerminator(Terminator* b);
+ void CheckTerminator(const Terminator* b);
/// Validates the given exit
/// @param e the exit to validate
- void CheckExit(Exit* e);
+ void CheckExit(const Exit* e);
/// Validates the given exit if
/// @param e the exit if to validate
- void CheckExitIf(ExitIf* e);
+ void CheckExitIf(const ExitIf* e);
/// Validates the given return
/// @param r the return to validate
- void CheckReturn(Return* r);
+ void CheckReturn(const Return* r);
/// Validates the @p exit targets a valid @p control instruction where the instruction may jump
/// over if control instructions.
/// @param exit the exit to validate
/// @param control the control instruction targeted
- void CheckControlsAllowingIf(Exit* exit, Instruction* control);
+ void CheckControlsAllowingIf(const Exit* exit, const Instruction* control);
/// Validates the given exit switch
/// @param s the exit switch to validate
- void CheckExitSwitch(ExitSwitch* s);
+ void CheckExitSwitch(const ExitSwitch* s);
/// Validates the given exit loop
/// @param l the exit loop to validate
- void CheckExitLoop(ExitLoop* l);
+ void CheckExitLoop(const ExitLoop* l);
/// Validates the given store
/// @param s the store to validate
- void CheckStore(Store* s);
+ void CheckStore(const Store* s);
/// Validates the given load vector element
/// @param l the load vector element to validate
- void CheckLoadVectorElement(LoadVectorElement* l);
+ void CheckLoadVectorElement(const LoadVectorElement* l);
/// Validates the given store vector element
/// @param s the store vector element to validate
- void CheckStoreVectorElement(StoreVectorElement* s);
+ void CheckStoreVectorElement(const StoreVectorElement* s);
/// @param inst the instruction
/// @param idx the operand index
/// @returns the vector pointer type for the given instruction operand
- const core::type::Type* GetVectorPtrElementType(Instruction* inst, size_t idx);
+ const core::type::Type* GetVectorPtrElementType(const Instruction* inst, size_t idx);
private:
- Module& mod_;
+ const Module& mod_;
std::shared_ptr<Source::File> disassembly_file;
diag::List diagnostics_;
Disassembler dis_{mod_};
- Block* current_block_ = nullptr;
- Hashset<Function*, 4> all_functions_;
- Hashset<Instruction*, 4> visited_instructions_;
- Vector<ControlInstruction*, 8> control_stack_;
+ const Block* current_block_ = nullptr;
+ Hashset<const Function*, 4> all_functions_;
+ Hashset<const Instruction*, 4> visited_instructions_;
+ Vector<const ControlInstruction*, 8> control_stack_;
void DisassembleIfNeeded();
};
-Validator::Validator(Module& mod) : mod_(mod) {}
+Validator::Validator(const Module& mod) : mod_(mod) {}
Validator::~Validator() = default;
@@ -333,11 +335,11 @@
return Success;
}
-std::string Validator::InstError(Instruction* inst, std::string err) {
+std::string Validator::InstError(const Instruction* inst, std::string err) {
return std::string(inst->FriendlyName()) + ": " + err;
}
-void Validator::AddError(Instruction* inst, std::string err) {
+void Validator::AddError(const Instruction* inst, std::string err) {
DisassembleIfNeeded();
auto src = dis_.InstructionSource(inst);
AddError(std::move(err), src);
@@ -347,9 +349,9 @@
}
}
-void Validator::AddError(Instruction* inst, size_t idx, std::string err) {
+void Validator::AddError(const Instruction* inst, size_t idx, std::string err) {
DisassembleIfNeeded();
- auto src = dis_.OperandSource(Usage{inst, static_cast<uint32_t>(idx)});
+ auto src = dis_.OperandSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
AddError(std::move(err), src);
if (current_block_) {
@@ -357,9 +359,9 @@
}
}
-void Validator::AddResultError(Instruction* inst, size_t idx, std::string err) {
+void Validator::AddResultError(const Instruction* inst, size_t idx, std::string err) {
DisassembleIfNeeded();
- auto src = dis_.ResultSource(Usage{inst, static_cast<uint32_t>(idx)});
+ auto src = dis_.ResultSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
AddError(std::move(err), src);
if (current_block_) {
@@ -367,25 +369,25 @@
}
}
-void Validator::AddError(Block* blk, std::string err) {
+void Validator::AddError(const Block* blk, std::string err) {
DisassembleIfNeeded();
auto src = dis_.BlockSource(blk);
AddError(std::move(err), src);
}
-void Validator::AddNote(Instruction* inst, std::string err) {
+void Validator::AddNote(const Instruction* inst, std::string err) {
DisassembleIfNeeded();
auto src = dis_.InstructionSource(inst);
AddNote(std::move(err), src);
}
-void Validator::AddNote(Instruction* inst, size_t idx, std::string err) {
+void Validator::AddNote(const Instruction* inst, size_t idx, std::string err) {
DisassembleIfNeeded();
- auto src = dis_.OperandSource(Usage{inst, static_cast<uint32_t>(idx)});
+ auto src = dis_.OperandSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
AddNote(std::move(err), src);
}
-void Validator::AddNote(Block* blk, std::string err) {
+void Validator::AddNote(const Block* blk, std::string err) {
DisassembleIfNeeded();
auto src = dis_.BlockSource(blk);
AddNote(std::move(err), src);
@@ -407,24 +409,26 @@
}
}
-std::string Validator::Name(Value* v) {
+std::string Validator::Name(const Value* v) {
return mod_.NameOf(v).Name();
}
-void Validator::CheckOperandNotNull(Instruction* inst, ir::Value* operand, size_t idx) {
+void Validator::CheckOperandNotNull(const Instruction* inst, const ir::Value* operand, size_t idx) {
if (operand == nullptr) {
AddError(inst, idx, InstError(inst, "operand is undefined"));
}
}
-void Validator::CheckOperandsNotNull(Instruction* inst, size_t start_operand, size_t end_operand) {
+void Validator::CheckOperandsNotNull(const Instruction* inst,
+ size_t start_operand,
+ size_t end_operand) {
auto operands = inst->Operands();
for (size_t i = start_operand; i <= end_operand; i++) {
CheckOperandNotNull(inst, operands[i], i);
}
}
-void Validator::CheckRootBlock(Block* blk) {
+void Validator::CheckRootBlock(const Block* blk) {
TINT_SCOPED_ASSIGNMENT(current_block_, blk);
for (auto* inst : *blk) {
@@ -444,11 +448,11 @@
}
}
-void Validator::CheckFunction(Function* func) {
+void Validator::CheckFunction(const Function* func) {
CheckBlock(func->Block());
}
-void Validator::CheckBlock(Block* blk) {
+void Validator::CheckBlock(const Block* blk) {
TINT_SCOPED_ASSIGNMENT(current_block_, blk);
if (!blk->Terminator()) {
@@ -470,7 +474,7 @@
}
}
-void Validator::CheckInstruction(Instruction* inst) {
+void Validator::CheckInstruction(const Instruction* inst) {
visited_instructions_.Add(inst);
if (!inst->Alive()) {
AddError(inst, InstError(inst, "destroyed instruction found in instruction list"));
@@ -506,7 +510,7 @@
InstError(inst, "instruction operand " + std::to_string(i) + " is not alive"));
}
- if (!op->Usages().Contains({inst, i})) {
+ if (!op->HasUsage(inst, i)) {
AddError(
inst, i,
InstError(inst, "instruction operand " + std::to_string(i) + " missing usage"));
@@ -514,34 +518,34 @@
}
tint::Switch(
- inst, //
- [&](Access* a) { CheckAccess(a); }, //
- [&](Binary* b) { CheckBinary(b); }, //
- [&](Call* c) { CheckCall(c); }, //
- [&](If* if_) { CheckIf(if_); }, //
- [&](Let* let) { CheckLet(let); }, //
- [&](Load*) {}, //
- [&](LoadVectorElement* l) { CheckLoadVectorElement(l); }, //
- [&](Loop* l) { CheckLoop(l); }, //
- [&](Store* s) { CheckStore(s); }, //
- [&](StoreVectorElement* s) { CheckStoreVectorElement(s); }, //
- [&](Switch* s) { CheckSwitch(s); }, //
- [&](Swizzle*) {}, //
- [&](Terminator* b) { CheckTerminator(b); }, //
- [&](Unary* u) { CheckUnary(u); }, //
- [&](Var* var) { CheckVar(var); }, //
- [&](Default) { AddError(inst, InstError(inst, "missing validation")); });
+ inst, //
+ [&](const Access* a) { CheckAccess(a); }, //
+ [&](const Binary* b) { CheckBinary(b); }, //
+ [&](const Call* c) { CheckCall(c); }, //
+ [&](const If* if_) { CheckIf(if_); }, //
+ [&](const Let* let) { CheckLet(let); }, //
+ [&](const Load*) {}, //
+ [&](const LoadVectorElement* l) { CheckLoadVectorElement(l); }, //
+ [&](const Loop* l) { CheckLoop(l); }, //
+ [&](const Store* s) { CheckStore(s); }, //
+ [&](const StoreVectorElement* s) { CheckStoreVectorElement(s); }, //
+ [&](const Switch* s) { CheckSwitch(s); }, //
+ [&](const Swizzle*) {}, //
+ [&](const Terminator* b) { CheckTerminator(b); }, //
+ [&](const Unary* u) { CheckUnary(u); }, //
+ [&](const Var* var) { CheckVar(var); }, //
+ [&](const Default) { AddError(inst, InstError(inst, "missing validation")); });
}
-void Validator::CheckVar(Var* var) {
- if (var->Result(0) && var->Initializer()) {
+void Validator::CheckVar(const Var* var) {
+ if (var->Result() && var->Initializer()) {
if (var->Initializer()->Type() != var->Result(0)->Type()->UnwrapPtr()) {
AddError(var, InstError(var, "initializer has incorrect type"));
}
}
}
-void Validator::CheckLet(Let* let) {
+void Validator::CheckLet(const Let* let) {
CheckOperandNotNull(let, let->Value(), Let::kValueOperandOffset);
if (let->Result(0) && let->Value()) {
@@ -551,23 +555,31 @@
}
}
-void Validator::CheckCall(Call* call) {
+void Validator::CheckCall(const Call* call) {
tint::Switch(
- call, //
- [&](Bitcast*) {}, //
- [&](BuiltinCall* c) { CheckBuiltinCall(c); }, //
- [&](Construct*) {}, //
- [&](Convert*) {}, //
- [&](Discard*) {}, //
- [&](UserCall* c) { CheckUserCall(c); }, //
+ call, //
+ [&](const Bitcast*) {}, //
+ [&](const BuiltinCall* c) { CheckBuiltinCall(c); }, //
+ [&](const Construct*) {}, //
+ [&](const Convert*) {}, //
+ [&](const Discard*) {}, //
+ [&](const UserCall* c) { CheckUserCall(c); }, //
[&](Default) {
// Validation of custom IR instructions
});
}
-void Validator::CheckBuiltinCall(BuiltinCall* call) {
- auto args = Transform<8>(call->Args(), [&](ir::Value* v) { return v->Type(); });
- intrinsic::Context context{call->TableData(), mod_.Types(), mod_.symbols, diagnostics_};
+void Validator::CheckBuiltinCall(const BuiltinCall* call) {
+ auto symbols = SymbolTable::Wrap(mod_.symbols);
+ auto type_mgr = type::Manager::Wrap(mod_.Types());
+
+ auto args = Transform<8>(call->Args(), [&](const ir::Value* v) { return v->Type(); });
+ intrinsic::Context context{
+ call->TableData(),
+ type_mgr,
+ symbols,
+ diagnostics_,
+ };
auto result = core::intrinsic::LookupFn(context, call->FriendlyName().c_str(), call->FuncId(),
args, core::EvaluationStage::kRuntime, Source{});
@@ -578,14 +590,14 @@
}
}
-void Validator::CheckUserCall(UserCall* call) {
+void Validator::CheckUserCall(const UserCall* call) {
if (!all_functions_.Contains(call->Target())) {
AddError(call, UserCall::kFunctionOperandOffset,
InstError(call, "call target is not part of the module"));
}
}
-void Validator::CheckAccess(Access* a) {
+void Validator::CheckAccess(const Access* a) {
bool is_ptr = a->Object()->Type()->Is<core::type::Pointer>();
auto* ty = a->Object()->Type()->UnwrapPtr();
@@ -654,11 +666,11 @@
}
}
-void Validator::CheckBinary(Binary* b) {
+void Validator::CheckBinary(const Binary* b) {
CheckOperandsNotNull(b, Binary::kLhsOperandOffset, Binary::kRhsOperandOffset);
}
-void Validator::CheckUnary(Unary* u) {
+void Validator::CheckUnary(const Unary* u) {
CheckOperandNotNull(u, u->Val(), Unary::kValueOperandOffset);
if (u->Result(0) && u->Val()) {
@@ -668,7 +680,7 @@
}
}
-void Validator::CheckIf(If* if_) {
+void Validator::CheckIf(const If* if_) {
CheckOperandNotNull(if_, if_->Condition(), If::kConditionOperandOffset);
if (if_->Condition() && !if_->Condition()->Type()->Is<core::type::Bool>()) {
@@ -685,7 +697,7 @@
}
}
-void Validator::CheckLoop(Loop* l) {
+void Validator::CheckLoop(const Loop* l) {
control_stack_.Push(l);
TINT_DEFER(control_stack_.Pop());
@@ -699,7 +711,7 @@
}
}
-void Validator::CheckSwitch(Switch* s) {
+void Validator::CheckSwitch(const Switch* s) {
control_stack_.Push(s);
TINT_DEFER(control_stack_.Pop());
@@ -708,23 +720,23 @@
}
}
-void Validator::CheckTerminator(Terminator* b) {
+void Validator::CheckTerminator(const Terminator* b) {
// Note, transforms create `undef` terminator arguments (this is done in MergeReturn and
// DemoteToHelper) so we can't add validation.
tint::Switch(
- b, //
- [&](ir::BreakIf*) {}, //
- [&](ir::Continue*) {}, //
- [&](ir::Exit* e) { CheckExit(e); }, //
- [&](ir::NextIteration*) {}, //
- [&](ir::Return* ret) { CheckReturn(ret); }, //
- [&](ir::TerminateInvocation*) {}, //
- [&](ir::Unreachable*) {}, //
+ b, //
+ [&](const ir::BreakIf*) {}, //
+ [&](const ir::Continue*) {}, //
+ [&](const ir::Exit* e) { CheckExit(e); }, //
+ [&](const ir::NextIteration*) {}, //
+ [&](const ir::Return* ret) { CheckReturn(ret); }, //
+ [&](const ir::TerminateInvocation*) {}, //
+ [&](const ir::Unreachable*) {}, //
[&](Default) { AddError(b, InstError(b, "missing validation")); });
}
-void Validator::CheckExit(Exit* e) {
+void Validator::CheckExit(const Exit* e) {
if (e->ControlInstruction() == nullptr) {
AddError(e, InstError(e, "has no parent control instruction"));
return;
@@ -757,21 +769,21 @@
}
tint::Switch(
- e, //
- [&](ir::ExitIf* i) { CheckExitIf(i); }, //
- [&](ir::ExitLoop* l) { CheckExitLoop(l); }, //
- [&](ir::ExitSwitch* s) { CheckExitSwitch(s); }, //
+ e, //
+ [&](const ir::ExitIf* i) { CheckExitIf(i); }, //
+ [&](const ir::ExitLoop* l) { CheckExitLoop(l); }, //
+ [&](const ir::ExitSwitch* s) { CheckExitSwitch(s); }, //
[&](Default) { AddError(e, InstError(e, "missing validation")); });
}
-void Validator::CheckExitIf(ExitIf* e) {
+void Validator::CheckExitIf(const ExitIf* e) {
if (control_stack_.Back() != e->If()) {
AddError(e, InstError(e, "if target jumps over other control instructions"));
AddNote(control_stack_.Back(), "first control instruction jumped");
}
}
-void Validator::CheckReturn(Return* ret) {
+void Validator::CheckReturn(const Return* ret) {
auto* func = ret->Func();
if (func == nullptr) {
AddError(ret, InstError(ret, "undefined function"));
@@ -790,7 +802,7 @@
}
}
-void Validator::CheckControlsAllowingIf(Exit* exit, Instruction* control) {
+void Validator::CheckControlsAllowingIf(const Exit* exit, const Instruction* control) {
bool found = false;
for (auto ctrl : tint::Reverse(control_stack_)) {
if (ctrl == control) {
@@ -811,15 +823,15 @@
}
}
-void Validator::CheckExitSwitch(ExitSwitch* s) {
+void Validator::CheckExitSwitch(const ExitSwitch* s) {
CheckControlsAllowingIf(s, s->ControlInstruction());
}
-void Validator::CheckExitLoop(ExitLoop* l) {
+void Validator::CheckExitLoop(const ExitLoop* l) {
CheckControlsAllowingIf(l, l->ControlInstruction());
- Instruction* inst = l;
- Loop* control = l->Loop();
+ const Instruction* inst = l;
+ const Loop* control = l->Loop();
while (inst) {
// Found parent loop
if (inst->Block()->Parent() == control) {
@@ -840,7 +852,7 @@
}
}
-void Validator::CheckStore(Store* s) {
+void Validator::CheckStore(const Store* s) {
CheckOperandsNotNull(s, Store::kToOperandOffset, Store::kFromOperandOffset);
if (auto* from = s->From()) {
@@ -853,7 +865,7 @@
}
}
-void Validator::CheckLoadVectorElement(LoadVectorElement* l) {
+void Validator::CheckLoadVectorElement(const LoadVectorElement* l) {
CheckOperandsNotNull(l, //
LoadVectorElement::kFromOperandOffset,
LoadVectorElement::kIndexOperandOffset);
@@ -867,7 +879,7 @@
}
}
-void Validator::CheckStoreVectorElement(StoreVectorElement* s) {
+void Validator::CheckStoreVectorElement(const StoreVectorElement* s) {
CheckOperandsNotNull(s, //
StoreVectorElement::kToOperandOffset,
StoreVectorElement::kValueOperandOffset);
@@ -882,7 +894,7 @@
}
}
-const core::type::Type* Validator::GetVectorPtrElementType(Instruction* inst, size_t idx) {
+const core::type::Type* Validator::GetVectorPtrElementType(const Instruction* inst, size_t idx) {
auto* operand = inst->Operands()[idx];
if (TINT_UNLIKELY(!operand)) {
return nullptr;
@@ -907,12 +919,12 @@
} // namespace
-Result<SuccessType> Validate(Module& mod) {
+Result<SuccessType> Validate(const Module& mod) {
Validator v(mod);
return v.Run();
}
-Result<SuccessType> ValidateAndDumpIfNeeded([[maybe_unused]] Module& ir,
+Result<SuccessType> ValidateAndDumpIfNeeded([[maybe_unused]] const Module& ir,
[[maybe_unused]] const char* msg) {
#if TINT_DUMP_IR_WHEN_VALIDATING
std::cout << "=========================================================" << std::endl;
diff --git a/src/tint/lang/core/ir/validator.h b/src/tint/lang/core/ir/validator.h
index cfc6a81..d6b0843 100644
--- a/src/tint/lang/core/ir/validator.h
+++ b/src/tint/lang/core/ir/validator.h
@@ -42,13 +42,13 @@
/// Validates that a given IR module is correctly formed
/// @param mod the module to validate
/// @returns success or failure
-Result<SuccessType> Validate(Module& mod);
+Result<SuccessType> Validate(const Module& mod);
/// Validates the module @p ir and dumps its contents if required by the build configuration.
/// @param ir the module to transform
/// @param msg the msg to accompany the output
/// @returns success or failure
-Result<SuccessType> ValidateAndDumpIfNeeded(Module& ir, const char* msg);
+Result<SuccessType> ValidateAndDumpIfNeeded(const Module& ir, const char* msg);
} // namespace tint::core::ir
diff --git a/src/tint/lang/glsl/writer/printer/printer.cc b/src/tint/lang/glsl/writer/printer/printer.cc
index f3dda8c..b25799e 100644
--- a/src/tint/lang/glsl/writer/printer/printer.cc
+++ b/src/tint/lang/glsl/writer/printer/printer.cc
@@ -50,7 +50,7 @@
public:
/// Constructor
/// @param module the Tint IR module to generate
- explicit Printer(core::ir::Module& module) : ir_(module) {}
+ explicit Printer(const core::ir::Module& module) : ir_(module) {}
/// @param version the GLSL version information
/// @returns the generated GLSL shader
@@ -84,7 +84,7 @@
}
private:
- core::ir::Module& ir_;
+ const core::ir::Module& ir_;
/// The buffer holding preamble text
TextBuffer preamble_buffer_;
@@ -169,7 +169,7 @@
};
} // namespace
-Result<std::string> Print(core::ir::Module& module, const Version& version) {
+Result<std::string> Print(const core::ir::Module& module, const Version& version) {
return Printer{module}.Generate(version);
}
diff --git a/src/tint/lang/glsl/writer/printer/printer.h b/src/tint/lang/glsl/writer/printer/printer.h
index 49c6301..6f75b39 100644
--- a/src/tint/lang/glsl/writer/printer/printer.h
+++ b/src/tint/lang/glsl/writer/printer/printer.h
@@ -45,7 +45,7 @@
/// @returns the generated GLSL shader on success, or failure
/// @param module the Tint IR module to generate
/// @param version the GLSL version information
-Result<std::string> Print(core::ir::Module& module, const Version& version);
+Result<std::string> Print(const core::ir::Module& module, const Version& version);
} // namespace tint::glsl::writer
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 08a44bb..c0f22f6 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -101,7 +101,7 @@
class State {
public:
- explicit State(core::ir::Module& m) : mod(m) {}
+ explicit State(const core::ir::Module& m) : mod(m) {}
Program Run() {
if (auto res = core::ir::Validate(mod); !res) {
@@ -127,7 +127,7 @@
};
/// The source IR module
- core::ir::Module& mod;
+ const core::ir::Module& mod;
/// The target ProgramBuilder
ProgramBuilder b;
@@ -152,10 +152,10 @@
using ValueBinding = std::variant<VariableValue, InlinedValue, ConsumedValue>;
/// IR values to their representation
- Hashmap<core::ir::Value*, ValueBinding, 32> bindings_;
+ Hashmap<const core::ir::Value*, ValueBinding, 32> bindings_;
/// Names for values
- Hashmap<core::ir::Value*, Symbol, 32> names_;
+ Hashmap<const core::ir::Value*, Symbol, 32> names_;
/// The nesting depth of the currently generated AST
/// 0 is module scope
@@ -168,10 +168,10 @@
StatementList* statements_ = nullptr;
/// The current switch case block
- core::ir::Block* current_switch_case_ = nullptr;
+ const core::ir::Block* current_switch_case_ = nullptr;
/// Values that can be inlined.
- Hashset<core::ir::Value*, 64> can_inline_;
+ Hashset<const core::ir::Value*, 64> can_inline_;
/// Set of enable directives emitted.
Hashset<wgsl::Extension, 4> enables_;
@@ -182,20 +182,20 @@
/// True if 'diagnostic(off, derivative_uniformity)' has been emitted
bool disabled_derivative_uniformity_ = false;
- void RootBlock(core::ir::Block* root) {
+ void RootBlock(const core::ir::Block* root) {
for (auto* inst : *root) {
tint::Switch(
- inst, //
- [&](core::ir::Var* var) { Var(var); }, //
+ inst, //
+ [&](const core::ir::Var* var) { Var(var); }, //
TINT_ICE_ON_NO_MATCH);
}
}
- const ast::Function* Fn(core::ir::Function* fn) {
+ const ast::Function* Fn(const core::ir::Function* fn) {
SCOPED_NESTING();
// TODO(crbug.com/tint/1915): Properly implement this when we've fleshed out Function
static constexpr size_t N = decltype(ast::Function::params)::static_length;
- auto params = tint::Transform<N>(fn->Params(), [&](core::ir::FunctionParam* param) {
+ auto params = tint::Transform<N>(fn->Params(), [&](const core::ir::FunctionParam* param) {
auto ty = Type(param->Type());
auto name = NameFor(param);
Bind(param, name, PtrKind::kPtr);
@@ -215,12 +215,12 @@
std::move(ret_attrs));
}
- const ast::BlockStatement* Block(core::ir::Block* block) {
+ const ast::BlockStatement* Block(const core::ir::Block* block) {
// TODO(crbug.com/tint/1902): Handle block arguments.
return b.Block(Statements(block));
}
- StatementList Statements(core::ir::Block* block) {
+ StatementList Statements(const core::ir::Block* block) {
StatementList stmts;
if (block) {
MarkInlinable(block);
@@ -232,10 +232,10 @@
return stmts;
}
- void MarkInlinable(core::ir::Block* block) {
+ void MarkInlinable(const core::ir::Block* block) {
// An ordered list of possibly-inlinable values returned by sequenced instructions that have
// not yet been marked-for or ruled-out-for inlining.
- UniqueVector<core::ir::Value*, 32> pending_resolution;
+ UniqueVector<const core::ir::Value*, 32> pending_resolution;
// Walk the instructions of the block starting with the first.
for (auto* inst : *block) {
@@ -276,7 +276,7 @@
auto* result = inst->Result(0);
// Only values with a single usage can be inlined.
// Named values are not inlined, as we want to emit the name for a let.
- if (result->Usages().Count() == 1 && !mod.NameOf(result).IsValid()) {
+ if (result->NumUsages() == 1 && !mod.NameOf(result).IsValid()) {
if (sequenced) {
// The value comes from a sequenced instruction. We need to ensure
// instruction ordering so add it to 'pending_resolution'.
@@ -301,35 +301,35 @@
void Append(const ast::Statement* inst) { statements_->Push(inst); }
- void Instruction(core::ir::Instruction* inst) {
+ void Instruction(const core::ir::Instruction* inst) {
tint::Switch(
- inst, //
- [&](core::ir::Access* i) { Access(i); }, //
- [&](core::ir::Binary* i) { Binary(i); }, //
- [&](core::ir::BreakIf* i) { BreakIf(i); }, //
- [&](core::ir::Call* i) { Call(i); }, //
- [&](core::ir::Continue*) {}, //
- [&](core::ir::ExitIf*) {}, //
- [&](core::ir::ExitLoop* i) { ExitLoop(i); }, //
- [&](core::ir::ExitSwitch* i) { ExitSwitch(i); }, //
- [&](core::ir::If* i) { If(i); }, //
- [&](core::ir::Let* i) { Let(i); }, //
- [&](core::ir::Load* l) { Load(l); }, //
- [&](core::ir::LoadVectorElement* i) { LoadVectorElement(i); }, //
- [&](core::ir::Loop* l) { Loop(l); }, //
- [&](core::ir::NextIteration*) {}, //
- [&](core::ir::Return* i) { Return(i); }, //
- [&](core::ir::Store* i) { Store(i); }, //
- [&](core::ir::StoreVectorElement* i) { StoreVectorElement(i); }, //
- [&](core::ir::Switch* i) { Switch(i); }, //
- [&](core::ir::Swizzle* i) { Swizzle(i); }, //
- [&](core::ir::Unary* i) { Unary(i); }, //
- [&](core::ir::Unreachable*) {}, //
- [&](core::ir::Var* i) { Var(i); }, //
+ inst, //
+ [&](const core::ir::Access* i) { Access(i); }, //
+ [&](const core::ir::Binary* i) { Binary(i); }, //
+ [&](const core::ir::BreakIf* i) { BreakIf(i); }, //
+ [&](const core::ir::Call* i) { Call(i); }, //
+ [&](const core::ir::Continue*) {}, //
+ [&](const core::ir::ExitIf*) {}, //
+ [&](const core::ir::ExitLoop* i) { ExitLoop(i); }, //
+ [&](const core::ir::ExitSwitch* i) { ExitSwitch(i); }, //
+ [&](const core::ir::If* i) { If(i); }, //
+ [&](const core::ir::Let* i) { Let(i); }, //
+ [&](const core::ir::Load* l) { Load(l); }, //
+ [&](const core::ir::LoadVectorElement* i) { LoadVectorElement(i); }, //
+ [&](const core::ir::Loop* l) { Loop(l); }, //
+ [&](const core::ir::NextIteration*) {}, //
+ [&](const core::ir::Return* i) { Return(i); }, //
+ [&](const core::ir::Store* i) { Store(i); }, //
+ [&](const core::ir::StoreVectorElement* i) { StoreVectorElement(i); }, //
+ [&](const core::ir::Switch* i) { Switch(i); }, //
+ [&](const core::ir::Swizzle* i) { Swizzle(i); }, //
+ [&](const core::ir::Unary* i) { Unary(i); }, //
+ [&](const core::ir::Unreachable*) {}, //
+ [&](const core::ir::Var* i) { Var(i); }, //
TINT_ICE_ON_NO_MATCH);
}
- void If(core::ir::If* if_) {
+ void If(const core::ir::If* if_) {
SCOPED_NESTING();
auto true_stmts = Statements(if_->True());
@@ -357,7 +357,7 @@
Append(b.If(cond, true_block, b.Else(false_block)));
}
- void Loop(core::ir::Loop* l) {
+ void Loop(const core::ir::Loop* l) {
SCOPED_NESTING();
// Build all the initializer statements
@@ -454,14 +454,14 @@
statements_->Push(loop);
}
- void Switch(core::ir::Switch* s) {
+ void Switch(const core::ir::Switch* s) {
SCOPED_NESTING();
auto* cond = Expr(s->Condition());
- auto cases = tint::Transform(
+ auto cases = tint::Transform<4>(
s->Cases(), //
- [&](core::ir::Switch::Case c) -> const tint::ast::CaseStatement* {
+ [&](const core::ir::Switch::Case& c) -> const tint::ast::CaseStatement* {
SCOPED_NESTING();
const ast::BlockStatement* body = nullptr;
@@ -471,7 +471,7 @@
}
auto selectors = tint::Transform(c.selectors, //
- [&](core::ir::Switch::CaseSelector cs) {
+ [&](const core::ir::Switch::CaseSelector& cs) {
return cs.IsDefault()
? b.DefaultCaseSelector()
: b.CaseSelector(Expr(cs.val));
@@ -491,9 +491,9 @@
void ExitLoop(const core::ir::ExitLoop*) { Append(b.Break()); }
- void BreakIf(core::ir::BreakIf* i) { Append(b.BreakIf(Expr(i->Condition()))); }
+ void BreakIf(const core::ir::BreakIf* i) { Append(b.BreakIf(Expr(i->Condition()))); }
- void Return(core::ir::Return* ret) {
+ void Return(const core::ir::Return* ret) {
if (ret->Args().IsEmpty()) {
// Return has no arguments.
// If this block is nested withing some control flow, then we must
@@ -514,7 +514,7 @@
Append(b.Return(Expr(ret->Args().Front())));
}
- void Var(core::ir::Var* var) {
+ void Var(const core::ir::Var* var) {
auto* val = var->Result();
auto* ptr = As<core::type::Pointer>(val->Type());
auto ty = Type(ptr->StoreType());
@@ -547,32 +547,32 @@
}
}
- void Let(core::ir::Let* let) {
+ void Let(const core::ir::Let* let) {
Symbol name = NameFor(let->Result());
Append(b.Decl(b.Let(name, Expr(let->Value(), PtrKind::kPtr))));
Bind(let->Result(), name, PtrKind::kPtr);
}
- void Store(core::ir::Store* store) {
+ void Store(const core::ir::Store* store) {
auto* dst = Expr(store->To());
auto* src = Expr(store->From());
Append(b.Assign(dst, src));
}
- void StoreVectorElement(core::ir::StoreVectorElement* store) {
+ void StoreVectorElement(const core::ir::StoreVectorElement* store) {
auto* ptr = Expr(store->To());
auto* val = Expr(store->Value());
Append(b.Assign(VectorMemberAccess(ptr, store->Index()), val));
}
- void Call(core::ir::Call* call) {
- auto args = tint::Transform<4>(call->Args(), [&](core::ir::Value* arg) {
+ void Call(const core::ir::Call* call) {
+ auto args = tint::Transform<4>(call->Args(), [&](const core::ir::Value* arg) {
// Pointer-like arguments are passed by pointer, never reference.
return Expr(arg, PtrKind::kPtr);
});
tint::Switch(
call, //
- [&](core::ir::UserCall* c) {
+ [&](const core::ir::UserCall* c) {
for (auto* arg : call->Args()) {
if (ArgRequiresFullPtrParameters(arg)) {
Enable(wgsl::Extension::kChromiumExperimentalFullPtrParameters);
@@ -580,13 +580,13 @@
}
}
auto* expr = b.Call(NameFor(c->Target()), std::move(args));
- if (call->Results().IsEmpty() || call->Result()->Usages().IsEmpty()) {
+ if (call->Results().IsEmpty() || !call->Result()->IsUsed()) {
Append(b.CallStmt(expr));
return;
}
Bind(c->Result(), expr, PtrKind::kPtr);
},
- [&](wgsl::ir::BuiltinCall* c) {
+ [&](const wgsl::ir::BuiltinCall* c) {
if (!disabled_derivative_uniformity_ && RequiresDerivativeUniformity(c->Func())) {
// TODO(crbug.com/tint/1985): Be smarter about disabling derivative uniformity.
b.DiagnosticDirective(wgsl::DiagnosticSeverity::kOff,
@@ -610,30 +610,30 @@
}
Bind(c->Result(), expr, PtrKind::kPtr);
},
- [&](core::ir::Construct* c) {
+ [&](const core::ir::Construct* c) {
auto ty = Type(c->Result()->Type());
Bind(c->Result(), b.Call(ty, std::move(args)), PtrKind::kPtr);
},
- [&](core::ir::Convert* c) {
+ [&](const core::ir::Convert* c) {
auto ty = Type(c->Result()->Type());
Bind(c->Result(), b.Call(ty, std::move(args)), PtrKind::kPtr);
},
- [&](core::ir::Bitcast* c) {
+ [&](const core::ir::Bitcast* c) {
auto ty = Type(c->Result()->Type());
Bind(c->Result(), b.Bitcast(ty, args[0]), PtrKind::kPtr);
},
- [&](core::ir::Discard*) { Append(b.Discard()); }, //
+ [&](const core::ir::Discard*) { Append(b.Discard()); }, //
TINT_ICE_ON_NO_MATCH);
}
- void Load(core::ir::Load* l) { Bind(l->Result(), Expr(l->From())); }
+ void Load(const core::ir::Load* l) { Bind(l->Result(), Expr(l->From())); }
- void LoadVectorElement(core::ir::LoadVectorElement* load) {
+ void LoadVectorElement(const core::ir::LoadVectorElement* load) {
auto* ptr = Expr(load->From());
Bind(load->Result(), VectorMemberAccess(ptr, load->Index()));
}
- void Unary(core::ir::Unary* u) {
+ void Unary(const core::ir::Unary* u) {
const ast::Expression* expr = nullptr;
switch (u->Op()) {
case core::ir::UnaryOp::kComplement:
@@ -646,7 +646,7 @@
Bind(u->Result(), expr);
}
- void Access(core::ir::Access* a) {
+ void Access(const core::ir::Access* a) {
auto* expr = Expr(a->Object());
auto* obj_ty = a->Object()->Type()->UnwrapPtr();
for (auto* index : a->Indices()) {
@@ -680,7 +680,7 @@
Bind(a->Result(), expr);
}
- void Swizzle(core::ir::Swizzle* s) {
+ void Swizzle(const core::ir::Swizzle* s) {
auto* vec = Expr(s->Object());
Vector<char, 4> components;
for (uint32_t i : s->Indices()) {
@@ -695,7 +695,7 @@
Bind(s->Result(), swizzle);
}
- void Binary(core::ir::Binary* e) {
+ void Binary(const core::ir::Binary* e) {
if (e->Op() == core::ir::BinaryOp::kEqual) {
auto* rhs = e->RHS()->As<core::ir::Constant>();
if (rhs && rhs->Type()->Is<core::type::Bool>() &&
@@ -763,12 +763,13 @@
TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
- const ast::Expression* Expr(core::ir::Value* value, PtrKind want_ptr_kind = PtrKind::kRef) {
+ const ast::Expression* Expr(const core::ir::Value* value,
+ PtrKind want_ptr_kind = PtrKind::kRef) {
using ExprAndPtrKind = std::pair<const ast::Expression*, PtrKind>;
auto [expr, got_ptr_kind] = tint::Switch(
value,
- [&](core::ir::Constant* c) -> ExprAndPtrKind {
+ [&](const core::ir::Constant* c) -> ExprAndPtrKind {
return {Constant(c), PtrKind::kRef};
},
[&](Default) -> ExprAndPtrKind {
@@ -819,7 +820,7 @@
TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
- const ast::Expression* Constant(core::ir::Constant* c) { return Constant(c->Value()); }
+ const ast::Expression* Constant(const core::ir::Constant* c) { return Constant(c->Value()); }
const ast::Expression* Constant(const core::constant::Value* c) {
auto composite = [&](bool can_splat) {
@@ -1010,7 +1011,7 @@
/// @returns the AST name for the given value, creating and returning a new name on the first
/// call.
- Symbol NameFor(core::ir::Value* value, std::string_view suggested = {}) {
+ Symbol NameFor(const core::ir::Value* value, std::string_view suggested = {}) {
return names_.GetOrCreate(value, [&] {
if (!suggested.empty()) {
return b.Symbols().Register(suggested);
@@ -1024,7 +1025,7 @@
/// Associates the IR value @p value with the AST expression @p expr.
/// @p ptr_kind defines how pointer values are represented by @p expr.
- void Bind(core::ir::Value* value,
+ void Bind(const core::ir::Value* value,
const ast::Expression* expr,
PtrKind ptr_kind = PtrKind::kRef) {
TINT_ASSERT(value);
@@ -1038,7 +1039,7 @@
expr = ToPtrKind(expr, ptr_kind, PtrKind::kPtr);
}
auto mod_name = mod.NameOf(value);
- if (value->Usages().IsEmpty() && !mod_name.IsValid()) {
+ if (!value->IsUsed() && !mod_name.IsValid()) {
// Value has no usages and no name.
// Assign to a phony. These support more data types than a 'let', and avoids
// allocation of unused names.
@@ -1057,7 +1058,7 @@
/// Associates the IR value @p value with the AST 'var', 'let' or parameter with the name @p
/// name.
/// @p ptr_kind defines how pointer values are represented by @p expr.
- void Bind(core::ir::Value* value, Symbol name, PtrKind ptr_kind) {
+ void Bind(const core::ir::Value* value, Symbol name, PtrKind ptr_kind) {
TINT_ASSERT(value);
bool added = bindings_.Add(value, VariableValue{name, ptr_kind});
@@ -1069,7 +1070,7 @@
////////////////////////////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////////////////////////////
- bool AsShortCircuit(core::ir::If* i,
+ bool AsShortCircuit(const core::ir::If* i,
const StatementList& true_stmts,
const StatementList& false_stmts) {
if (i->Results().IsEmpty()) {
@@ -1130,7 +1131,7 @@
return false;
}
- bool IsConstant(core::ir::Value* val, bool value) {
+ bool IsConstant(const core::ir::Value* val, bool value) {
if (auto* c = val->As<core::ir::Constant>()) {
if (c->Type()->Is<core::type::Bool>()) {
return c->Value()->ValueAs<bool>() == value;
@@ -1139,7 +1140,8 @@
return false;
}
- const ast::Expression* VectorMemberAccess(const ast::Expression* expr, core::ir::Value* index) {
+ const ast::Expression* VectorMemberAccess(const ast::Expression* expr,
+ const core::ir::Value* index) {
if (auto* c = index->As<core::ir::Constant>()) {
switch (c->Value()->ValueAs<int>()) {
case 0:
@@ -1205,7 +1207,7 @@
/// @returns true if the argument @p arg requires the kChromiumExperimentalFullPtrParameters
/// extension to be enabled.
- bool ArgRequiresFullPtrParameters(core::ir::Value* arg) {
+ bool ArgRequiresFullPtrParameters(const core::ir::Value* arg) {
if (!arg->Type()->Is<core::type::Pointer>()) {
return false;
}
@@ -1228,7 +1230,7 @@
} // namespace
-Program IRToProgram(core::ir::Module& i) {
+Program IRToProgram(const core::ir::Module& i) {
return State{i}.Run();
}
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h
index 267bb29..089a1e7 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h
@@ -40,7 +40,7 @@
/// @param module the IR module
/// @return the tint::Program.
/// @note Check the returned Program::Diagnostics() for any errors.
-Program IRToProgram(core::ir::Module& module);
+Program IRToProgram(const core::ir::Module& module);
} // namespace tint::wgsl::writer