[llvm] [Transforms/Util] Add SimplifySwitchVar pass (PR #149937)
Thomas Symalla via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 25 07:55:26 PDT 2025
================
@@ -0,0 +1,371 @@
+//===-- SimplifySwitchVar.cpp - Switch Variable simplification ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// This file implements switch variable simplification. It looks for a
+/// linear relationship between the case value of a switch and the constant
+/// offset of an operation. Knowing this relationship, we can simplify
+/// multiple individual operations into a single, more generic one, which
+/// can help with further optimizations.
+///
+/// It is similar to SimplifyIndVar, but instead of looking at an
+/// induction variable and modeling its scalar evolution over
+/// multiple iterations, it analyzes the switch variable and
+/// models how it affects constant offsets.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/SimplifySwitchVar.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/PatternMatch.h"
+#include <random>
+
+using namespace llvm;
+using namespace PatternMatch;
+
+/// Return the BB, where (most of) the cases meet.
+/// In that BB are phi nodes, that contain the case BBs.
+static BasicBlock *findMostCommonSuccessor(SwitchInst *Switch) {
+ uint64_t Max = 0;
+ BasicBlock *MostCommonSuccessor = nullptr;
+
+ for (auto &Case : Switch->cases()) {
+ auto *CaseBB = Case.getCaseSuccessor();
+ auto GetNumPredecessors = [](BasicBlock *BB) -> uint64_t {
+ return std::distance(predecessors(BB).begin(), predecessors(BB).end());
+ };
+
+ auto Length = GetNumPredecessors(CaseBB);
+
+ if (Length > Max) {
+ Max = Length;
+ MostCommonSuccessor = CaseBB;
+ }
+
+ for (auto *Successor : successors(CaseBB)) {
+ auto Length = GetNumPredecessors(Successor);
+ if (Length > Max) {
+ Max = Length;
+ MostCommonSuccessor = Successor;
+ }
+ }
+ }
+
+ return MostCommonSuccessor;
+}
+
+namespace {
+struct PhiCase {
+ int PhiIndex;
+ Value *IncomingValue;
+ ConstantInt *CaseValue;
+};
+} // namespace
+
+/// Collect the incoming value, index and associated case value from a phi node.
+/// Ignores incoming values, which do not come from a case BB from the switch.
+static SmallVector<PhiCase> collectPhiCases(PHINode &Phi, SwitchInst *Switch) {
+ SmallVector<PhiCase> PhiInputs;
+
+ for (auto *IncomingBlock : Phi.blocks()) {
+ auto *CaseVal = Switch->findCaseDest(IncomingBlock);
+ if (!CaseVal)
+ continue;
+
+ auto PhiIdx = Phi.getBasicBlockIndex(IncomingBlock);
+ PhiInputs.push_back({PhiIdx, Phi.getIncomingValue(PhiIdx), CaseVal});
+ }
+ return PhiInputs;
+}
+
+namespace {
+enum SupportedOp {
+ GetElementPtr,
+ IntegerAdd,
+ Unsupported,
+};
+
+struct NewInstParameters {
+ SupportedOp Op;
+ Value *BaseValue;
+ Type *OffsetTy;
+};
+} // namespace
+
+/// Find the common Base Value, Operation type and Index Type of the found phi
+/// incoming values.
+static NewInstParameters findInstParameters(SmallVector<PhiCase> &PhiCases) {
+ auto Op = SupportedOp::Unsupported;
+ DenseMap<Value *, uint64_t> BaseAddressCounts;
+ Type *OffsetTy = nullptr;
+
+ for (auto &Case : PhiCases) {
+ auto *GEP = dyn_cast<GetElementPtrInst>(Case.IncomingValue);
+ bool IsAdd =
----------------
tsymalla wrote:
This match can be moved to after the `if (GEP)` check, because the result will be unused if it's looking at an GEP.
https://github.com/llvm/llvm-project/pull/149937
More information about the llvm-commits
mailing list