aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp52
1 files changed, 37 insertions, 15 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index a98d151..3b6bc879 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6120,6 +6120,38 @@ calculateByteProvider(SDValue Op, unsigned Index, unsigned Depth,
return None;
}
+static unsigned LittleEndianByteAt(unsigned BW, unsigned i) {
+ return i;
+}
+
+static unsigned BigEndianByteAt(unsigned BW, unsigned i) {
+ return BW - i - 1;
+}
+
+// Check if the bytes offsets we are looking at match with either big or
+// little endian value loaded. Return true for big endian, false for little
+// endian, and None if match failed.
+static Optional<bool> isBigEndian(const SmallVector<int64_t, 4> &ByteOffsets,
+ int64_t FirstOffset) {
+ // The endian can be decided only when it is 2 bytes at least.
+ unsigned Width = ByteOffsets.size();
+ if (Width < 2)
+ return None;
+
+ bool BigEndian = true, LittleEndian = true;
+ for (unsigned i = 0; i < Width; i++) {
+ int64_t CurrentByteOffset = ByteOffsets[i] - FirstOffset;
+ LittleEndian &= CurrentByteOffset == LittleEndianByteAt(Width, i);
+ BigEndian &= CurrentByteOffset == BigEndianByteAt(Width, i);
+ if (!BigEndian && !LittleEndian)
+ return None;
+ }
+
+ assert((BigEndian != LittleEndian) && "It should be either big endian or"
+ "little endian");
+ return BigEndian;
+}
+
/// Match a pattern where a wide type scalar value is loaded by several narrow
/// loads and combined by shifts and ors. Fold it into a single load or a load
/// and a BSWAP if the targets supports it.
@@ -6167,11 +6199,6 @@ SDValue DAGCombiner::MatchLoadCombine(SDNode *N) {
if (LegalOperations && !TLI.isOperationLegal(ISD::LOAD, VT))
return SDValue();
- std::function<unsigned(unsigned, unsigned)> LittleEndianByteAt = [](
- unsigned BW, unsigned i) { return i; };
- std::function<unsigned(unsigned, unsigned)> BigEndianByteAt = [](
- unsigned BW, unsigned i) { return BW - i - 1; };
-
bool IsBigEndianTarget = DAG.getDataLayout().isBigEndian();
auto MemoryByteOffset = [&] (ByteProvider P) {
assert(P.isMemory() && "Must be a memory byte provider");
@@ -6238,15 +6265,10 @@ SDValue DAGCombiner::MatchLoadCombine(SDNode *N) {
// Check if the bytes of the OR we are looking at match with either big or
// little endian value load
- bool BigEndian = true, LittleEndian = true;
- for (unsigned i = 0; i < ByteWidth; i++) {
- int64_t CurrentByteOffset = ByteOffsets[i] - FirstOffset;
- LittleEndian &= CurrentByteOffset == LittleEndianByteAt(ByteWidth, i);
- BigEndian &= CurrentByteOffset == BigEndianByteAt(ByteWidth, i);
- if (!BigEndian && !LittleEndian)
- return SDValue();
- }
- assert((BigEndian != LittleEndian) && "should be either or");
+ Optional<bool> IsBigEndian = isBigEndian(ByteOffsets, FirstOffset);
+ if (!IsBigEndian.hasValue())
+ return SDValue();
+
assert(FirstByteProvider && "must be set");
// Ensure that the first byte is loaded from zero offset of the first load.
@@ -6259,7 +6281,7 @@ SDValue DAGCombiner::MatchLoadCombine(SDNode *N) {
// replace it with a single load and bswap if needed.
// If the load needs byte swap check if the target supports it
- bool NeedsBswap = IsBigEndianTarget != BigEndian;
+ bool NeedsBswap = IsBigEndianTarget != *IsBigEndian;
// Before legalize we can introduce illegal bswaps which will be later
// converted to an explicit bswap sequence. This way we end up with a single