# This reproduces a bug with instrumentation when trying to instrument
# functions that share a jump table with multiple indirect jumps. Usually,
# each indirect jump that uses a JT will have its own copy of it. When
# this does not happen, we need to duplicate the jump table safely, so
# we can split the edges correctly (each copy of the jump table may have
# different split edges). For this to happen, we need to correctly match
# the sequence of instructions that perform the indirect jump to identify
# the base address of the jump table and patch it to point to the new
# cloned JT.
#
# Here we test this variant:
# movq jt.2397(,%rax,8), %rax
# jmp *%rax
#
# Which is suboptimal since the compiler could've avoided using an intermediary
# register, but GCC does generate this code and it triggered a bug in our
# matcher. Usual jumps in non-PIC code have this format:
#
# jmp *jt.2397(,%rax,8)
#
# This is the C code fed to GCC:
# #include <stdio.h>
#int interp(char* code) {
# static void* jt[] = { &&op_end, &&op_inc, &&do_dec };
# int pc = 0;
# int res = 0;
# goto *jt[code[pc++] - '0'];
#
#op_inc:
# res += 1;
# printf("%d\n", res);
# goto *jt[code[pc++] - '0'];
#do_dec:
# res -= 1;
# printf("%d\n", res);
# goto *jt[code[pc++] - '0'];
#op_end:
# return res;
#}
#int main(int argc, char** argv) {
# return interp(argv[1]);
#}
# REQUIRES: system-linux,bolt-runtime
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
# RUN: %s -o %t.o
# RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe --instrument --instrumentation-file=%t.fdata \
# RUN: -o %t.instrumented
# Instrumented program needs to finish returning zero
# RUN: %t.instrumented 120
# Test that the instrumented data makes sense
# RUN: llvm-bolt %t.exe -o %t.bolted --data %t.fdata \
# RUN: --reorder-blocks=ext-tsp --reorder-functions=hfsort+ \
# RUN: --print-only=interp --print-finalized | FileCheck %s
# RUN: %t.bolted 120
# Check that our two indirect jumps are recorded in the fdata file and that
# each has its own independent profile
# CHECK: Successors: .Ltmp1 (mispreds: 0, count: 1), .Ltmp0 (mispreds: 0, count: 0), .Ltmp2 (mispreds: 0, count: 0)
# CHECK: Successors: .Ltmp0 (mispreds: 0, count: 1), .Ltmp2 (mispreds: 0, count: 1), .Ltmp1 (mispreds: 0, count: 0)
.file "test.c"
.text
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d\n"
.text
.p2align 4,,15
.globl interp
.type interp, @function
interp:
.LFB11:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
xorl %ebp, %ebp
pushq %rbx
.cfi_def_cfa_offset 24
.cfi_offset 3, -24
leaq 1(%rdi), %rbx
subq $8, %rsp
.cfi_def_cfa_offset 32
movsbl (%rdi), %eax
subl $48, %eax
cltq
movq jt.2397(,%rax,8), %rax
jmp *%rax
.p2align 4,,10
.p2align 3
.L3:
addl $1, %ebp
.L8:
movl %ebp, %esi
movl $.LC0, %edi
xorl %eax, %eax
addq $1, %rbx
call printf
movsbl -1(%rbx), %eax
subl $48, %eax
cltq
movq jt.2397(,%rax,8), %rax
jmp *%rax
.p2align 4,,10
.p2align 3
.L6:
addq $8, %rsp
.cfi_remember_state
.cfi_def_cfa_offset 24
movl %ebp, %eax
popq %rbx
.cfi_def_cfa_offset 16
popq %rbp
.cfi_def_cfa_offset 8
ret
.p2align 4,,10
.p2align 3
.L4:
.cfi_restore_state
subl $1, %ebp
jmp .L8
.cfi_endproc
.LFE11:
.size interp, .-interp
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB12:
.cfi_startproc
movq 8(%rsi), %rdi
jmp interp
.cfi_endproc
.LFE12:
.size main, .-main
.section .rodata
.align 16
.type jt.2397, @object
.size jt.2397, 24
jt.2397:
.quad .L6
.quad .L3
.quad .L4
.ident "GCC: (GNU) 8"
.section .note.GNU-stack,"",@progbits