llvm.org GIT mirror llvm / 156d5ee
[llvm-profdata] Add SaturatingAdd/SaturatingMultiply Helper Functions (2nd try) Summary: This change adds MathExtras helper functions for handling unsigned, saturating addition and multiplication. It also updates the instrumentation and sample profile merge implementations to use them. Reviewers: dnovillo, bogner, davidxl Subscribers: davidxl, llvm-commits Differential Revision: http://reviews.llvm.org/D14720 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253497 91177308-0d34-0410-b5e6-96231b3b80d8 Nathan Slingerland 3 years ago
5 changed file(s) with 98 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
225225 while (I != IE && I->Value < J->Value)
226226 ++I;
227227 if (I != IE && I->Value == J->Value) {
228 I->Count += J->Count;
228 I->Count = SaturatingAdd(I->Count, J->Count);
229229 ++I;
230230 continue;
231231 }
172172 /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
173173 /// around unsigned integers.
174174 void addSamples(uint64_t S) {
175 if (NumSamples <= std::numeric_limits::max() - S)
176 NumSamples += S;
177 else
178 NumSamples = std::numeric_limits::max();
175 NumSamples = SaturatingAdd(NumSamples, S);
179176 }
180177
181178 /// Add called function \p F with samples \p S.
184181 /// around unsigned integers.
185182 void addCalledTarget(StringRef F, uint64_t S) {
186183 uint64_t &TargetSamples = CallTargets[F];
187 if (TargetSamples <= std::numeric_limits::max() - S)
188 TargetSamples += S;
189 else
190 TargetSamples = std::numeric_limits::max();
184 TargetSamples = SaturatingAdd(TargetSamples, S);
191185 }
192186
193187 /// Return true if this sample record contains function calls.
652652 return int64_t(X << (64 - B)) >> (64 - B);
653653 }
654654
655 /// \brief Add two unsigned integers, X and Y, of type T.
656 /// Clamp the result to the maximum representable value of T on overflow.
657 template
658 typename std::enable_if::value, T>::type
659 SaturatingAdd(T X, T Y) {
660 // Hacker's Delight, p. 29
661 T Z = X + Y;
662 if (Z < X || Z < Y)
663 return std::numeric_limits::max();
664 else
665 return Z;
666 }
667
668 /// \brief Multiply two unsigned integers, X and Y, of type T.
669 /// Clamp the result to the maximum representable value of T on overflow.
670 template
671 typename std::enable_if::value, T>::type
672 SaturatingMultiply(T X, T Y) {
673 // Hacker's Delight, p. 30
674 T Z = X * Y;
675 if (Y != 0 && Z / Y != X)
676 return std::numeric_limits::max();
677 else
678 return Z;
679 }
680
655681 extern const float huge_valf;
656682 } // End llvm namespace
657683
349349 ASSERT_EQ(2U, VD_4[2].Count);
350350 }
351351
352 TEST_F(InstrProfTest, get_icall_data_merge1_saturation) {
353 const uint64_t Max = std::numeric_limits::max();
354
355 InstrProfRecord Record1("caller", 0x1234, {1});
356 InstrProfRecord Record2("caller", 0x1234, {1});
357 InstrProfRecord Record3("callee1", 0x1235, {3, 4});
358
359 Record1.reserveSites(IPVK_IndirectCallTarget, 1);
360 InstrProfValueData VD1[] = {{(uint64_t) "callee1", 1}};
361 Record1.addValueData(IPVK_IndirectCallTarget, 0, VD1, 1, nullptr);
362
363 Record2.reserveSites(IPVK_IndirectCallTarget, 1);
364 InstrProfValueData VD2[] = {{(uint64_t) "callee1", Max}};
365 Record2.addValueData(IPVK_IndirectCallTarget, 0, VD2, 1, nullptr);
366
367 Writer.addRecord(std::move(Record1));
368 Writer.addRecord(std::move(Record2));
369 Writer.addRecord(std::move(Record3));
370
371 auto Profile = Writer.writeBuffer();
372 readProfile(std::move(Profile));
373
374 // Verify saturation of counts.
375 ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234);
376 ASSERT_TRUE(NoError(R.getError()));
377 ASSERT_EQ(1U, R.get().getNumValueSites(IPVK_IndirectCallTarget));
378 std::unique_ptr VD =
379 R.get().getValueForSite(IPVK_IndirectCallTarget, 0);
380 ASSERT_EQ(StringRef("callee1"), StringRef((const char *)VD[0].Value, 7));
381 ASSERT_EQ(Max, VD[0].Count);
382 }
383
352384 TEST_F(InstrProfTest, get_max_function_count) {
353385 InstrProfRecord Record1("foo", 0x1234, {1ULL << 31, 2});
354386 InstrProfRecord Record2("bar", 0, {1ULL << 63});
189189 EXPECT_EQ(552u, RoundUpToAlignment(321, 255, 42));
190190 }
191191
192 }
192 template
193 void SaturatingAddTestHelper()
194 {
195 const T Max = std::numeric_limits::max();
196 EXPECT_EQ(T(3), SaturatingAdd(T(1), T(2)));
197 EXPECT_EQ(Max, SaturatingAdd(Max, T(1)));
198 EXPECT_EQ(Max, SaturatingAdd(T(1), Max));
199 EXPECT_EQ(Max, SaturatingAdd(Max, Max));
200 }
201
202 TEST(MathExtras, SaturatingAdd) {
203 SaturatingAddTestHelper();
204 SaturatingAddTestHelper();
205 SaturatingAddTestHelper();
206 SaturatingAddTestHelper();
207 }
208
209 template
210 void SaturatingMultiplyTestHelper()
211 {
212 const T Max = std::numeric_limits::max();
213 EXPECT_EQ(T(0), SaturatingMultiply(T(1), T(0)));
214 EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(1)));
215 EXPECT_EQ(T(6), SaturatingMultiply(T(2), T(3)));
216 EXPECT_EQ(Max, SaturatingMultiply(Max, T(2)));
217 EXPECT_EQ(Max, SaturatingMultiply(T(2),Max));
218 EXPECT_EQ(Max, SaturatingMultiply(Max, Max));
219 }
220
221 TEST(MathExtras, SaturatingMultiply) {
222 SaturatingMultiplyTestHelper();
223 SaturatingMultiplyTestHelper();
224 SaturatingMultiplyTestHelper();
225 SaturatingMultiplyTestHelper();
226 }
227
228 }