xref: /llvm-project/llvm/tools/llvm-reduce/deltas/ReduceOpcodes.cpp (revision 2592ccdea7a3b62bcfee4aef87fc0e2163a47d28)
1 //===- ReduceOpcodes.cpp - Specialized Delta Pass -------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Try to replace instructions that are likely to codegen to simpler or smaller
10 // sequences. This is a fuzzy and target specific concept.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "ReduceOpcodes.h"
15 #include "Delta.h"
16 #include "llvm/IR/IRBuilder.h"
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/IntrinsicInst.h"
19 #include "llvm/IR/Intrinsics.h"
20 #include "llvm/IR/IntrinsicsAMDGPU.h"
21 
22 static Value *replaceIntrinsic(Module &M, IntrinsicInst *II,
23                                Intrinsic::ID NewIID,
24                                ArrayRef<Type *> Tys = None) {
25   Function *NewFunc = Intrinsic::getDeclaration(&M, NewIID, Tys);
26   II->setCalledFunction(NewFunc);
27   return II;
28 }
29 
30 static Value *reduceInstruction(Module &M, Instruction &I) {
31   IRBuilder<> B(&I);
32   switch (I.getOpcode()) {
33   case Instruction::FDiv:
34   case Instruction::FRem:
35     // Divisions tends to codegen into a long sequence or a library call.
36     return B.CreateFMul(I.getOperand(0), I.getOperand(1));
37   case Instruction::UDiv:
38   case Instruction::SDiv:
39   case Instruction::URem:
40   case Instruction::SRem:
41     // Divisions tends to codegen into a long sequence or a library call.
42     return B.CreateMul(I.getOperand(0), I.getOperand(1));
43   case Instruction::Add:
44   case Instruction::Sub: {
45     // Add/sub are more likely codegen to instructions with carry out side
46     // effects.
47     return B.CreateOr(I.getOperand(0), I.getOperand(1));
48   }
49   case Instruction::Call: {
50     IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
51     if (!II)
52       return nullptr;
53 
54     switch (II->getIntrinsicID()) {
55     case Intrinsic::sqrt:
56       return B.CreateFMul(II->getArgOperand(0),
57                           ConstantFP::get(I.getType(), 2.0));
58     case Intrinsic::minnum:
59     case Intrinsic::maxnum:
60     case Intrinsic::minimum:
61     case Intrinsic::maximum:
62     case Intrinsic::amdgcn_fmul_legacy:
63       return B.CreateFMul(II->getArgOperand(0), II->getArgOperand(1));
64     case Intrinsic::amdgcn_workitem_id_y:
65     case Intrinsic::amdgcn_workitem_id_z:
66       return replaceIntrinsic(M, II, Intrinsic::amdgcn_workitem_id_x);
67     case Intrinsic::amdgcn_workgroup_id_y:
68     case Intrinsic::amdgcn_workgroup_id_z:
69       return replaceIntrinsic(M, II, Intrinsic::amdgcn_workgroup_id_x);
70     case Intrinsic::amdgcn_div_fixup:
71     case Intrinsic::amdgcn_fma_legacy:
72       return replaceIntrinsic(M, II, Intrinsic::fma, {II->getType()});
73     default:
74       return nullptr;
75     }
76 
77     return nullptr;
78   }
79   default:
80     return nullptr;
81   }
82 
83   return nullptr;
84 }
85 
86 static void replaceOpcodesInModule(Oracle &O, Module &Mod) {
87   for (Function &F : Mod) {
88     for (BasicBlock &BB : F)
89       for (Instruction &I : make_early_inc_range(BB)) {
90         if (O.shouldKeep())
91           continue;
92 
93         Instruction *Replacement =
94             dyn_cast_or_null<Instruction>(reduceInstruction(Mod, I));
95         if (Replacement && Replacement != &I) {
96           if (isa<FPMathOperator>(Replacement))
97             Replacement->copyFastMathFlags(&I);
98 
99           Replacement->copyIRFlags(&I);
100           Replacement->copyMetadata(I);
101           Replacement->takeName(&I);
102           I.replaceAllUsesWith(Replacement);
103           I.eraseFromParent();
104         }
105       }
106   }
107 }
108 
109 void llvm::reduceOpcodesDeltaPass(TestRunner &Test) {
110   runDeltaPass(Test, replaceOpcodesInModule, "Reducing Opcodes");
111 }
112