blob: 602090264b065f1409c06f0b3917c738a2bd36ef [file] [log] [blame]
Austin Engcc2516a2023-10-17 20:57:54 +00001// Copyright 2022 The Dawn & Tint Authors
dan sinclaireee8d882022-10-28 01:22:58 +00002//
Austin Engcc2516a2023-10-17 20:57:54 +00003// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are met:
dan sinclaireee8d882022-10-28 01:22:58 +00005//
Austin Engcc2516a2023-10-17 20:57:54 +00006// 1. Redistributions of source code must retain the above copyright notice, this
7// list of conditions and the following disclaimer.
dan sinclaireee8d882022-10-28 01:22:58 +00008//
Austin Engcc2516a2023-10-17 20:57:54 +00009// 2. Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12//
13// 3. Neither the name of the copyright holder nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dan sinclaireee8d882022-10-28 01:22:58 +000027
dan sinclair97c37272023-07-24 17:11:53 +000028#ifndef SRC_TINT_LANG_CORE_IR_BUILDER_H_
29#define SRC_TINT_LANG_CORE_IR_BUILDER_H_
dan sinclaireee8d882022-10-28 01:22:58 +000030
dan sinclair19ebcb22022-12-15 19:17:22 +000031#include <utility>
32
dan sinclair352f8c82023-07-21 00:40:07 +000033#include "src/tint/lang/core/constant/composite.h"
34#include "src/tint/lang/core/constant/scalar.h"
35#include "src/tint/lang/core/constant/splat.h"
dan sinclair97c37272023-07-24 17:11:53 +000036#include "src/tint/lang/core/ir/access.h"
37#include "src/tint/lang/core/ir/binary.h"
38#include "src/tint/lang/core/ir/bitcast.h"
39#include "src/tint/lang/core/ir/block_param.h"
40#include "src/tint/lang/core/ir/break_if.h"
41#include "src/tint/lang/core/ir/constant.h"
42#include "src/tint/lang/core/ir/construct.h"
43#include "src/tint/lang/core/ir/continue.h"
44#include "src/tint/lang/core/ir/convert.h"
45#include "src/tint/lang/core/ir/core_builtin_call.h"
46#include "src/tint/lang/core/ir/discard.h"
47#include "src/tint/lang/core/ir/exit_if.h"
48#include "src/tint/lang/core/ir/exit_loop.h"
49#include "src/tint/lang/core/ir/exit_switch.h"
50#include "src/tint/lang/core/ir/function.h"
51#include "src/tint/lang/core/ir/function_param.h"
52#include "src/tint/lang/core/ir/if.h"
53#include "src/tint/lang/core/ir/instruction_result.h"
dan sinclair97c37272023-07-24 17:11:53 +000054#include "src/tint/lang/core/ir/let.h"
55#include "src/tint/lang/core/ir/load.h"
56#include "src/tint/lang/core/ir/load_vector_element.h"
57#include "src/tint/lang/core/ir/loop.h"
58#include "src/tint/lang/core/ir/module.h"
59#include "src/tint/lang/core/ir/multi_in_block.h"
60#include "src/tint/lang/core/ir/next_iteration.h"
61#include "src/tint/lang/core/ir/return.h"
62#include "src/tint/lang/core/ir/store.h"
63#include "src/tint/lang/core/ir/store_vector_element.h"
64#include "src/tint/lang/core/ir/switch.h"
65#include "src/tint/lang/core/ir/swizzle.h"
66#include "src/tint/lang/core/ir/terminate_invocation.h"
67#include "src/tint/lang/core/ir/unary.h"
68#include "src/tint/lang/core/ir/unreachable.h"
69#include "src/tint/lang/core/ir/user_call.h"
70#include "src/tint/lang/core/ir/value.h"
71#include "src/tint/lang/core/ir/var.h"
dan sinclair34e03422023-08-02 20:42:41 +000072#include "src/tint/lang/core/type/array.h"
dan sinclair352f8c82023-07-21 00:40:07 +000073#include "src/tint/lang/core/type/bool.h"
74#include "src/tint/lang/core/type/f16.h"
75#include "src/tint/lang/core/type/f32.h"
76#include "src/tint/lang/core/type/i32.h"
dan sinclair34e03422023-08-02 20:42:41 +000077#include "src/tint/lang/core/type/matrix.h"
dan sinclair352f8c82023-07-21 00:40:07 +000078#include "src/tint/lang/core/type/pointer.h"
79#include "src/tint/lang/core/type/u32.h"
80#include "src/tint/lang/core/type/vector.h"
81#include "src/tint/lang/core/type/void.h"
Ben Claytonf848af22023-07-28 16:37:32 +000082#include "src/tint/utils/ice/ice.h"
dan sinclair22b4dd22023-07-21 00:40:07 +000083#include "src/tint/utils/macros/scoped_assignment.h"
84#include "src/tint/utils/rtti/switch.h"
dan sinclaireee8d882022-10-28 01:22:58 +000085
dan sinclair6f138fe2023-08-15 21:29:34 +000086namespace tint::core::ir {
dan sinclaireee8d882022-10-28 01:22:58 +000087
dan sinclair8bcb4e92023-01-06 19:45:13 +000088/// Builds an ir::Module
dan sinclaireee8d882022-10-28 01:22:58 +000089class Builder {
Ben Clayton8232b502023-06-29 16:10:29 +000090 /// Evaluates to true if T is a non-reference instruction pointer.
91 template <typename T>
92 static constexpr bool IsNonRefInstPtr =
93 std::is_pointer_v<T> && std::is_base_of_v<ir::Instruction, std::remove_pointer_t<T>>;
94
95 /// static_assert()s that ARGS contains no more than one non-reference instruction pointer.
96 /// This is used to detect patterns where C++ non-deterministic evaluation order may cause
97 /// instruction ordering bugs.
98 template <typename... ARGS>
99 static constexpr void CheckForNonDeterministicEvaluation() {
100 constexpr bool possibly_non_deterministic_eval =
101 ((IsNonRefInstPtr<ARGS> ? 1 : 0) + ...) > 1;
102 static_assert(!possibly_non_deterministic_eval,
103 "Detected possible non-deterministic ordering of instructions. "
104 "Consider hoisting Builder call arguments to separate statements.");
105 }
106
dan sinclairbae54e72023-07-28 15:01:54 +0000107 /// A helper used to enable overloads if the first type in `TYPES` is a Vector or
108 /// VectorRef.
Ben Clayton039ffdc2023-06-09 22:58:09 +0000109 template <typename... TYPES>
dan sinclairbae54e72023-07-28 15:01:54 +0000110 using EnableIfVectorLike = tint::traits::EnableIf<
111 tint::IsVectorLike<tint::traits::Decay<tint::traits::NthTypeOf<0, TYPES..., void>>>>;
Ben Clayton039ffdc2023-06-09 22:58:09 +0000112
dan sinclairbae54e72023-07-28 15:01:54 +0000113 /// A helper used to disable overloads if the first type in `TYPES` is a Vector or
114 /// VectorRef.
Ben Clayton039ffdc2023-06-09 22:58:09 +0000115 template <typename... TYPES>
dan sinclairbae54e72023-07-28 15:01:54 +0000116 using DisableIfVectorLike = tint::traits::EnableIf<
117 !tint::IsVectorLike<tint::traits::Decay<tint::traits::NthTypeOf<0, TYPES..., void>>>>;
Ben Clayton039ffdc2023-06-09 22:58:09 +0000118
Ben Clayton47fe0f52023-09-20 07:47:12 +0000119 /// A namespace for the various instruction insertion method
120 struct InsertionPoints {
121 /// Insertion point method that does no insertion
122 struct NoInsertion {
123 /// The insertion point function
124 void operator()(ir::Instruction*) {}
125 };
126 /// Insertion point method that inserts the instruction to the end of #block
127 struct AppendToBlock {
128 /// The block to insert new instructions to the end of
129 ir::Block* block = nullptr;
130 /// The insertion point function
131 /// @param i the instruction to insert
132 void operator()(ir::Instruction* i) { block->Append(i); }
133 };
134 /// Insertion point method that inserts the instruction to the front of #block
135 struct PrependToBlock {
136 /// The block to insert new instructions to the front of
137 ir::Block* block = nullptr;
138 /// The insertion point function
139 /// @param i the instruction to insert
140 void operator()(ir::Instruction* i) { block->Prepend(i); }
141 };
142 /// Insertion point method that inserts the instruction after #after
143 struct InsertAfter {
144 /// The instruction to insert new instructions after
145 ir::Instruction* after = nullptr;
146 /// The insertion point function
147 /// @param i the instruction to insert
148 void operator()(ir::Instruction* i) { i->InsertAfter(after); }
149 };
150 /// Insertion point method that inserts the instruction before #before
151 struct InsertBefore {
152 /// The instruction to insert new instructions before
153 ir::Instruction* before = nullptr;
154 /// The insertion point function
155 /// @param i the instruction to insert
156 void operator()(ir::Instruction* i) { i->InsertBefore(before); }
157 };
158 };
dan sinclair2ef23112023-06-14 10:16:53 +0000159
Ben Clayton47fe0f52023-09-20 07:47:12 +0000160 /// A variant of different instruction insertion methods
161 using InsertionPoint = std::variant<InsertionPoints::NoInsertion,
162 InsertionPoints::AppendToBlock,
163 InsertionPoints::PrependToBlock,
164 InsertionPoints::InsertAfter,
165 InsertionPoints::InsertBefore>;
166
167 /// The insertion method used for new instructions.
168 InsertionPoint insertion_point_{InsertionPoints::NoInsertion{}};
James Price36b63fd2023-07-26 22:07:39 +0000169
dan sinclaireee8d882022-10-28 01:22:58 +0000170 public:
171 /// Constructor
dan sinclaireee8d882022-10-28 01:22:58 +0000172 /// @param mod the ir::Module to wrap with this builder
dan sinclair809187c2023-05-15 23:42:33 +0000173 explicit Builder(Module& mod);
dan sinclair2ef23112023-06-14 10:16:53 +0000174 /// Constructor
175 /// @param mod the ir::Module to wrap with this builder
Ben Clayton47fe0f52023-09-20 07:47:12 +0000176 /// @param block the block to append to
dan sinclair2ef23112023-06-14 10:16:53 +0000177 Builder(Module& mod, ir::Block* block);
dan sinclaireee8d882022-10-28 01:22:58 +0000178 /// Destructor
179 ~Builder();
180
James Priceecbb3ec2023-07-26 22:07:39 +0000181 /// Creates a new builder that will append to the given block
182 /// @param b the block to append new instructions to
dan sinclair2ef23112023-06-14 10:16:53 +0000183 /// @returns the builder
James Priceecbb3ec2023-07-26 22:07:39 +0000184 Builder Append(ir::Block* b) { return Builder(ir, b); }
Ben Clayton26fbdaa2023-06-22 20:46:13 +0000185
186 /// Calls @p cb with the builder appending to block @p b
187 /// @param b the block to set as the block to append to
188 /// @param cb the function to call with the builder appending to block @p b
189 template <typename FUNCTION>
James Priceecbb3ec2023-07-26 22:07:39 +0000190 void Append(ir::Block* b, FUNCTION&& cb) {
Ben Clayton47fe0f52023-09-20 07:47:12 +0000191 TINT_SCOPED_ASSIGNMENT(insertion_point_, InsertionPoints::AppendToBlock{b});
192 cb();
193 }
194
195 /// Calls @p cb with the builder prepending to block @p b
196 /// @param b the block to set as the block to prepend to
197 /// @param cb the function to call with the builder prepending to block @p b
198 template <typename FUNCTION>
199 void Prepend(ir::Block* b, FUNCTION&& cb) {
200 TINT_SCOPED_ASSIGNMENT(insertion_point_, InsertionPoints::PrependToBlock{b});
201 cb();
202 }
203
204 /// Calls @p cb with the builder inserting after @p ip
205 /// @param ip the insertion point for new instructions
206 /// @param cb the function to call with the builder inserting new instructions after @p ip
207 template <typename FUNCTION>
208 void InsertAfter(ir::Instruction* ip, FUNCTION&& cb) {
209 TINT_SCOPED_ASSIGNMENT(insertion_point_, InsertionPoints::InsertAfter{ip});
Ben Clayton26fbdaa2023-06-22 20:46:13 +0000210 cb();
211 }
dan sinclair2ef23112023-06-14 10:16:53 +0000212
James Price36b63fd2023-07-26 22:07:39 +0000213 /// Calls @p cb with the builder inserting before @p ip
214 /// @param ip the insertion point for new instructions
215 /// @param cb the function to call with the builder inserting new instructions before @p ip
216 template <typename FUNCTION>
217 void InsertBefore(ir::Instruction* ip, FUNCTION&& cb) {
Ben Clayton47fe0f52023-09-20 07:47:12 +0000218 TINT_SCOPED_ASSIGNMENT(insertion_point_, InsertionPoints::InsertBefore{ip});
James Price36b63fd2023-07-26 22:07:39 +0000219 cb();
220 }
221
Ben Clayton47fe0f52023-09-20 07:47:12 +0000222 /// Adds and returns the instruction @p instruction to the current insertion point. If there
223 /// is no current insertion point set, then @p instruction is just returned.
224 /// @param instruction the instruction to append
dan sinclair56cb75e2023-06-22 16:59:35 +0000225 /// @returns the instruction
226 template <typename T>
Ben Clayton47fe0f52023-09-20 07:47:12 +0000227 T* Append(T* instruction) {
228 std::visit([instruction](auto&& mode) { mode(instruction); }, insertion_point_);
229 return instruction;
dan sinclair56cb75e2023-06-22 16:59:35 +0000230 }
231
Ben Clayton0ebf6772023-06-08 11:36:35 +0000232 /// @returns a new block
Ben Claytonc67a4fa2023-06-09 19:34:20 +0000233 ir::Block* Block();
dan sinclaireee8d882022-10-28 01:22:58 +0000234
Ben Clayton0ebf6772023-06-08 11:36:35 +0000235 /// @returns a new multi-in block
Ben Claytonc67a4fa2023-06-09 19:34:20 +0000236 ir::MultiInBlock* MultiInBlock();
Ben Clayton0ebf6772023-06-08 11:36:35 +0000237
Ben Claytonb2746782023-06-21 10:25:50 +0000238 /// Creates a function instruction
dan sinclairc9923d22023-05-15 23:44:04 +0000239 /// @param name the function name
240 /// @param return_type the function return type
dan sinclairf59547f2023-05-16 14:43:45 +0000241 /// @param stage the function stage
242 /// @param wg_size the workgroup_size
Ben Claytonb2746782023-06-21 10:25:50 +0000243 /// @returns the instruction
Ben Claytonc67a4fa2023-06-09 19:34:20 +0000244 ir::Function* Function(std::string_view name,
dan sinclaircedcdf32023-08-10 02:39:48 +0000245 const core::type::Type* return_type,
Ben Claytonc67a4fa2023-06-09 19:34:20 +0000246 Function::PipelineStage stage = Function::PipelineStage::kUndefined,
247 std::optional<std::array<uint32_t, 3>> wg_size = {});
dan sinclairc4722c22023-05-23 22:28:33 +0000248
Ben Claytonb2746782023-06-21 10:25:50 +0000249 /// Creates an if instruction
dan sinclairc9923d22023-05-15 23:44:04 +0000250 /// @param condition the if condition
Ben Claytonb2746782023-06-21 10:25:50 +0000251 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000252 template <typename T>
253 ir::If* If(T&& condition) {
Ben Clayton8232b502023-06-29 16:10:29 +0000254 auto* cond_val = Value(std::forward<T>(condition));
255 return Append(ir.instructions.Create<ir::If>(cond_val, Block(), Block()));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000256 }
dan sinclaireee8d882022-10-28 01:22:58 +0000257
Ben Claytonb2746782023-06-21 10:25:50 +0000258 /// Creates a loop instruction
259 /// @returns the instruction
Ben Claytonc67a4fa2023-06-09 19:34:20 +0000260 ir::Loop* Loop();
dan sinclaireee8d882022-10-28 01:22:58 +0000261
Ben Claytonb2746782023-06-21 10:25:50 +0000262 /// Creates a switch instruction
dan sinclairc9923d22023-05-15 23:44:04 +0000263 /// @param condition the switch condition
Ben Claytonb2746782023-06-21 10:25:50 +0000264 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000265 template <typename T>
266 ir::Switch* Switch(T&& condition) {
Ben Clayton8232b502023-06-29 16:10:29 +0000267 auto* cond_val = Value(std::forward<T>(condition));
268 return Append(ir.instructions.Create<ir::Switch>(cond_val));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000269 }
dan sinclaird3367332022-11-01 14:34:08 +0000270
Ben Claytonb2746782023-06-21 10:25:50 +0000271 /// Creates a case for the switch @p s with the given selectors
dan sinclaird3367332022-11-01 14:34:08 +0000272 /// @param s the switch to create the case into
273 /// @param selectors the case selectors for the case statement
Ben Claytonb2746782023-06-21 10:25:50 +0000274 /// @returns the start block for the case instruction
dan sinclairbae54e72023-07-28 15:01:54 +0000275 ir::Block* Case(ir::Switch* s, VectorRef<Switch::CaseSelector> selectors);
dan sinclaird3367332022-11-01 14:34:08 +0000276
Ben Claytonb2746782023-06-21 10:25:50 +0000277 /// Creates a case for the switch @p s with the given selectors
Ben Claytonb768af42023-06-09 23:31:16 +0000278 /// @param s the switch to create the case into
279 /// @param selectors the case selectors for the case statement
Ben Claytonb2746782023-06-21 10:25:50 +0000280 /// @returns the start block for the case instruction
Ben Claytonb768af42023-06-09 23:31:16 +0000281 ir::Block* Case(ir::Switch* s, std::initializer_list<Switch::CaseSelector> selectors);
282
dan sinclair19ebcb22022-12-15 19:17:22 +0000283 /// Creates a new ir::Constant
dan sinclaire272eaf2022-11-29 23:27:46 +0000284 /// @param val the constant value
285 /// @returns the new constant
dan sinclair464b3b82023-08-09 14:14:28 +0000286 ir::Constant* Constant(const core::constant::Value* val) {
Ben Claytona0aabaf2023-06-22 23:53:09 +0000287 return ir.constants.GetOrCreate(val, [&] { return ir.values.Create<ir::Constant>(val); });
dan sinclair2d108ae2022-11-29 20:36:59 +0000288 }
289
dan sinclair19ebcb22022-12-15 19:17:22 +0000290 /// Creates a ir::Constant for an i32 Scalar
291 /// @param v the value
292 /// @returns the new constant
dan sinclairce6dffe2023-08-14 21:01:40 +0000293 ir::Constant* Constant(core::i32 v) { return Constant(ConstantValue(v)); }
dan sinclair19ebcb22022-12-15 19:17:22 +0000294
295 /// Creates a ir::Constant for a u32 Scalar
296 /// @param v the value
297 /// @returns the new constant
dan sinclairce6dffe2023-08-14 21:01:40 +0000298 ir::Constant* Constant(core::u32 v) { return Constant(ConstantValue(v)); }
dan sinclair19ebcb22022-12-15 19:17:22 +0000299
300 /// Creates a ir::Constant for a f32 Scalar
301 /// @param v the value
302 /// @returns the new constant
dan sinclairce6dffe2023-08-14 21:01:40 +0000303 ir::Constant* Constant(core::f32 v) { return Constant(ConstantValue(v)); }
dan sinclair19ebcb22022-12-15 19:17:22 +0000304
305 /// Creates a ir::Constant for a f16 Scalar
306 /// @param v the value
307 /// @returns the new constant
dan sinclairce6dffe2023-08-14 21:01:40 +0000308 ir::Constant* Constant(core::f16 v) { return Constant(ConstantValue(v)); }
dan sinclair19ebcb22022-12-15 19:17:22 +0000309
310 /// Creates a ir::Constant for a bool Scalar
311 /// @param v the value
312 /// @returns the new constant
Ben Clayton6d3bf1a2023-07-11 15:10:09 +0000313 template <typename BOOL, typename = std::enable_if_t<std::is_same_v<BOOL, bool>>>
314 ir::Constant* Constant(BOOL v) {
dan sinclair34e03422023-08-02 20:42:41 +0000315 return Constant(ConstantValue(v));
316 }
317
318 /// Retrieves the inner constant from an ir::Constant
319 /// @param constant the ir constant
dan sinclair464b3b82023-08-09 14:14:28 +0000320 /// @returns the core::constant::Value inside the constant
321 const core::constant::Value* ConstantValue(ir::Constant* constant) { return constant->Value(); }
dan sinclair34e03422023-08-02 20:42:41 +0000322
dan sinclair464b3b82023-08-09 14:14:28 +0000323 /// Creates a core::constant::Value for an i32 Scalar
dan sinclair34e03422023-08-02 20:42:41 +0000324 /// @param v the value
325 /// @returns the new constant
dan sinclairce6dffe2023-08-14 21:01:40 +0000326 const core::constant::Value* ConstantValue(core::i32 v) { return ir.constant_values.Get(v); }
dan sinclair34e03422023-08-02 20:42:41 +0000327
dan sinclair464b3b82023-08-09 14:14:28 +0000328 /// Creates a core::constant::Value for a u32 Scalar
dan sinclair34e03422023-08-02 20:42:41 +0000329 /// @param v the value
330 /// @returns the new constant
dan sinclairce6dffe2023-08-14 21:01:40 +0000331 const core::constant::Value* ConstantValue(core::u32 v) { return ir.constant_values.Get(v); }
dan sinclair34e03422023-08-02 20:42:41 +0000332
dan sinclair464b3b82023-08-09 14:14:28 +0000333 /// Creates a core::constant::Value for a f32 Scalar
dan sinclair34e03422023-08-02 20:42:41 +0000334 /// @param v the value
335 /// @returns the new constant
dan sinclairce6dffe2023-08-14 21:01:40 +0000336 const core::constant::Value* ConstantValue(core::f32 v) { return ir.constant_values.Get(v); }
dan sinclair34e03422023-08-02 20:42:41 +0000337
dan sinclair464b3b82023-08-09 14:14:28 +0000338 /// Creates a core::constant::Value for a f16 Scalar
dan sinclair34e03422023-08-02 20:42:41 +0000339 /// @param v the value
340 /// @returns the new constant
dan sinclairce6dffe2023-08-14 21:01:40 +0000341 const core::constant::Value* ConstantValue(core::f16 v) { return ir.constant_values.Get(v); }
dan sinclair34e03422023-08-02 20:42:41 +0000342
dan sinclair464b3b82023-08-09 14:14:28 +0000343 /// Creates a core::constant::Value for a bool Scalar
dan sinclair34e03422023-08-02 20:42:41 +0000344 /// @param v the value
345 /// @returns the new constant
346 template <typename BOOL, typename = std::enable_if_t<std::is_same_v<BOOL, bool>>>
dan sinclair464b3b82023-08-09 14:14:28 +0000347 const core::constant::Value* ConstantValue(BOOL v) {
dan sinclair34e03422023-08-02 20:42:41 +0000348 return ir.constant_values.Get(v);
349 }
350
351 /// Creates a new ir::Constant
dan sinclair23314ca2023-08-03 16:02:22 +0000352 /// @param ty the splat type
353 /// @param value the splat value
354 /// @param size the number of items
355 /// @returns the new constant
356 template <typename ARG>
dan sinclaircedcdf32023-08-10 02:39:48 +0000357 ir::Constant* Splat(const core::type::Type* ty, ARG&& value, size_t size) {
dan sinclair23314ca2023-08-03 16:02:22 +0000358 return Constant(
359 ir.constant_values.Splat(ty, ConstantValue(std::forward<ARG>(value)), size));
360 }
361
362 /// Creates a new ir::Constant
dan sinclair34e03422023-08-02 20:42:41 +0000363 /// @param ty the constant type
364 /// @param values the composite values
365 /// @returns the new constant
366 template <typename... ARGS, typename = DisableIfVectorLike<ARGS...>>
dan sinclaircedcdf32023-08-10 02:39:48 +0000367 ir::Constant* Composite(const core::type::Type* ty, ARGS&&... values) {
dan sinclair34e03422023-08-02 20:42:41 +0000368 return Constant(
369 ir.constant_values.Composite(ty, Vector{ConstantValue(std::forward<ARGS>(values))...}));
Ben Clayton6d3bf1a2023-07-11 15:10:09 +0000370 }
dan sinclair19ebcb22022-12-15 19:17:22 +0000371
James Pricedcf6c422023-09-29 20:48:34 +0000372 /// Creates a new zero-value ir::Constant
373 /// @param ty the constant type
374 /// @returns the new constant
375 ir::Constant* Zero(const core::type::Type* ty) { return Constant(ir.constant_values.Zero(ty)); }
376
Ben Clayton8232b502023-06-29 16:10:29 +0000377 /// @param in the input value. One of: nullptr, ir::Value*, ir::Instruction* or a numeric value.
378 /// @returns an ir::Value* from the given argument.
dan sinclair0d80c3d2023-06-19 13:32:03 +0000379 template <typename T>
Ben Clayton8232b502023-06-29 16:10:29 +0000380 ir::Value* Value(T&& in) {
381 using D = std::decay_t<T>;
382 constexpr bool is_null = std::is_same_v<T, std::nullptr_t>;
383 constexpr bool is_ptr = std::is_pointer_v<D>;
dan sinclairce6dffe2023-08-14 21:01:40 +0000384 constexpr bool is_numeric = core::IsNumeric<D>;
Ben Clayton8232b502023-06-29 16:10:29 +0000385 static_assert(is_null || is_ptr || is_numeric, "invalid argument type for Value()");
386
387 if constexpr (is_null) {
388 return nullptr;
389 } else if constexpr (is_ptr) {
390 using P = std::remove_pointer_t<D>;
391 constexpr bool is_value = std::is_base_of_v<ir::Value, P>;
392 constexpr bool is_instruction = std::is_base_of_v<ir::Instruction, P>;
393 static_assert(is_value || is_instruction, "invalid pointer type for Value()");
394
395 if constexpr (is_value) {
396 return in; /// Pass-through
397 } else if constexpr (is_instruction) {
398 /// Extract the first result from the instruction
Ben Claytonf848af22023-07-28 16:37:32 +0000399 TINT_ASSERT(in->HasResults() && !in->HasMultiResults());
Ben Clayton8232b502023-06-29 16:10:29 +0000400 return in->Result();
401 }
402 } else if constexpr (is_numeric) {
403 /// Creates a value from the given number
404 return Constant(in);
405 }
dan sinclair0d80c3d2023-06-19 13:32:03 +0000406 }
Ben Clayton039ffdc2023-06-09 22:58:09 +0000407
408 /// Pass-through overload for Values() with vector-like argument
409 /// @param vec the vector of ir::Value*
410 /// @return @p vec
dan sinclairbae54e72023-07-28 15:01:54 +0000411 template <typename VEC, typename = EnableIfVectorLike<tint::traits::Decay<VEC>>>
Ben Clayton039ffdc2023-06-09 22:58:09 +0000412 auto Values(VEC&& vec) {
413 return std::forward<VEC>(vec);
414 }
415
dan sinclairbae54e72023-07-28 15:01:54 +0000416 /// Overload for Values() with tint::Empty argument
417 /// @return tint::Empty
418 tint::EmptyType Values(tint::EmptyType) { return tint::Empty; }
Ben Clayton039ffdc2023-06-09 22:58:09 +0000419
420 /// Overload for Values() with no arguments
dan sinclairbae54e72023-07-28 15:01:54 +0000421 /// @return tint::Empty
422 tint::EmptyType Values() { return tint::Empty; }
Ben Clayton039ffdc2023-06-09 22:58:09 +0000423
424 /// @param args the arguments to pass to Value()
425 /// @returns a vector of ir::Value* built from transforming the arguments with Value()
426 template <typename... ARGS, typename = DisableIfVectorLike<ARGS...>>
427 auto Values(ARGS&&... args) {
Ben Clayton8232b502023-06-29 16:10:29 +0000428 CheckForNonDeterministicEvaluation<ARGS...>();
dan sinclairbae54e72023-07-28 15:01:54 +0000429 return Vector{Value(std::forward<ARGS>(args))...};
Ben Clayton039ffdc2023-06-09 22:58:09 +0000430 }
431
dan sinclair669e15e2022-11-23 02:11:52 +0000432 /// Creates an op for `lhs kind rhs`
Ben Claytoneee2a832023-10-17 17:33:03 +0000433 /// @param op the binary operator
dan sinclair3e449f22023-01-03 20:25:13 +0000434 /// @param type the result type of the binary expression
dan sinclair669e15e2022-11-23 02:11:52 +0000435 /// @param lhs the left-hand-side of the operation
436 /// @param rhs the right-hand-side of the operation
437 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000438 template <typename LHS, typename RHS>
Ben Claytoneee2a832023-10-17 17:33:03 +0000439 ir::Binary* Binary(BinaryOp op, const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Clayton8232b502023-06-29 16:10:29 +0000440 CheckForNonDeterministicEvaluation<LHS, RHS>();
441 auto* lhs_val = Value(std::forward<LHS>(lhs));
442 auto* rhs_val = Value(std::forward<RHS>(rhs));
443 return Append(
Ben Claytoneee2a832023-10-17 17:33:03 +0000444 ir.instructions.Create<ir::Binary>(InstructionResult(type), op, lhs_val, rhs_val));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000445 }
dan sinclair669e15e2022-11-23 02:11:52 +0000446
447 /// Creates an And operation
dan sinclair3e449f22023-01-03 20:25:13 +0000448 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000449 /// @param lhs the lhs of the add
450 /// @param rhs the rhs of the add
451 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000452 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000453 ir::Binary* And(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000454 return Binary(BinaryOp::kAnd, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000455 }
dan sinclair669e15e2022-11-23 02:11:52 +0000456
457 /// Creates an Or operation
dan sinclair3e449f22023-01-03 20:25:13 +0000458 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000459 /// @param lhs the lhs of the add
460 /// @param rhs the rhs of the add
461 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000462 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000463 ir::Binary* Or(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000464 return Binary(BinaryOp::kOr, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000465 }
dan sinclair669e15e2022-11-23 02:11:52 +0000466
467 /// Creates an Xor operation
dan sinclair3e449f22023-01-03 20:25:13 +0000468 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000469 /// @param lhs the lhs of the add
470 /// @param rhs the rhs of the add
471 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000472 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000473 ir::Binary* Xor(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000474 return Binary(BinaryOp::kXor, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000475 }
dan sinclair669e15e2022-11-23 02:11:52 +0000476
dan sinclair669e15e2022-11-23 02:11:52 +0000477 /// Creates an Equal operation
dan sinclair3e449f22023-01-03 20:25:13 +0000478 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000479 /// @param lhs the lhs of the add
480 /// @param rhs the rhs of the add
481 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000482 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000483 ir::Binary* Equal(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000484 return Binary(BinaryOp::kEqual, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000485 }
dan sinclair669e15e2022-11-23 02:11:52 +0000486
487 /// Creates an NotEqual operation
dan sinclair3e449f22023-01-03 20:25:13 +0000488 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000489 /// @param lhs the lhs of the add
490 /// @param rhs the rhs of the add
491 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000492 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000493 ir::Binary* NotEqual(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000494 return Binary(BinaryOp::kNotEqual, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000495 }
dan sinclair669e15e2022-11-23 02:11:52 +0000496
497 /// Creates an LessThan operation
dan sinclair3e449f22023-01-03 20:25:13 +0000498 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000499 /// @param lhs the lhs of the add
500 /// @param rhs the rhs of the add
501 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000502 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000503 ir::Binary* LessThan(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000504 return Binary(BinaryOp::kLessThan, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000505 }
dan sinclair669e15e2022-11-23 02:11:52 +0000506
507 /// Creates an GreaterThan operation
dan sinclair3e449f22023-01-03 20:25:13 +0000508 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000509 /// @param lhs the lhs of the add
510 /// @param rhs the rhs of the add
511 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000512 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000513 ir::Binary* GreaterThan(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000514 return Binary(BinaryOp::kGreaterThan, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000515 }
dan sinclair669e15e2022-11-23 02:11:52 +0000516
517 /// Creates an LessThanEqual operation
dan sinclair3e449f22023-01-03 20:25:13 +0000518 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000519 /// @param lhs the lhs of the add
520 /// @param rhs the rhs of the add
521 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000522 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000523 ir::Binary* LessThanEqual(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000524 return Binary(BinaryOp::kLessThanEqual, type, std::forward<LHS>(lhs),
Ben Clayton039ffdc2023-06-09 22:58:09 +0000525 std::forward<RHS>(rhs));
526 }
dan sinclair669e15e2022-11-23 02:11:52 +0000527
528 /// Creates an GreaterThanEqual operation
dan sinclair3e449f22023-01-03 20:25:13 +0000529 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000530 /// @param lhs the lhs of the add
531 /// @param rhs the rhs of the add
532 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000533 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000534 ir::Binary* GreaterThanEqual(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000535 return Binary(BinaryOp::kGreaterThanEqual, type, std::forward<LHS>(lhs),
Ben Clayton039ffdc2023-06-09 22:58:09 +0000536 std::forward<RHS>(rhs));
537 }
dan sinclair669e15e2022-11-23 02:11:52 +0000538
539 /// Creates an ShiftLeft operation
dan sinclair3e449f22023-01-03 20:25:13 +0000540 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000541 /// @param lhs the lhs of the add
542 /// @param rhs the rhs of the add
543 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000544 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000545 ir::Binary* ShiftLeft(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000546 return Binary(BinaryOp::kShiftLeft, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000547 }
dan sinclair669e15e2022-11-23 02:11:52 +0000548
549 /// Creates an ShiftRight operation
dan sinclair3e449f22023-01-03 20:25:13 +0000550 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000551 /// @param lhs the lhs of the add
552 /// @param rhs the rhs of the add
553 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000554 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000555 ir::Binary* ShiftRight(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000556 return Binary(BinaryOp::kShiftRight, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000557 }
dan sinclair669e15e2022-11-23 02:11:52 +0000558
559 /// Creates an Add operation
dan sinclair3e449f22023-01-03 20:25:13 +0000560 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000561 /// @param lhs the lhs of the add
562 /// @param rhs the rhs of the add
563 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000564 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000565 ir::Binary* Add(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000566 return Binary(BinaryOp::kAdd, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000567 }
dan sinclair669e15e2022-11-23 02:11:52 +0000568
569 /// Creates an Subtract operation
dan sinclair3e449f22023-01-03 20:25:13 +0000570 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000571 /// @param lhs the lhs of the add
572 /// @param rhs the rhs of the add
573 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000574 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000575 ir::Binary* Subtract(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000576 return Binary(BinaryOp::kSubtract, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000577 }
dan sinclair669e15e2022-11-23 02:11:52 +0000578
579 /// Creates an Multiply operation
dan sinclair3e449f22023-01-03 20:25:13 +0000580 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000581 /// @param lhs the lhs of the add
582 /// @param rhs the rhs of the add
583 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000584 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000585 ir::Binary* Multiply(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000586 return Binary(BinaryOp::kMultiply, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000587 }
dan sinclair669e15e2022-11-23 02:11:52 +0000588
589 /// Creates an Divide operation
dan sinclair3e449f22023-01-03 20:25:13 +0000590 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000591 /// @param lhs the lhs of the add
592 /// @param rhs the rhs of the add
593 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000594 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000595 ir::Binary* Divide(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000596 return Binary(BinaryOp::kDivide, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000597 }
dan sinclair669e15e2022-11-23 02:11:52 +0000598
599 /// Creates an Modulo operation
dan sinclair3e449f22023-01-03 20:25:13 +0000600 /// @param type the result type of the expression
dan sinclair669e15e2022-11-23 02:11:52 +0000601 /// @param lhs the lhs of the add
602 /// @param rhs the rhs of the add
603 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000604 template <typename LHS, typename RHS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000605 ir::Binary* Modulo(const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
Ben Claytoneee2a832023-10-17 17:33:03 +0000606 return Binary(BinaryOp::kModulo, type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000607 }
dan sinclair669e15e2022-11-23 02:11:52 +0000608
Ben Claytonf7055d72023-10-21 01:39:08 +0000609 /// Creates an op for `op val`
610 /// @param op the unary operator
dan sinclair5aa7ef22023-04-26 00:08:35 +0000611 /// @param type the result type of the binary expression
612 /// @param val the value of the operation
613 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000614 template <typename VAL>
Ben Claytonf7055d72023-10-21 01:39:08 +0000615 ir::Unary* Unary(UnaryOp op, const core::type::Type* type, VAL&& val) {
Ben Clayton8232b502023-06-29 16:10:29 +0000616 auto* value = Value(std::forward<VAL>(val));
Ben Claytonf7055d72023-10-21 01:39:08 +0000617 return Append(ir.instructions.Create<ir::Unary>(InstructionResult(type), op, value));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000618 }
dan sinclair5aa7ef22023-04-26 00:08:35 +0000619
dan sinclair5aa7ef22023-04-26 00:08:35 +0000620 /// Creates a Complement operation
621 /// @param type the result type of the expression
622 /// @param val the value
623 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000624 template <typename VAL>
dan sinclaircedcdf32023-08-10 02:39:48 +0000625 ir::Unary* Complement(const core::type::Type* type, VAL&& val) {
Ben Claytonf7055d72023-10-21 01:39:08 +0000626 return Unary(ir::UnaryOp::kComplement, type, std::forward<VAL>(val));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000627 }
dan sinclair5aa7ef22023-04-26 00:08:35 +0000628
dan sinclair5aa7ef22023-04-26 00:08:35 +0000629 /// Creates a Negation operation
630 /// @param type the result type of the expression
631 /// @param val the value
632 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000633 template <typename VAL>
dan sinclaircedcdf32023-08-10 02:39:48 +0000634 ir::Unary* Negation(const core::type::Type* type, VAL&& val) {
Ben Claytonf7055d72023-10-21 01:39:08 +0000635 return Unary(ir::UnaryOp::kNegation, type, std::forward<VAL>(val));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000636 }
dan sinclair5aa7ef22023-04-26 00:08:35 +0000637
638 /// Creates a Not operation
639 /// @param type the result type of the expression
640 /// @param val the value
641 /// @returns the operation
Ben Clayton039ffdc2023-06-09 22:58:09 +0000642 template <typename VAL>
dan sinclaircedcdf32023-08-10 02:39:48 +0000643 ir::Binary* Not(const core::type::Type* type, VAL&& val) {
644 if (auto* vec = type->As<core::type::Vector>()) {
dan sinclair23314ca2023-08-03 16:02:22 +0000645 return Equal(type, std::forward<VAL>(val), Splat(vec, false, vec->Width()));
James Price57c46292023-07-14 16:30:28 +0000646 } else {
647 return Equal(type, std::forward<VAL>(val), Constant(false));
648 }
Ben Clayton039ffdc2023-06-09 22:58:09 +0000649 }
dan sinclair5aa7ef22023-04-26 00:08:35 +0000650
dan sinclair4cef4362023-01-03 20:29:43 +0000651 /// Creates a bitcast instruction
652 /// @param type the result type of the bitcast
653 /// @param val the value being bitcast
654 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000655 template <typename VAL>
dan sinclaircedcdf32023-08-10 02:39:48 +0000656 ir::Bitcast* Bitcast(const core::type::Type* type, VAL&& val) {
Ben Clayton8232b502023-06-29 16:10:29 +0000657 auto* value = Value(std::forward<VAL>(val));
658 return Append(ir.instructions.Create<ir::Bitcast>(InstructionResult(type), value));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000659 }
dan sinclair4cef4362023-01-03 20:29:43 +0000660
dan sinclair69108d02023-04-25 20:44:18 +0000661 /// Creates a discard instruction
662 /// @returns the instruction
663 ir::Discard* Discard();
664
dan sinclair724a70f2023-03-08 21:19:13 +0000665 /// Creates a user function call instruction
Ben Clayton50216312023-09-25 15:38:43 +0000666 /// @param func the function to call
667 /// @param args the call arguments
668 /// @returns the instruction
669 template <typename... ARGS>
670 ir::UserCall* Call(ir::Function* func, ARGS&&... args) {
671 return Call(func->ReturnType(), func, std::forward<ARGS>(args)...);
672 }
673
674 /// Creates a user function call instruction
dan sinclair724a70f2023-03-08 21:19:13 +0000675 /// @param type the return type of the call
Ben Clayton039ffdc2023-06-09 22:58:09 +0000676 /// @param func the function to call
dan sinclair724a70f2023-03-08 21:19:13 +0000677 /// @param args the call arguments
678 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000679 template <typename... ARGS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000680 ir::UserCall* Call(const core::type::Type* type, ir::Function* func, ARGS&&... args) {
dan sinclair0d80c3d2023-06-19 13:32:03 +0000681 return Append(ir.instructions.Create<ir::UserCall>(InstructionResult(type), func,
682 Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000683 }
Ben Clayton1d0ac042023-06-09 16:53:12 +0000684
dan sinclairffb45882023-07-13 22:10:41 +0000685 /// Creates a core builtin call instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000686 /// @param type the return type of the call
687 /// @param func the builtin function to call
Ben Clayton1d0ac042023-06-09 16:53:12 +0000688 /// @param args the call arguments
689 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000690 template <typename... ARGS>
Ben Claytond9766dc2023-09-21 12:41:20 +0000691 ir::CoreBuiltinCall* Call(const core::type::Type* type, core::BuiltinFn func, ARGS&&... args) {
dan sinclairffb45882023-07-13 22:10:41 +0000692 return Append(ir.instructions.Create<ir::CoreBuiltinCall>(
693 InstructionResult(type), func, Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000694 }
dan sinclair724a70f2023-03-08 21:19:13 +0000695
dan sinclair774b6a42023-09-06 21:04:30 +0000696 /// Creates a core builtin call instruction
697 /// @param type the return type of the call
698 /// @param func the builtin function to call
699 /// @param args the call arguments
700 /// @returns the instruction
701 template <typename KLASS, typename FUNC, typename... ARGS>
702 tint::traits::EnableIf<tint::traits::IsTypeOrDerived<KLASS, ir::BuiltinCall>, KLASS*>
703 Call(const core::type::Type* type, FUNC func, ARGS&&... args) {
704 return Append(ir.instructions.Create<KLASS>(InstructionResult(type), func,
705 Values(std::forward<ARGS>(args)...)));
706 }
707
Ben Clayton50216312023-09-25 15:38:43 +0000708 /// Creates a value conversion instruction to the template type T
709 /// @param val the value to be converted
710 /// @returns the instruction
711 template <typename T, typename VAL>
712 ir::Convert* Convert(VAL&& val) {
713 auto* type = ir.Types().Get<T>();
714 return Convert(type, std::forward<VAL>(val));
715 }
716
dan sinclair724a70f2023-03-08 21:19:13 +0000717 /// Creates a value conversion instruction
718 /// @param to the type converted to
Ben Clayton039ffdc2023-06-09 22:58:09 +0000719 /// @param val the value to be converted
dan sinclair724a70f2023-03-08 21:19:13 +0000720 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000721 template <typename VAL>
dan sinclaircedcdf32023-08-10 02:39:48 +0000722 ir::Convert* Convert(const core::type::Type* to, VAL&& val) {
dan sinclair0d80c3d2023-06-19 13:32:03 +0000723 return Append(ir.instructions.Create<ir::Convert>(InstructionResult(to),
724 Value(std::forward<VAL>(val))));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000725 }
dan sinclair724a70f2023-03-08 21:19:13 +0000726
Ben Clayton50216312023-09-25 15:38:43 +0000727 /// Creates a value constructor instruction to the template type T
728 /// @param args the arguments to the constructor
729 /// @returns the instruction
730 template <typename T, typename... ARGS>
731 ir::Construct* Construct(ARGS&&... args) {
732 auto* type = ir.Types().Get<T>();
733 return Construct(type, std::forward<ARGS>(args)...);
734 }
735
dan sinclair724a70f2023-03-08 21:19:13 +0000736 /// Creates a value constructor instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000737 /// @param type the type to constructed
Ben Clayton4abe1b02023-06-09 18:20:18 +0000738 /// @param args the arguments to the constructor
dan sinclair724a70f2023-03-08 21:19:13 +0000739 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000740 template <typename... ARGS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000741 ir::Construct* Construct(const core::type::Type* type, ARGS&&... args) {
dan sinclair0d80c3d2023-06-19 13:32:03 +0000742 return Append(ir.instructions.Create<ir::Construct>(InstructionResult(type),
743 Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000744 }
dan sinclair724a70f2023-03-08 21:19:13 +0000745
James Price90b8cc12023-05-17 18:41:27 +0000746 /// Creates a load instruction
747 /// @param from the expression being loaded from
748 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000749 template <typename VAL>
750 ir::Load* Load(VAL&& from) {
Ben Clayton8232b502023-06-29 16:10:29 +0000751 auto* value = Value(std::forward<VAL>(from));
dan sinclair0d80c3d2023-06-19 13:32:03 +0000752 return Append(
Ben Clayton8232b502023-06-29 16:10:29 +0000753 ir.instructions.Create<ir::Load>(InstructionResult(value->Type()->UnwrapPtr()), value));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000754 }
James Price90b8cc12023-05-17 18:41:27 +0000755
756 /// Creates a store instruction
dan sinclairaa97bb52023-04-26 00:15:31 +0000757 /// @param to the expression being stored too
758 /// @param from the expression being stored
759 /// @returns the instruction
Ben Clayton8232b502023-06-29 16:10:29 +0000760 template <typename TO, typename FROM>
761 ir::Store* Store(TO&& to, FROM&& from) {
762 CheckForNonDeterministicEvaluation<TO, FROM>();
763 auto* to_val = Value(std::forward<TO>(to));
764 auto* from_val = Value(std::forward<FROM>(from));
765 return Append(ir.instructions.Create<ir::Store>(to_val, from_val));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000766 }
dan sinclairaa97bb52023-04-26 00:15:31 +0000767
Ben Claytona8fce7c2023-07-12 18:39:00 +0000768 /// Creates a store vector element instruction
769 /// @param to the vector pointer expression being stored too
770 /// @param index the new vector element index
771 /// @param value the new vector element expression
772 /// @returns the instruction
773 template <typename TO, typename INDEX, typename VALUE>
774 ir::StoreVectorElement* StoreVectorElement(TO&& to, INDEX&& index, VALUE&& value) {
775 CheckForNonDeterministicEvaluation<TO, INDEX, VALUE>();
776 auto* to_val = Value(std::forward<TO>(to));
777 auto* index_val = Value(std::forward<INDEX>(index));
778 auto* value_val = Value(std::forward<VALUE>(value));
779 return Append(ir.instructions.Create<ir::StoreVectorElement>(to_val, index_val, value_val));
780 }
781
782 /// Creates a load vector element instruction
783 /// @param from the vector pointer expression being loaded from
784 /// @param index the new vector element index
785 /// @returns the instruction
786 template <typename FROM, typename INDEX>
787 ir::LoadVectorElement* LoadVectorElement(FROM&& from, INDEX&& index) {
788 CheckForNonDeterministicEvaluation<FROM, INDEX>();
789 auto* from_val = Value(std::forward<FROM>(from));
790 auto* index_val = Value(std::forward<INDEX>(index));
791 auto* res = InstructionResult(VectorPtrElementType(from_val->Type()));
792 return Append(ir.instructions.Create<ir::LoadVectorElement>(res, from_val, index_val));
793 }
794
dan sinclairc970e802023-05-02 15:47:29 +0000795 /// Creates a new `var` declaration
796 /// @param type the var type
dan sinclairc970e802023-05-02 15:47:29 +0000797 /// @returns the instruction
dan sinclaircedcdf32023-08-10 02:39:48 +0000798 ir::Var* Var(const core::type::Pointer* type);
dan sinclairc970e802023-05-02 15:47:29 +0000799
James Price54482352023-06-28 16:21:18 +0000800 /// Creates a new `var` declaration with a name
801 /// @param name the var name
802 /// @param type the var type
803 /// @returns the instruction
dan sinclaircedcdf32023-08-10 02:39:48 +0000804 ir::Var* Var(std::string_view name, const core::type::Pointer* type);
James Price54482352023-06-28 16:21:18 +0000805
Ben Clayton50216312023-09-25 15:38:43 +0000806 /// Creates a new `var` declaration with a name and initializer value
Ben Claytonfc754962023-09-26 07:12:46 +0000807 /// @tparam SPACE the var's address space
808 /// @tparam ACCESS the var's access mode
Ben Clayton50216312023-09-25 15:38:43 +0000809 /// @param name the var name
810 /// @param init the var initializer
811 /// @returns the instruction
812 template <core::AddressSpace SPACE = core::AddressSpace::kFunction,
813 core::Access ACCESS = core::Access::kReadWrite,
814 typename VALUE = void>
815 ir::Var* Var(std::string_view name, VALUE&& init) {
816 auto* val = Value(std::forward<VALUE>(init));
817 if (TINT_UNLIKELY(!val)) {
818 TINT_ASSERT(val);
819 return nullptr;
820 }
821 auto* var = Var(name, ir.Types().ptr(SPACE, val->Type(), ACCESS));
822 var->SetInitializer(val);
823 ir.SetName(var->Result(), name);
824 return var;
825 }
826
Ben Claytonfc754962023-09-26 07:12:46 +0000827 /// Creates a new `var` declaration
828 /// @tparam SPACE the var's address space
829 /// @tparam T the storage pointer's element type
830 /// @tparam ACCESS the var's access mode
831 /// @returns the instruction
832 template <core::AddressSpace SPACE, typename T, core::Access ACCESS = core::Access::kReadWrite>
833 ir::Var* Var() {
834 return Var(ir.Types().ptr<SPACE, T, ACCESS>());
835 }
836
837 /// Creates a new `var` declaration with a name
838 /// @tparam SPACE the var's address space
839 /// @tparam T the storage pointer's element type
840 /// @tparam ACCESS the var's access mode
841 /// @param name the var name
842 /// @returns the instruction
843 template <core::AddressSpace SPACE, typename T, core::Access ACCESS = core::Access::kReadWrite>
844 ir::Var* Var(std::string_view name) {
Ben Claytona1de3cc2023-09-26 17:43:06 +0000845 return Var(name, ir.Types().ptr<SPACE, T, ACCESS>());
Ben Claytonfc754962023-09-26 07:12:46 +0000846 }
847
Ben Clayton56343fe2023-07-11 09:01:04 +0000848 /// Creates a new `let` declaration
849 /// @param name the let name
850 /// @param value the let value
851 /// @returns the instruction
852 template <typename VALUE>
853 ir::Let* Let(std::string_view name, VALUE&& value) {
854 auto* val = Value(std::forward<VALUE>(value));
855 if (TINT_UNLIKELY(!val)) {
Ben Claytonf848af22023-07-28 16:37:32 +0000856 TINT_ASSERT(val);
Ben Clayton56343fe2023-07-11 09:01:04 +0000857 return nullptr;
858 }
859 auto* let = Append(ir.instructions.Create<ir::Let>(InstructionResult(val->Type()), val));
Ben Clayton56343fe2023-07-11 09:01:04 +0000860 ir.SetName(let->Result(), name);
861 return let;
862 }
863
dan sinclair68a8b092023-05-26 04:31:50 +0000864 /// Creates a return instruction
865 /// @param func the function being returned
Ben Clayton039ffdc2023-06-09 22:58:09 +0000866 /// @returns the instruction
dan sinclair367fad82023-06-19 12:58:53 +0000867 ir::Return* Return(ir::Function* func) {
868 return Append(ir.instructions.Create<ir::Return>(func));
869 }
Ben Clayton039ffdc2023-06-09 22:58:09 +0000870
871 /// Creates a return instruction
872 /// @param func the function being returned
James Price7d7dce32023-06-09 13:34:22 +0000873 /// @param value the return value
dan sinclair68a8b092023-05-26 04:31:50 +0000874 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000875 template <typename ARG>
876 ir::Return* Return(ir::Function* func, ARG&& value) {
James Price9e819bf2023-06-28 12:13:41 +0000877 if constexpr (std::is_same_v<std::decay_t<ARG>, ir::Value*>) {
878 if (value == nullptr) {
879 return Append(ir.instructions.Create<ir::Return>(func));
880 }
881 }
Ben Clayton8232b502023-06-29 16:10:29 +0000882 auto* val = Value(std::forward<ARG>(value));
883 return Append(ir.instructions.Create<ir::Return>(func, val));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000884 }
dan sinclair68a8b092023-05-26 04:31:50 +0000885
dan sinclair02025312023-05-26 13:14:44 +0000886 /// Creates a loop next iteration instruction
887 /// @param loop the loop being iterated
Ben Claytonb2746782023-06-21 10:25:50 +0000888 /// @param args the arguments for the target MultiInBlock
dan sinclair02025312023-05-26 13:14:44 +0000889 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000890 template <typename... ARGS>
891 ir::NextIteration* NextIteration(ir::Loop* loop, ARGS&&... args) {
dan sinclair2ef23112023-06-14 10:16:53 +0000892 return Append(
dan sinclair367fad82023-06-19 12:58:53 +0000893 ir.instructions.Create<ir::NextIteration>(loop, Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000894 }
dan sinclair02025312023-05-26 13:14:44 +0000895
dan sinclaire9825202023-05-26 11:33:38 +0000896 /// Creates a loop break-if instruction
897 /// @param condition the break condition
898 /// @param loop the loop being iterated
Ben Claytonb2746782023-06-21 10:25:50 +0000899 /// @param args the arguments for the target MultiInBlock
dan sinclaire9825202023-05-26 11:33:38 +0000900 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000901 template <typename CONDITION, typename... ARGS>
Ben Clayton3d9c5562023-06-28 23:59:23 +0000902 ir::BreakIf* BreakIf(ir::Loop* loop, CONDITION&& condition, ARGS&&... args) {
Ben Clayton8232b502023-06-29 16:10:29 +0000903 CheckForNonDeterministicEvaluation<CONDITION, ARGS...>();
904 auto* cond_val = Value(std::forward<CONDITION>(condition));
905 return Append(ir.instructions.Create<ir::BreakIf>(cond_val, loop,
906 Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000907 }
dan sinclaire9825202023-05-26 11:33:38 +0000908
dan sinclair49573272023-05-26 04:33:30 +0000909 /// Creates a continue instruction
910 /// @param loop the loop being continued
Ben Claytonb2746782023-06-21 10:25:50 +0000911 /// @param args the arguments for the target MultiInBlock
dan sinclair49573272023-05-26 04:33:30 +0000912 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000913 template <typename... ARGS>
914 ir::Continue* Continue(ir::Loop* loop, ARGS&&... args) {
dan sinclair367fad82023-06-19 12:58:53 +0000915 return Append(
916 ir.instructions.Create<ir::Continue>(loop, Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000917 }
dan sinclair49573272023-05-26 04:33:30 +0000918
dan sinclairbdbbffb2023-05-26 11:42:22 +0000919 /// Creates an exit switch instruction
920 /// @param sw the switch being exited
Ben Claytonb2746782023-06-21 10:25:50 +0000921 /// @param args the arguments for the target MultiInBlock
dan sinclairbdbbffb2023-05-26 11:42:22 +0000922 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000923 template <typename... ARGS>
924 ir::ExitSwitch* ExitSwitch(ir::Switch* sw, ARGS&&... args) {
dan sinclair367fad82023-06-19 12:58:53 +0000925 return Append(
926 ir.instructions.Create<ir::ExitSwitch>(sw, Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000927 }
dan sinclairbdbbffb2023-05-26 11:42:22 +0000928
929 /// Creates an exit loop instruction
930 /// @param loop the loop being exited
Ben Claytonb2746782023-06-21 10:25:50 +0000931 /// @param args the arguments for the target MultiInBlock
dan sinclairbdbbffb2023-05-26 11:42:22 +0000932 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000933 template <typename... ARGS>
934 ir::ExitLoop* ExitLoop(ir::Loop* loop, ARGS&&... args) {
dan sinclair367fad82023-06-19 12:58:53 +0000935 return Append(
936 ir.instructions.Create<ir::ExitLoop>(loop, Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000937 }
dan sinclairbdbbffb2023-05-26 11:42:22 +0000938
939 /// Creates an exit if instruction
940 /// @param i the if being exited
Ben Claytonb2746782023-06-21 10:25:50 +0000941 /// @param args the arguments for the target MultiInBlock
dan sinclair68b4e642023-05-23 22:26:24 +0000942 /// @returns the instruction
Ben Clayton039ffdc2023-06-09 22:58:09 +0000943 template <typename... ARGS>
944 ir::ExitIf* ExitIf(ir::If* i, ARGS&&... args) {
dan sinclair367fad82023-06-19 12:58:53 +0000945 return Append(ir.instructions.Create<ir::ExitIf>(i, Values(std::forward<ARGS>(args)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000946 }
dan sinclair68b4e642023-05-23 22:26:24 +0000947
Ben Claytona059e592023-06-19 16:59:00 +0000948 /// Creates an exit instruction for the given control instruction
949 /// @param inst the control instruction being exited
Ben Claytonb2746782023-06-21 10:25:50 +0000950 /// @param args the arguments for the target MultiInBlock
Ben Claytona059e592023-06-19 16:59:00 +0000951 /// @returns the exit instruction, or nullptr if the control instruction is not supported.
952 template <typename... ARGS>
Ben Claytonb2746782023-06-21 10:25:50 +0000953 ir::Exit* Exit(ir::ControlInstruction* inst, ARGS&&... args) {
Ben Claytona059e592023-06-19 16:59:00 +0000954 return tint::Switch(
955 inst, //
956 [&](ir::If* i) { return ExitIf(i, std::forward<ARGS>(args)...); },
957 [&](ir::Loop* i) { return ExitLoop(i, std::forward<ARGS>(args)...); },
958 [&](ir::Switch* i) { return ExitSwitch(i, std::forward<ARGS>(args)...); });
959 }
960
dan sinclair05316102023-05-17 13:28:47 +0000961 /// Creates a new `BlockParam`
962 /// @param type the parameter type
963 /// @returns the value
dan sinclaircedcdf32023-08-10 02:39:48 +0000964 ir::BlockParam* BlockParam(const core::type::Type* type);
dan sinclair05316102023-05-17 13:28:47 +0000965
James Price0a6f4082023-07-29 00:21:35 +0000966 /// Creates a new `BlockParam` with a name.
967 /// @param name the parameter name
968 /// @param type the parameter type
969 /// @returns the value
dan sinclaircedcdf32023-08-10 02:39:48 +0000970 ir::BlockParam* BlockParam(std::string_view name, const core::type::Type* type);
James Price0a6f4082023-07-29 00:21:35 +0000971
dan sinclair84d750e2023-05-18 08:50:34 +0000972 /// Creates a new `FunctionParam`
973 /// @param type the parameter type
974 /// @returns the value
dan sinclaircedcdf32023-08-10 02:39:48 +0000975 ir::FunctionParam* FunctionParam(const core::type::Type* type);
dan sinclair84d750e2023-05-18 08:50:34 +0000976
James Price25b51462023-06-28 12:13:41 +0000977 /// Creates a new `FunctionParam` with a name.
978 /// @param name the parameter name
979 /// @param type the parameter type
980 /// @returns the value
dan sinclaircedcdf32023-08-10 02:39:48 +0000981 ir::FunctionParam* FunctionParam(std::string_view name, const core::type::Type* type);
James Price25b51462023-06-28 12:13:41 +0000982
dan sinclairfb4d0ae2023-06-02 10:58:22 +0000983 /// Creates a new `Access`
984 /// @param type the return type
Ben Clayton039ffdc2023-06-09 22:58:09 +0000985 /// @param object the object being accessed
dan sinclairfb4d0ae2023-06-02 10:58:22 +0000986 /// @param indices the access indices
987 /// @returns the instruction
dan sinclair0d80c3d2023-06-19 13:32:03 +0000988 template <typename OBJ, typename... ARGS>
dan sinclaircedcdf32023-08-10 02:39:48 +0000989 ir::Access* Access(const core::type::Type* type, OBJ&& object, ARGS&&... indices) {
Ben Clayton8232b502023-06-29 16:10:29 +0000990 CheckForNonDeterministicEvaluation<OBJ, ARGS...>();
991 auto* obj_val = Value(std::forward<OBJ>(object));
992 return Append(ir.instructions.Create<ir::Access>(InstructionResult(type), obj_val,
dan sinclair367fad82023-06-19 12:58:53 +0000993 Values(std::forward<ARGS>(indices)...)));
Ben Clayton039ffdc2023-06-09 22:58:09 +0000994 }
dan sinclairfb4d0ae2023-06-02 10:58:22 +0000995
dan sinclair9c2369a2023-06-02 18:33:59 +0000996 /// Creates a new `Swizzle`
997 /// @param type the return type
Ben Clayton039ffdc2023-06-09 22:58:09 +0000998 /// @param object the object being swizzled
999 /// @param indices the swizzle indices
dan sinclair9c2369a2023-06-02 18:33:59 +00001000 /// @returns the instruction
dan sinclair0d80c3d2023-06-19 13:32:03 +00001001 template <typename OBJ>
dan sinclaircedcdf32023-08-10 02:39:48 +00001002 ir::Swizzle* Swizzle(const core::type::Type* type, OBJ&& object, VectorRef<uint32_t> indices) {
Ben Clayton8232b502023-06-29 16:10:29 +00001003 auto* obj_val = Value(std::forward<OBJ>(object));
1004 return Append(ir.instructions.Create<ir::Swizzle>(InstructionResult(type), obj_val,
1005 std::move(indices)));
dan sinclair0d80c3d2023-06-19 13:32:03 +00001006 }
Ben Clayton039ffdc2023-06-09 22:58:09 +00001007
1008 /// Creates a new `Swizzle`
1009 /// @param type the return type
1010 /// @param object the object being swizzled
1011 /// @param indices the swizzle indices
1012 /// @returns the instruction
dan sinclair0d80c3d2023-06-19 13:32:03 +00001013 template <typename OBJ>
dan sinclaircedcdf32023-08-10 02:39:48 +00001014 ir::Swizzle* Swizzle(const core::type::Type* type,
dan sinclair0d80c3d2023-06-19 13:32:03 +00001015 OBJ&& object,
1016 std::initializer_list<uint32_t> indices) {
Ben Clayton8232b502023-06-29 16:10:29 +00001017 auto* obj_val = Value(std::forward<OBJ>(object));
1018 return Append(ir.instructions.Create<ir::Swizzle>(InstructionResult(type), obj_val,
dan sinclairbae54e72023-07-28 15:01:54 +00001019 Vector<uint32_t, 4>(indices)));
dan sinclair0d80c3d2023-06-19 13:32:03 +00001020 }
dan sinclair9c2369a2023-06-02 18:33:59 +00001021
James Price3adb3212023-07-12 19:05:15 +00001022 /// Creates a terminate invocation instruction
1023 /// @returns the instruction
1024 ir::TerminateInvocation* TerminateInvocation();
1025
Ben Clayton4915adc2023-06-19 21:32:11 +00001026 /// Creates an unreachable instruction
1027 /// @returns the instruction
1028 ir::Unreachable* Unreachable();
1029
dan sinclair367fad82023-06-19 12:58:53 +00001030 /// Creates a new runtime value
1031 /// @param type the return type
1032 /// @returns the value
dan sinclaircedcdf32023-08-10 02:39:48 +00001033 ir::InstructionResult* InstructionResult(const core::type::Type* type) {
dan sinclair367fad82023-06-19 12:58:53 +00001034 return ir.values.Create<ir::InstructionResult>(type);
1035 }
1036
James Price6f8cb5f2023-07-29 13:11:28 +00001037 /// Create a ranged loop with a callback to build the loop body.
1038 /// @param ty the type manager to use for new types
1039 /// @param start the first loop index
1040 /// @param end one past the last loop index
1041 /// @param step the loop index step amount
1042 /// @param cb the callback to call for the loop body
1043 template <typename START, typename END, typename STEP, typename FUNCTION>
dan sinclaircedcdf32023-08-10 02:39:48 +00001044 void LoopRange(core::type::Manager& ty, START&& start, END&& end, STEP&& step, FUNCTION&& cb) {
James Price6f8cb5f2023-07-29 13:11:28 +00001045 auto* start_value = Value(std::forward<START>(start));
1046 auto* end_value = Value(std::forward<END>(end));
1047 auto* step_value = Value(std::forward<STEP>(step));
1048
1049 auto* loop = Loop();
1050 auto* idx = BlockParam("idx", start_value->Type());
1051 loop->Body()->SetParams({idx});
1052 Append(loop->Initializer(), [&] {
1053 // Start the loop with `idx = start`.
1054 NextIteration(loop, start_value);
1055 });
1056 Append(loop->Body(), [&] {
1057 // Loop until `idx == end`.
1058 auto* breakif = If(GreaterThanEqual(ty.bool_(), idx, end_value));
1059 Append(breakif->True(), [&] { //
1060 ExitLoop(loop);
1061 });
1062
1063 cb(idx);
1064
1065 Continue(loop);
1066 });
1067 Append(loop->Continuing(), [&] {
1068 // Update the index with `idx += step` and go to the next iteration.
1069 auto* new_idx = Add(idx->Type(), idx, step_value);
1070 NextIteration(loop, new_idx);
1071 });
1072 }
1073
dan sinclaireee8d882022-10-28 01:22:58 +00001074 /// The IR module.
dan sinclair809187c2023-05-15 23:42:33 +00001075 Module& ir;
Ben Claytona8fce7c2023-07-12 18:39:00 +00001076
1077 private:
1078 /// @returns the element type of the vector-pointer type
1079 /// Asserts and return i32 if @p type is not a pointer to a vector
dan sinclaircedcdf32023-08-10 02:39:48 +00001080 const core::type::Type* VectorPtrElementType(const core::type::Type* type);
dan sinclaireee8d882022-10-28 01:22:58 +00001081};
1082
dan sinclair6f138fe2023-08-15 21:29:34 +00001083} // namespace tint::core::ir
dan sinclaireee8d882022-10-28 01:22:58 +00001084
dan sinclair97c37272023-07-24 17:11:53 +00001085#endif // SRC_TINT_LANG_CORE_IR_BUILDER_H_