Transformation of the IR, identity mapping trivial expressions which would amount to nothing more than a move when emitted as TCG, but is required in LLVM IR to not break the IR.
Trivial expressions are mapped to a @IdentityMap pseudo instruction allowing them to be dealt with in a uniform manner down the line. Signed-off-by: Anton Johansson <a...@rev.ng> --- subprojects/helper-to-tcg/meson.build | 1 + .../passes/PrepareForTcgPass/IdentityMap.cpp | 80 +++++++++++++++++++ .../passes/PrepareForTcgPass/IdentityMap.h | 39 +++++++++ .../PrepareForTcgPass/PrepareForTcgPass.cpp | 4 + 4 files changed, 124 insertions(+) create mode 100644 subprojects/helper-to-tcg/passes/PrepareForTcgPass/IdentityMap.cpp create mode 100644 subprojects/helper-to-tcg/passes/PrepareForTcgPass/IdentityMap.h diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-tcg/meson.build index 50bb926f49..09caa74c63 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -49,6 +49,7 @@ sources = [ 'passes/PrepareForTcgPass/PrepareForTcgPass.cpp', 'passes/PrepareForTcgPass/TransformGEPs.cpp', 'passes/PrepareForTcgPass/CanonicalizeIR.cpp', + 'passes/PrepareForTcgPass/IdentityMap.cpp', ] clang = bindir / 'clang' diff --git a/subprojects/helper-to-tcg/passes/PrepareForTcgPass/IdentityMap.cpp b/subprojects/helper-to-tcg/passes/PrepareForTcgPass/IdentityMap.cpp new file mode 100644 index 0000000000..b173aeba9c --- /dev/null +++ b/subprojects/helper-to-tcg/passes/PrepareForTcgPass/IdentityMap.cpp @@ -0,0 +1,80 @@ +// +// 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 "IdentityMap.h" +#include <PseudoInst.h> +#include "backend/TcgType.h" +#include <llvm/ADT/SmallVector.h> +#include <llvm/IR/IRBuilder.h> +#include <llvm/IR/InstIterator.h> +#include <llvm/IR/Instruction.h> +#include <llvm/IR/Value.h> + +using namespace llvm; + +void identityMap(Module &M, Function &F) +{ + SmallVector<Instruction *, 8> InstToErase; + + for (auto &I : instructions(F)) { + auto *ZExt = dyn_cast<ZExtInst>(&I); + if (ZExt) { + auto *IntTy0 = + dyn_cast<IntegerType>(ZExt->getOperand(0)->getType()); + auto *IntTy1 = dyn_cast<IntegerType>(ZExt->getType()); + if (IntTy0 and IntTy1) { + uint32_t LlvmSize0 = IntTy0->getBitWidth(); + uint32_t LlvmSize1 = IntTy1->getBitWidth(); + + if (LlvmSize0 == 1) { + auto *ICmp = dyn_cast<ICmpInst>(ZExt->getOperand(0)); + if (ICmp) { + auto *ICmpOp = ICmp->getOperand(0); + LlvmSize0 = + cast<IntegerType>(ICmpOp->getType())->getBitWidth(); + } + } + + uint32_t TcgSize0 = llvmToTcgSize(LlvmSize0); + uint32_t TcgSize1 = llvmToTcgSize(LlvmSize1); + + if (TcgSize0 == TcgSize1) { + FunctionCallee Fn = + pseudoInstFunction(M, IdentityMap, IntTy1, {IntTy0}); + IRBuilder<> Builder(&I); + CallInst *Call = + Builder.CreateCall(Fn, {ZExt->getOperand(0)}); + ZExt->replaceAllUsesWith(Call); + InstToErase.push_back(&I); + } + } + } else if (isa<FreezeInst>(&I)) { + auto *IntTy0 = dyn_cast<IntegerType>(I.getOperand(0)->getType()); + auto *IntTy1 = dyn_cast<IntegerType>(I.getType()); + FunctionCallee Fn = + pseudoInstFunction(M, IdentityMap, IntTy1, {IntTy0}); + IRBuilder<> Builder(&I); + CallInst *Call = Builder.CreateCall(Fn, {I.getOperand(0)}); + I.replaceAllUsesWith(Call); + InstToErase.push_back(&I); + } + } + + for (auto *I : InstToErase) { + I->eraseFromParent(); + } +} diff --git a/subprojects/helper-to-tcg/passes/PrepareForTcgPass/IdentityMap.h b/subprojects/helper-to-tcg/passes/PrepareForTcgPass/IdentityMap.h new file mode 100644 index 0000000000..b0c938c25d --- /dev/null +++ b/subprojects/helper-to-tcg/passes/PrepareForTcgPass/IdentityMap.h @@ -0,0 +1,39 @@ +// +// 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/>. +// + +#pragma once + +#include <llvm/IR/Function.h> +#include <llvm/IR/Module.h> + +// +// Transformation of the IR, taking what would become trivial unary operations +// and maps them to a single @IdentityMap pseudo instruction. +// +// To motivate further, in order to produce nice IR on the other end, generally +// the operands of these trivial expressions needs to be forwarded and treated +// as the destination value (identity mapped). However, directly removing these +// instructions will result in broken LLVM IR (consider zext i8, i32 where both +// the source and destination would map to TCGv_i32). +// +// Moreover, handling these identity mapped values in an adhoc way quickly +// becomes cumbersome and spreads throughout the codebase. Therefore, +// introducing @IdentityMap allows code further down the pipeline to ignore the +// source of the identity map. +// + +void identityMap(llvm::Module &M, llvm::Function &F); diff --git a/subprojects/helper-to-tcg/passes/PrepareForTcgPass/PrepareForTcgPass.cpp b/subprojects/helper-to-tcg/passes/PrepareForTcgPass/PrepareForTcgPass.cpp index 7fdbc2a0c9..3e4713d837 100644 --- a/subprojects/helper-to-tcg/passes/PrepareForTcgPass/PrepareForTcgPass.cpp +++ b/subprojects/helper-to-tcg/passes/PrepareForTcgPass/PrepareForTcgPass.cpp @@ -17,6 +17,7 @@ #include "CanonicalizeIR.h" #include <CmdLineOptions.h> +#include "IdentityMap.h" #include <PrepareForTcgPass.h> #include "TransformGEPs.h" #include <llvm/ADT/SCCIterator.h> @@ -126,5 +127,8 @@ PreservedAnalyses PrepareForTcgPass::run(Module &M, ModuleAnalysisManager &MAM) transformGEPs(M, F, ResultTcgGlobalMap); } canonicalizeIR(M); + for (Function &F : M) { + identityMap(M, F); + } return PreservedAnalyses::none(); } -- 2.45.2