[llvm] [RISCV] Introduce pass to promote double constants to a global array (PR #160536)

Alex Bradbury via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 1 07:18:59 PDT 2025


================
@@ -0,0 +1,212 @@
+//==- RISCVPromoteConstant.cpp - Promote constant fp to global for RISC-V --==//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCV.h"
+#include "RISCVSubtarget.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "riscv-promote-const"
+
+STATISTIC(NumPromoted, "Number of promoted constants");
+STATISTIC(NumPromotedUses, "Number of promoted constants uses");
+
+namespace {
+
+class RISCVPromoteConstant : public ModulePass {
+public:
+  static char ID;
+  RISCVPromoteConstant() : ModulePass(ID) {}
+
+  StringRef getPassName() const override { return "RISC-V Promote Constant"; }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequired<TargetPassConfig>();
+    AU.setPreservesCFG();
+  }
+
+  /// Iterate over the functions and promote the double fp constants that
+  /// would otherwise go into the constant pool to a constant array.
+  bool runOnModule(Module &M) override {
+    LLVM_DEBUG(dbgs() << getPassName() << '\n');
+    // TargetMachine and Subtarget are needed to query isFPImmlegal. Get them
+    // from TargetPassConfig.
+    const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
+    const TargetMachine &TM = TPC.getTM<TargetMachine>();
+    if (skipModule(M))
+      return false;
+    bool Changed = false;
+    for (auto &MF : M) {
+      const RISCVSubtarget &ST = TM.getSubtarget<RISCVSubtarget>(MF);
+      const RISCVTargetLowering *TLI = ST.getTargetLowering();
+      Changed |= runOnFunction(MF, TLI);
+    }
+    return Changed;
+  }
+
+private:
+  bool runOnFunction(Function &F, const RISCVTargetLowering *TLI);
+};
+} // end anonymous namespace
+
+char RISCVPromoteConstant::ID = 0;
+
+ModulePass *llvm::createRISCVPromoteConstantPass() {
+  return new RISCVPromoteConstant();
+}
+
+bool RISCVPromoteConstant::runOnFunction(Function &F,
+                                         const RISCVTargetLowering *TLI) {
+  // Bail out and make no transformation if the target doesn't support
+  // doubles, or if we're not targeting RV64 as we currently see some
+  // regressions for those targets.
+  if (!TLI->isTypeLegal(MVT::f64) || !TLI->isTypeLegal(MVT::i64))
+    return false;
+
+  // Collect all unique double constants used in the function, and track their
+  // offset within the newly created global array. Also track uses that will
+  // be replaced later.
+  DenseMap<ConstantFP *, unsigned> ConstantMap;
+  SmallVector<Constant *, 16> ConstantVector;
+  DenseMap<ConstantFP *, SmallVector<Use *, 8>> UsesInFunc;
+
+  for (Instruction &I : instructions(F)) {
+    // PHI nodes are handled specially in a second loop below.
+    if (isa<PHINode>(I))
+      continue;
+    for (Use &U : I.operands()) {
+      if (auto *C = dyn_cast<ConstantFP>(U.get())) {
+        if (C->getType()->isDoubleTy()) {
+          if (TLI->isFPImmLegal(C->getValueAPF(), MVT::f64,
+                                /*ForCodeSize*/ false))
+            continue;
+          UsesInFunc[C].push_back(&U);
+          if (ConstantMap.find(C) == ConstantMap.end()) {
+            ConstantMap[C] = ConstantVector.size();
+            ConstantVector.push_back(C);
+            ++NumPromoted;
+          }
+        }
+      }
+    }
+  }
+
+  // Collect uses from PHI nodes after other uses, because when transforming
+  // the function, we handle PHI uses afterwards.
----------------
asb wrote:

Yes it's the awkward issue related to choosing a different insertion point when the use is a PHI or for a "normal" use.

But taking a step back, I feel I've failed to simplify this as much as possible. I'd started like AArch64ConstantPromotion with doing minimal inserts based on the dominator tree but decided it wasn't worth it initially, but never revisisted if there's any benefit to inserting as close to the use as possible. Things are kept much simpler by always inserting in the first possible insertion point (impact described in forthcoming top-level PR comment).

https://github.com/llvm/llvm-project/pull/160536


More information about the llvm-commits mailing list