1 /* 2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef LIBLLVMBACKEND_TRANSFORMS_PASSES_GC_INTRUSION_H 17 #define LIBLLVMBACKEND_TRANSFORMS_PASSES_GC_INTRUSION_H 18 19 #include <llvm/ADT/SetVector.h> 20 #include <llvm/IR/IRBuilder.h> 21 #include <llvm/IR/PassManager.h> 22 23 namespace ark::llvmbackend { 24 struct LLVMCompilerOptions; 25 } // namespace ark::llvmbackend 26 27 namespace ark::llvmbackend::passes { 28 29 class GcRefLiveness; 30 31 class GcIntrusion : public llvm::PassInfoMixin<GcIntrusion> { 32 public: ShouldInsert(const ark::llvmbackend::LLVMCompilerOptions * options)33 static bool ShouldInsert([[maybe_unused]] const ark::llvmbackend::LLVMCompilerOptions *options) 34 { 35 return true; 36 } 37 38 // NOLINTNEXTLINE(readability-identifier-naming) 39 llvm::PreservedAnalyses run(llvm::Function &function, llvm::FunctionAnalysisManager &analysisManager); 40 41 private: 42 using SSAVarRelocs = llvm::DenseMap<llvm::Value *, llvm::DenseMap<llvm::BasicBlock *, llvm::Value *>>; 43 using InstructionOrderMap = llvm::DenseMap<llvm::Value *, uint64_t>; 44 using SortedUses = llvm::DenseMap<llvm::Value *, std::list<llvm::Use *>>; 45 using RPOMap = llvm::DenseMap<llvm::BasicBlock *, uint32_t>; 46 struct GcIntrusionContext { 47 SSAVarRelocs relocs; 48 InstructionOrderMap orderMap; 49 SortedUses sortedUses; 50 RPOMap rpoMap; 51 }; 52 53 void RewriteWithGcInBlock(llvm::BasicBlock *block, GcRefLiveness *liveness, llvm::SetVector<llvm::Value *> *alive, 54 llvm::DenseSet<llvm::BasicBlock *> *visited, GcIntrusionContext *gcContext); 55 56 static bool ComesBefore(llvm::Value *a, llvm::Value *b, InstructionOrderMap *orderMap); 57 58 void HoistForRelocation(llvm::Function *function); 59 60 bool MoveComparisons(llvm::Function *function); 61 62 void FixupEscapedUsages(llvm::Instruction *inst, const llvm::SmallVector<llvm::Instruction *> &casts); 63 64 llvm::Value *CreateBackwardCasts(llvm::IRBuilder<> *builder, llvm::Value *from, 65 const llvm::SmallVector<llvm::Instruction *> &casts); 66 67 uint32_t GetStatepointId(const llvm::Instruction &inst); 68 69 void ReplaceWithPhi(llvm::Value *var, llvm::BasicBlock *block, GcIntrusionContext *gcContext); 70 71 void PropagateRelocs(GcRefLiveness *liveness, llvm::DenseSet<llvm::BasicBlock *> *visited, llvm::BasicBlock *block, 72 GcIntrusionContext *gcContext); 73 74 void CopySinglePredRelocs(GcRefLiveness *liveness, llvm::BasicBlock *block, GcIntrusionContext *gcContext); 75 76 llvm::Value *GetUniqueLiveOut(SSAVarRelocs *relocs, llvm::BasicBlock *block, llvm::Value *var) const; 77 78 void ReplaceWithRelocated(llvm::CallInst *call, llvm::CallInst *gcCall, llvm::Value *inst, llvm::Value *relocated, 79 GcIntrusionContext *gcContext); 80 81 void RewriteWithGc(llvm::CallInst *call, GcRefLiveness *liveness, llvm::SetVector<llvm::Value *> *refs, 82 GcIntrusionContext *gcContext); 83 84 std::vector<llvm::Value *> GetDeoptsFromInlineInfo(llvm::IRBuilder<> &builder, llvm::CallInst *call); 85 86 void CreateSortedUseList(llvm::BasicBlock *block, llvm::Value *from, GcIntrusionContext *gcContext); 87 88 void ReplaceDominatedUses(llvm::Value *from, llvm::Value *to, llvm::BasicBlock *block, 89 GcIntrusionContext *gcContext); 90 91 void UpdatePhiInputs(llvm::BasicBlock *block, SSAVarRelocs *relocs); 92 93 public: 94 static constexpr llvm::StringRef ARG_NAME = "gc-intrusion"; 95 }; 96 97 } // namespace ark::llvmbackend::passes 98 99 #endif // LIBLLVMBACKEND_TRANSFORMS_PASSES_GC_INTRUSION_H 100