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