Subzero: Use a "deterministic" random shuffle for register allocation.
To make this work, Subzero provides its own RandomShuffle() as a replacement for std::random_shuffle(), and the Subzero implementation doesn't depend on the stdlib implementation.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=4129
R=jvoung@chromium.org
Review URL: https://codereview.chromium.org/1072913002
diff --git a/src/IceRNG.h b/src/IceRNG.h
index bf01e41..a2d8e96 100644
--- a/src/IceRNG.h
+++ b/src/IceRNG.h
@@ -53,6 +53,15 @@
RandomNumberGenerator &RNG;
};
+// RandomShuffle is an implementation of std::random_shuffle() that
+// doesn't change across stdlib implementations. Adapted from a
+// sample implementation at cppreference.com.
+template <class RandomIt, class RandomFunc>
+void RandomShuffle(RandomIt First, RandomIt Last, RandomFunc &&RNG) {
+ for (auto i = Last - First - 1; i > 0; --i)
+ std::swap(First[i], First[RNG(i + 1)]);
+}
+
} // end of namespace Ice
#endif // SUBZERO_SRC_ICERNG_H
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 662ac54..bd67844 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -4621,7 +4621,7 @@
for (auto I : EquivalenceClasses) {
const RegisterList &List = I.second;
RegisterList Shuffled(List);
- std::random_shuffle(Shuffled.begin(), Shuffled.end(), RNG);
+ RandomShuffle(Shuffled.begin(), Shuffled.end(), RNG);
for (size_t SI = 0, SE = Shuffled.size(); SI < SE; ++SI) {
Permutation[List[SI]] = Shuffled[SI];
++NumShuffled;
diff --git a/tests_lit/llvm2ice_tests/randomize-regalloc.ll b/tests_lit/llvm2ice_tests/randomize-regalloc.ll
index f393938..696fce5 100644
--- a/tests_lit/llvm2ice_tests/randomize-regalloc.ll
+++ b/tests_lit/llvm2ice_tests/randomize-regalloc.ll
@@ -26,11 +26,11 @@
; OPTM1_1-NEXT: movups XMMWORD PTR [esp+0x20],xmm0
; OPTM1_1-NEXT: movups XMMWORD PTR [esp+0x10],xmm1
; OPTM1_1-NEXT: movups xmm0,XMMWORD PTR [esp+0x20]
-; OPTM1_1-NEXT: pshufd xmm7,XMMWORD PTR [esp+0x20],0x31
-; OPTM1_1-NEXT: pshufd xmm4,XMMWORD PTR [esp+0x10],0x31
+; OPTM1_1-NEXT: pshufd xmm1,XMMWORD PTR [esp+0x20],0x31
+; OPTM1_1-NEXT: pshufd xmm2,XMMWORD PTR [esp+0x10],0x31
; OPTM1_1-NEXT: pmuludq xmm0,XMMWORD PTR [esp+0x10]
-; OPTM1_1-NEXT: pmuludq xmm7,xmm4
-; OPTM1_1-NEXT: shufps xmm0,xmm7,0x88
+; OPTM1_1-NEXT: pmuludq xmm1,xmm2
+; OPTM1_1-NEXT: shufps xmm0,xmm1,0x88
; OPTM1_1-NEXT: pshufd xmm0,xmm0,0xd8
; OPTM1_1-NEXT: movups XMMWORD PTR [esp],xmm0
; OPTM1_1-NEXT: movups xmm0,XMMWORD PTR [esp]
@@ -38,14 +38,14 @@
; OPTM1_1-NEXT: ret
; CHECK_1-LABEL: mul_v4i32
-; CHECK_1: movups xmm6,xmm0
+; CHECK_1: movups xmm5,xmm0
; CHECK_1-NEXT: pshufd xmm0,xmm0,0x31
-; CHECK_1-NEXT: pshufd xmm5,xmm1,0x31
-; CHECK_1-NEXT: pmuludq xmm6,xmm1
-; CHECK_1-NEXT: pmuludq xmm0,xmm5
-; CHECK_1-NEXT: shufps xmm6,xmm0,0x88
-; CHECK_1-NEXT: pshufd xmm6,xmm6,0xd8
-; CHECK_1-NEXT: movups xmm0,xmm6
+; CHECK_1-NEXT: pshufd xmm3,xmm1,0x31
+; CHECK_1-NEXT: pmuludq xmm5,xmm1
+; CHECK_1-NEXT: pmuludq xmm0,xmm3
+; CHECK_1-NEXT: shufps xmm5,xmm0,0x88
+; CHECK_1-NEXT: pshufd xmm5,xmm5,0xd8
+; CHECK_1-NEXT: movups xmm0,xmm5
; CHECK_1-NEXT: ret
; OPTM1_123-LABEL: mul_v4i32
@@ -53,11 +53,11 @@
; OPTM1_123-NEXT: movups XMMWORD PTR [esp+0x20],xmm0
; OPTM1_123-NEXT: movups XMMWORD PTR [esp+0x10],xmm1
; OPTM1_123-NEXT: movups xmm0,XMMWORD PTR [esp+0x20]
-; OPTM1_123-NEXT: pshufd xmm2,XMMWORD PTR [esp+0x20],0x31
+; OPTM1_123-NEXT: pshufd xmm1,XMMWORD PTR [esp+0x20],0x31
; OPTM1_123-NEXT: pshufd xmm6,XMMWORD PTR [esp+0x10],0x31
; OPTM1_123-NEXT: pmuludq xmm0,XMMWORD PTR [esp+0x10]
-; OPTM1_123-NEXT: pmuludq xmm2,xmm6
-; OPTM1_123-NEXT: shufps xmm0,xmm2,0x88
+; OPTM1_123-NEXT: pmuludq xmm1,xmm6
+; OPTM1_123-NEXT: shufps xmm0,xmm1,0x88
; OPTM1_123-NEXT: pshufd xmm0,xmm0,0xd8
; OPTM1_123-NEXT: movups XMMWORD PTR [esp],xmm0
; OPTM1_123-NEXT: movups xmm0,XMMWORD PTR [esp]
@@ -65,14 +65,14 @@
; OPTM1_123-NEXT: ret
; CHECK_123-LABEL: mul_v4i32
-; CHECK_123: movups xmm3,xmm0
+; CHECK_123: movups xmm4,xmm0
; CHECK_123-NEXT: pshufd xmm0,xmm0,0x31
-; CHECK_123-NEXT: pshufd xmm7,xmm1,0x31
-; CHECK_123-NEXT: pmuludq xmm3,xmm1
-; CHECK_123-NEXT: pmuludq xmm0,xmm7
-; CHECK_123-NEXT: shufps xmm3,xmm0,0x88
-; CHECK_123-NEXT: pshufd xmm3,xmm3,0xd8
-; CHECK_123-NEXT: movups xmm0,xmm3
+; CHECK_123-NEXT: pshufd xmm2,xmm1,0x31
+; CHECK_123-NEXT: pmuludq xmm4,xmm1
+; CHECK_123-NEXT: pmuludq xmm0,xmm2
+; CHECK_123-NEXT: shufps xmm4,xmm0,0x88
+; CHECK_123-NEXT: pshufd xmm4,xmm4,0xd8
+; CHECK_123-NEXT: movups xmm0,xmm4
; CHECK_123-NEXT: ret
}
diff --git a/unittest/IceELFSectionTest.cpp b/unittest/IceELFSectionTest.cpp
index 8dbcc65..57e43c1 100644
--- a/unittest/IceELFSectionTest.cpp
+++ b/unittest/IceELFSectionTest.cpp
@@ -90,8 +90,11 @@
Strings.push_back(".shstrtab");
Strings.push_back("_start");
const SizeT NumTests = 128;
+ const uint64_t RandomSeed = 12345; // arbitrary value for now
+ RandomNumberGenerator R(RandomSeed);
+ RandomNumberGeneratorWrapper RNG(R);
for (SizeT i = 0; i < NumTests; ++i) {
- std::random_shuffle(Strings.begin(), Strings.end());
+ RandomShuffle(Strings.begin(), Strings.end(), RNG);
ELFStringTableSection Strtab(".strtab", SHT_STRTAB, 0, 1, 0);
for (auto &S : Strings) {
Strtab.add(S);