mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-21 20:12:56 +02:00
135 lines
4.5 KiB
C
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
|