1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/writer/msl/test_helper.h"
16
17 namespace tint {
18 namespace writer {
19 namespace msl {
20 namespace {
21
22 struct BinaryData {
23 const char* result;
24 ast::BinaryOp op;
25 };
operator <<(std::ostream & out,BinaryData data)26 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
27 out << data.op;
28 return out;
29 }
30 using MslBinaryTest = TestParamHelper<BinaryData>;
TEST_P(MslBinaryTest,Emit)31 TEST_P(MslBinaryTest, Emit) {
32 auto params = GetParam();
33
34 auto type = [&] {
35 return ((params.op == ast::BinaryOp::kLogicalAnd) ||
36 (params.op == ast::BinaryOp::kLogicalOr))
37 ? static_cast<const ast::Type*>(ty.bool_())
38 : static_cast<const ast::Type*>(ty.u32());
39 };
40
41 auto* left = Var("left", type());
42 auto* right = Var("right", type());
43
44 auto* expr =
45 create<ast::BinaryExpression>(params.op, Expr(left), Expr(right));
46 WrapInFunction(left, right, expr);
47
48 GeneratorImpl& gen = Build();
49
50 std::stringstream out;
51 ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
52 EXPECT_EQ(out.str(), params.result);
53 }
54 INSTANTIATE_TEST_SUITE_P(
55 MslGeneratorImplTest,
56 MslBinaryTest,
57 testing::Values(
58 BinaryData{"(left & right)", ast::BinaryOp::kAnd},
59 BinaryData{"(left | right)", ast::BinaryOp::kOr},
60 BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
61 BinaryData{"(left && right)", ast::BinaryOp::kLogicalAnd},
62 BinaryData{"(left || right)", ast::BinaryOp::kLogicalOr},
63 BinaryData{"(left == right)", ast::BinaryOp::kEqual},
64 BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
65 BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
66 BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
67 BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
68 BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
69 BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
70 BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
71 BinaryData{"(left + right)", ast::BinaryOp::kAdd},
72 BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
73 BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
74 BinaryData{"(left / right)", ast::BinaryOp::kDivide},
75 BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
76
77 using MslBinaryTest_SignedOverflowDefinedBehaviour =
78 TestParamHelper<BinaryData>;
TEST_P(MslBinaryTest_SignedOverflowDefinedBehaviour,Emit)79 TEST_P(MslBinaryTest_SignedOverflowDefinedBehaviour, Emit) {
80 auto params = GetParam();
81
82 auto* a_type = ty.i32();
83 auto* b_type = (params.op == ast::BinaryOp::kShiftLeft ||
84 params.op == ast::BinaryOp::kShiftRight)
85 ? static_cast<const ast::Type*>(ty.u32())
86 : ty.i32();
87
88 auto* a = Var("a", a_type);
89 auto* b = Var("b", b_type);
90
91 auto* expr = create<ast::BinaryExpression>(params.op, Expr(a), Expr(b));
92 WrapInFunction(a, b, expr);
93
94 GeneratorImpl& gen = Build();
95
96 std::stringstream out;
97 ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
98 EXPECT_EQ(out.str(), params.result);
99 }
100 using Op = ast::BinaryOp;
101 constexpr BinaryData signed_overflow_defined_behaviour_cases[] = {
102 {"as_type<int>((as_type<uint>(a) << b))", Op::kShiftLeft},
103 {"(a >> b)", Op::kShiftRight},
104 {"as_type<int>((as_type<uint>(a) + as_type<uint>(b)))", Op::kAdd},
105 {"as_type<int>((as_type<uint>(a) - as_type<uint>(b)))", Op::kSubtract},
106 {"as_type<int>((as_type<uint>(a) * as_type<uint>(b)))", Op::kMultiply}};
107 INSTANTIATE_TEST_SUITE_P(
108 MslGeneratorImplTest,
109 MslBinaryTest_SignedOverflowDefinedBehaviour,
110 testing::ValuesIn(signed_overflow_defined_behaviour_cases));
111
112 using MslBinaryTest_SignedOverflowDefinedBehaviour_Chained =
113 TestParamHelper<BinaryData>;
TEST_P(MslBinaryTest_SignedOverflowDefinedBehaviour_Chained,Emit)114 TEST_P(MslBinaryTest_SignedOverflowDefinedBehaviour_Chained, Emit) {
115 auto params = GetParam();
116
117 auto* a_type = ty.i32();
118 auto* b_type = (params.op == ast::BinaryOp::kShiftLeft ||
119 params.op == ast::BinaryOp::kShiftRight)
120 ? static_cast<const ast::Type*>(ty.u32())
121 : ty.i32();
122
123 auto* a = Var("a", a_type);
124 auto* b = Var("b", b_type);
125
126 auto* expr1 = create<ast::BinaryExpression>(params.op, Expr(a), Expr(b));
127 auto* expr2 = create<ast::BinaryExpression>(params.op, expr1, Expr(b));
128 WrapInFunction(a, b, expr2);
129
130 GeneratorImpl& gen = Build();
131
132 std::stringstream out;
133 ASSERT_TRUE(gen.EmitExpression(out, expr2)) << gen.error();
134 EXPECT_EQ(out.str(), params.result);
135 }
136 using Op = ast::BinaryOp;
137 constexpr BinaryData signed_overflow_defined_behaviour_chained_cases[] = {
138 {"as_type<int>((as_type<uint>(as_type<int>((as_type<uint>(a) << b))) << "
139 "b))",
140 Op::kShiftLeft},
141 {"((a >> b) >> b)", Op::kShiftRight},
142 {"as_type<int>((as_type<uint>(as_type<int>((as_type<uint>(a) + "
143 "as_type<uint>(b)))) + as_type<uint>(b)))",
144 Op::kAdd},
145 {"as_type<int>((as_type<uint>(as_type<int>((as_type<uint>(a) - "
146 "as_type<uint>(b)))) - as_type<uint>(b)))",
147 Op::kSubtract},
148 {"as_type<int>((as_type<uint>(as_type<int>((as_type<uint>(a) * "
149 "as_type<uint>(b)))) * as_type<uint>(b)))",
150 Op::kMultiply}};
151 INSTANTIATE_TEST_SUITE_P(
152 MslGeneratorImplTest,
153 MslBinaryTest_SignedOverflowDefinedBehaviour_Chained,
154 testing::ValuesIn(signed_overflow_defined_behaviour_chained_cases));
155
TEST_F(MslBinaryTest,ModF32)156 TEST_F(MslBinaryTest, ModF32) {
157 auto* left = Var("left", ty.f32());
158 auto* right = Var("right", ty.f32());
159 auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(left),
160 Expr(right));
161 WrapInFunction(left, right, expr);
162
163 GeneratorImpl& gen = Build();
164
165 std::stringstream out;
166 ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
167 EXPECT_EQ(out.str(), "fmod(left, right)");
168 }
169
TEST_F(MslBinaryTest,ModVec3F32)170 TEST_F(MslBinaryTest, ModVec3F32) {
171 auto* left = Var("left", ty.vec3<f32>());
172 auto* right = Var("right", ty.vec3<f32>());
173 auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(left),
174 Expr(right));
175 WrapInFunction(left, right, expr);
176
177 GeneratorImpl& gen = Build();
178
179 std::stringstream out;
180 ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
181 EXPECT_EQ(out.str(), "fmod(left, right)");
182 }
183
184 } // namespace
185 } // namespace msl
186 } // namespace writer
187 } // namespace tint
188