Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/IPO/FatLTOCleanup.cpp
213799 views
//===- FatLtoCleanup.cpp - clean up IR for the FatLTO pipeline --*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines operations used to clean up IR for the FatLTO pipeline.9// Instrumentation that is beneficial for bitcode sections used in LTO may10// need to be cleaned up to finish non-LTO compilation. llvm.checked.load is11// an example of an instruction that we want to preserve for LTO, but is12// incorrect to leave unchanged during the per-TU compilation in FatLTO.13//14//===----------------------------------------------------------------------===//1516#include "llvm/Transforms/IPO/FatLTOCleanup.h"17#include "llvm/IR/Function.h"18#include "llvm/IR/IRBuilder.h"19#include "llvm/IR/Intrinsics.h"20#include "llvm/IR/Module.h"21#include "llvm/IR/PassManager.h"22#include "llvm/IR/Use.h"23#include "llvm/Support/Debug.h"2425using namespace llvm;2627#define DEBUG_TYPE "fatlto-cleanup"2829namespace {30// Replaces uses of llvm.type.checked.load instructions with unchecked loads.31// In essence, we're undoing the frontends instrumentation, since it isn't32// correct for the non-LTO part of a FatLTO object.33//34// llvm.type.checked.load instruction sequences always have a particular form:35//36// clang-format off37//38// %0 = tail call { ptr, i1 } @llvm.type.checked.load(ptr %vtable, i32 0, metadata !"foo"), !nosanitize !039// %1 = extractvalue { ptr, i1 } %0, 1, !nosanitize !040// br i1 %1, label %cont2, label %trap1, !nosanitize !041//42// trap1: ; preds = %entry43// tail call void @llvm.ubsantrap(i8 2) #3, !nosanitize !044// unreachable, !nosanitize !045//46// cont2: ; preds = %entry47// %2 = extractvalue { ptr, i1 } %0, 0, !nosanitize !048// %call = tail call noundef i64 %2(ptr noundef nonnull align 8 dereferenceable(8) %p1) #449//50// clang-format on51//52// In this sequence, the vtable pointer is first loaded and checked against some53// metadata. The result indicates failure, then the program traps. On the54// success path, the pointer is used to make an indirect call to the function55// pointer loaded from the vtable.56//57// Since we won't be able to lower this correctly later in non-LTO builds, we58// need to drop the special load and trap, and emit a normal load of the59// function pointer from the vtable.60//61// This is straight forward, since the checked load can be replaced w/ a load62// of the vtable pointer and a GEP instruction to index into the vtable and get63// the correct method/function pointer. We replace the "check" with a constant64// indicating success, which allows later passes to simplify control flow and65// remove any now dead instructions.66//67// This logic holds for both llvm.type.checked.load and68// llvm.type.checked.load.relative instructions.69static bool cleanUpTypeCheckedLoad(Module &M, Function &CheckedLoadFn,70bool IsRelative) {71bool Changed = false;72for (User *User : llvm::make_early_inc_range(CheckedLoadFn.users())) {73Instruction *I = dyn_cast<Instruction>(User);74if (!I)75continue;76IRBuilder<> IRB(I);77Value *Ptr = I->getOperand(0);78Value *Offset = I->getOperand(1);79Type *PtrTy = I->getType()->getStructElementType(0);80ConstantInt *True = ConstantInt::getTrue(M.getContext());81Instruction *Load;82if (IsRelative) {83Load =84IRB.CreateIntrinsic(Intrinsic::load_relative, {Offset->getType()},85{Ptr, Offset}, /*FMFSource=*/nullptr, "rel_load");86} else {87Value *PtrAdd = IRB.CreatePtrAdd(Ptr, Offset);88Load = IRB.CreateLoad(PtrTy, PtrAdd, "vfunc");89}9091Value *Replacement = PoisonValue::get(I->getType());92Replacement = IRB.CreateInsertValue(Replacement, True, {1});93Replacement = IRB.CreateInsertValue(Replacement, Load, {0});94I->replaceAllUsesWith(Replacement);9596LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": erase " << *I << "\n");97I->eraseFromParent();98Changed = true;99}100if (Changed)101CheckedLoadFn.eraseFromParent();102return Changed;103}104} // namespace105106PreservedAnalyses FatLtoCleanup::run(Module &M, ModuleAnalysisManager &AM) {107Function *TypeCheckedLoadFn =108Intrinsic::getDeclarationIfExists(&M, Intrinsic::type_checked_load);109Function *TypeCheckedLoadRelFn = Intrinsic::getDeclarationIfExists(110&M, Intrinsic::type_checked_load_relative);111112bool Changed = false;113if (TypeCheckedLoadFn)114Changed |= cleanUpTypeCheckedLoad(M, *TypeCheckedLoadFn, false);115if (TypeCheckedLoadRelFn)116Changed |= cleanUpTypeCheckedLoad(M, *TypeCheckedLoadRelFn, true);117118if (Changed)119return PreservedAnalyses::none();120return PreservedAnalyses::all();121}122123124