| //===-- 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 MachineIRBuilder { |
| public: |
| // Pull in base class constructors. |
| using MachineIRBuilder::MachineIRBuilder; |
| |
| virtual ~ConstantFoldingMIRBuilder() = default; |
| |
| // Try to provide an overload for buildInstr for binary ops in order to |
| // constant fold. |
| MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef<DstOp> DstOps, |
| ArrayRef<SrcOp> SrcOps, |
| Optional<unsigned> Flags = None) override { |
| 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: { |
| assert(DstOps.size() == 1 && "Invalid dst ops"); |
| assert(SrcOps.size() == 2 && "Invalid src ops"); |
| const DstOp &Dst = DstOps[0]; |
| const SrcOp &Src0 = SrcOps[0]; |
| const SrcOp &Src1 = SrcOps[1]; |
| if (auto MaybeCst = |
| ConstantFoldBinOp(Opc, Src0.getReg(), Src1.getReg(), *getMRI())) |
| return buildConstant(Dst, MaybeCst->getSExtValue()); |
| break; |
| } |
| } |
| return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps); |
| } |
| }; |
| } // namespace llvm |