[ir] Renaming Register and Op

This CL renames Register to Value and Op to Instruction.

Bug: tint:1718
Change-Id: Ided22c524213235369aae366a678d8058a516b60
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112041
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:
dan sinclair 2022-11-28 22:02:39 +00:00 committed by Dawn LUCI CQ
parent 3728a505d6
commit 62a07738c8
19 changed files with 985 additions and 987 deletions

View File

@ -666,18 +666,18 @@ if(${TINT_BUILD_IR})
ir/function.h
ir/if.cc
ir/if.h
ir/instruction.cc
ir/instruction.h
ir/loop.cc
ir/loop.h
ir/module.cc
ir/module.h
ir/op.cc
ir/op.h
ir/register.cc
ir/register.h
ir/switch.cc
ir/switch.h
ir/terminator.cc
ir/terminator.h
ir/value.cc
ir/value.h
)
endif()
@ -1341,9 +1341,9 @@ if(TINT_BUILD_TESTS)
if (${TINT_BUILD_IR})
list(APPEND TINT_TEST_SRCS
ir/builder_impl_test.cc
ir/op_test.cc
ir/register_test.cc
ir/instruction_test.cc
ir/test_helper.h
ir/value_test.cc
)
endif()

View File

@ -16,7 +16,7 @@
#define SRC_TINT_IR_BLOCK_H_
#include "src/tint/ir/flow_node.h"
#include "src/tint/ir/op.h"
#include "src/tint/ir/instruction.h"
#include "src/tint/utils/vector.h"
namespace tint::ir {
@ -33,8 +33,8 @@ class Block : public Castable<Block, FlowNode> {
/// The node this block branches too.
const FlowNode* branch_target = nullptr;
/// The operations in the block
utils::Vector<Op, 16> ops;
/// The instructions in the block
utils::Vector<Instruction, 16> instructions;
};
} // namespace tint::ir

View File

@ -93,84 +93,84 @@ void Builder::Branch(Block* from, FlowNode* to) {
to->inbound_branches.Push(from);
}
Register::Id Builder::AllocateRegister() {
return next_register_id++;
Value::Id Builder::AllocateValue() {
return next_value_id++;
}
Op Builder::CreateOp(Op::Kind kind, Register lhs, Register rhs) {
return Op(kind, Register(AllocateRegister()), lhs, rhs);
Instruction Builder::CreateInstruction(Instruction::Kind kind, Value lhs, Value rhs) {
return Instruction(kind, Value(AllocateValue()), lhs, rhs);
}
Op Builder::And(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kAnd, lhs, rhs);
Instruction Builder::And(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kAnd, lhs, rhs);
}
Op Builder::Or(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kOr, lhs, rhs);
Instruction Builder::Or(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kOr, lhs, rhs);
}
Op Builder::Xor(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kXor, lhs, rhs);
Instruction Builder::Xor(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kXor, lhs, rhs);
}
Op Builder::LogicalAnd(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kLogicalAnd, lhs, rhs);
Instruction Builder::LogicalAnd(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kLogicalAnd, lhs, rhs);
}
Op Builder::LogicalOr(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kLogicalOr, lhs, rhs);
Instruction Builder::LogicalOr(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kLogicalOr, lhs, rhs);
}
Op Builder::Equal(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kEqual, lhs, rhs);
Instruction Builder::Equal(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kEqual, lhs, rhs);
}
Op Builder::NotEqual(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kNotEqual, lhs, rhs);
Instruction Builder::NotEqual(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kNotEqual, lhs, rhs);
}
Op Builder::LessThan(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kLessThan, lhs, rhs);
Instruction Builder::LessThan(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kLessThan, lhs, rhs);
}
Op Builder::GreaterThan(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kGreaterThan, lhs, rhs);
Instruction Builder::GreaterThan(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kGreaterThan, lhs, rhs);
}
Op Builder::LessThanEqual(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kLessThanEqual, lhs, rhs);
Instruction Builder::LessThanEqual(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kLessThanEqual, lhs, rhs);
}
Op Builder::GreaterThanEqual(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kGreaterThanEqual, lhs, rhs);
Instruction Builder::GreaterThanEqual(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kGreaterThanEqual, lhs, rhs);
}
Op Builder::ShiftLeft(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kShiftLeft, lhs, rhs);
Instruction Builder::ShiftLeft(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kShiftLeft, lhs, rhs);
}
Op Builder::ShiftRight(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kShiftRight, lhs, rhs);
Instruction Builder::ShiftRight(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kShiftRight, lhs, rhs);
}
Op Builder::Add(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kAdd, lhs, rhs);
Instruction Builder::Add(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kAdd, lhs, rhs);
}
Op Builder::Subtract(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kSubtract, lhs, rhs);
Instruction Builder::Subtract(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kSubtract, lhs, rhs);
}
Op Builder::Multiply(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kMultiply, lhs, rhs);
Instruction Builder::Multiply(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kMultiply, lhs, rhs);
}
Op Builder::Divide(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kDivide, lhs, rhs);
Instruction Builder::Divide(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kDivide, lhs, rhs);
}
Op Builder::Modulo(Register lhs, Register rhs) {
return CreateOp(Op::Kind::kModulo, lhs, rhs);
Instruction Builder::Modulo(Value lhs, Value rhs) {
return CreateInstruction(Instruction::Kind::kModulo, lhs, rhs);
}
} // namespace tint::ir

View File

@ -17,12 +17,12 @@
#include "src/tint/ir/function.h"
#include "src/tint/ir/if.h"
#include "src/tint/ir/instruction.h"
#include "src/tint/ir/loop.h"
#include "src/tint/ir/module.h"
#include "src/tint/ir/op.h"
#include "src/tint/ir/register.h"
#include "src/tint/ir/switch.h"
#include "src/tint/ir/terminator.h"
#include "src/tint/ir/value.h"
// Forward Declarations
namespace tint {
@ -88,124 +88,124 @@ class Builder {
/// @param lhs the left-hand-side of the operation
/// @param rhs the right-hand-side of the operation
/// @returns the operation
Op CreateOp(Op::Kind kind, Register lhs, Register rhs);
Instruction CreateInstruction(Instruction::Kind kind, Value lhs, Value rhs);
/// Creates an And operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op And(Register lhs, Register rhs);
Instruction And(Value lhs, Value rhs);
/// Creates an Or operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op Or(Register lhs, Register rhs);
Instruction Or(Value lhs, Value rhs);
/// Creates an Xor operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op Xor(Register lhs, Register rhs);
Instruction Xor(Value lhs, Value rhs);
/// Creates an LogicalAnd operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op LogicalAnd(Register lhs, Register rhs);
Instruction LogicalAnd(Value lhs, Value rhs);
/// Creates an LogicalOr operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op LogicalOr(Register lhs, Register rhs);
Instruction LogicalOr(Value lhs, Value rhs);
/// Creates an Equal operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op Equal(Register lhs, Register rhs);
Instruction Equal(Value lhs, Value rhs);
/// Creates an NotEqual operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op NotEqual(Register lhs, Register rhs);
Instruction NotEqual(Value lhs, Value rhs);
/// Creates an LessThan operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op LessThan(Register lhs, Register rhs);
Instruction LessThan(Value lhs, Value rhs);
/// Creates an GreaterThan operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op GreaterThan(Register lhs, Register rhs);
Instruction GreaterThan(Value lhs, Value rhs);
/// Creates an LessThanEqual operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op LessThanEqual(Register lhs, Register rhs);
Instruction LessThanEqual(Value lhs, Value rhs);
/// Creates an GreaterThanEqual operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op GreaterThanEqual(Register lhs, Register rhs);
Instruction GreaterThanEqual(Value lhs, Value rhs);
/// Creates an ShiftLeft operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op ShiftLeft(Register lhs, Register rhs);
Instruction ShiftLeft(Value lhs, Value rhs);
/// Creates an ShiftRight operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op ShiftRight(Register lhs, Register rhs);
Instruction ShiftRight(Value lhs, Value rhs);
/// Creates an Add operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op Add(Register lhs, Register rhs);
Instruction Add(Value lhs, Value rhs);
/// Creates an Subtract operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op Subtract(Register lhs, Register rhs);
Instruction Subtract(Value lhs, Value rhs);
/// Creates an Multiply operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op Multiply(Register lhs, Register rhs);
Instruction Multiply(Value lhs, Value rhs);
/// Creates an Divide operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op Divide(Register lhs, Register rhs);
Instruction Divide(Value lhs, Value rhs);
/// Creates an Modulo operation
/// @param lhs the lhs of the add
/// @param rhs the rhs of the add
/// @returns the operation
Op Modulo(Register lhs, Register rhs);
Instruction Modulo(Value lhs, Value rhs);
/// @returns a unique register id
Register::Id AllocateRegister();
/// @returns a unique Value id
Value::Id AllocateValue();
/// The IR module.
Module ir;
/// The next register number to allocate
Register::Id next_register_id = 1;
/// The next Value number to allocate
Value::Id next_value_id = 1;
};
} // namespace tint::ir

View File

@ -516,7 +516,7 @@ bool BuilderImpl::EmitBreakIf(const ast::BreakIfStatement* stmt) {
return true;
}
utils::Result<Register> 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); },
@ -551,7 +551,7 @@ bool BuilderImpl::EmitVariable(const ast::Variable* var) {
});
}
utils::Result<Register> 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;
@ -562,89 +562,87 @@ utils::Result<Register> BuilderImpl::EmitBinary(const ast::BinaryExpression* exp
return utils::Failure;
}
Op op;
Instruction instr;
switch (expr->op) {
case ast::BinaryOp::kAnd:
op = builder.And(lhs.Get(), rhs.Get());
instr = builder.And(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kOr:
op = builder.Or(lhs.Get(), rhs.Get());
instr = builder.Or(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kXor:
op = builder.Xor(lhs.Get(), rhs.Get());
instr = builder.Xor(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLogicalAnd:
op = builder.LogicalAnd(lhs.Get(), rhs.Get());
instr = builder.LogicalAnd(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLogicalOr:
op = builder.LogicalOr(lhs.Get(), rhs.Get());
instr = builder.LogicalOr(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kEqual:
op = builder.Equal(lhs.Get(), rhs.Get());
instr = builder.Equal(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kNotEqual:
op = builder.NotEqual(lhs.Get(), rhs.Get());
instr = builder.NotEqual(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLessThan:
op = builder.LessThan(lhs.Get(), rhs.Get());
instr = builder.LessThan(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kGreaterThan:
op = builder.GreaterThan(lhs.Get(), rhs.Get());
instr = builder.GreaterThan(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kLessThanEqual:
op = builder.LessThanEqual(lhs.Get(), rhs.Get());
instr = builder.LessThanEqual(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kGreaterThanEqual:
op = builder.GreaterThanEqual(lhs.Get(), rhs.Get());
instr = builder.GreaterThanEqual(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kShiftLeft:
op = builder.ShiftLeft(lhs.Get(), rhs.Get());
instr = builder.ShiftLeft(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kShiftRight:
op = builder.ShiftRight(lhs.Get(), rhs.Get());
instr = builder.ShiftRight(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kAdd:
op = builder.Add(lhs.Get(), rhs.Get());
instr = builder.Add(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kSubtract:
op = builder.Subtract(lhs.Get(), rhs.Get());
instr = builder.Subtract(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kMultiply:
op = builder.Multiply(lhs.Get(), rhs.Get());
instr = builder.Multiply(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kDivide:
op = builder.Divide(lhs.Get(), rhs.Get());
instr = builder.Divide(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kModulo:
op = builder.Modulo(lhs.Get(), rhs.Get());
instr = builder.Modulo(lhs.Get(), rhs.Get());
break;
case ast::BinaryOp::kNone:
TINT_ICE(IR, diagnostics_) << "missing binary operand type";
return utils::Failure;
}
auto result = op.Result();
current_flow_block->ops.Push(op);
auto result = instr.Result();
current_flow_block->instructions.Push(instr);
return result;
}
utils::Result<Register> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
utils::Result<Value> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
return tint::Switch( //
lit,
[&](const ast::BoolLiteralExpression* l) {
return utils::Result<Register>{Register(l->value)};
},
[&](const ast::BoolLiteralExpression* l) { return utils::Result<Value>{Value(l->value)}; },
[&](const ast::FloatLiteralExpression* l) {
if (l->suffix == ast::FloatLiteralExpression::Suffix::kF) {
return utils::Result<Register>{Register(f32(static_cast<float>(l->value)))};
return utils::Result<Value>{Value(f32(static_cast<float>(l->value)))};
}
return utils::Result<Register>{Register(f16(static_cast<float>(l->value)))};
return utils::Result<Value>{Value(f16(static_cast<float>(l->value)))};
},
[&](const ast::IntLiteralExpression* l) {
if (l->suffix == ast::IntLiteralExpression::Suffix::kI) {
return utils::Result<Register>{Register(i32(l->value))};
return utils::Result<Value>{Value(i32(l->value))};
}
return utils::Result<Register>{Register(u32(l->value))};
return utils::Result<Value>{Value(u32(l->value))};
},
[&](Default) {
diagnostics_.add_warning(tint::diag::System::IR,

View File

@ -23,7 +23,7 @@
#include "src/tint/ir/builder.h"
#include "src/tint/ir/flow_node.h"
#include "src/tint/ir/module.h"
#include "src/tint/ir/register.h"
#include "src/tint/ir/value.h"
#include "src/tint/utils/result.h"
// Forward Declarations
@ -140,7 +140,7 @@ class BuilderImpl {
/// Emits an expression
/// @param expr the expression to emit
/// @returns true if successful, false otherwise
utils::Result<Register> EmitExpression(const ast::Expression* expr);
utils::Result<Value> EmitExpression(const ast::Expression* expr);
/// Emits a variable
/// @param var the variable to emit
@ -149,13 +149,13 @@ class BuilderImpl {
/// Emits a binary expression
/// @param expr the binary expression
/// @returns the register storing the result if successful, utils::Failure otherwise
utils::Result<Register> EmitBinary(const ast::BinaryExpression* expr);
/// @returns the value storing the result if successful, utils::Failure otherwise
utils::Result<Value> EmitBinary(const ast::BinaryExpression* expr);
/// Emits a literal expression
/// @param lit the literal to emit
/// @returns true if successful, false otherwise
utils::Result<Register> EmitLiteral(const ast::LiteralExpression* lit);
utils::Result<Value> EmitLiteral(const ast::LiteralExpression* lit);
/// Emits a type
/// @param ty the type to emit

View File

@ -101,9 +101,9 @@ TEST_F(IR_BuilderImplTest, IfStatement) {
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
// Check condition
auto op = flow->condition;
ASSERT_TRUE(op.IsBool());
EXPECT_TRUE(op.AsBool());
auto instr = flow->condition;
ASSERT_TRUE(instr.IsBool());
EXPECT_TRUE(instr.AsBool());
}
TEST_F(IR_BuilderImplTest, IfStatement_TrueReturns) {
@ -502,9 +502,9 @@ TEST_F(IR_BuilderImplTest, Loop_WithReturn) {
EXPECT_EQ(loop_flow->merge_target->branch_target, nullptr);
// Check condition
auto op = if_flow->condition;
ASSERT_TRUE(op.IsBool());
EXPECT_TRUE(op.AsBool());
auto instr = if_flow->condition;
ASSERT_TRUE(instr.IsBool());
EXPECT_TRUE(instr.AsBool());
}
TEST_F(IR_BuilderImplTest, Loop_WithOnlyReturn) {
@ -947,9 +947,9 @@ TEST_F(IR_BuilderImplTest, While) {
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
// Check condition
auto op = if_flow->condition;
ASSERT_TRUE(op.IsBool());
EXPECT_FALSE(op.AsBool());
auto instr = if_flow->condition;
ASSERT_TRUE(instr.IsBool());
EXPECT_FALSE(instr.AsBool());
}
TEST_F(IR_BuilderImplTest, While_Return) {
@ -1071,9 +1071,9 @@ TEST_F(IR_BuilderImplTest, DISABLED_For) {
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
// Check condition
auto op = if_flow->condition;
ASSERT_TRUE(op.IsBool());
EXPECT_FALSE(op.AsBool());
auto instr = if_flow->condition;
ASSERT_TRUE(instr.IsBool());
EXPECT_FALSE(instr.AsBool());
}
TEST_F(IR_BuilderImplTest, For_NoInitCondOrContinuing) {
@ -1171,9 +1171,9 @@ TEST_F(IR_BuilderImplTest, Switch) {
EXPECT_EQ(flow->merge_target->branch_target, func->end_target);
// Check condition
auto op = flow->condition;
ASSERT_TRUE(op.IsI32());
EXPECT_EQ(1_i, op.AsI32());
auto instr = flow->condition;
ASSERT_TRUE(instr.IsI32());
EXPECT_EQ(1_i, instr.AsI32());
}
TEST_F(IR_BuilderImplTest, Switch_OnlyDefault) {
@ -1402,7 +1402,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Add) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 + 4
)");
}
@ -1413,7 +1413,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Subtract) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 - 4
)");
}
@ -1424,7 +1424,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Multiply) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 * 4
)");
}
@ -1435,7 +1435,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Div) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 / 4
)");
}
@ -1446,7 +1446,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Modulo) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 % 4
)");
}
@ -1457,7 +1457,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_And) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 & 4
)");
}
@ -1468,7 +1468,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Or) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 | 4
)");
}
@ -1479,7 +1479,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Xor) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 ^ 4
)");
}
@ -1490,7 +1490,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalAnd) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 && 4
)");
}
@ -1501,7 +1501,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LogicalOr) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 || 4
)");
}
@ -1512,7 +1512,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Eqaul) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 == 4
)");
}
@ -1523,7 +1523,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_NotEqual) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 != 4
)");
}
@ -1534,7 +1534,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThan) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 < 4
)");
}
@ -1545,7 +1545,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThan) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 > 4
)");
}
@ -1556,7 +1556,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_LessThanEqual) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 <= 4
)");
}
@ -1567,7 +1567,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_GreaterThanEqual) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 >= 4
)");
}
@ -1578,7 +1578,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftLeft) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 << 4
)");
}
@ -1589,7 +1589,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_ShiftRight) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 >> 4
)");
}
@ -1601,7 +1601,7 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Binary_Compound) {
ASSERT_TRUE(r);
Disassembler d;
d.EmitBlockOps(b.current_flow_block);
d.EmitBlockInstructions(b.current_flow_block);
EXPECT_EQ(d.AsString(), R"(%1 = 3 >> 4
%2 = %1 + 9
%3 = 1 < %2

View File

@ -61,9 +61,9 @@ std::ostream& Disassembler::Indent() {
return out_;
}
void Disassembler::EmitBlockOps(const Block* b) {
for (const auto& op : b->ops) {
out_ << op << std::endl;
void Disassembler::EmitBlockInstructions(const Block* b) {
for (const auto& instr : b->instructions) {
out_ << instr << std::endl;
}
}
@ -87,7 +87,7 @@ void Disassembler::Walk(const FlowNode* node) {
},
[&](const ir::Block* b) {
Indent() << "Block" << std::endl;
EmitBlockOps(b);
EmitBlockInstructions(b);
Walk(b->branch_target);
},
[&](const ir::Switch* s) {

View File

@ -36,9 +36,9 @@ class Disassembler {
/// @returns the string representation of the module
std::string Disassemble(const Module& mod);
/// Writes the block ops to the stream
/// @param b the block containing the ops
void EmitBlockOps(const Block* b);
/// Writes the block instructions to the stream
/// @param b the block containing the instructions
void EmitBlockInstructions(const Block* b);
/// @returns the string representation
std::string AsString() const { return out_.str(); }

View File

@ -17,7 +17,7 @@
#include "src/tint/ast/if_statement.h"
#include "src/tint/ir/flow_node.h"
#include "src/tint/ir/register.h"
#include "src/tint/ir/value.h"
// Forward declarations
namespace tint::ir {
@ -44,8 +44,8 @@ class If : public Castable<If, FlowNode> {
/// An block to reconvert the true/false barnches. The block always exists, but there maybe no
/// branches into it. (e.g. if both branches `return`)
Block* merge_target = nullptr;
/// Register holding the condition result
Register condition;
/// Value holding the condition result
Value condition;
};
} // namespace tint::ir

View File

@ -12,91 +12,91 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/ir/op.h"
#include "src/tint/ir/instruction.h"
namespace tint::ir {
Op::Op() {}
Instruction::Instruction() {}
Op::Op(Kind kind, Register result, Register lhs, Register rhs)
Instruction::Instruction(Kind kind, Value result, Value lhs, Value rhs)
: kind_(kind), result_(result), args_({lhs, rhs}) {}
Op::Op(const Op&) = default;
Instruction::Instruction(const Instruction&) = default;
Op::Op(Op&& o) = default;
Instruction::Instruction(Instruction&& instr) = default;
Op::~Op() = default;
Instruction::~Instruction() = default;
Op& Op::operator=(const Op& o) = default;
Instruction& Instruction::operator=(const Instruction& instr) = default;
Op& Op::operator=(Op&& o) = default;
Instruction& Instruction::operator=(Instruction&& instr) = default;
std::ostream& operator<<(std::ostream& out, const Op& op) {
out << op.Result() << " = ";
if (op.HasLHS()) {
out << op.LHS();
std::ostream& operator<<(std::ostream& out, const Instruction& instr) {
out << instr.Result() << " = ";
if (instr.HasLHS()) {
out << instr.LHS();
}
out << " ";
switch (op.GetKind()) {
case Op::Kind::kAdd:
switch (instr.GetKind()) {
case Instruction::Kind::kAdd:
out << "+";
break;
case Op::Kind::kSubtract:
case Instruction::Kind::kSubtract:
out << "-";
break;
case Op::Kind::kMultiply:
case Instruction::Kind::kMultiply:
out << "*";
break;
case Op::Kind::kDivide:
case Instruction::Kind::kDivide:
out << "/";
break;
case Op::Kind::kModulo:
case Instruction::Kind::kModulo:
out << "%";
break;
case Op::Kind::kAnd:
case Instruction::Kind::kAnd:
out << "&";
break;
case Op::Kind::kOr:
case Instruction::Kind::kOr:
out << "|";
break;
case Op::Kind::kXor:
case Instruction::Kind::kXor:
out << "^";
break;
case Op::Kind::kLogicalAnd:
case Instruction::Kind::kLogicalAnd:
out << "&&";
break;
case Op::Kind::kLogicalOr:
case Instruction::Kind::kLogicalOr:
out << "||";
break;
case Op::Kind::kEqual:
case Instruction::Kind::kEqual:
out << "==";
break;
case Op::Kind::kNotEqual:
case Instruction::Kind::kNotEqual:
out << "!=";
break;
case Op::Kind::kLessThan:
case Instruction::Kind::kLessThan:
out << "<";
break;
case Op::Kind::kGreaterThan:
case Instruction::Kind::kGreaterThan:
out << ">";
break;
case Op::Kind::kLessThanEqual:
case Instruction::Kind::kLessThanEqual:
out << "<=";
break;
case Op::Kind::kGreaterThanEqual:
case Instruction::Kind::kGreaterThanEqual:
out << ">=";
break;
case Op::Kind::kShiftLeft:
case Instruction::Kind::kShiftLeft:
out << "<<";
break;
case Op::Kind::kShiftRight:
case Instruction::Kind::kShiftRight:
out << ">>";
break;
}
if (op.HasRHS()) {
out << " " << op.RHS();
if (instr.HasRHS()) {
out << " " << instr.RHS();
}
return out;

View File

@ -12,20 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_IR_OP_H_
#define SRC_TINT_IR_OP_H_
#ifndef SRC_TINT_IR_INSTRUCTION_H_
#define SRC_TINT_IR_INSTRUCTION_H_
#include <ostream>
#include "src/tint/ir/register.h"
#include "src/tint/ir/value.h"
#include "src/tint/utils/vector.h"
namespace tint::ir {
/// An operation in the IR.
class Op {
/// An instruction in the IR.
class Instruction {
public:
/// The kind of operation.
/// The kind of instruction.
enum class Kind {
kAdd,
kSubtract,
@ -52,49 +52,49 @@ class Op {
};
/// Constructor
Op();
Instruction();
/// Constructor
/// @param kind the kind of operation
/// @param result the result register
/// @param lhs the lhs of the operation
/// @param rhs the rhs of the operation
Op(Kind kind, Register result, Register lhs, Register rhs);
/// @param kind the kind of instruction
/// @param result the result value
/// @param lhs the lhs of the instruction
/// @param rhs the rhs of the instruction
Instruction(Kind kind, Value result, Value lhs, Value rhs);
/// Copy constructor
/// @param o the op to copy from
Op(const Op& o);
/// @param instr the instruction to copy from
Instruction(const Instruction& instr);
/// Move constructor
/// @param o the op to move from
Op(Op&& o);
/// @param instr the instruction to move from
Instruction(Instruction&& instr);
/// Destructor
~Op();
~Instruction();
/// Copy assign
/// @param o the op to copy from
/// @param instr the instruction to copy from
/// @returns a reference to this
Op& operator=(const Op& o);
Instruction& operator=(const Instruction& instr);
/// Move assign
/// @param o the op to move from
/// @param instr the instruction to move from
/// @returns a reference to this
Op& operator=(Op&& o);
Instruction& operator=(Instruction&& instr);
/// @returns the kind of operation
/// @returns the kind of instruction
Kind GetKind() const { return kind_; }
/// @returns the result register for the operation
const Register& Result() const { return result_; }
/// @returns the result value for the instruction
const Value& Result() const { return result_; }
/// @returns true if the op has a LHS
/// @returns true if the instruction has a LHS
bool HasLHS() const { return args_.Length() >= 1; }
/// @returns the left-hand-side register for the operation
const Register& LHS() const {
/// @returns the left-hand-side value for the instruction
const Value& LHS() const {
TINT_ASSERT(IR, HasLHS());
return args_[0];
}
/// @returns true if the op has a RHS
/// @returns true if the instruction has a RHS
bool HasRHS() const { return args_.Length() >= 2; }
/// @returns the right-hand-side register for the operation
const Register& RHS() const {
/// @returns the right-hand-side value for the instruction
const Value& RHS() const {
TINT_ASSERT(IR, HasRHS());
return args_[1];
}
@ -102,12 +102,12 @@ class Op {
private:
Kind kind_;
Register result_;
utils::Vector<Register, 2> args_;
Value result_;
utils::Vector<Value, 2> args_;
};
std::ostream& operator<<(std::ostream& out, const Op&);
std::ostream& operator<<(std::ostream& out, const Instruction&);
} // namespace tint::ir
#endif // SRC_TINT_IR_OP_H_
#endif // SRC_TINT_IR_INSTRUCTION_H_

View File

@ -0,0 +1,494 @@
// 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_InstructionTest = TestHelper;
TEST_F(IR_InstructionTest, CreateAnd) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.And(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kAnd);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 & 2");
}
TEST_F(IR_InstructionTest, CreateOr) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.Or(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kOr);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 | 2");
}
TEST_F(IR_InstructionTest, CreateXor) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.Xor(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kXor);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 ^ 2");
}
TEST_F(IR_InstructionTest, CreateLogicalAnd) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.LogicalAnd(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLogicalAnd);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 && 2");
}
TEST_F(IR_InstructionTest, CreateLogicalOr) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.LogicalOr(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLogicalOr);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 || 2");
}
TEST_F(IR_InstructionTest, CreateEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.Equal(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kEqual);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 == 2");
}
TEST_F(IR_InstructionTest, CreateNotEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.NotEqual(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kNotEqual);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 != 2");
}
TEST_F(IR_InstructionTest, CreateLessThan) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.LessThan(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLessThan);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 < 2");
}
TEST_F(IR_InstructionTest, CreateGreaterThan) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.GreaterThan(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kGreaterThan);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 > 2");
}
TEST_F(IR_InstructionTest, CreateLessThanEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.LessThanEqual(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLessThanEqual);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 <= 2");
}
TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.GreaterThanEqual(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kGreaterThanEqual);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 >= 2");
}
TEST_F(IR_InstructionTest, CreateShiftLeft) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.ShiftLeft(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kShiftLeft);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 << 2");
}
TEST_F(IR_InstructionTest, CreateShiftRight) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.ShiftRight(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kShiftRight);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 >> 2");
}
TEST_F(IR_InstructionTest, CreateAdd) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.Add(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kAdd);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 + 2");
}
TEST_F(IR_InstructionTest, CreateSubtract) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.Subtract(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kSubtract);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 - 2");
}
TEST_F(IR_InstructionTest, CreateMultiply) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.Multiply(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kMultiply);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 * 2");
}
TEST_F(IR_InstructionTest, CreateDivide) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.Divide(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kDivide);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 / 2");
}
TEST_F(IR_InstructionTest, CreateModulo) {
auto& b = CreateEmptyBuilder();
b.builder.next_value_id = Value::Id(42);
auto instr = b.builder.Modulo(Value(i32(4)), Value(i32(2)));
EXPECT_EQ(instr.GetKind(), Instruction::Kind::kModulo);
ASSERT_TRUE(instr.Result().IsTemp());
EXPECT_EQ(Value::Id(42), instr.Result().AsId());
ASSERT_TRUE(instr.HasLHS());
auto& lhs = instr.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(instr.HasRHS());
auto& rhs = instr.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << instr;
EXPECT_EQ(str.str(), "%42 = 4 % 2");
}
} // namespace
} // namespace tint::ir

View File

@ -1,494 +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/op.h"
#include "src/tint/ir/test_helper.h"
namespace tint::ir {
namespace {
using IR_OpTest = TestHelper;
TEST_F(IR_OpTest, CreateAnd) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.And(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kAnd);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 & 2");
}
TEST_F(IR_OpTest, CreateOr) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.Or(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kOr);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 | 2");
}
TEST_F(IR_OpTest, CreateXor) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.Xor(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kXor);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 ^ 2");
}
TEST_F(IR_OpTest, CreateLogicalAnd) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.LogicalAnd(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kLogicalAnd);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 && 2");
}
TEST_F(IR_OpTest, CreateLogicalOr) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.LogicalOr(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kLogicalOr);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 || 2");
}
TEST_F(IR_OpTest, CreateEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.Equal(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kEqual);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 == 2");
}
TEST_F(IR_OpTest, CreateNotEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.NotEqual(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kNotEqual);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 != 2");
}
TEST_F(IR_OpTest, CreateLessThan) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.LessThan(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kLessThan);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 < 2");
}
TEST_F(IR_OpTest, CreateGreaterThan) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.GreaterThan(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kGreaterThan);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 > 2");
}
TEST_F(IR_OpTest, CreateLessThanEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.LessThanEqual(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kLessThanEqual);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 <= 2");
}
TEST_F(IR_OpTest, CreateGreaterThanEqual) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.GreaterThanEqual(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kGreaterThanEqual);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 >= 2");
}
TEST_F(IR_OpTest, CreateShiftLeft) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.ShiftLeft(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kShiftLeft);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 << 2");
}
TEST_F(IR_OpTest, CreateShiftRight) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.ShiftRight(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kShiftRight);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 >> 2");
}
TEST_F(IR_OpTest, CreateAdd) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.Add(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kAdd);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 + 2");
}
TEST_F(IR_OpTest, CreateSubtract) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.Subtract(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kSubtract);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 - 2");
}
TEST_F(IR_OpTest, CreateMultiply) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.Multiply(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kMultiply);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 * 2");
}
TEST_F(IR_OpTest, CreateDivide) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.Divide(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kDivide);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 / 2");
}
TEST_F(IR_OpTest, CreateModulo) {
auto& b = CreateEmptyBuilder();
b.builder.next_register_id = Register::Id(42);
auto o = b.builder.Modulo(Register(i32(4)), Register(i32(2)));
EXPECT_EQ(o.GetKind(), Op::Kind::kModulo);
ASSERT_TRUE(o.Result().IsTemp());
EXPECT_EQ(Register::Id(42), o.Result().AsId());
ASSERT_TRUE(o.HasLHS());
auto& lhs = o.LHS();
ASSERT_TRUE(lhs.IsI32());
EXPECT_EQ(i32(4), lhs.AsI32());
ASSERT_TRUE(o.HasRHS());
auto& rhs = o.RHS();
ASSERT_TRUE(rhs.IsI32());
EXPECT_EQ(i32(2), rhs.AsI32());
std::stringstream str;
str << o;
EXPECT_EQ(str.str(), "%42 = 4 % 2");
}
} // namespace
} // namespace tint::ir

View File

@ -1,183 +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/register.h"
#include "src/tint/ir/test_helper.h"
namespace tint::ir {
namespace {
using namespace tint::number_suffixes; // NOLINT
using IR_RegisterTest = TestHelper;
TEST_F(IR_RegisterTest, f32) {
std::stringstream str;
Register r(1.2_f);
EXPECT_EQ(1.2_f, r.AsF32());
str << r;
EXPECT_EQ("1.200000", str.str());
EXPECT_TRUE(r.IsF32());
EXPECT_FALSE(r.IsF16());
EXPECT_FALSE(r.IsI32());
EXPECT_FALSE(r.IsU32());
EXPECT_FALSE(r.IsTemp());
EXPECT_FALSE(r.IsVar());
EXPECT_FALSE(r.IsBool());
}
TEST_F(IR_RegisterTest, f16) {
std::stringstream str;
Register r(1.1_h);
EXPECT_EQ(1.1_h, r.AsF16());
str << r;
EXPECT_EQ("1.099609", str.str());
EXPECT_FALSE(r.IsF32());
EXPECT_TRUE(r.IsF16());
EXPECT_FALSE(r.IsI32());
EXPECT_FALSE(r.IsU32());
EXPECT_FALSE(r.IsTemp());
EXPECT_FALSE(r.IsVar());
EXPECT_FALSE(r.IsBool());
}
TEST_F(IR_RegisterTest, i32) {
std::stringstream str;
Register r(1_i);
EXPECT_EQ(1_i, r.AsI32());
str << r;
EXPECT_EQ("1", str.str());
EXPECT_FALSE(r.IsF32());
EXPECT_FALSE(r.IsF16());
EXPECT_TRUE(r.IsI32());
EXPECT_FALSE(r.IsU32());
EXPECT_FALSE(r.IsTemp());
EXPECT_FALSE(r.IsVar());
EXPECT_FALSE(r.IsBool());
}
TEST_F(IR_RegisterTest, u32) {
std::stringstream str;
Register r(2_u);
EXPECT_EQ(2_u, r.AsU32());
str << r;
EXPECT_EQ("2", str.str());
EXPECT_FALSE(r.IsF32());
EXPECT_FALSE(r.IsF16());
EXPECT_FALSE(r.IsI32());
EXPECT_TRUE(r.IsU32());
EXPECT_FALSE(r.IsTemp());
EXPECT_FALSE(r.IsVar());
EXPECT_FALSE(r.IsBool());
}
TEST_F(IR_RegisterTest, id) {
std::stringstream str;
Register r(Register::Id(4));
EXPECT_EQ(4u, r.AsId());
str << r;
EXPECT_EQ("%4", str.str());
EXPECT_FALSE(r.IsF32());
EXPECT_FALSE(r.IsF16());
EXPECT_FALSE(r.IsI32());
EXPECT_FALSE(r.IsU32());
EXPECT_TRUE(r.IsTemp());
EXPECT_FALSE(r.IsVar());
EXPECT_FALSE(r.IsBool());
}
TEST_F(IR_RegisterTest, bool) {
std::stringstream str;
Register r(false);
EXPECT_FALSE(r.AsBool());
str << r;
EXPECT_EQ("false", str.str());
str.str("");
r = Register(true);
EXPECT_TRUE(r.AsBool());
str << r;
EXPECT_EQ("true", str.str());
EXPECT_FALSE(r.IsF32());
EXPECT_FALSE(r.IsF16());
EXPECT_FALSE(r.IsI32());
EXPECT_FALSE(r.IsU32());
EXPECT_FALSE(r.IsTemp());
EXPECT_FALSE(r.IsVar());
EXPECT_TRUE(r.IsBool());
}
TEST_F(IR_RegisterTest, var) {
std::stringstream str;
Symbol s;
Register r(s, 2);
EXPECT_EQ(2u, r.AsVarData().id);
EXPECT_EQ(s, r.AsVarData().sym);
str << r;
EXPECT_EQ("%v2", str.str());
str.str("");
r = Register(s, 4);
EXPECT_EQ(4u, r.AsVarData().id);
EXPECT_EQ(s, r.AsVarData().sym);
str << r;
EXPECT_EQ("%v4", str.str());
EXPECT_FALSE(r.IsF32());
EXPECT_FALSE(r.IsF16());
EXPECT_FALSE(r.IsI32());
EXPECT_FALSE(r.IsU32());
EXPECT_FALSE(r.IsTemp());
EXPECT_TRUE(r.IsVar());
EXPECT_FALSE(r.IsBool());
}
TEST_F(IR_RegisterTest, uninitialized) {
Register r;
EXPECT_FALSE(r.IsF32());
EXPECT_FALSE(r.IsF16());
EXPECT_FALSE(r.IsI32());
EXPECT_FALSE(r.IsU32());
EXPECT_FALSE(r.IsTemp());
EXPECT_FALSE(r.IsVar());
EXPECT_FALSE(r.IsBool());
}
} // namespace
} // namespace tint::ir

View File

@ -17,7 +17,7 @@
#include "src/tint/ir/block.h"
#include "src/tint/ir/flow_node.h"
#include "src/tint/ir/register.h"
#include "src/tint/ir/value.h"
// Forward declarations
namespace tint::ast {
@ -52,8 +52,8 @@ class Switch : public Castable<Switch, FlowNode> {
/// The switch case statements
utils::Vector<Case, 4> cases;
/// Register holding the condition result
Register condition;
/// Value holding the condition result
Value condition;
};
} // namespace tint::ir

View File

@ -12,62 +12,62 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/ir/register.h"
#include "src/tint/ir/value.h"
namespace tint::ir {
Register::Register() : kind_(Kind::kUninitialized), data_(Id(0)) {}
Value::Value() : kind_(Kind::kUninitialized), data_(Id(0)) {}
Register::Register(Id id) : kind_(Kind::kTemp), data_(id) {}
Value::Value(Id id) : kind_(Kind::kTemp), data_(id) {}
Register::Register(f32 f) : kind_(Kind::kF32), data_(f) {}
Value::Value(f32 f) : kind_(Kind::kF32), data_(f) {}
Register::Register(f16 f) : kind_(Kind::kF16), data_(f) {}
Value::Value(f16 f) : kind_(Kind::kF16), data_(f) {}
Register::Register(u32 u) : kind_(Kind::kU32), data_(u) {}
Value::Value(u32 u) : kind_(Kind::kU32), data_(u) {}
Register::Register(i32 i) : kind_(Kind::kI32), data_(i) {}
Value::Value(i32 i) : kind_(Kind::kI32), data_(i) {}
Register::Register(bool b) : kind_(Kind::kBool), data_(b) {}
Value::Value(bool b) : kind_(Kind::kBool), data_(b) {}
Register::Register(Symbol s, Id id) : kind_(Kind::kVar), data_(VarData{s, id}) {}
Value::Value(Symbol s, Id id) : kind_(Kind::kVar), data_(VarData{s, id}) {}
Register::~Register() = default;
Value::~Value() = default;
Register::Register(const Register& o) = default;
Value::Value(const Value& o) = default;
Register::Register(Register&& o) = default;
Value::Value(Value&& o) = default;
Register& Register::operator=(const Register& o) = default;
Value& Value::operator=(const Value& o) = default;
Register& Register::operator=(Register&& o) = default;
Value& Value::operator=(Value&& o) = default;
std::ostream& operator<<(std::ostream& out, const Register& r) {
std::ostream& operator<<(std::ostream& out, const Value& r) {
switch (r.GetKind()) {
case Register::Kind::kTemp:
case Value::Kind::kTemp:
out << "%" << std::to_string(r.AsId());
break;
case Register::Kind::kF32:
case Value::Kind::kF32:
out << std::to_string(r.AsF32().value);
break;
case Register::Kind::kF16:
case Value::Kind::kF16:
out << std::to_string(r.AsF16().value);
break;
case Register::Kind::kI32:
case Value::Kind::kI32:
out << std::to_string(r.AsI32().value);
break;
case Register::Kind::kU32:
case Value::Kind::kU32:
out << std::to_string(r.AsU32().value);
break;
// TODO(dsinclair): Emit the symbol instead of v
case Register::Kind::kVar:
case Value::Kind::kVar:
out << "%v" << std::to_string(r.AsVarData().id);
break;
case Register::Kind::kBool:
case Value::Kind::kBool:
out << (r.AsBool() ? "true" : "false");
break;
case Register::Kind::kUninitialized:
out << "unknown register";
case Value::Kind::kUninitialized:
out << "unknown value";
break;
}
return out;

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_IR_REGISTER_H_
#define SRC_TINT_IR_REGISTER_H_
#ifndef SRC_TINT_IR_VALUE_H_
#define SRC_TINT_IR_VALUE_H_
#include <ostream>
#include <variant>
@ -23,37 +23,37 @@
namespace tint::ir {
/// Register in the IR. The register can be one of several types these include, but aren't limited
/// to, `f32`, `u32`, `temp`, `var`. The type of the register determines the type of data stored
/// in the register.
class Register {
/// Value in the IR. The value can be one of several types these include, but aren't limited
/// to, `f32`, `u32`, `temp`, `var`. The type of the value determines the type of data stored
/// in the value.
class Value {
public:
/// A register id.
/// A value id.
using Id = uint32_t;
/// The type of the register
/// The type of the value
enum class Kind {
/// A uninitialized register
/// A uninitialized value
kUninitialized,
/// A temporary allocated register
/// A temporary allocated value
kTemp,
/// A f32 register
/// A f32 value
kF32,
/// A f16 register
/// A f16 value
kF16,
/// An i32 register
/// An i32 value
kI32,
/// A u32 register
/// A u32 value
kU32,
/// A variable register
/// A variable value
kVar,
/// A boolean register
/// A boolean value
kBool,
};
/// Stores data for a given variable. There will be multiple `VarData` entries for a given `id`.
/// The `id` acts like a generation number (although they aren't sequential, they are
/// increasing). As the variable is stored too a new register will be created and the the `id`
/// increasing). As the variable is stored too a new value will be created and the the `id`
/// will be incremented.
struct VarData {
/// The symbol for the variable
@ -64,106 +64,106 @@ class Register {
};
/// Constructor
/// Creates a uninitialized register
Register();
/// Creates a uninitialized value
Value();
/// Constructor
/// @param id the id for the register
explicit Register(Id id);
/// @param id the id for the value
explicit Value(Id id);
/// Constructor
/// @param s the symbol for the register
/// @param id the id for the register
Register(Symbol s, Id id);
/// @param s the symbol for the value
/// @param id the id for the value
Value(Symbol s, Id id);
/// Constructor
/// @param b the `bool` value to store in the register
explicit Register(bool b);
/// @param b the `bool` value to store in the value
explicit Value(bool b);
/// Constructor
/// @param f the `f32` value to store in the register
explicit Register(f32 f);
/// @param f the `f32` value to store in the value
explicit Value(f32 f);
/// Constructor
/// @param f the `f16` value to store in the register
explicit Register(f16 f);
/// @param f the `f16` value to store in the value
explicit Value(f16 f);
/// Constructor
/// @param u the `u32` value to store in the register
explicit Register(u32 u);
/// @param u the `u32` value to store in the value
explicit Value(u32 u);
/// Constructor
/// @param i the `i32` value to store in the register
explicit Register(i32 i);
/// @param i the `i32` value to store in the value
explicit Value(i32 i);
/// Destructor
~Register();
~Value();
/// Copy constructor
/// @param o the register to copy from
Register(const Register& o);
/// @param o the value to copy from
Value(const Value& o);
/// Move constructor
/// @param o the register to move from
Register(Register&& o);
/// @param o the value to move from
Value(Value&& o);
/// Copy assign
/// @param o the register to copy from
/// @param o the value to copy from
/// @returns this
Register& operator=(const Register& o);
Value& operator=(const Value& o);
/// Move assign
/// @param o the register to move from
/// @param o the value to move from
/// @returns this
Register& operator=(Register&& o);
Value& operator=(Value&& o);
/// @returns true if this is a temporary register
/// @returns true if this is a temporary value
bool IsTemp() const { return kind_ == Kind::kTemp; }
/// @returns true if this is a f32 register
/// @returns true if this is a f32 value
bool IsF32() const { return kind_ == Kind::kF32; }
/// @returns true if this is a f16 register
/// @returns true if this is a f16 value
bool IsF16() const { return kind_ == Kind::kF16; }
/// @returns true if this is an i32 register
/// @returns true if this is an i32 value
bool IsI32() const { return kind_ == Kind::kI32; }
/// @returns true if this is a u32 register
/// @returns true if this is a u32 value
bool IsU32() const { return kind_ == Kind::kU32; }
/// @returns true if this is a var register
/// @returns true if this is a var value
bool IsVar() const { return kind_ == Kind::kVar; }
/// @returns true if this is a bool register
/// @returns true if this is a bool value
bool IsBool() const { return kind_ == Kind::kBool; }
/// @returns the kind of register
/// @returns the kind of value
Kind GetKind() const { return kind_; }
/// @returns the register data as a `f32`.
/// @returns the value data as a `f32`.
/// @note, must only be called if `IsF32()` is true
f32 AsF32() const { return std::get<f32>(data_); }
/// @returns the register data as a `f16`.
/// @returns the value data as a `f16`.
/// @note, must only be called if `IsF16()` is true
f16 AsF16() const { return std::get<f16>(data_); }
/// @returns the register data as an `i32`.
/// @returns the value data as an `i32`.
/// @note, must only be called if `IsI32()` is true
i32 AsI32() const { return std::get<i32>(data_); }
/// @returns the register data as a `u32`.
/// @returns the value data as a `u32`.
/// @note, must only be called if `IsU32()` is true
u32 AsU32() const { return std::get<u32>(data_); }
/// @returns the register data as an `Id`.
/// @returns the value data as an `Id`.
/// @note, must only be called if `IsTemp()` is true
Id AsId() const { return std::get<Id>(data_); }
/// @returns the register data as a `VarData` structure.
/// @returns the value data as a `VarData` structure.
/// @note, must only be called if `IsVar()` is true
VarData AsVarData() const { return std::get<VarData>(data_); }
/// @returns the register data as a `bool`.
/// @returns the value data as a `bool`.
/// @note, must only be called if `IsBool()` is true
bool AsBool() const { return std::get<bool>(data_); }
private:
/// The type of data stored in this register
/// The type of data stored in this value
Kind kind_;
/// The data stored in the register
/// The data stored in the value
std::variant<Id, f32, f16, u32, i32, VarData, bool> data_;
};
std::ostream& operator<<(std::ostream& out, const Register& r);
std::ostream& operator<<(std::ostream& out, const Value& r);
} // namespace tint::ir
#endif // SRC_TINT_IR_REGISTER_H_
#endif // SRC_TINT_IR_VALUE_H_

183
src/tint/ir/value_test.cc Normal file
View File

@ -0,0 +1,183 @@
// 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/test_helper.h"
#include "src/tint/ir/value.h"
namespace tint::ir {
namespace {
using namespace tint::number_suffixes; // NOLINT
using IR_ValueTest = TestHelper;
TEST_F(IR_ValueTest, f32) {
std::stringstream str;
Value val(1.2_f);
EXPECT_EQ(1.2_f, val.AsF32());
str << val;
EXPECT_EQ("1.200000", str.str());
EXPECT_TRUE(val.IsF32());
EXPECT_FALSE(val.IsF16());
EXPECT_FALSE(val.IsI32());
EXPECT_FALSE(val.IsU32());
EXPECT_FALSE(val.IsTemp());
EXPECT_FALSE(val.IsVar());
EXPECT_FALSE(val.IsBool());
}
TEST_F(IR_ValueTest, f16) {
std::stringstream str;
Value val(1.1_h);
EXPECT_EQ(1.1_h, val.AsF16());
str << val;
EXPECT_EQ("1.099609", str.str());
EXPECT_FALSE(val.IsF32());
EXPECT_TRUE(val.IsF16());
EXPECT_FALSE(val.IsI32());
EXPECT_FALSE(val.IsU32());
EXPECT_FALSE(val.IsTemp());
EXPECT_FALSE(val.IsVar());
EXPECT_FALSE(val.IsBool());
}
TEST_F(IR_ValueTest, i32) {
std::stringstream str;
Value val(1_i);
EXPECT_EQ(1_i, val.AsI32());
str << val;
EXPECT_EQ("1", str.str());
EXPECT_FALSE(val.IsF32());
EXPECT_FALSE(val.IsF16());
EXPECT_TRUE(val.IsI32());
EXPECT_FALSE(val.IsU32());
EXPECT_FALSE(val.IsTemp());
EXPECT_FALSE(val.IsVar());
EXPECT_FALSE(val.IsBool());
}
TEST_F(IR_ValueTest, u32) {
std::stringstream str;
Value val(2_u);
EXPECT_EQ(2_u, val.AsU32());
str << val;
EXPECT_EQ("2", str.str());
EXPECT_FALSE(val.IsF32());
EXPECT_FALSE(val.IsF16());
EXPECT_FALSE(val.IsI32());
EXPECT_TRUE(val.IsU32());
EXPECT_FALSE(val.IsTemp());
EXPECT_FALSE(val.IsVar());
EXPECT_FALSE(val.IsBool());
}
TEST_F(IR_ValueTest, id) {
std::stringstream str;
Value val(Value::Id(4));
EXPECT_EQ(4u, val.AsId());
str << val;
EXPECT_EQ("%4", str.str());
EXPECT_FALSE(val.IsF32());
EXPECT_FALSE(val.IsF16());
EXPECT_FALSE(val.IsI32());
EXPECT_FALSE(val.IsU32());
EXPECT_TRUE(val.IsTemp());
EXPECT_FALSE(val.IsVar());
EXPECT_FALSE(val.IsBool());
}
TEST_F(IR_ValueTest, bool) {
std::stringstream str;
Value val(false);
EXPECT_FALSE(val.AsBool());
str << val;
EXPECT_EQ("false", str.str());
str.str("");
val = Value(true);
EXPECT_TRUE(val.AsBool());
str << val;
EXPECT_EQ("true", str.str());
EXPECT_FALSE(val.IsF32());
EXPECT_FALSE(val.IsF16());
EXPECT_FALSE(val.IsI32());
EXPECT_FALSE(val.IsU32());
EXPECT_FALSE(val.IsTemp());
EXPECT_FALSE(val.IsVar());
EXPECT_TRUE(val.IsBool());
}
TEST_F(IR_ValueTest, var) {
std::stringstream str;
Symbol s;
Value val(s, 2);
EXPECT_EQ(2u, val.AsVarData().id);
EXPECT_EQ(s, val.AsVarData().sym);
str << val;
EXPECT_EQ("%v2", str.str());
str.str("");
val = Value(s, 4);
EXPECT_EQ(4u, val.AsVarData().id);
EXPECT_EQ(s, val.AsVarData().sym);
str << val;
EXPECT_EQ("%v4", str.str());
EXPECT_FALSE(val.IsF32());
EXPECT_FALSE(val.IsF16());
EXPECT_FALSE(val.IsI32());
EXPECT_FALSE(val.IsU32());
EXPECT_FALSE(val.IsTemp());
EXPECT_TRUE(val.IsVar());
EXPECT_FALSE(val.IsBool());
}
TEST_F(IR_ValueTest, uninitialized) {
Value val;
EXPECT_FALSE(val.IsF32());
EXPECT_FALSE(val.IsF16());
EXPECT_FALSE(val.IsI32());
EXPECT_FALSE(val.IsU32());
EXPECT_FALSE(val.IsTemp());
EXPECT_FALSE(val.IsVar());
EXPECT_FALSE(val.IsBool());
}
} // namespace
} // namespace tint::ir