Index: bolt/include/bolt/Core/BinaryFunction.h =================================================================== --- bolt/include/bolt/Core/BinaryFunction.h +++ bolt/include/bolt/Core/BinaryFunction.h @@ -370,7 +370,8 @@ BinaryFunction *FoldedIntoFunction{nullptr}; /// All fragments for a parent function. - SmallPtrSet Fragments; + using FragmentsSetTy = SmallPtrSet; + FragmentsSetTy Fragments; /// The profile data for the number of times the function was executed. uint64_t ExecutionCount{COUNT_NO_PROFILE}; @@ -1768,6 +1769,12 @@ return llvm::is_contained(Fragments, &Other); } + /// Return the child fragment form parent function + iterator_range getFragments() const { + return iterator_range(Fragments.begin(), + Fragments.end()); + } + /// Returns if this function is a parent or child of \p Other function. bool isParentOrChildOf(const BinaryFunction &Other) const { return isChildOf(Other) || isParentOf(Other); Index: bolt/lib/Passes/RegReAssign.cpp =================================================================== --- bolt/lib/Passes/RegReAssign.cpp +++ bolt/lib/Passes/RegReAssign.cpp @@ -304,6 +304,10 @@ << " with " << BC.MRI->getName(ExtReg) << "\n\n"); swap(Function, ClassicReg, ExtReg); FuncsChanged.insert(&Function); + for (BinaryFunction *ChildFrag : Function.getFragments()) { + swap(*ChildFrag, ClassicReg, ExtReg); + FuncsChanged.insert(ChildFrag); + } ++Begin; if (Begin == End) break; @@ -345,6 +349,10 @@ (void)BC; swap(Function, RBX, Candidate); FuncsChanged.insert(&Function); + for (BinaryFunction *ChildFrag : Function.getFragments()) { + swap(*ChildFrag, RBX, Candidate); + FuncsChanged.insert(ChildFrag); + } return true; } @@ -404,7 +412,7 @@ for (auto &I : BC.getBinaryFunctions()) { BinaryFunction &Function = I.second; - if (!Function.isSimple() || Function.isIgnored()) + if (!Function.isSimple() || Function.isIgnored() || Function.isFragment()) continue; LLVM_DEBUG(dbgs() << "====================================\n"); Index: bolt/test/X86/reg-reassign-swap-cold.s =================================================================== --- /dev/null +++ bolt/test/X86/reg-reassign-swap-cold.s @@ -0,0 +1,66 @@ +# This test case reproduces a bug where, during register swapping, +# the code fragments associated with the function need to be swapped +# together (which may be generated during PGO optimization). If not +# handled properly, optimized binary execution can result in a segmentation fault. + +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: link_fdata %s %t.o %t.fdata +# RUN: %clang -no-pie %t.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.out -data=%t.fdata --reg-reassign | FileCheck %s +# RUN: %t.out + +# CHECK: BOLT-INFO: Reg Reassignment Pass Stats +# CHECK-NEXT: 2 functions affected. + .text + .file "a.c" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function + .type main.cold,@function +main.cold: +.L1: + leaq .Lstr(%rip), %rdi + callq puts@PLT + mov $113, %rbx + jmp .L3 +main: # @main + .cfi_startproc +# %bb.0: # %entry + pushq %rax + pushq %r15 + pushq %rbx + .cfi_def_cfa_offset 16 + mov $1, %r15 + mov $111, %rbx +.L2: + jmp .L1 + add $1, %r15 +.L3: + cmp $113, %r15 + je .Lstr + xorl %eax, %eax + popq %rcx + popq %rbx + popq %r15 + .cfi_def_cfa_offset 8 + retq +# FDATA: 1 main.cold/1 7 1 puts@PLT 0 0 1 +# FDATA: 1 main.cold/1 13 1 main 0 0 100 +# FDATA: 1 main 1c 1 main 22 0 100 +# FDATA: 1 main 12 1 main.cold/1 0 0 100 + +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .type .Lstr,@object # @str + .section .rodata.str1.1,"aMS",@progbits,1 +.Lstr: + .asciz "success" + .size .Lstr, 8 + + .ident "clang version 15.0.4 (8589d40d00b8)" + .section ".note.GNU-stack","",@progbits + .addrsig