]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/include/llvm/CodeGen/GlobalISel/ConstantFoldingMIRBuilder.h
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / include / llvm / CodeGen / GlobalISel / ConstantFoldingMIRBuilder.h
1 //===-- 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
16 namespace llvm {
17
18 static 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.
71 class ConstantFoldingMIRBuilder
72     : public FoldableInstructionsBuilder<ConstantFoldingMIRBuilder> {
73 public:
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