blob: 8d61f9a68279829f6d07b651639e71abe4186398 [file] [log] [blame]
Andrew Scullcdfcccc2018-10-05 20:58:37 +01001//===-- llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h --*- C++ -*-==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9/// \file
10/// This file implements a version of MachineIRBuilder which does trivial
11/// constant folding.
12//===----------------------------------------------------------------------===//
13#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
14#include "llvm/CodeGen/GlobalISel/Utils.h"
15
16namespace llvm {
17
18static Optional<APInt> ConstantFoldBinOp(unsigned Opcode, const unsigned Op1,
19 const unsigned Op2,
20 const MachineRegisterInfo &MRI) {
21 auto MaybeOp1Cst = getConstantVRegVal(Op1, MRI);
22 auto MaybeOp2Cst = getConstantVRegVal(Op2, MRI);
23 if (MaybeOp1Cst && MaybeOp2Cst) {
24 LLT Ty = MRI.getType(Op1);
25 APInt C1(Ty.getSizeInBits(), *MaybeOp1Cst, true);
26 APInt C2(Ty.getSizeInBits(), *MaybeOp2Cst, true);
27 switch (Opcode) {
28 default:
29 break;
30 case TargetOpcode::G_ADD:
31 return C1 + C2;
32 case TargetOpcode::G_AND:
33 return C1 & C2;
34 case TargetOpcode::G_ASHR:
35 return C1.ashr(C2);
36 case TargetOpcode::G_LSHR:
37 return C1.lshr(C2);
38 case TargetOpcode::G_MUL:
39 return C1 * C2;
40 case TargetOpcode::G_OR:
41 return C1 | C2;
42 case TargetOpcode::G_SHL:
43 return C1 << C2;
44 case TargetOpcode::G_SUB:
45 return C1 - C2;
46 case TargetOpcode::G_XOR:
47 return C1 ^ C2;
48 case TargetOpcode::G_UDIV:
49 if (!C2.getBoolValue())
50 break;
51 return C1.udiv(C2);
52 case TargetOpcode::G_SDIV:
53 if (!C2.getBoolValue())
54 break;
55 return C1.sdiv(C2);
56 case TargetOpcode::G_UREM:
57 if (!C2.getBoolValue())
58 break;
59 return C1.urem(C2);
60 case TargetOpcode::G_SREM:
61 if (!C2.getBoolValue())
62 break;
63 return C1.srem(C2);
64 }
65 }
66 return None;
67}
68
69/// An MIRBuilder which does trivial constant folding of binary ops.
70/// Calls to buildInstr will also try to constant fold binary ops.
71class ConstantFoldingMIRBuilder
72 : public FoldableInstructionsBuilder<ConstantFoldingMIRBuilder> {
73public:
74 // Pull in base class constructors.
75 using FoldableInstructionsBuilder<
76 ConstantFoldingMIRBuilder>::FoldableInstructionsBuilder;
77 // Unhide buildInstr
78 using FoldableInstructionsBuilder<ConstantFoldingMIRBuilder>::buildInstr;
79
80 // Implement buildBinaryOp required by FoldableInstructionsBuilder which
81 // tries to constant fold.
82 MachineInstrBuilder buildBinaryOp(unsigned Opcode, unsigned Dst,
83 unsigned Src0, unsigned Src1) {
84 validateBinaryOp(Dst, Src0, Src1);
85 auto MaybeCst = ConstantFoldBinOp(Opcode, Src0, Src1, getMF().getRegInfo());
86 if (MaybeCst)
87 return buildConstant(Dst, MaybeCst->getSExtValue());
88 return buildInstr(Opcode).addDef(Dst).addUse(Src0).addUse(Src1);
89 }
90
91 template <typename DstTy, typename UseArg1Ty, typename UseArg2Ty>
92 MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty, UseArg1Ty &&Arg1,
93 UseArg2Ty &&Arg2) {
94 unsigned Dst = getDestFromArg(Ty);
95 return buildInstr(Opc, Dst, getRegFromArg(std::forward<UseArg1Ty>(Arg1)),
96 getRegFromArg(std::forward<UseArg2Ty>(Arg2)));
97 }
98
99 // Try to provide an overload for buildInstr for binary ops in order to
100 // constant fold.
101 MachineInstrBuilder buildInstr(unsigned Opc, unsigned Dst, unsigned Src0,
102 unsigned Src1) {
103 switch (Opc) {
104 default:
105 break;
106 case TargetOpcode::G_ADD:
107 case TargetOpcode::G_AND:
108 case TargetOpcode::G_ASHR:
109 case TargetOpcode::G_LSHR:
110 case TargetOpcode::G_MUL:
111 case TargetOpcode::G_OR:
112 case TargetOpcode::G_SHL:
113 case TargetOpcode::G_SUB:
114 case TargetOpcode::G_XOR:
115 case TargetOpcode::G_UDIV:
116 case TargetOpcode::G_SDIV:
117 case TargetOpcode::G_UREM:
118 case TargetOpcode::G_SREM: {
119 return buildBinaryOp(Opc, Dst, Src0, Src1);
120 }
121 }
122 return buildInstr(Opc).addDef(Dst).addUse(Src0).addUse(Src1);
123 }
124
125 // Fallback implementation of buildInstr.
126 template <typename DstTy, typename... UseArgsTy>
127 MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty,
128 UseArgsTy &&... Args) {
129 auto MIB = buildInstr(Opc).addDef(getDestFromArg(Ty));
130 addUsesFromArgs(MIB, std::forward<UseArgsTy>(Args)...);
131 return MIB;
132 }
133};
134} // namespace llvm