The input LLVM module may define an array of cpu_mapping structs,
describing the mapping between fields in a specified struct (usually
CPUArchState) and TCG globals.
Create a map between offsets into the specified struct and TCG globals
(name, size, number of elements, stride) by iterating over the global
cpu_mapping array. The name of this array is configurable via
the --tcg-global-mappings flag.
Signed-off-by: Anton Johansson <anjo@rev.ng>
---
.../helper-to-tcg/include/PrepareForTcgPass.h | 7 ++-
.../helper-to-tcg/include/TcgGlobalMap.h | 31 +++++++++++++
.../PrepareForTcgPass/PrepareForTcgPass.cpp | 43 +++++++++++++++++++
.../helper-to-tcg/pipeline/Pipeline.cpp | 9 ++--
4 files changed, 85 insertions(+), 5 deletions(-)
create mode 100644 subprojects/helper-to-tcg/include/TcgGlobalMap.h
diff --git a/subprojects/helper-to-tcg/include/PrepareForTcgPass.h b/subprojects/helper-to-tcg/include/PrepareForTcgPass.h
index a41edb4c2e..a731c70b4b 100644
--- a/subprojects/helper-to-tcg/include/PrepareForTcgPass.h
+++ b/subprojects/helper-to-tcg/include/PrepareForTcgPass.h
@@ -17,11 +17,16 @@
#pragma once
+#include "TcgGlobalMap.h"
#include <llvm/IR/PassManager.h>
class PrepareForTcgPass : public llvm::PassInfoMixin<PrepareForTcgPass> {
+ TcgGlobalMap &ResultTcgGlobalMap;
public:
- PrepareForTcgPass() {}
+ PrepareForTcgPass(TcgGlobalMap &ResultTcgGlobalMap)
+ : ResultTcgGlobalMap(ResultTcgGlobalMap)
+ {
+ }
llvm::PreservedAnalyses run(llvm::Module &M,
llvm::ModuleAnalysisManager &MAM);
};
diff --git a/subprojects/helper-to-tcg/include/TcgGlobalMap.h b/subprojects/helper-to-tcg/include/TcgGlobalMap.h
new file mode 100644
index 0000000000..7186d805ba
--- /dev/null
+++ b/subprojects/helper-to-tcg/include/TcgGlobalMap.h
@@ -0,0 +1,31 @@
+#pragma once
+
+//
+// Copyright(c) 2024 rev.ng Labs Srl. All Rights Reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/DenseMap.h>
+#include <stdint.h>
+
+struct TcgGlobal {
+ llvm::StringRef Code;
+ uint64_t Size;
+ uint64_t NumElements;
+ uint64_t Stride;
+};
+
+using TcgGlobalMap = llvm::DenseMap<uint32_t, TcgGlobal>;
diff --git a/subprojects/helper-to-tcg/passes/PrepareForTcgPass/PrepareForTcgPass.cpp b/subprojects/helper-to-tcg/passes/PrepareForTcgPass/PrepareForTcgPass.cpp
index a2808eafed..a453aa8558 100644
--- a/subprojects/helper-to-tcg/passes/PrepareForTcgPass/PrepareForTcgPass.cpp
+++ b/subprojects/helper-to-tcg/passes/PrepareForTcgPass/PrepareForTcgPass.cpp
@@ -15,6 +15,7 @@
// along with this program; if not, see <http://www.gnu.org/licenses/>.
//
+#include <CmdLineOptions.h>
#include <PrepareForTcgPass.h>
#include <llvm/ADT/SCCIterator.h>
#include <llvm/IR/Function.h>
@@ -71,11 +72,53 @@ inline void demotePhis(Function &F)
}
}
+static void collectTcgGlobals(Module &M, TcgGlobalMap &ResultTcgGlobalMap)
+{
+ auto *Map = M.getGlobalVariable(TcgGlobalMappingsName);
+ if (!Map) {
+ return;
+ }
+
+ // In case the `tcg_global_mappings` array is empty,
+ // casting to `ConstantArray` will fail, even though it's a
+ // `[0 x %struct.cpu_tcg_mapping]`.
+ auto *MapElems = dyn_cast<ConstantArray>(Map->getOperand(0));
+ if (!MapElems) {
+ return;
+ }
+
+ for (auto Row : MapElems->operand_values()) {
+ auto *ConstRow = cast<ConstantStruct>(Row);
+
+ // Get code string
+ auto *CodePtr = ConstRow->getOperand(0);
+ auto CodeStr =
+ cast<ConstantDataArray>(
+ cast<Constant>(CodePtr->getOperand(0))->getOperand(0))
+ ->getAsString();
+ CodeStr = CodeStr.rtrim('\0');
+
+ // Get offset in cpu env
+ auto *Offset = cast<ConstantInt>(ConstRow->getOperand(3));
+ // Get size of variable in cpu env
+ auto *SizeInBytes = cast<ConstantInt>(ConstRow->getOperand(4));
+ unsigned SizeInBits = 8 * SizeInBytes->getLimitedValue();
+
+ auto *Stride = cast<ConstantInt>(ConstRow->getOperand(5));
+ auto *NumElements = cast<ConstantInt>(ConstRow->getOperand(6));
+
+ ResultTcgGlobalMap[Offset->getLimitedValue()] = {
+ CodeStr, SizeInBits, NumElements->getLimitedValue(),
+ Stride->getLimitedValue()};
+ }
+}
+
PreservedAnalyses PrepareForTcgPass::run(Module &M, ModuleAnalysisManager &MAM)
{
removeFunctionsWithLoops(M, MAM);
for (Function &F : M) {
demotePhis(F);
}
+ collectTcgGlobals(M, ResultTcgGlobalMap);
return PreservedAnalyses::none();
}
diff --git a/subprojects/helper-to-tcg/pipeline/Pipeline.cpp b/subprojects/helper-to-tcg/pipeline/Pipeline.cpp
index 7d03389439..a8df592af3 100644
--- a/subprojects/helper-to-tcg/pipeline/Pipeline.cpp
+++ b/subprojects/helper-to-tcg/pipeline/Pipeline.cpp
@@ -58,9 +58,9 @@ cl::opt<bool> TranslateAllHelpers(
// Options for PrepareForTcgPass
cl::opt<std::string> TcgGlobalMappingsName(
"tcg-global-mappings",
- cl::desc("<Name of global cpu_mappings[] used for mapping accesses"
- "into a struct to TCG globals>"),
- cl::Required, cl::cat(Cat));
+ cl::desc("Name of global cpu_mappings[] used for mapping accesses"
+ "into a struct to TCG globals"),
+ cl::init("mappings"), cl::cat(Cat));
// Define a TargetTransformInfo (TTI) subclass, this allows for overriding
// common per-llvm-target information expected by other LLVM passes, such
@@ -216,7 +216,8 @@ int main(int argc, char **argv)
// easily to TCG.
//
- MPM.addPass(PrepareForTcgPass());
+ TcgGlobalMap TcgGlobals;
+ MPM.addPass(PrepareForTcgPass(TcgGlobals));
MPM.addPass(VerifierPass());
{
FunctionPassManager FPM;
--
2.45.2