blob: 620749519b4777c6d94e70809193d3b4821041d1 [file] [log] [blame]
Andrew Scullaa6c1092015-09-03 17:50:30 -07001//===- subzero/src/IceSwitchLowering.cpp - Switch lowering ----------------===//
Andrew Scull87f80c12015-07-20 10:19:16 -07002//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// This file implements platform independent analysis of switch cases to
12/// improve the generated code.
13///
14//===----------------------------------------------------------------------===//
15#include "IceSwitchLowering.h"
16
Andrew Scull86df4e92015-07-30 13:54:44 -070017#include "IceCfgNode.h"
Andrew Scull87f80c12015-07-20 10:19:16 -070018#include "IceTargetLowering.h"
19
20#include <algorithm>
21
22namespace Ice {
23
24CaseClusterArray CaseCluster::clusterizeSwitch(Cfg *Func,
25 const InstSwitch *Inst) {
26 CaseClusterArray CaseClusters;
27
28 // Load the cases
29 SizeT NumCases = Inst->getNumCases();
30 CaseClusters.reserve(NumCases);
31 for (SizeT I = 0; I < NumCases; ++I)
32 CaseClusters.emplace_back(Inst->getValue(I), Inst->getLabel(I));
33
34 // Sort the cases
35 std::sort(CaseClusters.begin(), CaseClusters.end(),
36 [](const CaseCluster &x, const CaseCluster &y) {
37 return x.High < y.Low;
38 });
39
40 // Merge adjacent case ranges
41 auto Active = CaseClusters.begin();
42 std::for_each(Active + 1, CaseClusters.end(),
43 [&Active](const CaseCluster &x) {
44 if (!Active->tryAppend(x))
45 *(++Active) = x;
46 });
47 CaseClusters.erase(Active + 1, CaseClusters.end());
48
49 // TODO(ascull): Merge in a cycle i.e. -1(=UINTXX_MAX) to 0. This depends on
50 // the types for correct wrap around behavior.
51
52 // A small number of cases is more efficient without a jump table
53 if (CaseClusters.size() < Func->getTarget()->getMinJumpTableSize())
54 return CaseClusters;
55
56 // Test for a single jump table. This can be done in constant time whereas
57 // finding the best set of jump table would be quadratic, too slow(?). If
58 // jump tables were included in the search tree we'd first have to traverse to
59 // them. Ideally we would have an unbalanced tree which is biased towards
60 // frequently executed code but we can't do this well without profiling data.
61 // So, this single jump table is a good starting point where you can get to
62 // the jump table quickly without figuring out how to unbalance the tree.
63 uint64_t MaxValue = CaseClusters.back().High;
64 uint64_t MinValue = CaseClusters.front().Low;
65 // Don't +1 yet to avoid (INT64_MAX-0)+1 overflow
66 uint64_t TotalRange = MaxValue - MinValue;
67
68 // Might be too sparse for the jump table
69 if (NumCases * 2 <= TotalRange)
70 return CaseClusters;
71 // Unlikely. Would mean can't store size of jump table.
72 if (TotalRange == UINT64_MAX)
73 return CaseClusters;
74 ++TotalRange;
75
76 // Replace everything with a jump table
77 InstJumpTable *JumpTable =
78 InstJumpTable::create(Func, TotalRange, Inst->getLabelDefault());
Andrew Scull016c56d2015-07-23 14:31:12 -070079 for (const CaseCluster &Case : CaseClusters) {
80 // Case.High could be UINT64_MAX which makes the loop awkward. Unwrap the
81 // last iteration to avoid wrap around problems.
82 for (uint64_t I = Case.Low; I < Case.High; ++I)
Andrew Scull86df4e92015-07-30 13:54:44 -070083 JumpTable->addTarget(I - MinValue, Case.Target);
84 JumpTable->addTarget(Case.High - MinValue, Case.Target);
85 Case.Target->setNeedsAlignment();
Andrew Scull016c56d2015-07-23 14:31:12 -070086 }
Andrew Scull86df4e92015-07-30 13:54:44 -070087 Func->addJumpTable(JumpTable);
Andrew Scull87f80c12015-07-20 10:19:16 -070088
89 CaseClusters.clear();
90 CaseClusters.emplace_back(MinValue, MaxValue, JumpTable);
91
92 return CaseClusters;
93}
94
95bool CaseCluster::tryAppend(const CaseCluster &New) {
96 // Can only append ranges with the same target and are adjacent
Andrew Scull86df4e92015-07-30 13:54:44 -070097 bool CanAppend = this->Target == New.Target && this->High + 1 == New.Low;
Andrew Scull87f80c12015-07-20 10:19:16 -070098 if (CanAppend)
99 this->High = New.High;
100 return CanAppend;
101}
102
103} // end of namespace Ice