Path: blob/main/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCBoolRetToInt.cpp
35266 views
//===- PPCBoolRetToInt.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements converting i1 values to i32/i64 if they could be more9// profitably allocated as GPRs rather than CRs. This pass will become totally10// unnecessary if Register Bank Allocation and Global Instruction Selection ever11// go upstream.12//13// Presently, the pass converts i1 Constants, and Arguments to i32/i64 if the14// transitive closure of their uses includes only PHINodes, CallInsts, and15// ReturnInsts. The rational is that arguments are generally passed and returned16// in GPRs rather than CRs, so casting them to i32/i64 at the LLVM IR level will17// actually save casts at the Machine Instruction level.18//19// It might be useful to expand this pass to add bit-wise operations to the list20// of safe transitive closure types. Also, we miss some opportunities when LLVM21// represents logical AND and OR operations with control flow rather than data22// flow. For example by lowering the expression: return (A && B && C)23//24// as: return A ? true : B && C.25//26// There's code in SimplifyCFG that code be used to turn control flow in data27// flow using SelectInsts. Selects are slow on some architectures (P7/P8), so28// this probably isn't good in general, but for the special case of i1, the29// Selects could be further lowered to bit operations that are fast everywhere.30//31//===----------------------------------------------------------------------===//3233#include "PPC.h"34#include "PPCTargetMachine.h"35#include "llvm/ADT/DenseMap.h"36#include "llvm/ADT/STLExtras.h"37#include "llvm/ADT/SmallPtrSet.h"38#include "llvm/ADT/SmallVector.h"39#include "llvm/ADT/Statistic.h"40#include "llvm/IR/Argument.h"41#include "llvm/IR/Constants.h"42#include "llvm/IR/Dominators.h"43#include "llvm/IR/Function.h"44#include "llvm/IR/Instruction.h"45#include "llvm/IR/Instructions.h"46#include "llvm/IR/IntrinsicInst.h"47#include "llvm/IR/IRBuilder.h"48#include "llvm/IR/OperandTraits.h"49#include "llvm/IR/Type.h"50#include "llvm/IR/Use.h"51#include "llvm/IR/User.h"52#include "llvm/IR/Value.h"53#include "llvm/Pass.h"54#include "llvm/CodeGen/TargetPassConfig.h"55#include "llvm/Support/Casting.h"56#include <cassert>5758using namespace llvm;5960namespace {6162#define DEBUG_TYPE "ppc-bool-ret-to-int"6364STATISTIC(NumBoolRetPromotion,65"Number of times a bool feeding a RetInst was promoted to an int");66STATISTIC(NumBoolCallPromotion,67"Number of times a bool feeding a CallInst was promoted to an int");68STATISTIC(NumBoolToIntPromotion,69"Total number of times a bool was promoted to an int");7071class PPCBoolRetToInt : public FunctionPass {72static SmallPtrSet<Value *, 8> findAllDefs(Value *V) {73SmallPtrSet<Value *, 8> Defs;74SmallVector<Value *, 8> WorkList;75WorkList.push_back(V);76Defs.insert(V);77while (!WorkList.empty()) {78Value *Curr = WorkList.pop_back_val();79auto *CurrUser = dyn_cast<User>(Curr);80// Operands of CallInst/Constant are skipped because they may not be Bool81// type. For CallInst, their positions are defined by ABI.82if (CurrUser && !isa<CallInst>(Curr) && !isa<Constant>(Curr))83for (auto &Op : CurrUser->operands())84if (Defs.insert(Op).second)85WorkList.push_back(Op);86}87return Defs;88}8990// Translate a i1 value to an equivalent i32/i64 value:91Value *translate(Value *V) {92assert(V->getType() == Type::getInt1Ty(V->getContext()) &&93"Expect an i1 value");9495Type *IntTy = ST->isPPC64() ? Type::getInt64Ty(V->getContext())96: Type::getInt32Ty(V->getContext());9798if (auto *P = dyn_cast<PHINode>(V)) {99// Temporarily set the operands to 0. We'll fix this later in100// runOnUse.101Value *Zero = Constant::getNullValue(IntTy);102PHINode *Q =103PHINode::Create(IntTy, P->getNumIncomingValues(), P->getName(), P->getIterator());104for (unsigned i = 0; i < P->getNumOperands(); ++i)105Q->addIncoming(Zero, P->getIncomingBlock(i));106return Q;107}108109IRBuilder IRB(V->getContext());110if (auto *I = dyn_cast<Instruction>(V))111IRB.SetInsertPoint(I->getNextNode());112else113IRB.SetInsertPoint(&Func->getEntryBlock(), Func->getEntryBlock().begin());114return IRB.CreateZExt(V, IntTy);115}116117typedef SmallPtrSet<const PHINode *, 8> PHINodeSet;118119// A PHINode is Promotable if:120// 1. Its type is i1 AND121// 2. All of its uses are ReturnInt, CallInst, PHINode, or DbgInfoIntrinsic122// AND123// 3. All of its operands are Constant or Argument or124// CallInst or PHINode AND125// 4. All of its PHINode uses are Promotable AND126// 5. All of its PHINode operands are Promotable127static PHINodeSet getPromotablePHINodes(const Function &F) {128PHINodeSet Promotable;129// Condition 1130for (auto &BB : F)131for (auto &I : BB)132if (const auto *P = dyn_cast<PHINode>(&I))133if (P->getType()->isIntegerTy(1))134Promotable.insert(P);135136SmallVector<const PHINode *, 8> ToRemove;137for (const PHINode *P : Promotable) {138// Condition 2 and 3139auto IsValidUser = [] (const Value *V) -> bool {140return isa<ReturnInst>(V) || isa<CallInst>(V) || isa<PHINode>(V) ||141isa<DbgInfoIntrinsic>(V);142};143auto IsValidOperand = [] (const Value *V) -> bool {144return isa<Constant>(V) || isa<Argument>(V) || isa<CallInst>(V) ||145isa<PHINode>(V);146};147const auto &Users = P->users();148const auto &Operands = P->operands();149if (!llvm::all_of(Users, IsValidUser) ||150!llvm::all_of(Operands, IsValidOperand))151ToRemove.push_back(P);152}153154// Iterate to convergence155auto IsPromotable = [&Promotable] (const Value *V) -> bool {156const auto *Phi = dyn_cast<PHINode>(V);157return !Phi || Promotable.count(Phi);158};159while (!ToRemove.empty()) {160for (auto &User : ToRemove)161Promotable.erase(User);162ToRemove.clear();163164for (const PHINode *P : Promotable) {165// Condition 4 and 5166const auto &Users = P->users();167const auto &Operands = P->operands();168if (!llvm::all_of(Users, IsPromotable) ||169!llvm::all_of(Operands, IsPromotable))170ToRemove.push_back(P);171}172}173174return Promotable;175}176177typedef DenseMap<Value *, Value *> B2IMap;178179public:180static char ID;181182PPCBoolRetToInt() : FunctionPass(ID) {183initializePPCBoolRetToIntPass(*PassRegistry::getPassRegistry());184}185186bool runOnFunction(Function &F) override {187if (skipFunction(F))188return false;189190auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();191if (!TPC)192return false;193194auto &TM = TPC->getTM<PPCTargetMachine>();195ST = TM.getSubtargetImpl(F);196Func = &F;197198PHINodeSet PromotablePHINodes = getPromotablePHINodes(F);199B2IMap Bool2IntMap;200bool Changed = false;201for (auto &BB : F) {202for (auto &I : BB) {203if (auto *R = dyn_cast<ReturnInst>(&I))204if (F.getReturnType()->isIntegerTy(1))205Changed |=206runOnUse(R->getOperandUse(0), PromotablePHINodes, Bool2IntMap);207208if (auto *CI = dyn_cast<CallInst>(&I))209for (auto &U : CI->operands())210if (U->getType()->isIntegerTy(1))211Changed |= runOnUse(U, PromotablePHINodes, Bool2IntMap);212}213}214215return Changed;216}217218bool runOnUse(Use &U, const PHINodeSet &PromotablePHINodes,219B2IMap &BoolToIntMap) {220auto Defs = findAllDefs(U);221222// If the values are all Constants or Arguments, don't bother223if (llvm::none_of(Defs, [](Value *V) { return isa<Instruction>(V); }))224return false;225226// Presently, we only know how to handle PHINode, Constant, Arguments and227// CallInst. Potentially, bitwise operations (AND, OR, XOR, NOT) and sign228// extension could also be handled in the future.229for (Value *V : Defs)230if (!isa<PHINode>(V) && !isa<Constant>(V) &&231!isa<Argument>(V) && !isa<CallInst>(V))232return false;233234for (Value *V : Defs)235if (const auto *P = dyn_cast<PHINode>(V))236if (!PromotablePHINodes.count(P))237return false;238239if (isa<ReturnInst>(U.getUser()))240++NumBoolRetPromotion;241if (isa<CallInst>(U.getUser()))242++NumBoolCallPromotion;243++NumBoolToIntPromotion;244245for (Value *V : Defs)246if (!BoolToIntMap.count(V))247BoolToIntMap[V] = translate(V);248249// Replace the operands of the translated instructions. They were set to250// zero in the translate function.251for (auto &Pair : BoolToIntMap) {252auto *First = dyn_cast<User>(Pair.first);253auto *Second = dyn_cast<User>(Pair.second);254assert((!First || Second) && "translated from user to non-user!?");255// Operands of CallInst/Constant are skipped because they may not be Bool256// type. For CallInst, their positions are defined by ABI.257if (First && !isa<CallInst>(First) && !isa<Constant>(First))258for (unsigned i = 0; i < First->getNumOperands(); ++i)259Second->setOperand(i, BoolToIntMap[First->getOperand(i)]);260}261262Value *IntRetVal = BoolToIntMap[U];263Type *Int1Ty = Type::getInt1Ty(U->getContext());264auto *I = cast<Instruction>(U.getUser());265Value *BackToBool =266new TruncInst(IntRetVal, Int1Ty, "backToBool", I->getIterator());267U.set(BackToBool);268269return true;270}271272void getAnalysisUsage(AnalysisUsage &AU) const override {273AU.addPreserved<DominatorTreeWrapperPass>();274FunctionPass::getAnalysisUsage(AU);275}276277private:278const PPCSubtarget *ST;279Function *Func;280};281282} // end anonymous namespace283284char PPCBoolRetToInt::ID = 0;285INITIALIZE_PASS(PPCBoolRetToInt, "ppc-bool-ret-to-int",286"Convert i1 constants to i32/i64 if they are returned", false,287false)288289FunctionPass *llvm::createPPCBoolRetToIntPass() { return new PPCBoolRetToInt(); }290291292