Import Tint changes from Dawn
Changes:
- afd7f2aa21719374eee8a8201b2e4357b49c046d [ir] Add usage tracking to ir::Value. by dan sinclair <dsinclair@chromium.org>
- 4cef4362b0654b52e3c1a6ee5a3133456cf0107d [ir] Add bitcast expression. by dan sinclair <dsinclair@chromium.org>
- cf58122c58bbaa37322e60d685c2d7cb862a4f1d Minor cleanups from #114202. by dan sinclair <dsinclair@chromium.org>
- 3e449f219449b5d7f12ed9f12a6757aee4fdb8be [ir] Add types to the ir::Value classes. by dan sinclair <dsinclair@chromium.org>
GitOrigin-RevId: afd7f2aa21719374eee8a8201b2e4357b49c046d
Change-Id: I9b85c98331f8ecd60586053e5ba456dc0822b2cb
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/116200
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index e158941..7988364 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -678,6 +678,8 @@
list(APPEND TINT_LIB_SRCS
ir/binary.cc
ir/binary.h
+ ir/bitcast.cc
+ ir/bitcast.h
ir/block.cc
ir/block.h
ir/builder.cc
@@ -1378,6 +1380,7 @@
if (${TINT_BUILD_IR})
list(APPEND TINT_TEST_SRCS
ir/binary_test.cc
+ ir/bitcast_test.cc
ir/builder_impl_test.cc
ir/constant_test.cc
ir/temp_test.cc
diff --git a/src/tint/ir/binary.cc b/src/tint/ir/binary.cc
index ccb679b..e48ca86 100644
--- a/src/tint/ir/binary.cc
+++ b/src/tint/ir/binary.cc
@@ -19,11 +19,12 @@
namespace tint::ir {
-Binary::Binary(Kind kind, const Value* result, const Value* lhs, const Value* rhs)
- : kind_(kind), result_(result), lhs_(lhs), rhs_(rhs) {
- TINT_ASSERT(IR, result_);
+Binary::Binary(Kind kind, Value* result, Value* lhs, Value* rhs)
+ : Base(result), kind_(kind), lhs_(lhs), rhs_(rhs) {
TINT_ASSERT(IR, lhs_);
TINT_ASSERT(IR, rhs_);
+ lhs_->AddUsage(this);
+ rhs_->AddUsage(this);
}
Binary::~Binary() = default;
diff --git a/src/tint/ir/binary.h b/src/tint/ir/binary.h
index 0f7fe57..85ad9dc 100644
--- a/src/tint/ir/binary.h
+++ b/src/tint/ir/binary.h
@@ -19,8 +19,8 @@
#include "src/tint/castable.h"
#include "src/tint/ir/instruction.h"
-#include "src/tint/ir/value.h"
#include "src/tint/symbol_table.h"
+#include "src/tint/type/type.h"
namespace tint::ir {
@@ -58,7 +58,7 @@
/// @param result the result value
/// @param lhs the lhs of the instruction
/// @param rhs the rhs of the instruction
- Binary(Kind kind, const Value* result, const Value* lhs, const Value* rhs);
+ Binary(Kind kind, Value* result, Value* lhs, Value* rhs);
Binary(const Binary& instr) = delete;
Binary(Binary&& instr) = delete;
~Binary() override;
@@ -69,9 +69,6 @@
/// @returns the kind of instruction
Kind GetKind() const { return kind_; }
- /// @returns the result value for the instruction
- const Value* Result() const { return result_; }
-
/// @returns the left-hand-side value for the instruction
const Value* LHS() const { return lhs_; }
@@ -86,9 +83,8 @@
private:
Kind kind_;
- const Value* result_ = nullptr;
- const Value* lhs_ = nullptr;
- const Value* rhs_ = nullptr;
+ Value* lhs_ = nullptr;
+ Value* rhs_ = nullptr;
};
std::ostream& operator<<(std::ostream& out, const Binary&);
diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc
index f90661b..f234879 100644
--- a/src/tint/ir/binary_test.cc
+++ b/src/tint/ir/binary_test.cc
@@ -28,11 +28,13 @@
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.And(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.And(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd);
ASSERT_TRUE(instr->Result()->Is<Temp>());
+ ASSERT_NE(instr->Result()->Type(), nullptr);
EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
ASSERT_TRUE(instr->LHS()->Is<Constant>());
@@ -47,14 +49,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 & 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 & 2");
}
TEST_F(IR_InstructionTest, CreateOr) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Or(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.Or(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kOr);
@@ -73,14 +76,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 | 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 | 2");
}
TEST_F(IR_InstructionTest, CreateXor) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Xor(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.Xor(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kXor);
@@ -99,14 +103,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 ^ 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 ^ 2");
}
TEST_F(IR_InstructionTest, CreateLogicalAnd) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.LogicalAnd(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.LogicalAnd(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kLogicalAnd);
@@ -125,14 +130,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 && 2");
+ EXPECT_EQ(str.str(), "%42 (bool) = 4 && 2");
}
TEST_F(IR_InstructionTest, CreateLogicalOr) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.LogicalOr(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.LogicalOr(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kLogicalOr);
@@ -151,14 +157,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 || 2");
+ EXPECT_EQ(str.str(), "%42 (bool) = 4 || 2");
}
TEST_F(IR_InstructionTest, CreateEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Equal(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.Equal(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kEqual);
@@ -177,14 +184,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 == 2");
+ EXPECT_EQ(str.str(), "%42 (bool) = 4 == 2");
}
TEST_F(IR_InstructionTest, CreateNotEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.NotEqual(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.NotEqual(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kNotEqual);
@@ -203,14 +211,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 != 2");
+ EXPECT_EQ(str.str(), "%42 (bool) = 4 != 2");
}
TEST_F(IR_InstructionTest, CreateLessThan) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.LessThan(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.LessThan(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kLessThan);
@@ -229,14 +238,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 < 2");
+ EXPECT_EQ(str.str(), "%42 (bool) = 4 < 2");
}
TEST_F(IR_InstructionTest, CreateGreaterThan) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.GreaterThan(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.GreaterThan(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kGreaterThan);
@@ -255,14 +265,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 > 2");
+ EXPECT_EQ(str.str(), "%42 (bool) = 4 > 2");
}
TEST_F(IR_InstructionTest, CreateLessThanEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.LessThanEqual(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.LessThanEqual(b.builder.ir.types.Get<type::Bool>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kLessThanEqual);
@@ -281,15 +292,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 <= 2");
+ EXPECT_EQ(str.str(), "%42 (bool) = 4 <= 2");
}
TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr =
- b.builder.GreaterThanEqual(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.GreaterThanEqual(
+ b.builder.ir.types.Get<type::Bool>(), b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kGreaterThanEqual);
@@ -308,14 +319,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 >= 2");
+ EXPECT_EQ(str.str(), "%42 (bool) = 4 >= 2");
}
TEST_F(IR_InstructionTest, CreateShiftLeft) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.ShiftLeft(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.ShiftLeft(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kShiftLeft);
@@ -334,14 +346,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 << 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 << 2");
}
TEST_F(IR_InstructionTest, CreateShiftRight) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.ShiftRight(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.ShiftRight(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kShiftRight);
@@ -360,14 +373,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 >> 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 >> 2");
}
TEST_F(IR_InstructionTest, CreateAdd) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Add(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.Add(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kAdd);
@@ -386,14 +400,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 + 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 + 2");
}
TEST_F(IR_InstructionTest, CreateSubtract) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Subtract(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.Subtract(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kSubtract);
@@ -412,14 +427,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 - 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 - 2");
}
TEST_F(IR_InstructionTest, CreateMultiply) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Multiply(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.Multiply(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kMultiply);
@@ -438,14 +454,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 * 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 * 2");
}
TEST_F(IR_InstructionTest, CreateDivide) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Divide(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.Divide(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kDivide);
@@ -464,14 +481,15 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 / 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 / 2");
}
TEST_F(IR_InstructionTest, CreateModulo) {
auto& b = CreateEmptyBuilder();
b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Modulo(b.builder.Constant(4_i), b.builder.Constant(2_i));
+ const auto* instr = b.builder.Modulo(b.builder.ir.types.Get<type::I32>(),
+ b.builder.Constant(4_i), b.builder.Constant(2_i));
EXPECT_EQ(instr->GetKind(), Binary::Kind::kModulo);
@@ -490,7 +508,50 @@
std::stringstream str;
instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 % 2");
+ EXPECT_EQ(str.str(), "%42 (i32) = 4 % 2");
+}
+
+TEST_F(IR_InstructionTest, Binary_Usage) {
+ auto& b = CreateEmptyBuilder();
+
+ b.builder.next_temp_id = Temp::Id(42);
+ const auto* instr = b.builder.And(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i),
+ b.builder.Constant(2_i));
+
+ EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd);
+
+ ASSERT_NE(instr->Result(), nullptr);
+ ASSERT_EQ(instr->Result()->Usage().Length(), 1);
+ EXPECT_EQ(instr->Result()->Usage()[0], instr);
+
+ ASSERT_NE(instr->LHS(), nullptr);
+ ASSERT_EQ(instr->LHS()->Usage().Length(), 1);
+ EXPECT_EQ(instr->LHS()->Usage()[0], instr);
+
+ ASSERT_NE(instr->RHS(), nullptr);
+ ASSERT_EQ(instr->RHS()->Usage().Length(), 1);
+ EXPECT_EQ(instr->RHS()->Usage()[0], instr);
+}
+
+TEST_F(IR_InstructionTest, Binary_Usage_DuplicateValue) {
+ auto& b = CreateEmptyBuilder();
+
+ auto val = b.builder.Constant(4_i);
+
+ b.builder.next_temp_id = Temp::Id(42);
+ const auto* instr = b.builder.And(b.builder.ir.types.Get<type::I32>(), val, val);
+
+ EXPECT_EQ(instr->GetKind(), Binary::Kind::kAnd);
+
+ ASSERT_NE(instr->Result(), nullptr);
+ ASSERT_EQ(instr->Result()->Usage().Length(), 1);
+ EXPECT_EQ(instr->Result()->Usage()[0], instr);
+
+ ASSERT_EQ(instr->LHS(), instr->RHS());
+
+ ASSERT_NE(instr->LHS(), nullptr);
+ ASSERT_EQ(instr->LHS()->Usage().Length(), 1);
+ EXPECT_EQ(instr->LHS()->Usage()[0], instr);
}
} // namespace
diff --git a/src/tint/ir/bitcast.cc b/src/tint/ir/bitcast.cc
new file mode 100644
index 0000000..512d93a
--- /dev/null
+++ b/src/tint/ir/bitcast.cc
@@ -0,0 +1,37 @@
+// 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/bitcast.h"
+#include "src/tint/debug.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Bitcast);
+
+namespace tint::ir {
+
+Bitcast::Bitcast(Value* result, Value* val) : Base(result), val_(val) {
+ TINT_ASSERT(IR, val_);
+ val_->AddUsage(this);
+}
+
+Bitcast::~Bitcast() = default;
+
+std::ostream& Bitcast::ToString(std::ostream& out, const SymbolTable& st) const {
+ Result()->ToString(out, st);
+ out << " = bitcast(";
+ val_->ToString(out, st);
+ out << ")";
+ return out;
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/bitcast.h b/src/tint/ir/bitcast.h
new file mode 100644
index 0000000..df8a05e
--- /dev/null
+++ b/src/tint/ir/bitcast.h
@@ -0,0 +1,58 @@
+// 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_BITCAST_H_
+#define SRC_TINT_IR_BITCAST_H_
+
+#include <ostream>
+
+#include "src/tint/castable.h"
+#include "src/tint/ir/instruction.h"
+#include "src/tint/symbol_table.h"
+#include "src/tint/type/type.h"
+
+namespace tint::ir {
+
+/// A bitcast instruction in the IR.
+class Bitcast : public Castable<Bitcast, Instruction> {
+ public:
+ /// Constructor
+ /// @param result the result value
+ /// @param val the value being bitcast
+ Bitcast(Value* result, Value* val);
+ Bitcast(const Bitcast& instr) = delete;
+ Bitcast(Bitcast&& instr) = delete;
+ ~Bitcast() override;
+
+ Bitcast& operator=(const Bitcast& instr) = delete;
+ Bitcast& operator=(Bitcast&& instr) = delete;
+
+ /// @returns the left-hand-side value for the instruction
+ const Value* Val() const { return val_; }
+
+ /// Write the instruction to the given stream
+ /// @param out the stream to write to
+ /// @param st the symbol table
+ /// @returns the stream
+ std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
+
+ private:
+ Value* val_ = nullptr;
+};
+
+std::ostream& operator<<(std::ostream& out, const Bitcast&);
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_BITCAST_H_
diff --git a/src/tint/ir/bitcast_test.cc b/src/tint/ir/bitcast_test.cc
new file mode 100644
index 0000000..91c5c4b
--- /dev/null
+++ b/src/tint/ir/bitcast_test.cc
@@ -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 <sstream>
+
+#include "src/tint/ir/instruction.h"
+#include "src/tint/ir/test_helper.h"
+
+namespace tint::ir {
+namespace {
+
+using namespace tint::number_suffixes; // NOLINT
+ //
+using IR_InstructionTest = TestHelper;
+
+TEST_F(IR_InstructionTest, Bitcast) {
+ auto& b = CreateEmptyBuilder();
+
+ b.builder.next_temp_id = Temp::Id(42);
+ const auto* instr =
+ b.builder.Bitcast(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
+
+ ASSERT_TRUE(instr->Result()->Is<Temp>());
+ EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
+ ASSERT_NE(instr->Result()->Type(), nullptr);
+
+ ASSERT_TRUE(instr->Val()->Is<Constant>());
+ auto val = instr->Val()->As<Constant>()->value;
+ ASSERT_TRUE(val->Is<constant::Scalar<i32>>());
+ EXPECT_EQ(4_i, val->As<constant::Scalar<i32>>()->ValueAs<i32>());
+
+ std::stringstream str;
+ instr->ToString(str, program->Symbols());
+ EXPECT_EQ(str.str(), "%42 (i32) = bitcast(4)");
+}
+
+TEST_F(IR_InstructionTest, Bitcast_Usage) {
+ auto& b = CreateEmptyBuilder();
+
+ b.builder.next_temp_id = Temp::Id(42);
+ const auto* instr =
+ b.builder.Bitcast(b.builder.ir.types.Get<type::I32>(), b.builder.Constant(4_i));
+
+ ASSERT_NE(instr->Result(), nullptr);
+ ASSERT_EQ(instr->Result()->Usage().Length(), 1);
+ EXPECT_EQ(instr->Result()->Usage()[0], instr);
+
+ ASSERT_NE(instr->Val(), nullptr);
+ ASSERT_EQ(instr->Val()->Usage().Length(), 1);
+ EXPECT_EQ(instr->Val()->Usage()[0], instr);
+}
+
+} // namespace
+} // namespace tint::ir
diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc
index 35e4f70..e65c2fc 100644
--- a/src/tint/ir/builder.cc
+++ b/src/tint/ir/builder.cc
@@ -97,80 +97,84 @@
return next_temp_id++;
}
-const Binary* Builder::CreateBinary(Binary::Kind kind, const Value* lhs, const Value* rhs) {
- return ir.instructions.Create<ir::Binary>(kind, Temp(), lhs, rhs);
+Binary* Builder::CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs) {
+ return ir.instructions.Create<ir::Binary>(kind, Temp(type), lhs, rhs);
}
-const Binary* Builder::And(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kAnd, lhs, rhs);
+Binary* Builder::And(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kAnd, type, lhs, rhs);
}
-const Binary* Builder::Or(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kOr, lhs, rhs);
+Binary* Builder::Or(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kOr, type, lhs, rhs);
}
-const Binary* Builder::Xor(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kXor, lhs, rhs);
+Binary* Builder::Xor(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kXor, type, lhs, rhs);
}
-const Binary* Builder::LogicalAnd(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kLogicalAnd, lhs, rhs);
+Binary* Builder::LogicalAnd(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kLogicalAnd, type, lhs, rhs);
}
-const Binary* Builder::LogicalOr(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kLogicalOr, lhs, rhs);
+Binary* Builder::LogicalOr(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kLogicalOr, type, lhs, rhs);
}
-const Binary* Builder::Equal(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kEqual, lhs, rhs);
+Binary* Builder::Equal(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kEqual, type, lhs, rhs);
}
-const Binary* Builder::NotEqual(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kNotEqual, lhs, rhs);
+Binary* Builder::NotEqual(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kNotEqual, type, lhs, rhs);
}
-const Binary* Builder::LessThan(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kLessThan, lhs, rhs);
+Binary* Builder::LessThan(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kLessThan, type, lhs, rhs);
}
-const Binary* Builder::GreaterThan(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kGreaterThan, lhs, rhs);
+Binary* Builder::GreaterThan(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kGreaterThan, type, lhs, rhs);
}
-const Binary* Builder::LessThanEqual(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kLessThanEqual, lhs, rhs);
+Binary* Builder::LessThanEqual(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kLessThanEqual, type, lhs, rhs);
}
-const Binary* Builder::GreaterThanEqual(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kGreaterThanEqual, lhs, rhs);
+Binary* Builder::GreaterThanEqual(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kGreaterThanEqual, type, lhs, rhs);
}
-const Binary* Builder::ShiftLeft(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kShiftLeft, lhs, rhs);
+Binary* Builder::ShiftLeft(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kShiftLeft, type, lhs, rhs);
}
-const Binary* Builder::ShiftRight(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kShiftRight, lhs, rhs);
+Binary* Builder::ShiftRight(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kShiftRight, type, lhs, rhs);
}
-const Binary* Builder::Add(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kAdd, lhs, rhs);
+Binary* Builder::Add(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kAdd, type, lhs, rhs);
}
-const Binary* Builder::Subtract(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kSubtract, lhs, rhs);
+Binary* Builder::Subtract(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kSubtract, type, lhs, rhs);
}
-const Binary* Builder::Multiply(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kMultiply, lhs, rhs);
+Binary* Builder::Multiply(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kMultiply, type, lhs, rhs);
}
-const Binary* Builder::Divide(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kDivide, lhs, rhs);
+Binary* Builder::Divide(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kDivide, type, lhs, rhs);
}
-const Binary* Builder::Modulo(const Value* lhs, const Value* rhs) {
- return CreateBinary(Binary::Kind::kModulo, lhs, rhs);
+Binary* Builder::Modulo(const type::Type* type, Value* lhs, Value* rhs) {
+ return CreateBinary(Binary::Kind::kModulo, type, lhs, rhs);
+}
+
+ir::Bitcast* Builder::Bitcast(const type::Type* type, Value* val) {
+ return ir.instructions.Create<ir::Bitcast>(Temp(type), val);
}
} // namespace tint::ir
diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h
index ca21b8d..ad9e2e1 100644
--- a/src/tint/ir/builder.h
+++ b/src/tint/ir/builder.h
@@ -19,6 +19,7 @@
#include "src/tint/constant/scalar.h"
#include "src/tint/ir/binary.h"
+#include "src/tint/ir/bitcast.h"
#include "src/tint/ir/constant.h"
#include "src/tint/ir/function.h"
#include "src/tint/ir/if.h"
@@ -104,163 +105,191 @@
/// Creates a new ir::Constant
/// @param val the constant value
/// @returns the new constant
- const ir::Constant* Constant(const constant::Value* val) {
+ ir::Constant* Constant(const constant::Value* val) {
return ir.values.Create<ir::Constant>(val);
}
/// Creates a ir::Constant for an i32 Scalar
/// @param v the value
/// @returns the new constant
- const ir::Constant* Constant(i32 v) {
+ ir::Constant* Constant(i32 v) {
return Constant(create<constant::Scalar<i32>>(ir.types.Get<type::I32>(), v));
}
/// Creates a ir::Constant for a u32 Scalar
/// @param v the value
/// @returns the new constant
- const ir::Constant* Constant(u32 v) {
+ ir::Constant* Constant(u32 v) {
return Constant(create<constant::Scalar<u32>>(ir.types.Get<type::U32>(), v));
}
/// Creates a ir::Constant for a f32 Scalar
/// @param v the value
/// @returns the new constant
- const ir::Constant* Constant(f32 v) {
+ ir::Constant* Constant(f32 v) {
return Constant(create<constant::Scalar<f32>>(ir.types.Get<type::F32>(), v));
}
/// Creates a ir::Constant for a f16 Scalar
/// @param v the value
/// @returns the new constant
- const ir::Constant* Constant(f16 v) {
+ ir::Constant* Constant(f16 v) {
return Constant(create<constant::Scalar<f16>>(ir.types.Get<type::F16>(), v));
}
/// Creates a ir::Constant for a bool Scalar
/// @param v the value
/// @returns the new constant
- const ir::Constant* Constant(bool v) {
+ ir::Constant* Constant(bool v) {
return Constant(create<constant::Scalar<bool>>(ir.types.Get<type::Bool>(), v));
}
/// Creates a new Temporary
+ /// @param type the type of the temporary
/// @returns the new temporary
- const ir::Temp* Temp() { return ir.values.Create<ir::Temp>(AllocateTempId()); }
+ ir::Temp* Temp(const type::Type* type) {
+ return ir.values.Create<ir::Temp>(type, AllocateTempId());
+ }
/// Creates an op for `lhs kind rhs`
/// @param kind the kind of operation
+ /// @param type the result type of the binary expression
/// @param lhs the left-hand-side of the operation
/// @param rhs the right-hand-side of the operation
/// @returns the operation
- const Binary* CreateBinary(Binary::Kind kind, const Value* lhs, const Value* rhs);
+ Binary* CreateBinary(Binary::Kind kind, const type::Type* type, Value* lhs, Value* rhs);
/// Creates an And operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* And(const Value* lhs, const Value* rhs);
+ Binary* And(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an Or operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* Or(const Value* lhs, const Value* rhs);
+ Binary* Or(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an Xor operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* Xor(const Value* lhs, const Value* rhs);
+ Binary* Xor(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an LogicalAnd operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* LogicalAnd(const Value* lhs, const Value* rhs);
+ Binary* LogicalAnd(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an LogicalOr operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* LogicalOr(const Value* lhs, const Value* rhs);
+ Binary* LogicalOr(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an Equal operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* Equal(const Value* lhs, const Value* rhs);
+ Binary* Equal(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an NotEqual operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* NotEqual(const Value* lhs, const Value* rhs);
+ Binary* NotEqual(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an LessThan operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* LessThan(const Value* lhs, const Value* rhs);
+ Binary* LessThan(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an GreaterThan operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* GreaterThan(const Value* lhs, const Value* rhs);
+ Binary* GreaterThan(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an LessThanEqual operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* LessThanEqual(const Value* lhs, const Value* rhs);
+ Binary* LessThanEqual(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an GreaterThanEqual operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* GreaterThanEqual(const Value* lhs, const Value* rhs);
+ Binary* GreaterThanEqual(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an ShiftLeft operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* ShiftLeft(const Value* lhs, const Value* rhs);
+ Binary* ShiftLeft(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an ShiftRight operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* ShiftRight(const Value* lhs, const Value* rhs);
+ Binary* ShiftRight(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an Add operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* Add(const Value* lhs, const Value* rhs);
+ Binary* Add(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an Subtract operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* Subtract(const Value* lhs, const Value* rhs);
+ Binary* Subtract(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an Multiply operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* Multiply(const Value* lhs, const Value* rhs);
+ Binary* Multiply(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an Divide operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* Divide(const Value* lhs, const Value* rhs);
+ Binary* Divide(const type::Type* type, Value* lhs, Value* rhs);
/// Creates an Modulo operation
+ /// @param type the result type of the expression
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
- const Binary* Modulo(const Value* lhs, const Value* rhs);
+ Binary* Modulo(const type::Type* type, Value* lhs, Value* rhs);
+
+ /// Creates a bitcast instruction
+ /// @param type the result type of the bitcast
+ /// @param val the value being bitcast
+ /// @returns the instruction
+ ir::Bitcast* Bitcast(const type::Type* type, Value* val);
/// @returns a unique temp id
Temp::Id AllocateTempId();
diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc
index afa56f5..517e09b 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -16,6 +16,7 @@
#include "src/tint/ast/alias.h"
#include "src/tint/ast/binary_expression.h"
+#include "src/tint/ast/bitcast_expression.h"
#include "src/tint/ast/block_statement.h"
#include "src/tint/ast/bool_literal_expression.h"
#include "src/tint/ast/break_if_statement.h"
@@ -517,12 +518,12 @@
return true;
}
-utils::Result<const Value*> BuilderImpl::EmitExpression(const ast::Expression* expr) {
+utils::Result<Value*> BuilderImpl::EmitExpression(const ast::Expression* expr) {
return tint::Switch(
expr,
// [&](const ast::IndexAccessorExpression* a) { return EmitIndexAccessor(a); },
[&](const ast::BinaryExpression* b) { return EmitBinary(b); },
- // [&](const ast::BitcastExpression* b) { return EmitBitcast(b); },
+ [&](const ast::BitcastExpression* b) { return EmitBitcast(b); },
// [&](const ast::CallExpression* c) { return EmitCall(c); },
// [&](const ast::IdentifierExpression* i) { return EmitIdentifier(i); },
[&](const ast::LiteralExpression* l) { return EmitLiteral(l); },
@@ -552,7 +553,7 @@
});
}
-utils::Result<const Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) {
+utils::Result<Value*> BuilderImpl::EmitBinary(const ast::BinaryExpression* expr) {
auto lhs = EmitExpression(expr->lhs);
if (!lhs) {
return utils::Failure;
@@ -563,61 +564,62 @@
return utils::Failure;
}
- const Binary* instr = nullptr;
+ auto* sem = builder.ir.program->Sem().Get(expr);
+ Binary* instr = nullptr;
switch (expr->op) {
case ast::BinaryOp::kAnd:
- instr = builder.And(lhs.Get(), rhs.Get());
+ instr = builder.And(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kOr:
- instr = builder.Or(lhs.Get(), rhs.Get());
+ instr = builder.Or(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kXor:
- instr = builder.Xor(lhs.Get(), rhs.Get());
+ instr = builder.Xor(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLogicalAnd:
- instr = builder.LogicalAnd(lhs.Get(), rhs.Get());
+ instr = builder.LogicalAnd(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLogicalOr:
- instr = builder.LogicalOr(lhs.Get(), rhs.Get());
+ instr = builder.LogicalOr(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kEqual:
- instr = builder.Equal(lhs.Get(), rhs.Get());
+ instr = builder.Equal(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kNotEqual:
- instr = builder.NotEqual(lhs.Get(), rhs.Get());
+ instr = builder.NotEqual(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLessThan:
- instr = builder.LessThan(lhs.Get(), rhs.Get());
+ instr = builder.LessThan(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kGreaterThan:
- instr = builder.GreaterThan(lhs.Get(), rhs.Get());
+ instr = builder.GreaterThan(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLessThanEqual:
- instr = builder.LessThanEqual(lhs.Get(), rhs.Get());
+ instr = builder.LessThanEqual(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kGreaterThanEqual:
- instr = builder.GreaterThanEqual(lhs.Get(), rhs.Get());
+ instr = builder.GreaterThanEqual(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kShiftLeft:
- instr = builder.ShiftLeft(lhs.Get(), rhs.Get());
+ instr = builder.ShiftLeft(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kShiftRight:
- instr = builder.ShiftRight(lhs.Get(), rhs.Get());
+ instr = builder.ShiftRight(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kAdd:
- instr = builder.Add(lhs.Get(), rhs.Get());
+ instr = builder.Add(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kSubtract:
- instr = builder.Subtract(lhs.Get(), rhs.Get());
+ instr = builder.Subtract(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kMultiply:
- instr = builder.Multiply(lhs.Get(), rhs.Get());
+ instr = builder.Multiply(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kDivide:
- instr = builder.Divide(lhs.Get(), rhs.Get());
+ instr = builder.Divide(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kModulo:
- instr = builder.Modulo(lhs.Get(), rhs.Get());
+ instr = builder.Modulo(sem->Type(), lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kNone:
TINT_ICE(IR, diagnostics_) << "missing binary operand type";
@@ -625,10 +627,23 @@
}
current_flow_block->instructions.Push(instr);
- return utils::Result<const Value*>(instr->Result());
+ return instr->Result();
}
-utils::Result<const Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
+utils::Result<Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpression* expr) {
+ auto val = EmitExpression(expr->expr);
+ if (!val) {
+ return utils::Failure;
+ }
+
+ auto* sem = builder.ir.program->Sem().Get(expr);
+ auto* instr = builder.Bitcast(sem->Type(), val.Get());
+
+ current_flow_block->instructions.Push(instr);
+ return instr->Result();
+}
+
+utils::Result<Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
auto* sem = builder.ir.program->Sem().Get(lit);
if (!sem) {
diagnostics_.add_error(
@@ -646,7 +661,7 @@
lit->source);
return utils::Failure;
}
- return utils::Result<const Value*>(builder.Constant(cv));
+ return builder.Constant(cv);
}
bool BuilderImpl::EmitType(const ast::Type* ty) {
diff --git a/src/tint/ir/builder_impl.h b/src/tint/ir/builder_impl.h
index 5090be7..5d6fbd7 100644
--- a/src/tint/ir/builder_impl.h
+++ b/src/tint/ir/builder_impl.h
@@ -32,6 +32,7 @@
} // namespace tint
namespace tint::ast {
class BinaryExpression;
+class BitcastExpression;
class BlockStatement;
class BreakIfStatement;
class BreakStatement;
@@ -140,7 +141,7 @@
/// Emits an expression
/// @param expr the expression to emit
/// @returns true if successful, false otherwise
- utils::Result<const Value*> EmitExpression(const ast::Expression* expr);
+ utils::Result<Value*> EmitExpression(const ast::Expression* expr);
/// Emits a variable
/// @param var the variable to emit
@@ -150,12 +151,17 @@
/// Emits a binary expression
/// @param expr the binary expression
/// @returns the value storing the result if successful, utils::Failure otherwise
- utils::Result<const Value*> EmitBinary(const ast::BinaryExpression* expr);
+ utils::Result<Value*> EmitBinary(const ast::BinaryExpression* expr);
+
+ /// Emits a bitcast expression
+ /// @param expr the bitcast expression
+ /// @returns the value storing the result if successful, utils::Failure otherwise
+ utils::Result<Value*> EmitBitcast(const ast::BitcastExpression* expr);
/// Emits a literal expression
/// @param lit the literal to emit
/// @returns true if successful, false otherwise
- utils::Result<const Value*> EmitLiteral(const ast::LiteralExpression* lit);
+ utils::Result<Value*> EmitLiteral(const ast::LiteralExpression* lit);
/// Emits a type
/// @param ty the type to emit
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index 0600a15..41a3f4c 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -1437,7 +1437,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 + 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 + 4
)");
}
@@ -1452,7 +1452,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 - 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 - 4
)");
}
@@ -1467,7 +1467,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 * 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 * 4
)");
}
@@ -1482,7 +1482,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 / 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 / 4
)");
}
@@ -1497,7 +1497,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 % 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 % 4
)");
}
@@ -1512,7 +1512,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 & 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 & 4
)");
}
@@ -1527,7 +1527,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 | 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 | 4
)");
}
@@ -1542,7 +1542,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 ^ 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 ^ 4
)");
}
@@ -1557,7 +1557,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = true && false
+ EXPECT_EQ(d.AsString(), R"(%1 (bool) = true && false
)");
}
@@ -1572,7 +1572,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = false || true
+ EXPECT_EQ(d.AsString(), R"(%1 (bool) = false || true
)");
}
@@ -1587,7 +1587,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 == 4
+ EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 == 4
)");
}
@@ -1602,7 +1602,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 != 4
+ EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 != 4
)");
}
@@ -1617,7 +1617,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 < 4
+ EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 < 4
)");
}
@@ -1632,7 +1632,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 > 4
+ EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 > 4
)");
}
@@ -1647,7 +1647,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 <= 4
+ EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 <= 4
)");
}
@@ -1662,7 +1662,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 >= 4
+ EXPECT_EQ(d.AsString(), R"(%1 (bool) = 3 >= 4
)");
}
@@ -1677,7 +1677,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 << 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 << 4
)");
}
@@ -1692,7 +1692,7 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 >> 4
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
)");
}
@@ -1708,15 +1708,29 @@
Disassembler d(b.builder.ir);
d.EmitBlockInstructions(b.current_flow_block);
- EXPECT_EQ(d.AsString(), R"(%1 = 3 >> 4
-%2 = %1 + 9
-%3 = 1 < %2
-%4 = 2.3 * 5.5
-%5 = 6.7 / %4
-%6 = 2.5 > %5
-%7 = %3 || %6
+ EXPECT_EQ(d.AsString(), R"(%1 (u32) = 3 >> 4
+%2 (u32) = %1 (u32) + 9
+%3 (bool) = 1 < %2 (u32)
+%4 (f32) = 2.3 * 5.5
+%5 (f32) = 6.7 / %4 (f32)
+%6 (bool) = 2.5 > %5 (f32)
+%7 (bool) = %3 (bool) || %6 (bool)
)");
}
+TEST_F(IR_BuilderImplTest, EmitExpression_Bitcast) {
+ auto* expr = Bitcast(ty.f32(), 3_u);
+ WrapInFunction(expr);
+
+ auto& b = CreateBuilder();
+ InjectFlowBlock();
+ auto r = b.EmitExpression(expr);
+ ASSERT_TRUE(r) << b.error();
+
+ Disassembler d(b.builder.ir);
+ d.EmitBlockInstructions(b.current_flow_block);
+ EXPECT_EQ(d.AsString(), R"(%1 (f32) = bitcast(3)
+)");
+}
} // namespace
} // namespace tint::ir
diff --git a/src/tint/ir/constant.h b/src/tint/ir/constant.h
index c5ee079..10b41d3 100644
--- a/src/tint/ir/constant.h
+++ b/src/tint/ir/constant.h
@@ -31,6 +31,9 @@
explicit Constant(const constant::Value* val);
~Constant() override;
+ /// @returns the type of the constant
+ const type::Type* Type() const override { return value->Type(); }
+
/// Write the constant to the given stream
/// @param out the stream to write to
/// @param st the symbol table
diff --git a/src/tint/ir/instruction.cc b/src/tint/ir/instruction.cc
index e54b13f..46644dd 100644
--- a/src/tint/ir/instruction.cc
+++ b/src/tint/ir/instruction.cc
@@ -18,7 +18,10 @@
namespace tint::ir {
-Instruction::Instruction() = default;
+Instruction::Instruction(Value* result) : result_(result) {
+ TINT_ASSERT(IR, result_);
+ result_->AddUsage(this);
+}
Instruction::~Instruction() = default;
diff --git a/src/tint/ir/instruction.h b/src/tint/ir/instruction.h
index 82842ba..8cd9ba8 100644
--- a/src/tint/ir/instruction.h
+++ b/src/tint/ir/instruction.h
@@ -18,6 +18,7 @@
#include <ostream>
#include "src/tint/castable.h"
+#include "src/tint/ir/value.h"
#include "src/tint/symbol_table.h"
namespace tint::ir {
@@ -33,6 +34,9 @@
Instruction& operator=(const Instruction& instr) = delete;
Instruction& operator=(Instruction&& instr) = delete;
+ /// @returns the result value for the instruction
+ Value* Result() const { return result_; }
+
/// Write the instruction to the given stream
/// @param out the stream to write to
/// @param st the symbol table
@@ -41,7 +45,11 @@
protected:
/// Constructor
- Instruction();
+ /// @param result the result value
+ explicit Instruction(Value* result);
+
+ private:
+ Value* result_ = nullptr;
};
} // namespace tint::ir
diff --git a/src/tint/ir/instruction_test.cc b/src/tint/ir/instruction_test.cc
deleted file mode 100644
index c9307f0..0000000
--- a/src/tint/ir/instruction_test.cc
+++ /dev/null
@@ -1,499 +0,0 @@
-// 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 <sstream>
-
-#include "src/tint/ir/instruction.h"
-#include "src/tint/ir/test_helper.h"
-
-namespace tint::ir {
-namespace {
-
-using IR_BinaryTest = TestHelper;
-
-TEST_F(IR_BinaryTest, CreateAnd) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.And(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kAnd);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 & 2");
-}
-
-TEST_F(IR_BinaryTest, CreateOr) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Or(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kOr);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 | 2");
-}
-
-TEST_F(IR_BinaryTest, CreateXor) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Xor(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kXor);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 ^ 2");
-}
-
-TEST_F(IR_BinaryTest, CreateLogicalAnd) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr =
- b.builder.LogicalAnd(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLogicalAnd);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 && 2");
-}
-
-TEST_F(IR_BinaryTest, CreateLogicalOr) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.LogicalOr(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLogicalOr);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 || 2");
-}
-
-TEST_F(IR_BinaryTest, CreateEqual) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Equal(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kEqual);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 == 2");
-}
-
-TEST_F(IR_BinaryTest, CreateNotEqual) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.NotEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kNotEqual);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 != 2");
-}
-
-TEST_F(IR_BinaryTest, CreateLessThan) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.LessThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLessThan);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 < 2");
-}
-
-TEST_F(IR_BinaryTest, CreateGreaterThan) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr =
- b.builder.GreaterThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kGreaterThan);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 > 2");
-}
-
-TEST_F(IR_BinaryTest, CreateLessThanEqual) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr =
- b.builder.LessThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLessThanEqual);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 <= 2");
-}
-
-TEST_F(IR_BinaryTest, CreateGreaterThanEqual) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr =
- b.builder.GreaterThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kGreaterThanEqual);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 >= 2");
-}
-
-TEST_F(IR_BinaryTest, CreateShiftLeft) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.ShiftLeft(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kShiftLeft);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 << 2");
-}
-
-TEST_F(IR_BinaryTest, CreateShiftRight) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr =
- b.builder.ShiftRight(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kShiftRight);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 >> 2");
-}
-
-TEST_F(IR_BinaryTest, CreateAdd) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Add(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kAdd);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 + 2");
-}
-
-TEST_F(IR_BinaryTest, CreateSubtract) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Subtract(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kSubtract);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 - 2");
-}
-
-TEST_F(IR_BinaryTest, CreateMultiply) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Multiply(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kMultiply);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 * 2");
-}
-
-TEST_F(IR_BinaryTest, CreateDivide) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Divide(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kDivide);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 / 2");
-}
-
-TEST_F(IR_BinaryTest, CreateModulo) {
- auto& b = CreateEmptyBuilder();
-
- b.builder.next_temp_id = Temp::Id(42);
- const auto* instr = b.builder.Modulo(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
-
- EXPECT_EQ(instr->GetKind(), Instruction::Kind::kModulo);
-
- ASSERT_TRUE(instr->Result()->Is<Temp>());
- EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
-
- ASSERT_TRUE(instr->LHS()->Is<Constant>());
- auto lhs = instr->LHS()->As<Constant>();
- ASSERT_TRUE(lhs->IsI32());
- EXPECT_EQ(i32(4), lhs->AsI32());
-
- ASSERT_TRUE(instr->RHS()->Is<Constant>());
- auto rhs = instr->RHS()->As<Constant>();
- ASSERT_TRUE(rhs->IsI32());
- EXPECT_EQ(i32(2), rhs->AsI32());
-
- std::stringstream str;
- instr->ToString(str, program->Symbols());
- EXPECT_EQ(str.str(), "%42 = 4 % 2");
-}
-
-} // namespace
-} // namespace tint::ir
diff --git a/src/tint/ir/temp.cc b/src/tint/ir/temp.cc
index afd0921..e925561 100644
--- a/src/tint/ir/temp.cc
+++ b/src/tint/ir/temp.cc
@@ -20,12 +20,12 @@
namespace tint::ir {
-Temp::Temp(Id id) : id_(id) {}
+Temp::Temp(const type::Type* type, Id id) : type_(type), id_(id) {}
Temp::~Temp() = default;
-std::ostream& Temp::ToString(std::ostream& out, const SymbolTable&) const {
- out << "%" << std::to_string(AsId());
+std::ostream& Temp::ToString(std::ostream& out, const SymbolTable& st) const {
+ out << "%" << std::to_string(AsId()) << " (" << type_->FriendlyName(st) << ")";
return out;
}
diff --git a/src/tint/ir/temp.h b/src/tint/ir/temp.h
index 2db81f3..1a4a38d 100644
--- a/src/tint/ir/temp.h
+++ b/src/tint/ir/temp.h
@@ -29,8 +29,9 @@
using Id = uint32_t;
/// Constructor
+ /// @param type the type of the temporary
/// @param id the id for the value
- explicit Temp(Id id);
+ Temp(const type::Type* type, Id id);
/// Destructor
~Temp() override;
@@ -44,6 +45,9 @@
/// @returns the value data as an `Id`.
Id AsId() const { return id_; }
+ /// @returns the type of the temporary
+ const type::Type* Type() const override { return type_; }
+
/// Write the temp to the given stream
/// @param out the stream to write to
/// @param st the symbol table
@@ -51,6 +55,7 @@
std::ostream& ToString(std::ostream& out, const SymbolTable& st) const override;
private:
+ const type::Type* type_ = nullptr;
Id id_ = 0;
};
diff --git a/src/tint/ir/temp_test.cc b/src/tint/ir/temp_test.cc
index 6b79a51..81a4992 100644
--- a/src/tint/ir/temp_test.cc
+++ b/src/tint/ir/temp_test.cc
@@ -30,11 +30,11 @@
std::stringstream str;
b.builder.next_temp_id = Temp::Id(4);
- auto* val = b.builder.Temp();
+ auto* val = b.builder.Temp(b.builder.ir.types.Get<type::I32>());
EXPECT_EQ(4u, val->AsId());
val->ToString(str, program->Symbols());
- EXPECT_EQ("%4", str.str());
+ EXPECT_EQ("%4 (i32)", str.str());
}
} // namespace
diff --git a/src/tint/ir/value.h b/src/tint/ir/value.h
index 6dffc3e..1f9619f 100644
--- a/src/tint/ir/value.h
+++ b/src/tint/ir/value.h
@@ -19,6 +19,13 @@
#include "src/tint/castable.h"
#include "src/tint/symbol_table.h"
+#include "src/tint/type/type.h"
+#include "src/tint/utils/unique_vector.h"
+
+// Forward declarations
+namespace tint::ir {
+class Instruction;
+} // namespace tint::ir
namespace tint::ir {
@@ -34,6 +41,17 @@
Value& operator=(const Value&) = delete;
Value& operator=(Value&&) = delete;
+ /// Adds an instruction which uses this value.
+ /// @param instr the instruction
+ void AddUsage(const Instruction* instr) { uses_.Add(instr); }
+
+ /// @returns the vector of instructions which use this value. An instruction will only be
+ /// returned once even if that instruction uses the given value multiple times.
+ utils::VectorRef<const Instruction*> Usage() const { return uses_; }
+
+ /// @returns the type of the value
+ virtual const type::Type* Type() const = 0;
+
/// Write the value to the given stream
/// @param out the stream to write to
/// @param st the symbol table
@@ -43,6 +61,9 @@
protected:
/// Constructor
Value();
+
+ private:
+ utils::UniqueVector<const Instruction*, 4> uses_;
};
} // namespace tint::ir
diff --git a/src/tint/program_builder.cc b/src/tint/program_builder.cc
index 87c6a4c..a219de3 100644
--- a/src/tint/program_builder.cc
+++ b/src/tint/program_builder.cc
@@ -153,4 +153,39 @@
});
}
+const constant::Value* ProgramBuilder::createSplatOrComposite(
+ const type::Type* type,
+ utils::VectorRef<const constant::Value*> elements) {
+ if (elements.IsEmpty()) {
+ return nullptr;
+ }
+
+ bool any_zero = false;
+ bool all_zero = true;
+ bool all_equal = true;
+ auto* first = elements.Front();
+ for (auto* el : elements) {
+ if (!el) {
+ return nullptr;
+ }
+ if (!any_zero && el->AnyZero()) {
+ any_zero = true;
+ }
+ if (all_zero && !el->AllZero()) {
+ all_zero = false;
+ }
+ if (all_equal && el != first) {
+ if (!el->Equal(first)) {
+ all_equal = false;
+ }
+ }
+ }
+ if (all_equal) {
+ return create<constant::Splat>(type, elements[0], elements.Length());
+ }
+
+ return constant_nodes_.Create<constant::Composite>(type, std::move(elements), all_zero,
+ any_zero);
+}
+
} // namespace tint
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 4dac010..9b688f0 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -493,42 +493,13 @@
/// @param type the composite type
/// @param elements the composite elements
/// @returns the node pointer
- template <typename T>
- traits::EnableIf<traits::IsTypeOrDerived<T, constant::Composite> ||
- traits::IsTypeOrDerived<T, constant::Splat>,
- const constant::Value>*
- create(const type::Type* type, utils::VectorRef<const constant::Value*> elements) {
+ template <typename T,
+ typename = traits::EnableIf<traits::IsTypeOrDerived<T, constant::Composite> ||
+ traits::IsTypeOrDerived<T, constant::Splat>>>
+ const constant::Value* create(const type::Type* type,
+ utils::VectorRef<const constant::Value*> elements) {
AssertNotMoved();
- if (elements.IsEmpty()) {
- return nullptr;
- }
-
- bool any_zero = false;
- bool all_zero = true;
- bool all_equal = true;
- auto* first = elements.Front();
- for (auto* el : elements) {
- if (!el) {
- return nullptr;
- }
- if (!any_zero && el->AnyZero()) {
- any_zero = true;
- }
- if (all_zero && !el->AllZero()) {
- all_zero = false;
- }
- if (all_equal && el != first) {
- if (!el->Equal(first)) {
- all_equal = false;
- }
- }
- }
- if (all_equal) {
- return create<constant::Splat>(type, elements[0], elements.Length());
- }
-
- return constant_nodes_.Create<constant::Composite>(type, std::move(elements), all_zero,
- any_zero);
+ return createSplatOrComposite(type, elements);
}
/// Constructs a splat constant.
@@ -536,9 +507,10 @@
/// @param element the splat element
/// @param n the number of elements
/// @returns the node pointer
- template <typename T>
- traits::EnableIf<traits::IsTypeOrDerived<T, constant::Splat>, const constant::Splat>*
- create(const type::Type* type, const constant::Value* element, size_t n) {
+ template <typename T, typename = traits::EnableIf<traits::IsTypeOrDerived<T, constant::Splat>>>
+ const constant::Splat* create(const type::Type* type,
+ const constant::Value* element,
+ size_t n) {
AssertNotMoved();
return constant_nodes_.Create<constant::Splat>(type, element, n);
}
@@ -3351,6 +3323,10 @@
void AssertNotMoved() const;
private:
+ const constant::Value* createSplatOrComposite(
+ const type::Type* type,
+ utils::VectorRef<const constant::Value*> elements);
+
ProgramID id_;
ast::NodeID last_ast_node_id_ = ast::NodeID{static_cast<decltype(ast::NodeID::value)>(0) - 1};
type::Manager types_;