Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions llvm/include/llvm/Transforms/Scalar/IsolatePath.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===- IsolatePath.h - Path isolation for undefined behavior ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the interface for the IsolatePath pass.
//
// The pass identifies undefined behavior (UB) that is reachable via a PHI node
// that can select a null pointer. It then refactors the control-flow graph to
// isolate the UB-triggering path from the safe paths.
//
// Once isolated, the UB path is terminated, either with an 'unreachable'
// instruction or, optionally, with a 'trap' followed by 'unreachable'. This
// prevents the optimizer from making unsafe assumptions based on the presence
// of UB, which could otherwise lead to miscompilations.
//
// For example, a null pointer dereference is transformed from:
//
// bb:
// %phi = phi ptr [ %valid_ptr, %pred1 ], [ null, %pred2 ]
// %val = load i32, ptr %phi
//
// To:
//
// bb:
// %phi = phi ptr [ %valid_ptr, %pred1 ]
// %val = load i32, ptr %phi
// ...
//
// bb.ub.path:
// %phi.ub = phi ptr [ null, %pred2 ]
// unreachable
//
// Or to this with the optional trap-unreachable flag:
//
// bb.ub.path:
// %phi.ub = phi ptr [ null, %pred2 ]
// %val.ub = load volatile i32, ptr %phi.ub ; Optional trap
// call void @llvm.trap()
// unreachable
//
// This ensures that the presence of the null path does not interfere with
// valid code paths.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_SCALAR_ISOLATEPATH_H
#define LLVM_TRANSFORMS_SCALAR_ISOLATEPATH_H

#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/IR/PassManager.h"

namespace llvm {

class BasicBlock;
class DomTreeUpdater;
class Function;
class LoopInfo;

/// A pass that isolates paths with undefined behavior and converts the UB into
/// a trap or unreachable instruction.
class IsolatePathPass : public PassInfoMixin<IsolatePathPass> {
SmallPtrSet<BasicBlock *, 4> SplitUBBlocks;

bool ProcessPointerUndefinedBehavior(BasicBlock *BB, DomTreeUpdater *DTU,
LoopInfo *LI);

public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};

} // end namespace llvm

#endif // LLVM_TRANSFORMS_SCALAR_ISOLATEPATH_H
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@
#include "llvm/Transforms/Scalar/InferAddressSpaces.h"
#include "llvm/Transforms/Scalar/InferAlignment.h"
#include "llvm/Transforms/Scalar/InstSimplifyPass.h"
#include "llvm/Transforms/Scalar/IsolatePath.h"
#include "llvm/Transforms/Scalar/JumpTableToSwitch.h"
#include "llvm/Transforms/Scalar/JumpThreading.h"
#include "llvm/Transforms/Scalar/LICM.h"
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Passes/PassBuilderPipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
#include "llvm/Transforms/Scalar/IndVarSimplify.h"
#include "llvm/Transforms/Scalar/InferAlignment.h"
#include "llvm/Transforms/Scalar/InstSimplifyPass.h"
#include "llvm/Transforms/Scalar/IsolatePath.h"
#include "llvm/Transforms/Scalar/JumpTableToSwitch.h"
#include "llvm/Transforms/Scalar/JumpThreading.h"
#include "llvm/Transforms/Scalar/LICM.h"
Expand Down Expand Up @@ -598,6 +599,10 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true)));
}

// Isolate paths with undefined behavior. At this point, all inlinable
// functions should be inlined and constants propagated.
FPM.addPass(IsolatePathPass());

// Speculative execution if the target has divergent branches; otherwise nop.
FPM.addPass(SpeculativeExecutionPass(/* OnlyIfDivergentTarget =*/true));

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ FUNCTION_PASS("interleaved-access", InterleavedAccessPass(TM))
FUNCTION_PASS("interleaved-load-combine", InterleavedLoadCombinePass(TM))
FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass())
FUNCTION_PASS("irce", IRCEPass())
FUNCTION_PASS("isolate-path", IsolatePathPass());
FUNCTION_PASS("jump-threading", JumpThreadingPass())
FUNCTION_PASS("jump-table-to-switch", JumpTableToSwitchPass());
FUNCTION_PASS("kcfi", KCFIPass())
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Scalar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ add_llvm_component_library(LLVMScalarOpts
InferAddressSpaces.cpp
InferAlignment.cpp
InstSimplifyPass.cpp
IsolatePath.cpp
JumpThreading.cpp
JumpTableToSwitch.cpp
LICM.cpp
Expand Down
Loading
Loading