Subzero: Deterministically sort constant pool entries.
Otherwise, constant pools are emitted in hash table order, which can vary across systems.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=4129
R=jvoung@chromium.org
Review URL: https://codereview.chromium.org/1069453003
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index c710edf..1c9e3c4 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -64,6 +64,54 @@
}
};
+// Define a key comparison function for sorting the constant pool's
+// values after they are dumped to a vector. This covers integer
+// types, floating point types, and ConstantRelocatable values.
+template <typename ValueType, class Enable = void> struct KeyCompareLess {};
+
+template <typename ValueType>
+struct KeyCompareLess<ValueType,
+ typename std::enable_if<std::is_floating_point<
+ typename ValueType::PrimType>::value>::type> {
+ bool operator()(const Constant *Const1, const Constant *Const2) const {
+ typedef uint64_t CompareType;
+ static_assert(sizeof(typename ValueType::PrimType) <= sizeof(CompareType),
+ "Expected floating-point type of width 64-bit or less");
+ typename ValueType::PrimType V1 = llvm::cast<ValueType>(Const1)->getValue();
+ typename ValueType::PrimType V2 = llvm::cast<ValueType>(Const2)->getValue();
+ // We avoid "V1<V2" because of NaN.
+ // We avoid "memcmp(&V1,&V2,sizeof(V1))<0" which depends on the
+ // endian-ness of the host system running Subzero.
+ // Instead, compare the result of bit_cast to uint64_t.
+ uint64_t I1 = 0, I2 = 0;
+ memcpy(&I1, &V1, sizeof(V1));
+ memcpy(&I2, &V2, sizeof(V2));
+ return I1 < I2;
+ }
+};
+template <typename ValueType>
+struct KeyCompareLess<ValueType,
+ typename std::enable_if<std::is_integral<
+ typename ValueType::PrimType>::value>::type> {
+ bool operator()(const Constant *Const1, const Constant *Const2) const {
+ typename ValueType::PrimType V1 = llvm::cast<ValueType>(Const1)->getValue();
+ typename ValueType::PrimType V2 = llvm::cast<ValueType>(Const2)->getValue();
+ return V1 < V2;
+ }
+};
+template <typename ValueType>
+struct KeyCompareLess<
+ ValueType, typename std::enable_if<
+ std::is_same<ValueType, ConstantRelocatable>::value>::type> {
+ bool operator()(const Constant *Const1, const Constant *Const2) const {
+ auto V1 = llvm::cast<ValueType>(Const1);
+ auto V2 = llvm::cast<ValueType>(Const2);
+ if (V1->getName() == V2->getName())
+ return V1->getOffset() < V2->getOffset();
+ return V1->getName() < V2->getName();
+ }
+};
+
// TypePool maps constants of type KeyType (e.g. float) to pointers to
// type ValueType (e.g. ConstantFloat).
template <Type Ty, typename KeyType, typename ValueType> class TypePool {
@@ -85,6 +133,10 @@
Constants.reserve(Pool.size());
for (auto &I : Pool)
Constants.push_back(I.second);
+ // The sort (and its KeyCompareLess machinery) is not strictly
+ // necessary, but is desirable for producing output that is
+ // deterministic across unordered_map::iterator implementations.
+ std::sort(Constants.begin(), Constants.end(), KeyCompareLess<ValueType>());
return Constants;
}
diff --git a/tests_lit/llvm2ice_tests/elf_container.ll b/tests_lit/llvm2ice_tests/elf_container.ll
index aff0cf5..f95ed2a 100644
--- a/tests_lit/llvm2ice_tests/elf_container.ll
+++ b/tests_lit/llvm2ice_tests/elf_container.ll
@@ -330,7 +330,7 @@
; CHECK: AddressAlignment: 8
; CHECK: EntrySize: 8
; CHECK: SectionData (
-; CHECK: 0000: 03000000 0000F8FF FFFFFFFF FFFFF7FF
+; CHECK: 0000: FFFFFFFF FFFFF7FF 03000000 0000F8FF
; CHECK: 0010: FFFFFFFF FFFFFFFF
; CHECK: )
; CHECK: }
@@ -429,7 +429,7 @@
; CHECK-NEXT: }
; CHECK: Symbol {
; CHECK: Name: .L$double$2
-; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Value: 0x8
; CHECK-NEXT: Size: 0
; CHECK-NEXT: Binding: Local (0x0)
; CHECK-NEXT: Type: None (0x0)