Jlm
Loading...
Searching...
No Matches
RegionPredicateTraceTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2026 Helge Bahmann <hcb@chaoticmind.net>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
11#include <jlm/rvsdg/control.hpp>
12#include <jlm/rvsdg/gamma.hpp>
13#include <jlm/rvsdg/graph.hpp>
19#include <jlm/rvsdg/theta.hpp>
20
21TEST(RegionPredicateTraceTests, TestTracing)
22{
23 using namespace jlm;
24
25 auto valueType = rvsdg::TestType::createValueType();
26 auto ctl2 = rvsdg::ControlType::Create(2);
27
28 rvsdg::Graph rvsdg;
29 auto & pred1 = rvsdg::GraphImport::Create(rvsdg, ctl2, "pred1");
30 auto & pred2 = rvsdg::GraphImport::Create(rvsdg, ctl2, "pred2");
31
32 // First gamma, computes a predicate
33 auto gamma1 = rvsdg::GammaNode::create(&pred1, 2);
34 auto g1_left = gamma1->subregion(0);
35 auto g1_right = gamma1->subregion(1);
36 auto & g1_p0 = rvsdg::ControlConstantOperation::createTrue(*g1_left);
37 auto & g1_p1 = rvsdg::ControlConstantOperation::createFalse(*g1_right);
38 auto pred3 = gamma1->AddExitVar({ &g1_p0, &g1_p1 }).output;
39
40 // Second gamma, depends on that predicate.
41 auto gamma2 = rvsdg::GammaNode::create(pred3, 2);
42 auto g2_left = gamma2->subregion(0);
43 auto g2_right = gamma2->subregion(1);
44 auto r0 = rvsdg::TestOperation::createNode(g2_left, {}, { valueType });
45 auto r1 = rvsdg::TestOperation::createNode(g2_right, {}, { valueType });
46 auto r = gamma2->AddExitVar({ r0->output(0), r1->output(0) }).output;
47 rvsdg::GraphExport::Create(*r, "result1");
48
49 // Third gamma, depends on unrelated predicate.
50 auto gamma3 = rvsdg::GammaNode::create(&pred2, 2);
51 auto g3_left = gamma3->subregion(0);
52 auto g3_right = gamma3->subregion(1);
53 auto s0 = rvsdg::TestOperation::createNode(g3_left, {}, { valueType });
54 auto s1 = rvsdg::TestOperation::createNode(g3_right, {}, { valueType });
55 auto s = gamma3->AddExitVar({ s0->output(0), s1->output(0) }).output;
56 rvsdg::GraphExport::Create(*s, "result2");
57
59
60 // Since gamma1 dominates gamma2, not all cross-paths are possible.
61 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_left, *g2_right));
62 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_right, *g2_left));
63 EXPECT_FALSE(trace.CheckPredicatesSatisfiable(*g1_left, *g2_left));
64 EXPECT_FALSE(trace.CheckPredicatesSatisfiable(*g1_right, *g2_right));
65
66 // Since gamma1 and gamma3 are unrelated, all cross-paths are possible.
67 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_left, *g3_right));
68 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_right, *g3_left));
69 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_left, *g3_left));
70 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_right, *g3_right));
71
72 // Now change the graph, and check again.
73 gamma2->predicate()->divert_to(&pred2);
74
75 // Now, everything is uncorrelated.
76 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_left, *g2_right));
77 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_right, *g2_left));
78 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_left, *g2_left));
79 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_right, *g2_right));
80 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_left, *g3_right));
81 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_right, *g3_left));
82 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_left, *g3_left));
83 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*g1_right, *g3_right));
84}
85
86TEST(RegionPredicateTraceTests, TraceOutOfTheta)
87{
115 using namespace jlm;
116
117 // Arrange
118 auto bit32 = rvsdg::BitType::Create(32);
119
120 rvsdg::Graph rvsdg;
121 auto theta0 = rvsdg::ThetaNode::create(&rvsdg.GetRootRegion());
122 auto undef0 =
123 rvsdg::CreateOpNode<rvsdg::TestNullaryOperation>(rvsdg.GetRootRegion(), bit32).output(0);
124 auto loopVar0 = theta0->AddLoopVar(undef0);
125
126 // theta1
127 auto theta1 = rvsdg::ThetaNode::create(theta0->subregion());
128 auto undef1 =
129 rvsdg::CreateOpNode<rvsdg::TestNullaryOperation>(*theta0->subregion(), bit32).output(0);
130 auto loopVar1 = theta1->AddLoopVar(undef1);
131 auto & int3Output = rvsdg::BitConstantOperation::create(*theta1->subregion(), { 32, 3 });
132 loopVar1.post->divert_to(&int3Output);
133
134 // theta2
135 auto theta2 = rvsdg::ThetaNode::create(theta0->subregion());
136 auto loopVar2 = theta2->AddLoopVar(loopVar1.output);
137
138 // theta3
139 auto theta3 = rvsdg::ThetaNode::create(theta0->subregion());
140 auto undef3 =
141 rvsdg::CreateOpNode<rvsdg::TestNullaryOperation>(*theta0->subregion(), bit32).output(0);
142 auto loopVar3 = theta3->AddLoopVar(undef3);
143
144 // theta4
145 auto theta4 = rvsdg::ThetaNode::create(theta3->subregion());
146 auto loopVar4 = theta4->AddLoopVar(loopVar3.pre);
147 auto & int7Output = rvsdg::BitConstantOperation::create(*theta4->subregion(), { 32, 7 });
148 loopVar4.post->divert_to(&int7Output);
149 loopVar3.post->divert_to(loopVar4.output);
150
151 // ADD inside theta0's subregion, combining outputs from theta2 and theta3/theta4
152 auto & addOutput = *rvsdg::bitadd_op::create(32, loopVar2.output, loopVar3.output);
153 loopVar0.post->divert_to(&addOutput);
154
155 rvsdg::GraphExport::Create(*loopVar0.output, "x");
156
157 // Assert
159
160 // Every region can be reached from the root region
161 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(rvsdg.GetRootRegion(), *theta0->subregion()));
162 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(rvsdg.GetRootRegion(), *theta1->subregion()));
163 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(rvsdg.GetRootRegion(), *theta2->subregion()));
164 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(rvsdg.GetRootRegion(), *theta3->subregion()));
165 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(rvsdg.GetRootRegion(), *theta4->subregion()));
166
167 // Every region can reach the root region
168 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta0->subregion(), rvsdg.GetRootRegion()));
169 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta1->subregion(), rvsdg.GetRootRegion()));
170 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta1->subregion(), rvsdg.GetRootRegion()));
171 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta1->subregion(), rvsdg.GetRootRegion()));
172 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta1->subregion(), rvsdg.GetRootRegion()));
173
174 // theta0 can reach every region inside it
175 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta0->subregion(), *theta1->subregion()));
176 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta0->subregion(), *theta2->subregion()));
177 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta0->subregion(), *theta3->subregion()));
178 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta0->subregion(), *theta4->subregion()));
179
180 // theta0 can also be reached by every region inside it
181 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta1->subregion(), *theta0->subregion()));
182 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta2->subregion(), *theta0->subregion()));
183 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta3->subregion(), *theta0->subregion()));
184 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta4->subregion(), *theta0->subregion()));
185
186 // theta2 can be reached from theta1
187 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta1->subregion(), *theta2->subregion()));
188
189 // theta3 and theta4 can reach each other
190 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta3->subregion(), *theta4->subregion()));
191 EXPECT_TRUE(trace.CheckPredicatesSatisfiable(*theta4->subregion(), *theta3->subregion()));
192}
193
194TEST(RegionPredicateTraceTests, TraceIntoGamma)
195{
221 using namespace jlm;
222
223 auto controlType = rvsdg::ControlType::Create(2);
224
225 rvsdg::Graph rvsdg;
226 auto & outerCtrl0 = rvsdg::ControlConstantOperation::createFalse(rvsdg.GetRootRegion());
227 auto & gamma0 = *rvsdg::GammaNode::create(&outerCtrl0, 2);
228
229 // Left subregion of gamma0
230 auto & leftCtrl0 = rvsdg::ControlConstantOperation::createFalse(*gamma0.subregion(0));
231 auto & leftCtrl1 = rvsdg::ControlConstantOperation::createTrue(*gamma0.subregion(0));
232
233 auto & gamma1 = *rvsdg::GammaNode::create(&leftCtrl0, 2);
234 auto gamma1Entry0 = gamma1.AddEntryVar(&leftCtrl0);
235 auto gamma1Entry1 = gamma1.AddEntryVar(&leftCtrl1);
236 auto gamma1Exit =
237 gamma1.AddExitVar({ gamma1Entry0.branchArgument[0], gamma1Entry1.branchArgument[1] });
238
239 // Right subregion of gamma1
240 auto & rightCtrl1 = rvsdg::ControlConstantOperation::createTrue(*gamma0.subregion(1));
241
242 auto gamma0Exit = gamma0.AddExitVar({ gamma1Exit.output, &rightCtrl1 });
243
244 auto & gamma2 = *rvsdg::GammaNode::create(gamma0Exit.output, 2);
245
246 // Assert
248
249 // targeting gamma2's left subregion
250 ASSERT_TRUE(trace.CheckPredicatesSatisfiable(*gamma1.subregion(0), *gamma2.subregion(0)));
251 ASSERT_FALSE(trace.CheckPredicatesSatisfiable(*gamma1.subregion(1), *gamma2.subregion(0)));
252 ASSERT_TRUE(trace.CheckPredicatesSatisfiable(*gamma0.subregion(0), *gamma2.subregion(0)));
253 ASSERT_FALSE(trace.CheckPredicatesSatisfiable(*gamma0.subregion(1), *gamma2.subregion(0)));
254
255 // targeting gamma2's right subregion
256 ASSERT_FALSE(trace.CheckPredicatesSatisfiable(*gamma1.subregion(0), *gamma2.subregion(1)));
257 ASSERT_TRUE(trace.CheckPredicatesSatisfiable(*gamma1.subregion(1), *gamma2.subregion(1)));
258 ASSERT_TRUE(trace.CheckPredicatesSatisfiable(*gamma0.subregion(0), *gamma2.subregion(1)));
259 ASSERT_TRUE(trace.CheckPredicatesSatisfiable(*gamma0.subregion(1), *gamma2.subregion(1)));
260}
TEST(RegionPredicateTraceTests, TestTracing)
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
Traces region reachability by predicate assertions.
bool CheckPredicatesSatisfiable(Region &originRegion, Region &targetRegion)
Checks for dynamic reachability between two regions.