diff options
-rw-r--r-- | llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp | 70 | ||||
-rw-r--r-- | llvm/test/CodeGen/Hexagon/cext-opt-shifted-range.mir | 34 |
2 files changed, 86 insertions, 18 deletions
diff --git a/llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp b/llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp index dd759fe9ce5..88b5e808271 100644 --- a/llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp +++ b/llvm/lib/Target/Hexagon/HexagonConstExtenders.cpp @@ -39,18 +39,43 @@ namespace llvm { FunctionPass *createHexagonConstExtenders(); } +static int32_t adjustUp(int32_t V, uint8_t A, uint8_t O) { + assert(isPowerOf2_32(A)); + int32_t U = (V & -A) + O; + return U >= V ? U : U+A; +} + +static int32_t adjustDown(int32_t V, uint8_t A, uint8_t O) { + assert(isPowerOf2_32(A)); + int32_t U = (V & -A) + O; + return U <= V ? U : U-A; +} + namespace { struct OffsetRange { + // The range of values between Min and Max that are of form Align*N+Offset, + // for some integer N. Min and Max are required to be of that form as well, + // except in the case of an empty range. int32_t Min = INT_MIN, Max = INT_MAX; uint8_t Align = 1; + uint8_t Offset = 0; OffsetRange() = default; - OffsetRange(int32_t L, int32_t H, uint8_t A) - : Min(L), Max(H), Align(A) {} + OffsetRange(int32_t L, int32_t H, uint8_t A, uint8_t O = 0) + : Min(L), Max(H), Align(A), Offset(O) {} OffsetRange &intersect(OffsetRange A) { - Align = std::max(Align, A.Align); - Min = std::max(Min, A.Min); - Max = std::min(Max, A.Max); + if (Align < A.Align) + std::swap(*this, A); + + // Align >= A.Align. + if (Offset >= A.Offset && (Offset - A.Offset) % A.Align == 0) { + Min = adjustUp(std::max(Min, A.Min), Align, Offset); + Max = adjustDown(std::min(Max, A.Max), Align, Offset); + } else { + // Make an empty range. + Min = 0; + Max = -1; + } // Canonicalize empty ranges. if (Min > Max) std::tie(Min, Max, Align) = std::make_tuple(0, -1, 1); @@ -59,10 +84,12 @@ namespace { OffsetRange &shift(int32_t S) { Min += S; Max += S; + Offset = (Offset+S) % Align; return *this; } OffsetRange &extendBy(int32_t D) { // If D < 0, extend Min, otherwise extend Max. + assert(D % Align == 0); if (D < 0) Min = (INT_MIN-D < Min) ? Min+D : INT_MIN; else @@ -73,7 +100,7 @@ namespace { return Min > Max; } bool contains(int32_t V) const { - return Min <= V && V <= Max && (V % Align) == 0; + return Min <= V && V <= Max && (V-Offset) % Align == 0; } bool operator==(const OffsetRange &R) const { return Min == R.Min && Max == R.Max && Align == R.Align; @@ -407,7 +434,8 @@ namespace { raw_ostream &operator<< (raw_ostream &OS, const OffsetRange &OR) { if (OR.Min > OR.Max) OS << '!'; - OS << '[' << OR.Min << ',' << OR.Max << "]a" << unsigned(OR.Align); + OS << '[' << OR.Min << ',' << OR.Max << "]a" << unsigned(OR.Align) + << '+' << unsigned(OR.Offset); return OS; } @@ -1283,11 +1311,17 @@ void HCE::assignInits(const ExtRoot &ER, unsigned Begin, unsigned End, SmallVector<RangeTree::Node*,8> Nodes; Tree.order(Nodes); - auto MaxAlign = [](const SmallVectorImpl<RangeTree::Node*> &Nodes) { - uint8_t Align = 1; - for (RangeTree::Node *N : Nodes) - Align = std::max(Align, N->Range.Align); - return Align; + auto MaxAlign = [](const SmallVectorImpl<RangeTree::Node*> &Nodes, + uint8_t Align, uint8_t Offset) { + for (RangeTree::Node *N : Nodes) { + if (N->Range.Align <= Align || N->Range.Offset < Offset) + continue; + if ((N->Range.Offset - Offset) % Align != 0) + continue; + Align = N->Range.Align; + Offset = N->Range.Offset; + } + return std::make_pair(Align, Offset); }; // Construct the set of all potential definition points from the endpoints @@ -1297,14 +1331,14 @@ void HCE::assignInits(const ExtRoot &ER, unsigned Begin, unsigned End, std::set<int32_t> CandSet; for (RangeTree::Node *N : Nodes) { const OffsetRange &R = N->Range; - uint8_t A0 = MaxAlign(Tree.nodesWith(R.Min, false)); + auto P0 = MaxAlign(Tree.nodesWith(R.Min, false), R.Align, R.Offset); CandSet.insert(R.Min); - if (R.Align < A0) - CandSet.insert(R.Min < 0 ? -alignDown(-R.Min, A0) : alignTo(R.Min, A0)); - uint8_t A1 = MaxAlign(Tree.nodesWith(R.Max, false)); + if (R.Align < P0.first) + CandSet.insert(adjustUp(R.Min, P0.first, P0.second)); + auto P1 = MaxAlign(Tree.nodesWith(R.Max, false), R.Align, R.Offset); CandSet.insert(R.Max); - if (R.Align < A1) - CandSet.insert(R.Max < 0 ? -alignTo(-R.Max, A1) : alignDown(R.Max, A1)); + if (R.Align < P1.first) + CandSet.insert(adjustDown(R.Max, P1.first, P1.second)); } // Build the assignment map: candidate C -> { list of extender indexes }. diff --git a/llvm/test/CodeGen/Hexagon/cext-opt-shifted-range.mir b/llvm/test/CodeGen/Hexagon/cext-opt-shifted-range.mir new file mode 100644 index 00000000000..f67ace6e28f --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/cext-opt-shifted-range.mir @@ -0,0 +1,34 @@ +# RUN: llc -march=hexagon -run-pass hexagon-cext-opt %s -o - | FileCheck %s + +# Check that "misaligned" extended offsets are handled correctly, that is +# that the non-extended offsets are still aligned. + +# CHECK: %[[B:[0-9]+]]:intregs = A2_addi %{{[0-9]+}}, @array + 174 +# CHECK-DAG: S2_storerd_io %[[B]], 0, +# CHECK-DAG: S2_storerd_io %[[B]], 8, +# CHECK-DAG: S2_storerd_io %[[B]], 24, +# CHECK-DAG: S2_storerd_io %[[B]], 16, + +--- | + define void @fred() { + ret void + } + + @array = external global [10000 x i16], align 8 +... + +--- +name: fred +tracksRegLiveness: true +body: | + bb.0: + liveins: %r0 + %0:intregs = COPY %r0 + %1:intregs = S4_ori_asl_ri 2, %0, 1 + %2:doubleregs = A2_tfrpi 0 + S2_storerd_io %1, @array + 174, %2 + S2_storerd_io %1, @array + 182, %2 + S2_storerd_io %1, @array + 198, %2 + S2_storerd_io %1, @array + 190, %2 +... + |