Skip to content

Commit fb47115

Browse files
[llvm] boilerplate for new callbrprepare codegen IR pass
Because this pass is to be a codegen pass, it must use the legacy pass manager. Link: https://discourse.llvm.org/t/rfc-syncing-asm-goto-with-outputs-with-gcc/65453/8 Reviewed By: aeubanks, void Differential Revision: https://reviews.llvm.org/D139861
1 parent 45a291b commit fb47115

File tree

11 files changed

+118
-1
lines changed

11 files changed

+118
-1
lines changed

llvm/include/llvm/CodeGen/CodeGenPassBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,7 @@ template <typename Derived>
714714
void CodeGenPassBuilder<Derived>::addISelPrepare(AddIRPass &addPass) const {
715715
derived().addPreISel(addPass);
716716

717+
// addPass(CallBrPrepare()); // TODO(ndesaulniers): impl pass
717718
// Add both the safe stack and the stack protection passes: each of them will
718719
// only protect functions that have corresponding attributes.
719720
addPass(SafeStackPass());

llvm/include/llvm/CodeGen/MachinePassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ DUMMY_FUNCTION_PASS("cfguard-dispatch", CFGuardDispatchPass, ())
123123
DUMMY_FUNCTION_PASS("cfguard-check", CFGuardCheckPass, ())
124124
DUMMY_FUNCTION_PASS("gc-info-printer", GCInfoPrinterPass, ())
125125
DUMMY_FUNCTION_PASS("select-optimize", SelectOptimizePass, ())
126+
DUMMY_FUNCTION_PASS("callbrprepare", CallBrPrepare, ())
126127
#undef DUMMY_FUNCTION_PASS
127128

128129
#ifndef DUMMY_MODULE_PASS

llvm/include/llvm/CodeGen/Passes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,8 @@ namespace llvm {
597597

598598
/// This pass converts conditional moves to conditional jumps when profitable.
599599
FunctionPass *createSelectOptimizePass();
600+
601+
FunctionPass *createCallBrPass();
600602
} // End llvm namespace
601603

602604
#endif

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ void initializeCFGuardLongjmpPass(PassRegistry&);
8383
void initializeCFGViewerLegacyPassPass(PassRegistry&);
8484
void initializeCFIFixupPass(PassRegistry&);
8585
void initializeCFIInstrInserterPass(PassRegistry&);
86+
void initializeCallBrPreparePass(PassRegistry &);
8687
void initializeCallGraphDOTPrinterPass(PassRegistry&);
8788
void initializeCallGraphPrinterLegacyPassPass(PassRegistry&);
8889
void initializeCallGraphViewerPass(PassRegistry&);

llvm/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ add_llvm_component_library(LLVMCodeGen
3535
BasicBlockSections.cpp
3636
BasicBlockSectionsProfileReader.cpp
3737
CalcSpillWeights.cpp
38+
CallBrPrepare.cpp
3839
CallingConvLower.cpp
3940
CFGuardLongjmp.cpp
4041
CFIFixup.cpp

llvm/lib/CodeGen/CallBrPrepare.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===-- CallBrPrepare - Prepare callbr for code generation ----------------===//
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+
// This pass lowers callbrs in LLVM IR in order to to assist SelectionDAG's
10+
// codegen.
11+
//
12+
// In particular, this pass assists in inserting register copies for the output
13+
// values of a callbr along the edges leading to the indirect target blocks.
14+
// Though the output SSA value is defined by the callbr instruction itself in
15+
// the IR representation, the value cannot be copied to the appropriate virtual
16+
// registers prior to jumping to an indirect label, since the jump occurs
17+
// within the user-provided assembly blob.
18+
//
19+
// Instead, those copies must occur separately at the beginning of each
20+
// indirect target. That requires that we create a separate SSA definition in
21+
// each of them (via llvm.callbr.landingpad), and may require splitting
22+
// critical edges so we have a location to place the intrinsic. Finally, we
23+
// remap users of the original callbr output SSA value to instead point to the
24+
// appropriate llvm.callbr.landingpad value.
25+
//
26+
// Ideally, this could be done inside SelectionDAG, or in the
27+
// MachineInstruction representation, without the use of an IR-level intrinsic.
28+
// But, within the current framework, it’s simpler to implement as an IR pass.
29+
// (If support for callbr in GlobalISel is implemented, it’s worth considering
30+
// whether this is still required.)
31+
//
32+
//===----------------------------------------------------------------------===//
33+
34+
#include "llvm/CodeGen/Passes.h"
35+
#include "llvm/IR/BasicBlock.h"
36+
#include "llvm/IR/Function.h"
37+
#include "llvm/IR/Instructions.h"
38+
#include "llvm/InitializePasses.h"
39+
#include "llvm/Pass.h"
40+
41+
using namespace llvm;
42+
43+
#define DEBUG_TYPE "callbrprepare"
44+
45+
namespace {
46+
47+
class CallBrPrepare : public FunctionPass {
48+
public:
49+
CallBrPrepare() : FunctionPass(ID) {}
50+
static char ID;
51+
void getAnalysisUsage(AnalysisUsage &AU) const override;
52+
bool runOnFunction(Function &Fn) override;
53+
};
54+
55+
} // end anonymous namespace
56+
57+
char CallBrPrepare::ID = 0;
58+
INITIALIZE_PASS(CallBrPrepare, DEBUG_TYPE, "Prepare callbr", false, false)
59+
60+
FunctionPass *llvm::createCallBrPass() { return new CallBrPrepare(); }
61+
62+
void CallBrPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
63+
AU.setPreservesAll();
64+
}
65+
66+
bool CallBrPrepare::runOnFunction(Function &Fn) {
67+
for (BasicBlock &BB : Fn) {
68+
auto *CBR = dyn_cast<CallBrInst>(BB.getTerminator());
69+
if (!CBR)
70+
continue;
71+
// TODO: something interesting.
72+
// https://discourse.llvm.org/t/rfc-syncing-asm-goto-with-outputs-with-gcc/65453/8
73+
}
74+
return false;
75+
}

llvm/lib/CodeGen/CodeGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
2424
initializeBasicBlockSectionsPass(Registry);
2525
initializeBranchFolderPassPass(Registry);
2626
initializeBranchRelaxationPass(Registry);
27+
initializeCallBrPreparePass(Registry);
2728
initializeCFGuardLongjmpPass(Registry);
2829
initializeCFIFixupPass(Registry);
2930
initializeCFIInstrInserterPass(Registry);

llvm/lib/CodeGen/TargetPassConfig.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,8 @@ void TargetPassConfig::addISelPrepare() {
978978
if (requiresCodeGenSCCOrder())
979979
addPass(new DummyCGSCCPass);
980980

981+
// addPass(createCallBrPass()); // TODO(ndesaulniers): impl pass
982+
981983
// Add both the safe stack and the stack protection passes: each of them will
982984
// only protect functions that have corresponding attributes.
983985
addPass(createSafeStackPass());
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt %s -callbrprepare -S -o - | FileCheck %s
3+
4+
; TODO: update this test to split critical edges.
5+
define i32 @test0() {
6+
; CHECK-LABEL: @test0(
7+
; CHECK-NEXT: entry:
8+
; CHECK-NEXT: [[OUT:%.*]] = callbr i32 asm "# $0", "=r,!i"()
9+
; CHECK-NEXT: to label [[DIRECT:%.*]] [label %indirect]
10+
; CHECK: direct:
11+
; CHECK-NEXT: [[OUT2:%.*]] = callbr i32 asm "# $0", "=r,!i"()
12+
; CHECK-NEXT: to label [[DIRECT2:%.*]] [label %indirect]
13+
; CHECK: direct2:
14+
; CHECK-NEXT: ret i32 0
15+
; CHECK: indirect:
16+
; CHECK-NEXT: [[OUT3:%.*]] = phi i32 [ [[OUT]], [[ENTRY:%.*]] ], [ [[OUT2]], [[DIRECT]] ]
17+
; CHECK-NEXT: ret i32 [[OUT3]]
18+
;
19+
entry:
20+
%out = callbr i32 asm "# $0", "=r,!i"()
21+
to label %direct [label %indirect]
22+
direct:
23+
%out2 = callbr i32 asm "# $0", "=r,!i"()
24+
to label %direct2 [label %indirect]
25+
direct2:
26+
ret i32 0
27+
indirect:
28+
%out3 = phi i32 [%out, %entry], [%out2, %direct]
29+
ret i32 %out3
30+
}

llvm/tools/opt/opt.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ static bool shouldPinPassToLegacyPM(StringRef Pass) {
392392
"expand-large-div-rem",
393393
"structurizecfg",
394394
"fix-irreducible",
395-
"expand-large-fp-convert"
395+
"expand-large-fp-convert",
396+
"callbrprepare",
396397
};
397398
for (const auto &P : PassNamePrefix)
398399
if (Pass.startswith(P))
@@ -444,6 +445,7 @@ int main(int argc, char **argv) {
444445
initializeExpandMemCmpPassPass(Registry);
445446
initializeScalarizeMaskedMemIntrinLegacyPassPass(Registry);
446447
initializeSelectOptimizePass(Registry);
448+
initializeCallBrPreparePass(Registry);
447449
initializeCodeGenPreparePass(Registry);
448450
initializeAtomicExpandPass(Registry);
449451
initializeRewriteSymbolsLegacyPassPass(Registry);

llvm/utils/gn/secondary/llvm/lib/CodeGen/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ static_library("CodeGen") {
3434
"CFIFixup.cpp",
3535
"CFIInstrInserter.cpp",
3636
"CalcSpillWeights.cpp",
37+
"CallBrPrepare.cpp",
3738
"CallingConvLower.cpp",
3839
"CodeGen.cpp",
3940
"CodeGenCommonISel.cpp",

0 commit comments

Comments
 (0)