| // Copyright 2022 The Tint Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "src/tint/ir/builder.h" |
| |
| #include <utility> |
| |
| #include "src/tint/constant/scalar.h" |
| #include "src/tint/type/pointer.h" |
| #include "src/tint/type/reference.h" |
| |
| namespace tint::ir { |
| |
| Builder::Builder(Module& mod) : ir(mod) {} |
| |
| Builder::~Builder() = default; |
| |
| ir::Block* Builder::CreateRootBlockIfNeeded() { |
| if (!ir.root_block) { |
| ir.root_block = CreateBlock(); |
| } |
| return ir.root_block; |
| } |
| |
| Block* Builder::CreateBlock() { |
| return ir.blocks.Create<Block>(); |
| } |
| |
| RootTerminator* Builder::CreateRootTerminator() { |
| return ir.blocks.Create<RootTerminator>(); |
| } |
| |
| Function* Builder::CreateFunction(std::string_view name, |
| const type::Type* return_type, |
| Function::PipelineStage stage, |
| std::optional<std::array<uint32_t, 3>> wg_size) { |
| TINT_ASSERT(IR, return_type); |
| |
| auto* ir_func = ir.values.Create<Function>(return_type, stage, wg_size); |
| ir_func->SetStartTarget(CreateBlock()); |
| ir.SetName(ir_func, name); |
| return ir_func; |
| } |
| |
| If* Builder::CreateIf(Value* condition) { |
| TINT_ASSERT(IR, condition); |
| return ir.values.Create<If>(condition, CreateBlock(), CreateBlock(), CreateBlock()); |
| } |
| |
| Loop* Builder::CreateLoop() { |
| return ir.values.Create<Loop>(CreateBlock(), CreateBlock(), CreateBlock()); |
| } |
| |
| Switch* Builder::CreateSwitch(Value* condition) { |
| return ir.values.Create<Switch>(condition, CreateBlock()); |
| } |
| |
| Block* Builder::CreateCase(Switch* s, utils::VectorRef<Switch::CaseSelector> selectors) { |
| s->Cases().Push(Switch::Case{std::move(selectors), CreateBlock()}); |
| |
| Block* b = s->Cases().Back().Start(); |
| b->AddInboundBranch(s); |
| return b; |
| } |
| |
| Binary* Builder::CreateBinary(enum Binary::Kind kind, |
| const type::Type* type, |
| Value* lhs, |
| Value* rhs) { |
| return ir.values.Create<ir::Binary>(kind, type, lhs, rhs); |
| } |
| |
| Binary* Builder::And(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kAnd, type, lhs, rhs); |
| } |
| |
| Binary* Builder::Or(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kOr, type, lhs, rhs); |
| } |
| |
| Binary* Builder::Xor(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kXor, type, lhs, rhs); |
| } |
| |
| Binary* Builder::Equal(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kEqual, type, lhs, rhs); |
| } |
| |
| Binary* Builder::NotEqual(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kNotEqual, type, lhs, rhs); |
| } |
| |
| Binary* Builder::LessThan(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kLessThan, type, lhs, rhs); |
| } |
| |
| Binary* Builder::GreaterThan(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kGreaterThan, type, lhs, rhs); |
| } |
| |
| Binary* Builder::LessThanEqual(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kLessThanEqual, type, lhs, rhs); |
| } |
| |
| Binary* Builder::GreaterThanEqual(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kGreaterThanEqual, type, lhs, rhs); |
| } |
| |
| Binary* Builder::ShiftLeft(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kShiftLeft, type, lhs, rhs); |
| } |
| |
| Binary* Builder::ShiftRight(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kShiftRight, type, lhs, rhs); |
| } |
| |
| Binary* Builder::Add(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kAdd, type, lhs, rhs); |
| } |
| |
| Binary* Builder::Subtract(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kSubtract, type, lhs, rhs); |
| } |
| |
| Binary* Builder::Multiply(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kMultiply, type, lhs, rhs); |
| } |
| |
| Binary* Builder::Divide(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kDivide, type, lhs, rhs); |
| } |
| |
| Binary* Builder::Modulo(const type::Type* type, Value* lhs, Value* rhs) { |
| return CreateBinary(Binary::Kind::kModulo, type, lhs, rhs); |
| } |
| |
| Unary* Builder::CreateUnary(enum Unary::Kind kind, const type::Type* type, Value* val) { |
| return ir.values.Create<ir::Unary>(kind, type, val); |
| } |
| |
| Unary* Builder::Complement(const type::Type* type, Value* val) { |
| return CreateUnary(Unary::Kind::kComplement, type, val); |
| } |
| |
| Unary* Builder::Negation(const type::Type* type, Value* val) { |
| return CreateUnary(Unary::Kind::kNegation, type, val); |
| } |
| |
| Binary* Builder::Not(const type::Type* type, Value* val) { |
| return Equal(type, val, Constant(false)); |
| } |
| |
| ir::Bitcast* Builder::Bitcast(const type::Type* type, Value* val) { |
| return ir.values.Create<ir::Bitcast>(type, val); |
| } |
| |
| ir::Discard* Builder::Discard() { |
| return ir.values.Create<ir::Discard>(); |
| } |
| |
| ir::UserCall* Builder::UserCall(const type::Type* type, |
| Function* func, |
| utils::VectorRef<Value*> args) { |
| return ir.values.Create<ir::UserCall>(type, func, std::move(args)); |
| } |
| |
| ir::Convert* Builder::Convert(const type::Type* to, |
| const type::Type* from, |
| utils::VectorRef<Value*> args) { |
| return ir.values.Create<ir::Convert>(to, from, std::move(args)); |
| } |
| |
| ir::Construct* Builder::Construct(const type::Type* to, utils::VectorRef<Value*> args) { |
| return ir.values.Create<ir::Construct>(to, std::move(args)); |
| } |
| |
| ir::Builtin* Builder::Builtin(const type::Type* type, |
| builtin::Function func, |
| utils::VectorRef<Value*> args) { |
| return ir.values.Create<ir::Builtin>(type, func, args); |
| } |
| |
| ir::Load* Builder::Load(Value* from) { |
| auto* ptr = from->Type()->As<type::Pointer>(); |
| TINT_ASSERT(IR, ptr); |
| return ir.values.Create<ir::Load>(ptr->StoreType(), from); |
| } |
| |
| ir::Store* Builder::Store(Value* to, Value* from) { |
| return ir.values.Create<ir::Store>(to, from); |
| } |
| |
| ir::Var* Builder::Declare(const type::Type* type) { |
| return ir.values.Create<ir::Var>(type); |
| } |
| |
| ir::Branch* Builder::Branch(Block* to, utils::VectorRef<Value*> args) { |
| return ir.values.Create<ir::Branch>(to, args); |
| } |
| |
| ir::Return* Builder::Return(Function* func, utils::VectorRef<Value*> args) { |
| return ir.values.Create<ir::Return>(func, args); |
| } |
| |
| ir::Continue* Builder::Continue(Loop* loop) { |
| return ir.values.Create<ir::Continue>(loop); |
| } |
| |
| ir::BlockParam* Builder::BlockParam(const type::Type* type) { |
| return ir.values.Create<ir::BlockParam>(type); |
| } |
| |
| ir::FunctionParam* Builder::FunctionParam(const type::Type* type) { |
| return ir.values.Create<ir::FunctionParam>(type); |
| } |
| |
| } // namespace tint::ir |