[llvm] Added optimization for switches of powers of two (PR #70977)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 1 14:50:28 PDT 2023
https://github.com/DKay7 updated https://github.com/llvm/llvm-project/pull/70977
>From fc2336b268d67bd966aaacb352709af0d1128509 Mon Sep 17 00:00:00 2001
From: Daniil <kalinin.de at phystech.edu>
Date: Wed, 1 Nov 2023 22:32:23 +0300
Subject: [PATCH] Added optimization for switches of powers of two
Optimization reduces range for switches which cases are positive powers of two by replacing each case with count_trailing_zero(case).
Also, this optimization is performed only for switches with default case unreachable
Resolves #70756
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 67 ++++++++++++++++++++++-
1 file changed, 64 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 68b5b1a78a3460e..4ab4e7ffb869265 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -50,6 +50,7 @@
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Metadata.h"
@@ -6792,9 +6793,6 @@ static bool ReduceSwitchRange(SwitchInst *SI, IRBuilder<> &Builder,
// This transform can be done speculatively because it is so cheap - it
// results in a single rotate operation being inserted.
- // FIXME: It's possible that optimizing a switch on powers of two might also
- // be beneficial - flag values are often powers of two and we could use a CLZ
- // as the key function.
// countTrailingZeros(0) returns 64. As Values is guaranteed to have more than
// one element and LLVM disallows duplicate cases, Shift is guaranteed to be
@@ -6839,6 +6837,66 @@ static bool ReduceSwitchRange(SwitchInst *SI, IRBuilder<> &Builder,
return true;
}
+static bool isSwitchOfPowersOfTwo(ArrayRef<int64_t> Values) {
+ for (auto &Value : Values) {
+ if (Value <= 0 || (Value & (Value - 1)) != 0)
+ return false;
+ }
+
+ return true;
+}
+
+static bool simplifySwitchOfPowersOfTwo(SwitchInst *SI, IRBuilder<> &Builder,
+ const DataLayout &DL) {
+
+ auto *CondTy = cast<IntegerType>(SI->getCondition()->getType());
+
+ if (CondTy->getIntegerBitWidth() > 64 ||
+ !DL.fitsInLegalInteger(CondTy->getIntegerBitWidth()))
+ return false;
+
+ // Only bother with this optimization if there are more than 3 switch cases;
+ // SDAG will only bother creating jump tables for 4 or more cases.
+ if (SI->getNumCases() < 4)
+ return false;
+
+ SmallVector<int64_t, 4> Values;
+ for (const auto &Case : SI->cases())
+ Values.push_back(Case.getCaseValue()->getValue().getSExtValue());
+
+ // We perform this optimization only for switches with
+ // unreachable default case.
+ // This assumtion will save us from checking if `Condition` is a power of two
+ bool HasDefault =
+ !isa<UnreachableInst>(SI->getDefaultDest()->getFirstNonPHIOrDbg());
+
+ if (!isSwitchOfPowersOfTwo(Values) || HasDefault)
+ return false;
+
+ Builder.SetInsertPoint(SI);
+
+ auto *Condition = SI->getCondition();
+ auto &Context = SI->getContext();
+ Function *Cttz =
+ Intrinsic::getDeclaration(SI->getModule(), Intrinsic::cttz, {CondTy});
+
+ // FIXME maybe we should check if cttz intrinsic is cheap on the target
+ // architecture
+ auto *ConditionTrailingZeros = Builder.CreateCall(
+ Cttz, {Condition, ConstantInt::get(Type::getInt1Ty(Context), 0)});
+
+ SI->replaceUsesOfWith(Condition, ConditionTrailingZeros);
+
+ // Replace each case with its trailing zeros number
+ for (auto &Case : SI->cases()) {
+ auto *OrigValue = Case.getCaseValue();
+ Case.setValue(cast<ConstantInt>(ConstantInt::get(
+ OrigValue->getType(), OrigValue->getValue().countr_zero())));
+ }
+
+ return true;
+}
+
bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
BasicBlock *BB = SI->getParent();
@@ -6886,6 +6944,9 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
SwitchToLookupTable(SI, Builder, DTU, DL, TTI))
return requestResimplify();
+ if (simplifySwitchOfPowersOfTwo(SI, Builder, DL))
+ return requestResimplify();
+
if (ReduceSwitchRange(SI, Builder, DL, TTI))
return requestResimplify();
More information about the llvm-commits
mailing list