blob: 436c1bb848a11557823b12107b067ce2f2707b60 [file] [edit]
; Tests basic CopyProf instrumentation of special member functions.
;
; RUN: opt < %s -passes='function(copyprof),module(copyprof-module)' -S | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"
;; Verifies that the module constructor and global ctors are set up.
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }]
; CHECK-SAME: i32 0, ptr @copyprof.module_ctor
;; Tests constructor instrumentation (1-arg: this).
define void @ctor(ptr %this) "copyprof-ctor"="24" {
entry:
%field = getelementptr i8, ptr %this, i64 8
store i32 0, ptr %field
ret void
}
; CHECK-LABEL: define void @ctor(ptr %this)
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @__copyprof_ctor_enter_callback(ptr %this, i64 24)
; CHECK-NOT: call void @__copyprof_ctor_enter_callback
; CHECK: call void @__copyprof_ctor_exit_callback(ptr %this, i64 24)
; CHECK-NEXT: ret void
;; Tests copy constructor instrumentation (2-arg: this, other).
define void @copy_ctor(ptr %this, ptr %other) "copyprof-copy-ctor"="16" {
entry:
%val = load i32, ptr %other
store i32 %val, ptr %this
ret void
}
; CHECK-LABEL: define void @copy_ctor(ptr %this, ptr %other)
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @__copyprof_copy_ctor_enter_callback(ptr %this, ptr %other, i64 16)
; CHECK-NOT: call void @__copyprof_copy_ctor_enter_callback
; CHECK: call void @__copyprof_copy_ctor_exit_callback(ptr %this, ptr %other, i64 16)
; CHECK-NEXT: ret void
;; Tests copy assignment operator instrumentation (2-arg: this, other).
define void @copy_assign(ptr %this, ptr %other) "copyprof-copy-assign-op"="32" {
entry:
%val = load i64, ptr %other
store i64 %val, ptr %this
ret void
}
; CHECK-LABEL: define void @copy_assign(ptr %this, ptr %other)
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @__copyprof_copy_assign_op_enter_callback(ptr %this, ptr %other, i64 32)
; CHECK-NOT: call void @__copyprof_copy_assign_op_enter_callback
; CHECK: call void @__copyprof_copy_assign_op_exit_callback(ptr %this, ptr %other, i64 32)
; CHECK-NEXT: ret void
;; Tests destructor instrumentation (1-arg: this).
define void @dtor(ptr %this) "copyprof-dtor"="24" {
entry:
ret void
}
; CHECK-LABEL: define void @dtor(ptr %this)
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @__copyprof_dtor_enter_callback(ptr %this, i64 24)
; CHECK-NOT: call void @__copyprof_dtor_enter_callback
; CHECK: call void @__copyprof_dtor_exit_callback(ptr %this, i64 24)
; CHECK-NEXT: ret void
;; Tests that exit callbacks are inserted before multiple return instructions.
define void @ctor_multi_ret(ptr %this, i1 %cond) "copyprof-ctor"="8" {
entry:
br i1 %cond, label %then, label %else
then:
ret void
else:
ret void
}
; CHECK-LABEL: define void @ctor_multi_ret(ptr %this, i1 %cond)
; CHECK: call void @__copyprof_ctor_enter_callback(ptr %this, i64 8)
; CHECK-NOT: call void @__copyprof_ctor_enter_callback
; CHECK: then:
; CHECK: call void @__copyprof_ctor_exit_callback(ptr %this, i64 8)
; CHECK-NEXT: ret void
; CHECK: else:
; CHECK: call void @__copyprof_ctor_exit_callback(ptr %this, i64 8)
; CHECK-NEXT: ret void
;; Tests that exit callbacks are inserted before resume instructions
;; (exception unwinding).
define void @ctor_with_resume(ptr %this) "copyprof-ctor"="8" personality ptr @__gxx_personality_v0 {
entry:
invoke void @may_throw() to label %cont unwind label %lpad
cont:
ret void
lpad:
%lp = landingpad { ptr, i32 } cleanup
resume { ptr, i32 } %lp
}
declare void @may_throw()
declare i32 @__gxx_personality_v0(...)
; CHECK-LABEL: define void @ctor_with_resume(ptr %this)
; CHECK: call void @__copyprof_ctor_enter_callback(ptr %this, i64 8)
; CHECK: cont:
; CHECK: call void @__copyprof_ctor_exit_callback(ptr %this, i64 8)
; CHECK-NEXT: ret void
; CHECK: lpad:
; CHECK: call void @__copyprof_ctor_exit_callback(ptr %this, i64 8)
; CHECK-NEXT: resume
;; Tests that a function containing a musttail call is skipped entirely.
declare void @tail_callee(ptr)
define void @ctor_with_musttail(ptr %this) "copyprof-ctor"="8" {
entry:
musttail call void @tail_callee(ptr %this)
ret void
}
; CHECK-LABEL: define void @ctor_with_musttail(ptr %this)
; CHECK-NEXT: entry:
; CHECK-NEXT: musttail call void @tail_callee(ptr %this)
; CHECK-NEXT: ret void
; CHECK-NOT: call void @__copyprof_
;; Tests that a function containing an ordinary tail call is instrumented normally,
;; with the exit callback inserted between the tail call and return instructions.
define void @ctor_with_tail(ptr %this) "copyprof-ctor"="8" {
entry:
tail call void @tail_callee(ptr %this)
ret void
}
; CHECK-LABEL: define void @ctor_with_tail(ptr %this)
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @__copyprof_ctor_enter_callback(ptr %this, i64 8)
; CHECK-NEXT: tail call void @tail_callee(ptr %this)
; CHECK-NEXT: call void @__copyprof_ctor_exit_callback(ptr %this, i64 8)
; CHECK-NEXT: ret void
;; Tests that entry callbacks are inserted after alloca instructions.
define void @ctor_with_alloca(ptr %this) "copyprof-ctor"="8" {
entry:
%tmp = alloca i32
store i32 0, ptr %tmp
ret void
}
; CHECK-LABEL: define void @ctor_with_alloca(ptr %this)
; CHECK: %tmp = alloca i32
; CHECK-NEXT: call void @__copyprof_ctor_enter_callback(ptr %this, i64 8)
; CHECK: call void @__copyprof_ctor_exit_callback(ptr %this, i64 8)
; CHECK-NEXT: ret void
;; Tests that no exit callback is inserted before unreachable terminators.
define void @ctor_with_unreachable(ptr %this) "copyprof-ctor"="8" {
entry:
call void @may_throw()
unreachable
}
; CHECK-LABEL: define void @ctor_with_unreachable(ptr %this)
; CHECK: call void @__copyprof_ctor_enter_callback(ptr %this, i64 8)
; CHECK-NOT: call void @__copyprof_ctor_exit_callback
; CHECK: unreachable
;; Verifies that the module constructor calls the init function and is marked so
;; that it's never instrumented itself.
; CHECK: define internal void @copyprof.module_ctor()
; CHECK: call void @__copyprof_init_once()
; CHECK: disable_sanitizer_instrumentation