[ir] Add assignment statements
This CL adds Assignment and CompoundAssignment statements to the IR builder. Bug: tint:1718 Change-Id: I3037da0115c7f4fe68941565b7e48866d421bbbf Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/129201 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
5b541ff3c2
commit
aa97bb5327
|
@ -736,6 +736,8 @@ if(${TINT_BUILD_IR})
|
|||
ir/module.h
|
||||
ir/runtime.cc
|
||||
ir/runtime.h
|
||||
ir/store.cc
|
||||
ir/store.h
|
||||
ir/switch.cc
|
||||
ir/switch.h
|
||||
ir/terminator.cc
|
||||
|
@ -1419,6 +1421,7 @@ if(TINT_BUILD_TESTS)
|
|||
ir/constant_test.cc
|
||||
ir/discard_test.cc
|
||||
ir/runtime_test.cc
|
||||
ir/store_test.cc
|
||||
ir/test_helper.h
|
||||
ir/unary_test.cc
|
||||
)
|
||||
|
|
|
@ -227,4 +227,8 @@ ir::Builtin* Builder::Builtin(const type::Type* type,
|
|||
return ir.instructions.Create<ir::Builtin>(Runtime(type), func, args);
|
||||
}
|
||||
|
||||
ir::Store* Builder::Store(Value* to, Value* from) {
|
||||
return ir.instructions.Create<ir::Store>(to, from);
|
||||
}
|
||||
|
||||
} // namespace tint::ir
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "src/tint/ir/loop.h"
|
||||
#include "src/tint/ir/module.h"
|
||||
#include "src/tint/ir/runtime.h"
|
||||
#include "src/tint/ir/store.h"
|
||||
#include "src/tint/ir/switch.h"
|
||||
#include "src/tint/ir/terminator.h"
|
||||
#include "src/tint/ir/unary.h"
|
||||
|
@ -359,6 +360,12 @@ class Builder {
|
|||
builtin::Function func,
|
||||
utils::VectorRef<Value*> args);
|
||||
|
||||
/// Creates an store instruction
|
||||
/// @param to the expression being stored too
|
||||
/// @param from the expression being stored
|
||||
/// @returns the instruction
|
||||
ir::Store* Store(Value* to, Value* from);
|
||||
|
||||
/// @returns a unique runtime id
|
||||
Runtime::Id AllocateRuntimeId();
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "src/tint/ast/alias.h"
|
||||
#include "src/tint/ast/assignment_statement.h"
|
||||
#include "src/tint/ast/binary_expression.h"
|
||||
#include "src/tint/ast/bitcast_expression.h"
|
||||
#include "src/tint/ast/block_statement.h"
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "src/tint/ast/break_statement.h"
|
||||
#include "src/tint/ast/call_expression.h"
|
||||
#include "src/tint/ast/call_statement.h"
|
||||
#include "src/tint/ast/compound_assignment_statement.h"
|
||||
#include "src/tint/ast/const.h"
|
||||
#include "src/tint/ast/const_assert.h"
|
||||
#include "src/tint/ast/continue_statement.h"
|
||||
|
@ -54,8 +56,10 @@
|
|||
#include "src/tint/ir/if.h"
|
||||
#include "src/tint/ir/loop.h"
|
||||
#include "src/tint/ir/module.h"
|
||||
#include "src/tint/ir/store.h"
|
||||
#include "src/tint/ir/switch.h"
|
||||
#include "src/tint/ir/terminator.h"
|
||||
#include "src/tint/ir/value.h"
|
||||
#include "src/tint/program.h"
|
||||
#include "src/tint/sem/builtin.h"
|
||||
#include "src/tint/sem/call.h"
|
||||
|
@ -236,17 +240,13 @@ void BuilderImpl::EmitStatements(utils::VectorRef<const ast::Statement*> stmts)
|
|||
|
||||
void BuilderImpl::EmitStatement(const ast::Statement* stmt) {
|
||||
tint::Switch(
|
||||
stmt,
|
||||
// [&](const ast::AssignmentStatement* a) {
|
||||
// TODO(dsinclair): Implement
|
||||
// },
|
||||
stmt, //
|
||||
[&](const ast::AssignmentStatement* a) { EmitAssignment(a); },
|
||||
[&](const ast::BlockStatement* b) { EmitBlock(b); },
|
||||
[&](const ast::BreakStatement* b) { EmitBreak(b); },
|
||||
[&](const ast::BreakIfStatement* b) { EmitBreakIf(b); },
|
||||
[&](const ast::CallStatement* c) { EmitCall(c); },
|
||||
// [&](const ast::CompoundAssignmentStatement* c) {
|
||||
// TODO(dsinclair): Implement
|
||||
// },
|
||||
[&](const ast::CompoundAssignmentStatement* c) { EmitCompoundAssignment(c); },
|
||||
[&](const ast::ContinueStatement* c) { EmitContinue(c); },
|
||||
[&](const ast::DiscardStatement* d) { EmitDiscard(d); },
|
||||
[&](const ast::IfStatement* i) { EmitIf(i); },
|
||||
|
@ -265,6 +265,98 @@ void BuilderImpl::EmitStatement(const ast::Statement* stmt) {
|
|||
});
|
||||
}
|
||||
|
||||
void BuilderImpl::EmitAssignment(const ast::AssignmentStatement* stmt) {
|
||||
auto lhs = EmitExpression(stmt->lhs);
|
||||
if (!lhs) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto rhs = EmitExpression(stmt->rhs);
|
||||
if (!rhs) {
|
||||
return;
|
||||
}
|
||||
auto store = builder.Store(lhs.Get(), rhs.Get());
|
||||
current_flow_block->instructions.Push(store);
|
||||
}
|
||||
|
||||
void BuilderImpl::EmitCompoundAssignment(const ast::CompoundAssignmentStatement* stmt) {
|
||||
auto lhs = EmitExpression(stmt->lhs);
|
||||
if (!lhs) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto rhs = EmitExpression(stmt->rhs);
|
||||
if (!rhs) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* ty = lhs.Get()->Type();
|
||||
Binary* instr = nullptr;
|
||||
switch (stmt->op) {
|
||||
case ast::BinaryOp::kAnd:
|
||||
instr = builder.And(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kOr:
|
||||
instr = builder.Or(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kXor:
|
||||
instr = builder.Xor(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kLogicalAnd:
|
||||
instr = builder.LogicalAnd(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kLogicalOr:
|
||||
instr = builder.LogicalOr(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kEqual:
|
||||
instr = builder.Equal(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kNotEqual:
|
||||
instr = builder.NotEqual(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kLessThan:
|
||||
instr = builder.LessThan(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kGreaterThan:
|
||||
instr = builder.GreaterThan(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kLessThanEqual:
|
||||
instr = builder.LessThanEqual(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kGreaterThanEqual:
|
||||
instr = builder.GreaterThanEqual(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kShiftLeft:
|
||||
instr = builder.ShiftLeft(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kShiftRight:
|
||||
instr = builder.ShiftRight(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kAdd:
|
||||
instr = builder.Add(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kSubtract:
|
||||
instr = builder.Subtract(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kMultiply:
|
||||
instr = builder.Multiply(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kDivide:
|
||||
instr = builder.Divide(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kModulo:
|
||||
instr = builder.Modulo(ty, lhs.Get(), rhs.Get());
|
||||
break;
|
||||
case ast::BinaryOp::kNone:
|
||||
TINT_ICE(IR, diagnostics_) << "missing binary operand type";
|
||||
return;
|
||||
}
|
||||
current_flow_block->instructions.Push(instr);
|
||||
|
||||
auto store = builder.Store(lhs.Get(), instr->Result());
|
||||
current_flow_block->instructions.Push(store);
|
||||
}
|
||||
|
||||
void BuilderImpl::EmitBlock(const ast::BlockStatement* block) {
|
||||
// Note, this doesn't need to emit a Block as the current block flow node should be
|
||||
// sufficient as the blocks all get flattened. Each flow control node will inject the basic
|
||||
|
|
|
@ -34,6 +34,7 @@ class Program;
|
|||
} // namespace tint
|
||||
namespace tint::ast {
|
||||
class Attribute;
|
||||
class AssignmentStatement;
|
||||
class BinaryExpression;
|
||||
class BitcastExpression;
|
||||
class BlockStatement;
|
||||
|
@ -41,6 +42,7 @@ class BreakIfStatement;
|
|||
class BreakStatement;
|
||||
class CallExpression;
|
||||
class CallStatement;
|
||||
class CompoundAssignmentStatement;
|
||||
class ContinueStatement;
|
||||
class DiscardStatement;
|
||||
class Expression;
|
||||
|
@ -142,6 +144,14 @@ class BuilderImpl {
|
|||
/// @param stmt the break-if statement
|
||||
void EmitBreakIf(const ast::BreakIfStatement* stmt);
|
||||
|
||||
/// Emits an assignment statement
|
||||
/// @param stmt the statement
|
||||
void EmitAssignment(const ast::AssignmentStatement* stmt);
|
||||
|
||||
/// Emits a compound assignment statement
|
||||
/// @param stmt the statement
|
||||
void EmitCompoundAssignment(const ast::CompoundAssignmentStatement* stmt);
|
||||
|
||||
/// Emits an expression
|
||||
/// @param expr the expression to emit
|
||||
/// @returns true if successful, false otherwise
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2023 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/store.h"
|
||||
#include "src/tint/debug.h"
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::ir::Store);
|
||||
|
||||
namespace tint::ir {
|
||||
|
||||
Store::Store(Value* to, Value* from) : Base(to), from_(from) {
|
||||
TINT_ASSERT(IR, from_);
|
||||
from_->AddUsage(this);
|
||||
}
|
||||
|
||||
Store::~Store() = default;
|
||||
|
||||
utils::StringStream& Store::ToString(utils::StringStream& out) const {
|
||||
Result()->ToString(out);
|
||||
out << " = ";
|
||||
from_->ToString(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace tint::ir
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2023 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.
|
||||
|
||||
#ifndef SRC_TINT_IR_STORE_H_
|
||||
#define SRC_TINT_IR_STORE_H_
|
||||
|
||||
#include "src/tint/ir/instruction.h"
|
||||
#include "src/tint/utils/castable.h"
|
||||
#include "src/tint/utils/string_stream.h"
|
||||
|
||||
namespace tint::ir {
|
||||
|
||||
/// An instruction in the IR.
|
||||
class Store : public utils::Castable<Store, Instruction> {
|
||||
public:
|
||||
/// Constructor
|
||||
/// @param to the value to store too
|
||||
/// @param from the value being stored from
|
||||
Store(Value* to, Value* from);
|
||||
Store(const Store& instr) = delete;
|
||||
Store(Store&& instr) = delete;
|
||||
~Store() override;
|
||||
|
||||
Store& operator=(const Store& instr) = delete;
|
||||
Store& operator=(Store&& instr) = delete;
|
||||
|
||||
/// @returns the value being stored
|
||||
const Value* from() const { return from_; }
|
||||
|
||||
/// Write the instruction to the given stream
|
||||
/// @param out the stream to write to
|
||||
/// @returns the stream
|
||||
utils::StringStream& ToString(utils::StringStream& out) const override;
|
||||
|
||||
private:
|
||||
Value* from_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace tint::ir
|
||||
|
||||
#endif // SRC_TINT_IR_STORE_H_
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2023 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/instruction.h"
|
||||
#include "src/tint/ir/test_helper.h"
|
||||
#include "src/tint/utils/string_stream.h"
|
||||
|
||||
namespace tint::ir {
|
||||
namespace {
|
||||
|
||||
using namespace tint::number_suffixes; // NOLINT
|
||||
|
||||
using IR_InstructionTest = TestHelper;
|
||||
|
||||
TEST_F(IR_InstructionTest, CreateStore) {
|
||||
auto& b = CreateEmptyBuilder();
|
||||
|
||||
b.builder.next_runtime_id = Runtime::Id(42);
|
||||
|
||||
auto* rt = b.builder.Runtime(b.builder.ir.types.Get<type::I32>());
|
||||
const auto* instr = b.builder.Store(rt, b.builder.Constant(4_i));
|
||||
|
||||
ASSERT_TRUE(instr->Result()->Is<Runtime>());
|
||||
ASSERT_NE(instr->Result()->Type(), nullptr);
|
||||
EXPECT_EQ(Runtime::Id(42), instr->Result()->As<Runtime>()->AsId());
|
||||
|
||||
ASSERT_TRUE(instr->from()->Is<Constant>());
|
||||
auto lhs = instr->from()->As<Constant>()->value;
|
||||
ASSERT_TRUE(lhs->Is<constant::Scalar<i32>>());
|
||||
EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
|
||||
|
||||
utils::StringStream str;
|
||||
instr->ToString(str);
|
||||
EXPECT_EQ(str.str(), "%42 (i32) = 4");
|
||||
}
|
||||
|
||||
TEST_F(IR_InstructionTest, Store_Usage) {
|
||||
auto& b = CreateEmptyBuilder();
|
||||
|
||||
b.builder.next_runtime_id = Runtime::Id(42);
|
||||
auto* rt = b.builder.Runtime(b.builder.ir.types.Get<type::I32>());
|
||||
const auto* instr = b.builder.Store(rt, b.builder.Constant(4_i));
|
||||
|
||||
ASSERT_NE(instr->Result(), nullptr);
|
||||
ASSERT_EQ(instr->Result()->Usage().Length(), 1u);
|
||||
EXPECT_EQ(instr->Result()->Usage()[0], instr);
|
||||
|
||||
ASSERT_NE(instr->from(), nullptr);
|
||||
ASSERT_EQ(instr->from()->Usage().Length(), 1u);
|
||||
EXPECT_EQ(instr->from()->Usage()[0], instr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::ir
|
Loading…
Reference in New Issue