
#define RPMALLOC_EXPORT __declspec(dllimport)
#include "llvm/Support/rpnew.h"

#pragma comment(lib, "LLVM-21.lib")

#include "llvm/IR/Attributes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"

using namespace llvm;

namespace {

// Windows x64 LLVM21 のバグ回避用パス
// パイプラインの最初に実行し、可変長引数関数に noinline 属性を強制付与
struct TeForceNoinlineVarArgFunctionPass
    : public PassInfoMixin<TeForceNoinlineVarArgFunctionPass> {
  PreservedAnalyses run(Module& M, ModuleAnalysisManager& MAM) {
    bool Changed = false;

    for (Function& F : M) {
      if (F.isDeclaration()) continue;

      if (F.isVarArg() && !F.hasFnAttribute(Attribute::NoInline)) {
        F.addFnAttr(Attribute::NoInline);
        Changed = true;
      }
    }

    return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
  }

  static bool isRequired() { return true; }
};

}  // namespace

extern "C" LLVM_ATTRIBUTE_WEAK
::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
  return {
    LLVM_PLUGIN_API_VERSION, "TeBugFix", LLVM_VERSION_STRING,
    [](PassBuilder& PB) {
      PB.registerPipelineStartEPCallback(
        [](ModulePassManager& MPM, OptimizationLevel) {
          MPM.addPass(TeForceNoinlineVarArgFunctionPass());
        }
      );
    }
  };
}
