1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-21 12:02:58 +02:00
llvm-mirror/include/llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h
Aditya Nandakumar 60a589c3f5 [GISel] Refactor MachineIRBuilder to allow transformations while
building.

https://reviews.llvm.org/D45067

This change attempts to do two things:
1) It separates out the state that is stored in the
MachineIRBuilder(InsertionPt, MF, MRI, InsertFunction etc) into a
separate object called MachineIRBuilderState.
2) Add the ability to constant fold operations while building instructions
(optionally). MachineIRBuilder is now refactored into a MachineIRBuilderBase
which contains lots of non foldable build methods and their implementation.
Instructions which can be constant folded/transformed are now in a class
called FoldableInstructionBuilder which uses CRTP to use the implementation
of the derived class for buildBinaryOps. Additionally buildInstr in the derived
class can be used to implement other kinds of transformations.

Also because of separation of state, given a MachineIRBuilder in an API,
if one wishes to use another MachineIRBuilder, a new one can be
constructed from the state locally. For eg,

void doFoo(MachineIRBuilder &B) {
  MyCustomBuilder CustomB(B.getState());
  // Use CustomB for building.
}

reviewed by : aemerson

llvm-svn: 329596
2018-04-09 17:30:56 +00:00

135 lines
4.5 KiB
C++

//===-- llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h --*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements a version of MachineIRBuilder which does trivial
/// constant folding.
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
namespace llvm {
static Optional<APInt> ConstantFoldBinOp(unsigned Opcode, const unsigned Op1,
const unsigned Op2,
const MachineRegisterInfo &MRI) {
auto MaybeOp1Cst = getConstantVRegVal(Op1, MRI);
auto MaybeOp2Cst = getConstantVRegVal(Op2, MRI);
if (MaybeOp1Cst && MaybeOp2Cst) {
LLT Ty = MRI.getType(Op1);
APInt C1(Ty.getSizeInBits(), *MaybeOp1Cst, true);
APInt C2(Ty.getSizeInBits(), *MaybeOp2Cst, true);
switch (Opcode) {
default:
break;
case TargetOpcode::G_ADD:
return C1 + C2;
case TargetOpcode::G_AND:
return C1 & C2;
case TargetOpcode::G_ASHR:
return C1.ashr(C2);
case TargetOpcode::G_LSHR:
return C1.lshr(C2);
case TargetOpcode::G_MUL:
return C1 * C2;
case TargetOpcode::G_OR:
return C1 | C2;
case TargetOpcode::G_SHL:
return C1 << C2;
case TargetOpcode::G_SUB:
return C1 - C2;
case TargetOpcode::G_XOR:
return C1 ^ C2;
case TargetOpcode::G_UDIV:
if (!C2.getBoolValue())
break;
return C1.udiv(C2);
case TargetOpcode::G_SDIV:
if (!C2.getBoolValue())
break;
return C1.sdiv(C2);
case TargetOpcode::G_UREM:
if (!C2.getBoolValue())
break;
return C1.urem(C2);
case TargetOpcode::G_SREM:
if (!C2.getBoolValue())
break;
return C1.srem(C2);
}
}
return None;
}
/// An MIRBuilder which does trivial constant folding of binary ops.
/// Calls to buildInstr will also try to constant fold binary ops.
class ConstantFoldingMIRBuilder
: public FoldableInstructionsBuilder<ConstantFoldingMIRBuilder> {
public:
// Pull in base class constructors.
using FoldableInstructionsBuilder<
ConstantFoldingMIRBuilder>::FoldableInstructionsBuilder;
// Unhide buildInstr
using FoldableInstructionsBuilder<ConstantFoldingMIRBuilder>::buildInstr;
// Implement buildBinaryOp required by FoldableInstructionsBuilder which
// tries to constant fold.
MachineInstrBuilder buildBinaryOp(unsigned Opcode, unsigned Dst,
unsigned Src0, unsigned Src1) {
validateBinaryOp(Dst, Src0, Src1);
auto MaybeCst = ConstantFoldBinOp(Opcode, Src0, Src1, getMF().getRegInfo());
if (MaybeCst)
return buildConstant(Dst, MaybeCst->getSExtValue());
return buildInstr(Opcode).addDef(Dst).addUse(Src0).addUse(Src1);
}
template <typename DstTy, typename UseArg1Ty, typename UseArg2Ty>
MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty, UseArg1Ty &&Arg1,
UseArg2Ty &&Arg2) {
unsigned Dst = getDestFromArg(Ty);
return buildInstr(Opc, Dst, getRegFromArg(std::forward<UseArg1Ty>(Arg1)),
getRegFromArg(std::forward<UseArg2Ty>(Arg2)));
}
// Try to provide an overload for buildInstr for binary ops in order to
// constant fold.
MachineInstrBuilder buildInstr(unsigned Opc, unsigned Dst, unsigned Src0,
unsigned Src1) {
switch (Opc) {
default:
break;
case TargetOpcode::G_ADD:
case TargetOpcode::G_AND:
case TargetOpcode::G_ASHR:
case TargetOpcode::G_LSHR:
case TargetOpcode::G_MUL:
case TargetOpcode::G_OR:
case TargetOpcode::G_SHL:
case TargetOpcode::G_SUB:
case TargetOpcode::G_XOR:
case TargetOpcode::G_UDIV:
case TargetOpcode::G_SDIV:
case TargetOpcode::G_UREM:
case TargetOpcode::G_SREM: {
return buildBinaryOp(Opc, Dst, Src0, Src1);
}
}
return buildInstr(Opc).addDef(Dst).addUse(Src0).addUse(Src1);
}
// Fallback implementation of buildInstr.
template <typename DstTy, typename... UseArgsTy>
MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty,
UseArgsTy &&... Args) {
auto MIB = buildInstr(Opc).addDef(getDestFromArg(Ty));
addUsesFromArgs(MIB, std::forward<UseArgsTy>(Args)...);
return MIB;
}
};
} // namespace llvm