Jlm
Loading...
Searching...
No Matches
OperatorsTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2017 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
8#include <llvm/ADT/APFloat.h>
9
16#include <jlm/rvsdg/lambda.hpp>
18
19namespace jlm::llvm
20{
21
22template<ICmpPredicate Predicate>
23static void
25{
26 using namespace jlm::rvsdg;
27
28 // Arrange
29 Graph graph;
30 auto region = &graph.GetRootRegion();
31
32 auto i32Type = BitType::Create(32);
33 auto & oneNode = IntegerConstantOperation::Create(*region, 32, 1);
34
35 auto & allocaNode1 = AllocaOperation::createNode(i32Type, *oneNode.output(0), 4);
36 auto & allocaNode2 = AllocaOperation::createNode(i32Type, *oneNode.output(0), 4);
37
38 auto & ptr1 = AllocaOperation::getPointerOutput(allocaNode1);
39 auto & ptr2 = AllocaOperation::getPointerOutput(allocaNode2);
40
41 auto & cmpNode1 = PtrCmpOperation::createNode(Predicate, ptr1, ptr1);
42 auto & cmpNode2 = PtrCmpOperation::createNode(Predicate, ptr1, ptr2);
43
44 auto & x1 = GraphExport::Create(*cmpNode1.output(0), "x1");
45 auto & x2 = GraphExport::Create(*cmpNode2.output(0), "x2");
46
47 // Act
48 ReduceNode<PtrCmpOperation>(PtrCmpOperation::normalizeIdenticalOperands, cmpNode1);
49 ReduceNode<PtrCmpOperation>(PtrCmpOperation::normalizeIdenticalOperands, cmpNode2);
50
51 graph.PruneNodes();
52
53 // Assert
54 {
55 auto [_, op] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*x1.origin());
56 EXPECT_NE(op, nullptr);
57 EXPECT_EQ(op->Representation().nbits(), 1u);
58 EXPECT_EQ(op->Representation().to_uint(), expected);
59 }
60
61 {
62 auto [node, op] = TryGetSimpleNodeAndOptionalOp<PtrCmpOperation>(*x2.origin());
63 EXPECT_NE(op, nullptr);
64 EXPECT_EQ(node, &cmpNode2);
65 }
66}
67
68TEST(PtrCmpOperationTests, testNormalizeNullPointerComparison)
69{
70 using namespace jlm::rvsdg;
71
72 // Arrange
73 auto pointerType = PointerType::Create();
74 auto i1Type = BitType::Create(1);
75 auto i32Type = BitType::Create(32);
76 auto functionType1 = FunctionType::Create({}, { pointerType });
77 auto functionType2 =
78 FunctionType::Create({}, { i1Type, i1Type, i1Type, i1Type, i1Type, i1Type, i1Type });
79
80 Graph graph;
81
82 auto & i0 = LlvmGraphImport::create(
83 graph,
84 i32Type,
85 pointerType,
86 "i0",
89 true,
90 4);
91
92 auto deltaNode = DeltaNode::Create(
93 &graph.GetRootRegion(),
94 LlvmDeltaOperation::Create(pointerType, "delta", Linkage::externalLinkage, "", true, 4));
95 auto & ptrNullDeltaNode = ConstantPointerNullOperation::createNode(*deltaNode->subregion());
96 auto & deltaOutput = deltaNode->finalize(ptrNullDeltaNode.output(0));
97
98 auto lambdaNode1 = LambdaNode::Create(
99 graph.GetRootRegion(),
101 functionType1,
102 "lambda",
105 {}));
106 auto & ptrNullLambdaNode = ConstantPointerNullOperation::createNode(*lambdaNode1->subregion());
107 auto lambdaOutput = lambdaNode1->finalize({ ptrNullLambdaNode.output(0) });
108 auto & fnToPtrNode = CreateOpNode<FunctionToPointerOperation>({ lambdaOutput }, functionType1);
109
110 auto lambdaNode2 = LambdaNode::Create(
111 graph.GetRootRegion(),
113 functionType2,
114 "lambda",
117 {}));
118 auto i0CtxVar = lambdaNode2->AddContextVar(i0);
119 auto deltaCtxVar = lambdaNode2->AddContextVar(deltaOutput);
120 auto fnToPtrCtxVar = lambdaNode2->AddContextVar(*fnToPtrNode.output(0));
121
122 auto & oneNode = IntegerConstantOperation::Create(*lambdaNode2->subregion(), 32, 1);
123 auto & allocaNode = AllocaOperation::createNode(i32Type, *oneNode.output(0), 4);
124
125 auto & cPtrNullNode = ConstantPointerNullOperation::createNode(*lambdaNode2->subregion());
126
127 auto & ptrCmpNode1 = PtrCmpOperation::createNode(
130 *cPtrNullNode.output(0));
131
132 auto & ptrCmpNode2 = PtrCmpOperation::createNode(
135 *cPtrNullNode.output(0));
136
137 auto & ptrCmpNode3 =
138 PtrCmpOperation::createNode(ICmpPredicate::Ne, *i0CtxVar.inner, *cPtrNullNode.output(0));
139
140 auto & ptrCmpNode4 =
141 PtrCmpOperation::createNode(ICmpPredicate::Ne, *deltaCtxVar.inner, *cPtrNullNode.output(0));
142
143 auto & ptrCmpNode5 =
144 PtrCmpOperation::createNode(ICmpPredicate::Ne, *fnToPtrCtxVar.inner, *cPtrNullNode.output(0));
145
146 auto & ptrCmpNode6 = PtrCmpOperation::createNode(
148 *cPtrNullNode.output(0),
149 *cPtrNullNode.output(0));
150
151 auto & ptrCmpNode7 = PtrCmpOperation::createNode(
153 *cPtrNullNode.output(0),
154 *cPtrNullNode.output(0));
155
156 lambdaNode2->finalize({ ptrCmpNode1.output(0),
157 ptrCmpNode2.output(0),
158 ptrCmpNode3.output(0),
159 ptrCmpNode4.output(0),
160 ptrCmpNode5.output(0),
161 ptrCmpNode6.output(0),
162 ptrCmpNode7.output(0) });
163
164 // Act
172
173 // Assert
174 {
175 auto [constantNode, constantOperation] =
177 *lambdaNode2->GetFunctionResults()[0]->origin());
178 EXPECT_NE(constantOperation, nullptr);
179 EXPECT_EQ(constantOperation->Representation().nbits(), 1u);
180 EXPECT_EQ(constantOperation->Representation().to_uint(), 0u);
181 }
182
183 {
184 auto [constantNode, constantOperation] =
186 *lambdaNode2->GetFunctionResults()[1]->origin());
187 EXPECT_NE(constantOperation, nullptr);
188 EXPECT_EQ(constantOperation->Representation().nbits(), 1u);
189 EXPECT_EQ(constantOperation->Representation().to_uint(), 1u);
190 }
191
192 {
193 auto [constantNode, constantOperation] =
195 *lambdaNode2->GetFunctionResults()[2]->origin());
196 EXPECT_NE(constantOperation, nullptr);
197 EXPECT_EQ(constantOperation->Representation().nbits(), 1u);
198 EXPECT_EQ(constantOperation->Representation().to_uint(), 1u);
199 }
200
201 {
202 auto [constantNode, constantOperation] =
204 *lambdaNode2->GetFunctionResults()[3]->origin());
205 EXPECT_NE(constantOperation, nullptr);
206 EXPECT_EQ(constantOperation->Representation().nbits(), 1u);
207 EXPECT_EQ(constantOperation->Representation().to_uint(), 1u);
208 }
209
210 {
211 auto [constantNode, constantOperation] =
213 *lambdaNode2->GetFunctionResults()[4]->origin());
214 EXPECT_NE(constantOperation, nullptr);
215 EXPECT_EQ(constantOperation->Representation().nbits(), 1u);
216 EXPECT_EQ(constantOperation->Representation().to_uint(), 1u);
217 }
218
219 {
220 auto [constantNode, constantOperation] =
222 *lambdaNode2->GetFunctionResults()[5]->origin());
223 EXPECT_NE(constantOperation, nullptr);
224 EXPECT_EQ(constantOperation->Representation().nbits(), 1u);
225 EXPECT_EQ(constantOperation->Representation().to_uint(), 1u);
226 }
227
228 {
229 auto [constantNode, constantOperation] =
231 *lambdaNode2->GetFunctionResults()[6]->origin());
232 EXPECT_NE(constantOperation, nullptr);
233 EXPECT_EQ(constantOperation->Representation().nbits(), 1u);
234 EXPECT_EQ(constantOperation->Representation().to_uint(), 0u);
235 }
236}
237
239{
240 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Eq>(1);
241 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Sge>(1);
242 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Sle>(1);
243 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Uge>(1);
244 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Ule>(1);
245
246 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Ne>(0);
247 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Sgt>(0);
248 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Slt>(0);
249 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Ugt>(0);
250 testPtrCmpNormalizeIdenticalOperands<ICmpPredicate::Ult>(0);
251}
252
253TEST(FCmpOperationTests, testFoldConstants)
254{
255 using namespace jlm::rvsdg;
256
257 Graph graph;
258 auto region = &graph.GetRootRegion();
259
261
262 {
263 auto & cNeg1 = ConstantFP::createNode(*region, fpsize::dbl, ::llvm::APFloat(-1.0));
264 auto & c0 = ConstantFP::createNode(*region, fpsize::dbl, ::llvm::APFloat(0.0));
265 auto & c1 = ConstantFP::createNode(*region, fpsize::dbl, ::llvm::APFloat(1.0));
266 auto & c2 = ConstantFP::createNode(*region, fpsize::dbl, ::llvm::APFloat(2.0));
267 auto & cNaN = ConstantFP::createNode(
268 *region,
270 ::llvm::APFloat::getNaN(::llvm::APFloat::IEEEdouble()));
271
272 const auto expectFoldedTo =
273 [&](fpcmp predicate, rvsdg::Output * lhs, rvsdg::Output * rhs, bool expected)
274 {
275 const FCmpOperation operation(predicate, fpt);
276 const auto folded = FCmpOperation::foldConstants(operation, { lhs, rhs });
277 ASSERT_TRUE(folded.has_value())
278 << "Expected folding for predicate " << static_cast<int>(predicate);
279 ASSERT_EQ(folded->size(), 1u);
280
281 auto [node, constantOperation] =
283 ASSERT_NE(constantOperation, nullptr);
284 EXPECT_EQ(constantOperation->Representation().nbits(), 1u);
285 EXPECT_EQ(constantOperation->Representation().to_uint(), expected ? 1u : 0u)
286 << "Predicate " << static_cast<int>(predicate);
287 };
288
289 // FALSE / TRUE
290 expectFoldedTo(fpcmp::FALSE, c0.output(0), c1.output(0), false);
291 expectFoldedTo(fpcmp::TRUE, c0.output(0), c1.output(0), true);
292
293 // Ordered comparisons (no NaN)
294 expectFoldedTo(fpcmp::oeq, c1.output(0), c1.output(0), true);
295 expectFoldedTo(fpcmp::oeq, c1.output(0), c2.output(0), false);
296
297 expectFoldedTo(fpcmp::ogt, c2.output(0), c1.output(0), true);
298 expectFoldedTo(fpcmp::ogt, c1.output(0), c2.output(0), false);
299
300 expectFoldedTo(fpcmp::oge, c2.output(0), c1.output(0), true);
301 expectFoldedTo(fpcmp::oge, c1.output(0), c1.output(0), true);
302 expectFoldedTo(fpcmp::oge, c1.output(0), c2.output(0), false);
303
304 expectFoldedTo(fpcmp::olt, c1.output(0), c2.output(0), true);
305 expectFoldedTo(fpcmp::olt, c2.output(0), c1.output(0), false);
306
307 expectFoldedTo(fpcmp::ole, c1.output(0), c2.output(0), true);
308 expectFoldedTo(fpcmp::ole, c1.output(0), c1.output(0), true);
309 expectFoldedTo(fpcmp::ole, c2.output(0), c1.output(0), false);
310
311 expectFoldedTo(fpcmp::one, c1.output(0), c2.output(0), true);
312 expectFoldedTo(fpcmp::one, c1.output(0), c1.output(0), false);
313
314 expectFoldedTo(fpcmp::ord, cNeg1.output(0), c2.output(0), true);
315 expectFoldedTo(fpcmp::uno, cNeg1.output(0), c2.output(0), false);
316
317 // Unordered comparisons (NaN)
318 expectFoldedTo(fpcmp::ord, cNaN.output(0), c1.output(0), false);
319 expectFoldedTo(fpcmp::uno, cNaN.output(0), c1.output(0), true);
320
321 expectFoldedTo(fpcmp::ueq, cNaN.output(0), cNaN.output(0), true);
322 expectFoldedTo(fpcmp::ueq, c1.output(0), c1.output(0), true);
323 expectFoldedTo(fpcmp::ueq, c1.output(0), c2.output(0), false);
324
325 expectFoldedTo(fpcmp::une, cNaN.output(0), c1.output(0), true);
326 expectFoldedTo(fpcmp::une, c1.output(0), c1.output(0), false);
327 expectFoldedTo(fpcmp::une, c1.output(0), c2.output(0), true);
328
329 expectFoldedTo(fpcmp::ugt, cNaN.output(0), c1.output(0), true);
330 expectFoldedTo(fpcmp::ugt, c2.output(0), c1.output(0), true);
331 expectFoldedTo(fpcmp::ugt, c1.output(0), c2.output(0), false);
332
333 expectFoldedTo(fpcmp::uge, cNaN.output(0), c1.output(0), true);
334 expectFoldedTo(fpcmp::uge, c2.output(0), c1.output(0), true);
335 expectFoldedTo(fpcmp::uge, c1.output(0), c1.output(0), true);
336 expectFoldedTo(fpcmp::uge, c1.output(0), c2.output(0), false);
337
338 expectFoldedTo(fpcmp::ult, cNaN.output(0), c1.output(0), true);
339 expectFoldedTo(fpcmp::ult, c1.output(0), c2.output(0), true);
340 expectFoldedTo(fpcmp::ult, c2.output(0), c1.output(0), false);
341
342 expectFoldedTo(fpcmp::ule, cNaN.output(0), c1.output(0), true);
343 expectFoldedTo(fpcmp::ule, c1.output(0), c2.output(0), true);
344 expectFoldedTo(fpcmp::ule, c1.output(0), c1.output(0), true);
345 expectFoldedTo(fpcmp::ule, c2.output(0), c1.output(0), false);
346 }
347
348 {
349 auto & nonConst = LlvmGraphImport::create(
350 graph,
351 fpt,
352 fpt,
353 "x",
356 false,
357 8);
358
359 auto & c0Node = ConstantFP::createNode(*region, fpsize::dbl, ::llvm::APFloat(0.0));
360
361 const FCmpOperation operation(fpcmp::oeq, fpt);
362 const auto notFolded = FCmpOperation::foldConstants(
363 operation,
364 std::vector<rvsdg::Output *>({ &nonConst, c0Node.output(0) }));
365 EXPECT_FALSE(notFolded.has_value());
366 }
367}
368
369TEST(FBinaryOperationTests, testFoldConstants)
370{
371 using namespace jlm::rvsdg;
372
373 Graph graph;
374 auto region = &graph.GetRootRegion();
375
377
378 auto & c1 = ConstantFP::createNode(*region, fpsize::dbl, ::llvm::APFloat(7.25));
379 auto & c2 = ConstantFP::createNode(*region, fpsize::dbl, ::llvm::APFloat(2.0));
380
381 const auto expectFoldedTo = [&](fpop op, Output * lhs, Output * rhs, double expected)
382 {
383 const FBinaryOperation operation(op, fpt);
384 const auto folded = FBinaryOperation::foldConstants(operation, { lhs, rhs });
385 ASSERT_TRUE(folded.has_value()) << "Expected folding for fpop " << static_cast<int>(op);
386 ASSERT_EQ(folded->size(), 1u);
387
388 auto [node, constantOperation] =
390 ASSERT_NE(constantOperation, nullptr);
391 EXPECT_EQ(&constantOperation->constant().getSemantics(), &::llvm::APFloat::IEEEdouble());
392 EXPECT_TRUE(constantOperation->constant().bitwiseIsEqual(::llvm::APFloat(expected)))
393 << "fpop " << static_cast<int>(op);
394 };
395
396 expectFoldedTo(fpop::add, c1.output(0), c2.output(0), 9.25);
397 expectFoldedTo(fpop::sub, c1.output(0), c2.output(0), 5.25);
398 expectFoldedTo(fpop::mul, c1.output(0), c2.output(0), 14.5);
399 expectFoldedTo(fpop::div, c1.output(0), c2.output(0), 3.625);
400 expectFoldedTo(fpop::mod, c1.output(0), c2.output(0), 1.25);
401
402 {
403 auto & nonConst = LlvmGraphImport::create(
404 graph,
405 fpt,
406 fpt,
407 "x",
410 false,
411 8);
412
413 const FBinaryOperation operation(fpop::add, fpt);
414 const auto notFolded = FBinaryOperation::foldConstants(
415 operation,
416 std::vector<Output *>({ &nonConst, c1.output(0) }));
417 EXPECT_FALSE(notFolded.has_value());
418 }
419}
420
421}
std::int64_t c1
std::int64_t c2
std::int64_t expected
static rvsdg::SimpleNode & createNode(std::shared_ptr< const rvsdg::Type > allocatedType, rvsdg::Output &count, const size_t alignment)
Definition alloca.hpp:109
static rvsdg::Output & getPointerOutput(rvsdg::Node &node)
Definition alloca.hpp:74
static rvsdg::Node & createNode(rvsdg::Region &region, fpsize size, const ::llvm::APFloat &constant)
static rvsdg::Node & createNode(rvsdg::Region &region)
static std::optional< std::vector< rvsdg::Output * > > foldConstants(const FBinaryOperation &operation, const std::vector< rvsdg::Output * > &operands)
static std::optional< std::vector< rvsdg::Output * > > foldConstants(const FCmpOperation &operation, const std::vector< rvsdg::Output * > &operands)
static std::shared_ptr< const FloatingPointType > Create(fpsize size)
Definition types.cpp:117
static rvsdg::Node & Create(rvsdg::Region &region, IntegerValueRepresentation representation)
static std::unique_ptr< LlvmDeltaOperation > Create(std::shared_ptr< const rvsdg::Type > type, const std::string &name, const Linkage &linkage, std::string section, bool constant, const size_t alignment)
Definition delta.hpp:82
static LlvmGraphImport & create(rvsdg::Graph &graph, std::shared_ptr< const rvsdg::Type > valueType, std::shared_ptr< const rvsdg::Type > importedType, std::string name, Linkage linkage, CallingConvention callingConvention, const bool isConstant, const size_t alignment)
static std::unique_ptr< LlvmLambdaOperation > Create(std::shared_ptr< const jlm::rvsdg::FunctionType > type, std::string name, const jlm::llvm::Linkage &linkage, jlm::llvm::CallingConvention callingConvention, jlm::llvm::AttributeSet attributes)
Definition lambda.hpp:84
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static rvsdg::SimpleNode & createNode(const ICmpPredicate kind, rvsdg::Output &operand1, rvsdg::Output &operand2)
static std::optional< std::vector< rvsdg::Output * > > normalizeIdenticalOperands(const PtrCmpOperation &ptrCmpOperation, const std::vector< rvsdg::Output * > &operands)
static std::optional< std::vector< rvsdg::Output * > > normalizeNullPointerComparison(const PtrCmpOperation &ptrCmpOperation, 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 void testPtrCmpNormalizeIdenticalOperands(const std::uint64_t expected)
TEST(ControlOperationsTests, foldConstants)
static void testNormalizeIdenticalOperands(const std::uint64_t expected)
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872