Jlm
Loading...
Searching...
No Matches
IntegerOperationsTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2026 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
11#include <jlm/rvsdg/view.hpp>
12
13namespace jlm::llvm
14{
15
16namespace
17{
18struct FoldConstantsTestInput
19{
20 std::int64_t c1;
21 std::uint64_t numBitsC1;
22
23 std::int64_t c2;
24 std::uint64_t numBitsC2;
25
26 std::int64_t expected;
27 std::int64_t numBitsExpected;
28};
29}
30
31template<typename Operation>
32static void
33TestFoldConstants(const FoldConstantsTestInput & input)
34{
35 using namespace jlm::rvsdg;
36
37 // Arrange
38 Graph graph;
39
41 graph.GetRootRegion(),
42 BitValueRepresentation(input.numBitsC1, input.c1));
44 graph.GetRootRegion(),
45 BitValueRepresentation(input.numBitsC2, input.c2));
46
47 auto & node1 = Operation::createNode(32, *c1.output(0), *c2.output(0));
48
49 auto & x1 = GraphExport::Create(*node1.output(0), "x1");
50
51 view(graph, stdout);
52
53 // Act
54 ReduceNode<Operation>(Operation::foldConstants, dynamic_cast<SimpleNode &>(node1));
55
56 graph.PruneNodes();
57
58 view(graph, stdout);
59
60 // Assert
61 {
62 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x1.origin());
63 EXPECT_TRUE(op);
64 EXPECT_EQ(op->Representation().to_int(), input.expected);
65 EXPECT_EQ(op->Representation().nbits(), static_cast<size_t>(input.numBitsExpected));
66 }
67}
68
69template<typename Operation>
70static void
72{
73 using namespace jlm::rvsdg;
74
75 // Arrange
76 auto iType = BitType::Create(32);
77
78 Graph graph;
79
80 auto & i0 = GraphImport::Create(graph, iType, "i0");
81 auto & i1 = GraphImport::Create(graph, iType, "i1");
82
83 auto & node1 = Operation::createNode(32, i0, i0);
84 auto & node2 = Operation::createNode(32, i0, i1);
85
86 auto & x1 = GraphExport::Create(*node1.output(0), "x1");
87 auto & x2 = GraphExport::Create(*node2.output(0), "x2");
88
89 // Act
90 ReduceNode<Operation>(Operation::normalizeIdenticalOperands, dynamic_cast<SimpleNode &>(node1));
91 ReduceNode<Operation>(Operation::normalizeIdenticalOperands, dynamic_cast<SimpleNode &>(node2));
92
93 graph.PruneNodes();
94
95 // Assert
96 {
97 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x1.origin());
98 EXPECT_TRUE(op);
99 EXPECT_EQ(op->Representation().nbits(), 1u);
100 EXPECT_EQ(op->Representation().to_uint(), expected);
101 }
102
103 {
104 auto [node, op] = TryGetSimpleNodeAndOptionalOp<Operation>(*x2.origin());
105 EXPECT_TRUE(op);
106 EXPECT_EQ(node, &node2);
107 }
108}
109
110TEST(IntegerEqOperationTest, foldConstants)
111{
112 TestFoldConstants<IntegerEqOperation>({ 4, 32, 4, 32, -1, 1 });
113 TestFoldConstants<IntegerEqOperation>({ 4, 32, -4, 32, 0, 1 });
114}
115
116TEST(IntegerNeOperationTest, foldConstants)
117{
118 TestFoldConstants<IntegerNeOperation>({ 4, 32, 4, 32, 0, 1 });
119 TestFoldConstants<IntegerNeOperation>({ 4, 32, -4, 32, -1, 1 });
120}
121
122TEST(IntegerSgeOperationTest, foldConstants)
123{
124 TestFoldConstants<IntegerSgeOperation>({ 4, 32, 4, 32, -1, 1 });
125 TestFoldConstants<IntegerSgeOperation>({ 4, 32, -4, 32, -1, 1 });
126}
127
128TEST(IntegerSgtOperationTest, foldConstants)
129{
130 TestFoldConstants<IntegerSgtOperation>({ 4, 32, 4, 32, 0, 1 });
131 TestFoldConstants<IntegerSgtOperation>({ 4, 32, -4, 32, -1, 1 });
132}
133
134TEST(IntegerSleOperationTest, foldConstants)
135{
136 TestFoldConstants<IntegerSleOperation>({ 4, 32, 4, 32, -1, 1 });
137 TestFoldConstants<IntegerSleOperation>({ 4, 32, -4, 32, 0, 1 });
138}
139
140TEST(IntegerSltOperationTest, foldConstants)
141{
142 TestFoldConstants<IntegerSltOperation>({ 4, 32, 4, 32, 0, 1 });
143 TestFoldConstants<IntegerSltOperation>({ 4, 32, -4, 32, 0, 1 });
144}
145
146TEST(IntegerUgeOperationTest, foldConstants)
147{
148 TestFoldConstants<IntegerUgeOperation>({ 4, 32, 4, 32, -1, 1 });
149 TestFoldConstants<IntegerUgeOperation>({ 4, 32, -4, 32, 0, 1 });
150}
151
152TEST(IntegerUgtOperationTest, foldConstants)
153{
154 TestFoldConstants<IntegerUgtOperation>({ 4, 32, 4, 32, 0, 1 });
155 TestFoldConstants<IntegerUgtOperation>({ 4, 32, -4, 32, 0, 1 });
156}
157
158TEST(IntegerUleOperationTest, foldConstants)
159{
160 TestFoldConstants<IntegerUleOperation>({ 4, 32, 4, 32, -1, 1 });
161 TestFoldConstants<IntegerUleOperation>({ 4, 32, -4, 32, -1, 1 });
162}
163
164TEST(IntegerUltOperationTest, foldConstants)
165{
166 TestFoldConstants<IntegerUltOperation>({ 4, 32, 4, 32, 0, 1 });
167 TestFoldConstants<IntegerUltOperation>({ 4, 32, -4, 32, -1, 1 });
168}
169
170TEST(IntegerOrOperationTest, foldConstants)
171{
172 TestFoldConstants<IntegerOrOperation>({ 4, 32, 4, 32, 4, 32 });
173 TestFoldConstants<IntegerOrOperation>({ 0, 32, -1, 32, -1, 32 });
174 TestFoldConstants<IntegerOrOperation>({ 1, 32, 2, 32, 3, 32 });
175}
176
177TEST(IntegerOrOperationTest, normalizeIdempotent)
178{
179 using namespace jlm::rvsdg;
180
181 // Arrange
182 auto i32Type = BitType::Create(32);
183
184 Graph graph;
185
186 auto & i0 = GraphImport::Create(graph, i32Type, "i0");
187
188 auto & zeroNode = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
189 auto & oneNode = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 1);
190
191 auto & subNode1 = IntegerOrOperation::createNode(32, i0, *zeroNode.output(0));
192 auto & subNode2 = IntegerOrOperation::createNode(32, *zeroNode.output(0), i0);
193 auto & subNode3 = IntegerOrOperation::createNode(32, i0, *oneNode.output(0));
194 auto & subNode4 = IntegerOrOperation::createNode(32, *oneNode.output(0), i0);
195
196 auto & x1 = GraphExport::Create(*subNode1.output(0), "x1");
197 auto & x2 = GraphExport::Create(*subNode2.output(0), "x2");
198 auto & x3 = GraphExport::Create(*subNode3.output(0), "x3");
199 auto & x4 = GraphExport::Create(*subNode4.output(0), "x4");
200
201 // Act
202 ReduceNode<IntegerOrOperation>(
204 dynamic_cast<SimpleNode &>(subNode1));
205 ReduceNode<IntegerOrOperation>(
207 dynamic_cast<SimpleNode &>(subNode2));
208 ReduceNode<IntegerOrOperation>(
210 dynamic_cast<SimpleNode &>(subNode3));
211 ReduceNode<IntegerOrOperation>(
213 dynamic_cast<SimpleNode &>(subNode4));
214
215 graph.PruneNodes();
216
217 view(graph, stdout);
218
219 // Assert
220 EXPECT_EQ(x1.origin(), &i0);
221 EXPECT_EQ(x2.origin(), &i0);
222 EXPECT_EQ(x3.origin(), subNode3.output(0));
223 EXPECT_EQ(x4.origin(), subNode4.output(0));
224}
225
226TEST(IntegerAndOperationTest, foldConstants)
227{
228 TestFoldConstants<IntegerAndOperation>({ 4, 32, 4, 32, 4, 32 });
229 TestFoldConstants<IntegerAndOperation>({ 0, 32, -1, 32, 0, 32 });
230}
231
232TEST(IntegerXorOperationTest, foldConstants)
233{
234 TestFoldConstants<IntegerXorOperation>({ 4, 32, 4, 32, 0, 32 });
235 TestFoldConstants<IntegerXorOperation>({ 0, 32, -1, 32, -1, 32 });
236}
237
238TEST(IntegerAddOperationTest, foldConstants)
239{
240 TestFoldConstants<IntegerAddOperation>({ 12, 32, 7, 32, 19, 32 });
241 TestFoldConstants<IntegerAddOperation>({ -1, 32, 2, 32, 1, 32 });
242}
243
244TEST(IntegerSubOperationTest, foldConstants)
245{
246 TestFoldConstants<IntegerSubOperation>({ 12, 32, 7, 32, 5, 32 });
247 TestFoldConstants<IntegerSubOperation>({ 0, 32, 1, 32, -1, 32 });
248}
249
250TEST(IntegerMulOperationTest, foldConstants)
251{
252 TestFoldConstants<IntegerMulOperation>({ 6, 32, 7, 32, 42, 32 });
253 TestFoldConstants<IntegerMulOperation>({ -6, 32, 7, 32, -42, 32 });
254}
255
256TEST(IntegerSDivOperationTest, foldConstants)
257{
258 TestFoldConstants<IntegerSDivOperation>({ -13, 32, 3, 32, -4, 32 });
259 TestFoldConstants<IntegerSDivOperation>({ 13, 32, -3, 32, -4, 32 });
260}
261
262TEST(IntegerUDivOperationTest, foldConstants)
263{
264 TestFoldConstants<IntegerUDivOperation>({ 13, 32, 3, 32, 4, 32 });
265 TestFoldConstants<IntegerUDivOperation>({ -1, 32, 2, 32, 2147483647, 32 });
266}
267
268TEST(IntegerSRemOperationTest, foldConstants)
269{
270 TestFoldConstants<IntegerSRemOperation>({ -13, 32, 3, 32, -1, 32 });
271 TestFoldConstants<IntegerSRemOperation>({ 13, 32, -3, 32, 1, 32 });
272}
273
274TEST(IntegerURemOperationTest, foldConstants)
275{
276 TestFoldConstants<IntegerURemOperation>({ 13, 32, 3, 32, 1, 32 });
277 TestFoldConstants<IntegerURemOperation>({ -1, 32, 10, 32, 5, 32 });
278}
279
280TEST(IntegerAShrOperationTest, foldConstants)
281{
282 TestFoldConstants<IntegerAShrOperation>({ -0x10, 32, 2, 32, -0x4, 32 });
283 TestFoldConstants<IntegerAShrOperation>({ 0x10, 32, 2, 32, 0x4, 32 });
284}
285
286TEST(IntegerShlOperationTest, foldConstants)
287{
288 TestFoldConstants<IntegerShlOperation>({ 0x3, 32, 2, 32, 0xc, 32 });
289 TestFoldConstants<IntegerShlOperation>({ 0x400, 32, 2, 32, 0x1000, 32 });
290}
291
292TEST(IntegerLShrOperationTest, foldConstants)
293{
294 TestFoldConstants<IntegerLShrOperation>({ -0x1, 32, 2, 32, 0x3fffffff, 32 });
295 TestFoldConstants<IntegerLShrOperation>({ 0x10, 32, 2, 32, 0x4, 32 });
296}
297
298TEST(IntegerSubOperationTests, normalizeAdditiveInverse)
299{
300 using namespace jlm::rvsdg;
301
302 // Arrange
303 auto i32Type = BitType::Create(32);
304
305 Graph graph;
306
307 auto & i0 = GraphImport::Create(graph, i32Type, "i0");
308
309 auto structuralNode = TestStructuralNode::create(&graph.GetRootRegion(), 1);
310 auto inputVar = structuralNode->addInputWithArguments(i0);
311
312 auto & subNode =
313 IntegerSubOperation::createNode(32, *inputVar.argument[0], *inputVar.argument[0]);
314
315 auto outputVar = structuralNode->addOutputWithResults({ subNode.output(0) });
316
317 GraphExport::Create(*outputVar.output, "x0");
318
319 // Act
320 ReduceNode<IntegerSubOperation>(
322 dynamic_cast<SimpleNode &>(subNode));
323
324 graph.PruneNodes();
325
326 view(graph, stdout);
327
328 // Assert
329 {
330 auto [_, op] =
331 TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*outputVar.result[0]->origin());
332 EXPECT_TRUE(op);
333 EXPECT_EQ(op->Representation().to_int(), 0u);
334 EXPECT_EQ(op->Representation().nbits(), 32u);
335 }
336}
337
338TEST(IntegerEqOperationTests, normalizeIdenticalOperands)
339{
340 testNormalizeIdenticalOperands<IntegerEqOperation>(1);
341}
342
343TEST(IntegerNeOperationTests, normalizeIdenticalOperands)
344{
345 testNormalizeIdenticalOperands<IntegerNeOperation>(0);
346}
347
348TEST(IntegerSgeOperationTests, normalizeIdenticalOperands)
349{
350 testNormalizeIdenticalOperands<IntegerSgeOperation>(1);
351}
352
353TEST(IntegerSgtOperationTests, normalizeIdenticalOperands)
354{
355 testNormalizeIdenticalOperands<IntegerSgtOperation>(0);
356}
357
358TEST(IntegerSleOperationTests, normalizeIdenticalOperands)
359{
360 testNormalizeIdenticalOperands<IntegerSleOperation>(1);
361}
362
363TEST(IntegerSltOperationTests, normalizeIdenticalOperands)
364{
365 testNormalizeIdenticalOperands<IntegerSltOperation>(0);
366}
367
368TEST(IntegerUgeOperationTests, normalizeIdenticalOperands)
369{
370 testNormalizeIdenticalOperands<IntegerUgeOperation>(1);
371}
372
373TEST(IntegerUgtOperationTests, normalizeIdenticalOperands)
374{
375 testNormalizeIdenticalOperands<IntegerUgtOperation>(0);
376}
377
378TEST(IntegerUltOperationTests, normalizeIdenticalOperands)
379{
380 testNormalizeIdenticalOperands<IntegerUltOperation>(0);
381}
382
383}
std::uint64_t numBitsC2
std::uint64_t numBitsC1
std::int64_t numBitsExpected
std::int64_t c1
std::int64_t c2
std::int64_t expected
static rvsdg::Node & Create(rvsdg::Region &region, IntegerValueRepresentation representation)
static rvsdg::Node & createNode(const size_t numBits, rvsdg::Output &operand1, rvsdg::Output &operand2)
static std::optional< std::vector< rvsdg::Output * > > normalizeIdempotent(const IntegerOrOperation &operation, const std::vector< rvsdg::Output * > &operands)
static rvsdg::Node & createNode(const size_t numBits, rvsdg::Output &operand1, rvsdg::Output &operand2)
static std::optional< std::vector< rvsdg::Output * > > normalizeAdditiveInverse(const IntegerSubOperation &operation, const std::vector< rvsdg::Output * > &operands)
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
void PruneNodes()
Definition graph.hpp:116
Global memory state passed between functions.
static std::optional< std::vector< rvsdg::Output * > > normalizeIdenticalOperands(const std::vector< rvsdg::Output * > &operands, const std::int64_t result)
TEST(ControlOperationsTests, foldConstants)
static void TestFoldConstants(const FoldConstantsTestInput &input)
static void testNormalizeIdenticalOperands(const std::uint64_t expected)