[ir] Make dump output more consistent.

This Cl updates the dump output for the IR to be a bit more consistent.
Brackets are removed, named calls are used in place of symbols. Trailing
commas cleaned up. Values have their type appended to make it clearer
what they are when a literal is emitted.

Bug: tint:1718
Change-Id: Ie202d4a4f8267d00b9af4864063b7133f4c7f324
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/130000
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
dan sinclair 2023-05-02 08:27:28 +00:00 committed by Dawn LUCI CQ
parent 255a116ea1
commit 642a4f1d8c
18 changed files with 576 additions and 522 deletions

View File

@ -31,67 +31,66 @@ Binary::~Binary() = default;
utils::StringStream& Binary::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = ";
lhs_->ToValue(out) << " ";
switch (GetKind()) {
case Binary::Kind::kAdd:
out << "+";
out << "add";
break;
case Binary::Kind::kSubtract:
out << "-";
out << "sub";
break;
case Binary::Kind::kMultiply:
out << "*";
out << "mul";
break;
case Binary::Kind::kDivide:
out << "/";
out << "div";
break;
case Binary::Kind::kModulo:
out << "%";
out << "mod";
break;
case Binary::Kind::kAnd:
out << "&";
out << "bit_and";
break;
case Binary::Kind::kOr:
out << "|";
out << "bit_or";
break;
case Binary::Kind::kXor:
out << "^";
out << "bit_xor";
break;
case Binary::Kind::kLogicalAnd:
out << "&&";
out << "log_and";
break;
case Binary::Kind::kLogicalOr:
out << "||";
out << "log_or";
break;
case Binary::Kind::kEqual:
out << "==";
out << "eq";
break;
case Binary::Kind::kNotEqual:
out << "!=";
out << "neq";
break;
case Binary::Kind::kLessThan:
out << "<";
out << "lt";
break;
case Binary::Kind::kGreaterThan:
out << ">";
out << "gt";
break;
case Binary::Kind::kLessThanEqual:
out << "<=";
out << "lte";
break;
case Binary::Kind::kGreaterThanEqual:
out << ">=";
out << "gte";
break;
case Binary::Kind::kShiftLeft:
out << "<<";
out << "shiftl";
break;
case Binary::Kind::kShiftRight:
out << ">>";
out << "shiftr";
break;
}
out << " ";
lhs_->ToValue(out) << ", ";
rhs_->ToValue(out);
return out;
}

View File

@ -45,7 +45,7 @@ TEST_F(IR_InstructionTest, CreateAnd) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 & 2");
EXPECT_EQ(str.str(), "%1(i32) = bit_and 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateOr) {
@ -69,7 +69,7 @@ TEST_F(IR_InstructionTest, CreateOr) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 | 2");
EXPECT_EQ(str.str(), "%1(i32) = bit_or 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateXor) {
@ -93,7 +93,7 @@ TEST_F(IR_InstructionTest, CreateXor) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 ^ 2");
EXPECT_EQ(str.str(), "%1(i32) = bit_xor 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateLogicalAnd) {
@ -117,7 +117,7 @@ TEST_F(IR_InstructionTest, CreateLogicalAnd) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 && 2");
EXPECT_EQ(str.str(), "%1(bool) = log_and 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateLogicalOr) {
@ -141,7 +141,7 @@ TEST_F(IR_InstructionTest, CreateLogicalOr) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 || 2");
EXPECT_EQ(str.str(), "%1(bool) = log_or 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateEqual) {
@ -165,7 +165,7 @@ TEST_F(IR_InstructionTest, CreateEqual) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 == 2");
EXPECT_EQ(str.str(), "%1(bool) = eq 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateNotEqual) {
@ -189,7 +189,7 @@ TEST_F(IR_InstructionTest, CreateNotEqual) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 != 2");
EXPECT_EQ(str.str(), "%1(bool) = neq 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateLessThan) {
@ -213,7 +213,7 @@ TEST_F(IR_InstructionTest, CreateLessThan) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 < 2");
EXPECT_EQ(str.str(), "%1(bool) = lt 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateGreaterThan) {
@ -237,7 +237,7 @@ TEST_F(IR_InstructionTest, CreateGreaterThan) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 > 2");
EXPECT_EQ(str.str(), "%1(bool) = gt 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateLessThanEqual) {
@ -261,7 +261,7 @@ TEST_F(IR_InstructionTest, CreateLessThanEqual) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 <= 2");
EXPECT_EQ(str.str(), "%1(bool) = lte 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
@ -285,7 +285,7 @@ TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = 4 >= 2");
EXPECT_EQ(str.str(), "%1(bool) = gte 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateShiftLeft) {
@ -309,7 +309,7 @@ TEST_F(IR_InstructionTest, CreateShiftLeft) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 << 2");
EXPECT_EQ(str.str(), "%1(i32) = shiftl 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateShiftRight) {
@ -333,7 +333,7 @@ TEST_F(IR_InstructionTest, CreateShiftRight) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 >> 2");
EXPECT_EQ(str.str(), "%1(i32) = shiftr 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateAdd) {
@ -357,7 +357,7 @@ TEST_F(IR_InstructionTest, CreateAdd) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 + 2");
EXPECT_EQ(str.str(), "%1(i32) = add 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateSubtract) {
@ -381,7 +381,7 @@ TEST_F(IR_InstructionTest, CreateSubtract) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 - 2");
EXPECT_EQ(str.str(), "%1(i32) = sub 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateMultiply) {
@ -405,7 +405,7 @@ TEST_F(IR_InstructionTest, CreateMultiply) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 * 2");
EXPECT_EQ(str.str(), "%1(i32) = mul 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateDivide) {
@ -429,7 +429,7 @@ TEST_F(IR_InstructionTest, CreateDivide) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 / 2");
EXPECT_EQ(str.str(), "%1(i32) = div 4i, 2i");
}
TEST_F(IR_InstructionTest, CreateModulo) {
@ -453,7 +453,7 @@ TEST_F(IR_InstructionTest, CreateModulo) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = 4 % 2");
EXPECT_EQ(str.str(), "%1(i32) = mod 4i, 2i");
}
TEST_F(IR_InstructionTest, Binary_Usage) {

View File

@ -25,9 +25,8 @@ Bitcast::Bitcast(uint32_t id, const type::Type* type, Value* val)
Bitcast::~Bitcast() = default;
utils::StringStream& Bitcast::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = bitcast(";
ToValue(out) << " = bitcast ";
EmitArgs(out);
out << ")";
return out;
}

View File

@ -39,7 +39,7 @@ TEST_F(IR_InstructionTest, Bitcast) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = bitcast(4)");
EXPECT_EQ(str.str(), "%1(i32) = bitcast 4i");
}
TEST_F(IR_InstructionTest, Bitcast_Usage) {

View File

@ -33,7 +33,7 @@ class Block : public utils::Castable<Block, FlowNode> {
/// @returns true if this is a dead block. This can happen in the case like a loop merge block
/// which is never reached.
bool IsDead() const { return branch.target == nullptr; }
bool IsDead() const override { return branch.target == nullptr; }
/// The node this block branches too.
Branch branch = {};

File diff suppressed because it is too large Load Diff

View File

@ -29,9 +29,8 @@ Builtin::Builtin(uint32_t id,
Builtin::~Builtin() = default;
utils::StringStream& Builtin::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = " << builtin::str(func_) << "(";
ToValue(out) << " = " << builtin::str(func_) << " ";
EmitArgs(out);
out << ")";
return out;
}

View File

@ -35,27 +35,33 @@ utils::StringStream& Constant::ToValue(utils::StringStream& out) const {
c,
[&](const constant::Scalar<AFloat>* scalar) { out << scalar->ValueAs<AFloat>().value; },
[&](const constant::Scalar<AInt>* scalar) { out << scalar->ValueAs<AInt>().value; },
[&](const constant::Scalar<i32>* scalar) { out << scalar->ValueAs<i32>().value; },
[&](const constant::Scalar<u32>* scalar) { out << scalar->ValueAs<u32>().value; },
[&](const constant::Scalar<f32>* scalar) { out << scalar->ValueAs<f32>().value; },
[&](const constant::Scalar<f16>* scalar) { out << scalar->ValueAs<f16>().value; },
[&](const constant::Scalar<i32>* scalar) {
out << scalar->ValueAs<i32>().value << "i";
},
[&](const constant::Scalar<u32>* scalar) {
out << scalar->ValueAs<u32>().value << "u";
},
[&](const constant::Scalar<f32>* scalar) {
out << scalar->ValueAs<f32>().value << "f";
},
[&](const constant::Scalar<f16>* scalar) {
out << scalar->ValueAs<f16>().value << "h";
},
[&](const constant::Scalar<bool>* scalar) {
out << (scalar->ValueAs<bool>() ? "true" : "false");
},
[&](const constant::Splat* splat) {
out << splat->Type()->FriendlyName() << "(";
out << splat->Type()->FriendlyName() << " ";
emit(splat->Index(0));
out << ")";
},
[&](const constant::Composite* composite) {
out << composite->Type()->FriendlyName() << "(";
out << composite->Type()->FriendlyName() << " ";
for (const auto* elem : composite->elements) {
if (elem != composite->elements[0]) {
out << ", ";
}
emit(elem);
}
out << ")";
});
};
emit(value);

View File

@ -32,7 +32,7 @@ TEST_F(IR_ConstantTest, f32) {
EXPECT_EQ(1.2_f, c->value->As<constant::Scalar<f32>>()->ValueAs<f32>());
c->ToValue(str);
EXPECT_EQ("1.20000004768371582031", str.str());
EXPECT_EQ("1.20000004768371582031f", str.str());
EXPECT_TRUE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
@ -50,7 +50,7 @@ TEST_F(IR_ConstantTest, f16) {
EXPECT_EQ(1.1_h, c->value->As<constant::Scalar<f16>>()->ValueAs<f16>());
c->ToValue(str);
EXPECT_EQ("1.099609375", str.str());
EXPECT_EQ("1.099609375h", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_TRUE(c->value->Is<constant::Scalar<f16>>());
@ -68,7 +68,7 @@ TEST_F(IR_ConstantTest, i32) {
EXPECT_EQ(1_i, c->value->As<constant::Scalar<i32>>()->ValueAs<i32>());
c->ToValue(str);
EXPECT_EQ("1", str.str());
EXPECT_EQ("1i", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
@ -86,7 +86,7 @@ TEST_F(IR_ConstantTest, u32) {
EXPECT_EQ(2_u, c->value->As<constant::Scalar<u32>>()->ValueAs<u32>());
c->ToValue(str);
EXPECT_EQ("2", str.str());
EXPECT_EQ("2u", str.str());
EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());

View File

@ -25,12 +25,8 @@ Construct::Construct(uint32_t id, const type::Type* type, utils::VectorRef<Value
Construct::~Construct() = default;
utils::StringStream& Construct::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = construct(";
if (!Args().IsEmpty()) {
out << ", ";
EmitArgs(out);
}
out << ")";
ToValue(out) << " = construct ";
EmitArgs(out);
return out;
}

View File

@ -28,9 +28,8 @@ Convert::Convert(uint32_t id,
Convert::~Convert() = default;
utils::StringStream& Convert::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = convert(" << from_type_->FriendlyName() << ", ";
ToValue(out) << " = convert " << from_type_->FriendlyName() << ", ";
EmitArgs(out);
out << ")";
return out;
}

View File

@ -89,7 +89,7 @@ void Disassembler::Walk(const FlowNode* node) {
tint::Switch(
node,
[&](const ir::Function* f) {
Indent() << "%bb" << GetIdForNode(f) << " = Function " << f->name.Name() << std::endl;
Indent() << "%fn" << GetIdForNode(f) << " = func " << f->name.Name() << std::endl;
{
ScopedIndent func_indent(&indent_size_);
@ -101,27 +101,28 @@ void Disassembler::Walk(const FlowNode* node) {
[&](const ir::Block* b) {
// If this block is dead, nothing to do
if (b->IsDead()) {
Indent() << "# Dead" << std::endl;
return;
}
Indent() << "%bb" << GetIdForNode(b) << " = Block" << std::endl;
Indent() << "%fn" << GetIdForNode(b) << " = block" << std::endl;
EmitBlockInstructions(b);
if (b->branch.target->Is<Terminator>()) {
Indent() << "Return";
Indent() << "ret";
} else {
Indent() << "BranchTo "
<< "%bb" << GetIdForNode(b->branch.target);
Indent() << "branch "
<< "%fn" << GetIdForNode(b->branch.target);
}
out_ << " (";
for (const auto* v : b->branch.args) {
if (v != b->branch.args.Front()) {
out_ << ", ";
if (!b->branch.args.IsEmpty()) {
out_ << " ";
for (const auto* v : b->branch.args) {
if (v != b->branch.args.Front()) {
out_ << ", ";
}
v->ToValue(out_);
}
v->ToValue(out_);
}
out_ << ")" << std::endl;
out_ << std::endl;
if (!b->branch.target->Is<Terminator>()) {
out_ << std::endl;
@ -130,15 +131,37 @@ void Disassembler::Walk(const FlowNode* node) {
Walk(b->branch.target);
},
[&](const ir::Switch* s) {
Indent() << "%bb" << GetIdForNode(s) << " = Switch (";
Indent() << "%fn" << GetIdForNode(s) << " = switch ";
s->condition->ToValue(out_);
out_ << ")" << std::endl;
out_ << " [";
for (const auto& c : s->cases) {
if (&c != &s->cases.Front()) {
out_ << ", ";
}
out_ << "c: (";
for (const auto& selector : c.selectors) {
if (&selector != &c.selectors.Front()) {
out_ << " ";
}
if (selector.IsDefault()) {
out_ << "default";
} else {
selector.val->ToValue(out_);
}
}
out_ << ", %fn" << GetIdForNode(c.start.target) << ")";
}
if (s->merge.target->IsConnected()) {
out_ << ", m: %fn" << GetIdForNode(s->merge.target);
}
out_ << "]" << std::endl;
{
ScopedIndent switch_indent(&indent_size_);
ScopedStopNode scope(&stop_nodes_, s->merge.target);
for (const auto& c : s->cases) {
Indent() << "# Case ";
Indent() << "# case ";
for (const auto& selector : c.selectors) {
if (&selector != &c.selectors.Front()) {
out_ << " ";
@ -155,13 +178,20 @@ void Disassembler::Walk(const FlowNode* node) {
}
}
Indent() << "# Switch Merge" << std::endl;
Walk(s->merge.target);
if (s->merge.target->IsConnected()) {
Indent() << "# switch merge" << std::endl;
Walk(s->merge.target);
}
},
[&](const ir::If* i) {
Indent() << "%bb" << GetIdForNode(i) << " = if (";
Indent() << "%fn" << GetIdForNode(i) << " = if ";
i->condition->ToValue(out_);
out_ << ")" << std::endl;
out_ << " [t: %fn" << GetIdForNode(i->true_.target) << ", f: %fn"
<< GetIdForNode(i->false_.target);
if (i->merge.target->IsConnected()) {
out_ << ", m: %fn" << GetIdForNode(i->merge.target);
}
out_ << "]" << std::endl;
{
ScopedIndent if_indent(&indent_size_);
@ -174,13 +204,23 @@ void Disassembler::Walk(const FlowNode* node) {
Walk(i->false_.target);
}
if (!i->merge.target->IsDisconnected()) {
if (i->merge.target->IsConnected()) {
Indent() << "# if merge" << std::endl;
Walk(i->merge.target);
}
},
[&](const ir::Loop* l) {
Indent() << "%bb" << GetIdForNode(l) << " = loop" << std::endl;
Indent() << "%fn" << GetIdForNode(l) << " = loop [s: %fn"
<< GetIdForNode(l->start.target);
if (l->continuing.target->IsConnected()) {
out_ << ", c: %fn" << GetIdForNode(l->continuing.target);
}
if (l->merge.target->IsConnected()) {
out_ << ", m: %fn" << GetIdForNode(l->merge.target);
}
out_ << "]" << std::endl;
{
ScopedStopNode loop_scope(&stop_nodes_, l->merge.target);
ScopedIndent loop_indent(&indent_size_);
@ -190,14 +230,18 @@ void Disassembler::Walk(const FlowNode* node) {
Walk(l->start.target);
}
Indent() << "# loop continuing" << std::endl;
Walk(l->continuing.target);
if (l->continuing.target->IsConnected()) {
Indent() << "# loop continuing" << std::endl;
Walk(l->continuing.target);
}
}
Indent() << "# loop merge" << std::endl;
Walk(l->merge.target);
if (l->merge.target->IsConnected()) {
Indent() << "# loop merge" << std::endl;
Walk(l->merge.target);
}
},
[&](const ir::Terminator*) { Indent() << "FunctionEnd" << std::endl
[&](const ir::Terminator*) { Indent() << "func_end" << std::endl
<< std::endl; });
}

View File

@ -32,8 +32,11 @@ class FlowNode : public utils::Castable<FlowNode> {
/// - Node is a continue target outside control flow (loop that returns)
utils::Vector<FlowNode*, 2> inbound_branches;
/// @returns true if this node has no inbound branches
bool IsDisconnected() const { return inbound_branches.IsEmpty(); }
/// @returns true if this node has inbound branches and branches out
bool IsConnected() const { return !IsDead() && !inbound_branches.IsEmpty(); }
/// @returns true if the node does not branch out
virtual bool IsDead() const { return false; }
protected:
/// Constructor

View File

@ -29,9 +29,9 @@ Store::Store(Value* to, Value* from) : Base(), to_(to), from_(from) {
Store::~Store() = default;
utils::StringStream& Store::ToInstruction(utils::StringStream& out) const {
out << "store(";
out << "store ";
to_->ToValue(out) << ", ";
from_->ToValue(out) << ")";
from_->ToValue(out);
return out;
}

View File

@ -41,7 +41,7 @@ TEST_F(IR_InstructionTest, CreateStore) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "store(%0, 4)");
EXPECT_EQ(str.str(), "store %0, 4i");
}
TEST_F(IR_InstructionTest, Store_Usage) {

View File

@ -31,21 +31,22 @@ utils::StringStream& Unary::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = ";
switch (GetKind()) {
case Unary::Kind::kAddressOf:
out << "&";
out << "addr_of";
break;
case Unary::Kind::kComplement:
out << "~";
out << "bit_complement";
break;
case Unary::Kind::kIndirection:
out << "*";
out << "indirection";
break;
case Unary::Kind::kNegation:
out << "-";
out << "negation";
break;
case Unary::Kind::kNot:
out << "!";
out << "log_not";
break;
}
out << " ";
val_->ToValue(out);
return out;
}

View File

@ -45,7 +45,7 @@ TEST_F(IR_InstructionTest, CreateAddressOf) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(ptr<private, i32, read_write>) = &4");
EXPECT_EQ(str.str(), "%1(ptr<private, i32, read_write>) = addr_of 4i");
}
TEST_F(IR_InstructionTest, CreateComplement) {
@ -63,7 +63,7 @@ TEST_F(IR_InstructionTest, CreateComplement) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = ~4");
EXPECT_EQ(str.str(), "%1(i32) = bit_complement 4i");
}
TEST_F(IR_InstructionTest, CreateIndirection) {
@ -83,7 +83,7 @@ TEST_F(IR_InstructionTest, CreateIndirection) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = *4");
EXPECT_EQ(str.str(), "%1(i32) = indirection 4i");
}
TEST_F(IR_InstructionTest, CreateNegation) {
@ -101,7 +101,7 @@ TEST_F(IR_InstructionTest, CreateNegation) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(i32) = -4");
EXPECT_EQ(str.str(), "%1(i32) = negation 4i");
}
TEST_F(IR_InstructionTest, CreateNot) {
@ -119,7 +119,7 @@ TEST_F(IR_InstructionTest, CreateNot) {
utils::StringStream str;
inst->ToInstruction(str);
EXPECT_EQ(str.str(), "%1(bool) = !true");
EXPECT_EQ(str.str(), "%1(bool) = log_not true");
}
TEST_F(IR_InstructionTest, Unary_Usage) {

View File

@ -25,9 +25,11 @@ UserCall::UserCall(uint32_t id, const type::Type* type, Symbol name, utils::Vect
UserCall::~UserCall() = default;
utils::StringStream& UserCall::ToInstruction(utils::StringStream& out) const {
ToValue(out) << " = call(" << name_.Name() << ", ";
ToValue(out) << " = call " << name_.Name();
if (Args().Length() > 0) {
out << ", ";
}
EmitArgs(out);
out << ")";
return out;
}