| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| // Tests that we assign appropriate identifiers to indirect calls and targets | ||
| // specifically for C++ class and instance methods. | ||
|
|
||
| // RUN: %clang_cc1 -triple x86_64-unknown-linux -fcall-graph-section -S \ | ||
| // RUN: -emit-llvm -o %t %s | ||
| // RUN: FileCheck --check-prefix=FT %s < %t | ||
| // RUN: FileCheck --check-prefix=CST %s < %t | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // Class definitions (check for indirect target metadata) | ||
|
|
||
| class Cls1 { | ||
| public: | ||
| // FT-DAG: define {{.*}} ptr @_ZN4Cls18receiverEPcPf({{.*}} !type [[F_TCLS1RECEIVER:![0-9]+]] | ||
| static int *receiver(char *a, float *b) { return 0; } | ||
| }; | ||
|
|
||
| class Cls2 { | ||
| public: | ||
| int *(*fp)(char *, float *); | ||
|
|
||
| // FT-DAG: define {{.*}} i32 @_ZN4Cls22f1Ecfd({{.*}} !type [[F_TCLS2F1:![0-9]+]] | ||
| int f1(char a, float b, double c) { return 0; } | ||
|
|
||
| // FT-DAG: define {{.*}} ptr @_ZN4Cls22f2EPcPfPd({{.*}} !type [[F_TCLS2F2:![0-9]+]] | ||
| int *f2(char *a, float *b, double *c) { return 0; } | ||
|
|
||
| // FT-DAG: define {{.*}} void @_ZN4Cls22f3E4Cls1({{.*}} !type [[F_TCLS2F3F4:![0-9]+]] | ||
| void f3(Cls1 a) {} | ||
|
|
||
| // FT-DAG: define {{.*}} void @_ZN4Cls22f4E4Cls1({{.*}} !type [[F_TCLS2F3F4]] | ||
| void f4(const Cls1 a) {} | ||
|
|
||
| // FT-DAG: define {{.*}} void @_ZN4Cls22f5EP4Cls1({{.*}} !type [[F_TCLS2F5:![0-9]+]] | ||
| void f5(Cls1 *a) {} | ||
|
|
||
| // FT-DAG: define {{.*}} void @_ZN4Cls22f6EPK4Cls1({{.*}} !type [[F_TCLS2F6:![0-9]+]] | ||
| void f6(const Cls1 *a) {} | ||
|
|
||
| // FT-DAG: define {{.*}} void @_ZN4Cls22f7ER4Cls1({{.*}} !type [[F_TCLS2F7:![0-9]+]] | ||
| void f7(Cls1 &a) {} | ||
|
|
||
| // FT-DAG: define {{.*}} void @_ZN4Cls22f8ERK4Cls1({{.*}} !type [[F_TCLS2F8:![0-9]+]] | ||
| void f8(const Cls1 &a) {} | ||
|
|
||
| // FT-DAG: define {{.*}} void @_ZNK4Cls22f9Ev({{.*}} !type [[F_TCLS2F9:![0-9]+]] | ||
| void f9() const {} | ||
| }; | ||
|
|
||
| // FT-DAG: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPvS_S_E.generalized"} | ||
| // FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPvS_S_S_E.generalized"} | ||
| // FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"} | ||
| // FT-DAG: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"} | ||
| // FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvPvE.generalized"} | ||
| // FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPKvE.generalized"} | ||
| // FT-DAG: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"} | ||
| // FT-DAG: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"} | ||
| // FT-DAG: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"} | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // Callsites (check for indirect callsite operand bundles) | ||
|
|
||
| // CST-LABEL: define {{.*}} @_Z3foov | ||
| void foo() { | ||
| Cls2 ObjCls2; | ||
| ObjCls2.fp = &Cls1::receiver; | ||
|
|
||
| // CST: call noundef ptr %{{.*}} [ "type"(metadata !"_ZTSFPvS_S_E.generalized") ] | ||
| ObjCls2.fp(0, 0); | ||
|
|
||
| auto fp_f1 = &Cls2::f1; | ||
| auto fp_f2 = &Cls2::f2; | ||
| auto fp_f3 = &Cls2::f3; | ||
| auto fp_f4 = &Cls2::f4; | ||
| auto fp_f5 = &Cls2::f5; | ||
| auto fp_f6 = &Cls2::f6; | ||
| auto fp_f7 = &Cls2::f7; | ||
| auto fp_f8 = &Cls2::f8; | ||
| auto fp_f9 = &Cls2::f9; | ||
|
|
||
| Cls2 *ObjCls2Ptr = &ObjCls2; | ||
| Cls1 Cls1Param; | ||
|
|
||
| // CST: call noundef i32 %{{.*}} [ "type"(metadata !"_ZTSFicfdE.generalized") ] | ||
| (ObjCls2Ptr->*fp_f1)(0, 0, 0); | ||
|
|
||
| // CST: call noundef ptr %{{.*}} [ "type"(metadata !"_ZTSFPvS_S_S_E.generalized") ] | ||
| (ObjCls2Ptr->*fp_f2)(0, 0, 0); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFv4Cls1E.generalized") ] | ||
| (ObjCls2Ptr->*fp_f3)(Cls1Param); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFv4Cls1E.generalized") ] | ||
| (ObjCls2Ptr->*fp_f4)(Cls1Param); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPvE.generalized") ] | ||
| (ObjCls2Ptr->*fp_f5)(&Cls1Param); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPKvE.generalized") ] | ||
| (ObjCls2Ptr->*fp_f6)(&Cls1Param); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvR4Cls1E.generalized") ] | ||
| (ObjCls2Ptr->*fp_f7)(Cls1Param); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvRK4Cls1E.generalized") ] | ||
| (ObjCls2Ptr->*fp_f8)(Cls1Param); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSKFvvE.generalized") ] | ||
| (ObjCls2Ptr->*fp_f9)(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| // Tests that we assign appropriate identifiers to indirect calls and targets | ||
| // specifically for C++ templates. | ||
|
|
||
| // RUN: %clang_cc1 -triple x86_64-unknown-linux -fcall-graph-section -S \ | ||
| // RUN: -emit-llvm -o %t %s | ||
| // RUN: FileCheck --check-prefix=FT %s < %t | ||
| // RUN: FileCheck --check-prefix=CST %s < %t | ||
| // RUN: FileCheck --check-prefix=CHECK %s < %t | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // Class definitions and template classes (check for indirect target metadata) | ||
|
|
||
| class Cls1 {}; | ||
|
|
||
| // Cls2 is instantiated with T=Cls1 in foo(). Following checks are for this | ||
| // instantiation. | ||
| template <class T> | ||
| class Cls2 { | ||
| public: | ||
| // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev({{.*}} !type [[F_TCLS2F1:![0-9]+]] | ||
| void f1() {} | ||
|
|
||
| // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_({{.*}} !type [[F_TCLS2F2:![0-9]+]] | ||
| void f2(T a) {} | ||
|
|
||
| // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_({{.*}} !type [[F_TCLS2F3:![0-9]+]] | ||
| void f3(T *a) {} | ||
|
|
||
| // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_({{.*}} !type [[F_TCLS2F4:![0-9]+]] | ||
| void f4(const T *a) {} | ||
|
|
||
| // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_({{.*}} !type [[F_TCLS2F5:![0-9]+]] | ||
| void f5(T &a) {} | ||
|
|
||
| // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_({{.*}} !type [[F_TCLS2F6:![0-9]+]] | ||
| void f6(const T &a) {} | ||
|
|
||
| // Mixed type function pointer member | ||
| T *(*fp)(T a, T *b, const T *c, T &d, const T &e); | ||
| }; | ||
|
|
||
| // FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"} | ||
| // FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"} | ||
| // FT-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvPvE.generalized"} | ||
| // FT-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPKvE.generalized"} | ||
| // FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"} | ||
| // FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"} | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // Callsites (check for indirect callsite operand bundles) | ||
|
|
||
| template <class T> | ||
| T *T_func(T a, T *b, const T *c, T &d, const T &e) { return b; } | ||
|
|
||
| // CST-LABEL: define {{.*}} @_Z3foov | ||
| void foo() { | ||
| // Methods for Cls2<Cls1> is checked above within the template description. | ||
| Cls2<Cls1> Obj; | ||
|
|
||
| // CHECK-DAG: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_({{.*}} !type [[F_TFUNC_CLS1:![0-9]+]] | ||
| // CHECK-DAG: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFPv4Cls1S_PKvRS0_RKS0_E.generalized"} | ||
| Obj.fp = T_func<Cls1>; | ||
| Cls1 Cls1Obj; | ||
|
|
||
| // CST: call noundef ptr %{{.*}} [ "type"(metadata !"_ZTSFPv4Cls1S_PKvRS0_RKS0_E.generalized") ] | ||
| Obj.fp(Cls1Obj, &Cls1Obj, &Cls1Obj, Cls1Obj, Cls1Obj); | ||
|
|
||
| // Make indirect calls to Cls2's member methods | ||
| auto fp_f1 = &Cls2<Cls1>::f1; | ||
| auto fp_f2 = &Cls2<Cls1>::f2; | ||
| auto fp_f3 = &Cls2<Cls1>::f3; | ||
| auto fp_f4 = &Cls2<Cls1>::f4; | ||
| auto fp_f5 = &Cls2<Cls1>::f5; | ||
| auto fp_f6 = &Cls2<Cls1>::f6; | ||
|
|
||
| auto *Obj2Ptr = &Obj; | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvvE.generalized") ] | ||
| (Obj2Ptr->*fp_f1)(); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFv4Cls1E.generalized") ] | ||
| (Obj2Ptr->*fp_f2)(Cls1Obj); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPvE.generalized") ] | ||
| (Obj2Ptr->*fp_f3)(&Cls1Obj); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvPKvE.generalized") ] | ||
| (Obj2Ptr->*fp_f4)(&Cls1Obj); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvR4Cls1E.generalized") ] | ||
| (Obj2Ptr->*fp_f5)(Cls1Obj); | ||
|
|
||
| // CST: call void %{{.*}} [ "type"(metadata !"_ZTSFvRK4Cls1E.generalized") ] | ||
| (Obj2Ptr->*fp_f6)(Cls1Obj); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // Tests that we assign appropriate identifiers to indirect calls and targets | ||
| // specifically for virtual methods. | ||
|
|
||
| // RUN: %clang_cc1 -triple x86_64-unknown-linux -fcall-graph-section -S \ | ||
| // RUN: -emit-llvm -o %t %s | ||
| // RUN: FileCheck --check-prefix=FT %s < %t | ||
| // RUN: FileCheck --check-prefix=CST %s < %t | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // Class definitions (check for indirect target metadata) | ||
|
|
||
| class Base { | ||
| public: | ||
| // FT-DAG: define {{.*}} @_ZN4Base2vfEPc({{.*}} !type [[F_TVF:![0-9]+]] | ||
| virtual int vf(char *a) { return 0; }; | ||
| }; | ||
|
|
||
| class Derived : public Base { | ||
| public: | ||
| // FT-DAG: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]] | ||
| int vf(char *a) override { return 1; }; | ||
| }; | ||
|
|
||
| // FT-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPvE.generalized"} | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // Callsites (check for indirect callsite operand bundles) | ||
|
|
||
| // CST-LABEL: define {{.*}} @_Z3foov | ||
| void foo() { | ||
| auto B = Base(); | ||
| auto D = Derived(); | ||
|
|
||
| Base *Bptr = &B; | ||
| Base *BptrToD = &D; | ||
| Derived *Dptr = &D; | ||
|
|
||
| auto FpBaseVf = &Base::vf; | ||
| auto FpDerivedVf = &Derived::vf; | ||
|
|
||
| // CST: call noundef i32 %{{.*}} [ "type"(metadata !"_ZTSFiPvE.generalized") ] | ||
| (Bptr->*FpBaseVf)(0); | ||
|
|
||
| // CST: call noundef i32 %{{.*}} [ "type"(metadata !"_ZTSFiPvE.generalized") ] | ||
| (BptrToD->*FpBaseVf)(0); | ||
|
|
||
| // CST: call noundef i32 %{{.*}} [ "type"(metadata !"_ZTSFiPvE.generalized") ] | ||
| (Dptr->*FpBaseVf)(0); | ||
|
|
||
| // CST: call noundef i32 %{{.*}} [ "type"(metadata !"_ZTSFiPvE.generalized") ] | ||
| (Dptr->*FpDerivedVf)(0); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| // Tests that we assign appropriate identifiers to indirect calls and targets. | ||
|
|
||
| // RUN: %clang_cc1 -triple x86_64-unknown-linux -fcall-graph-section -S \ | ||
| // RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,ITANIUM %s | ||
|
|
||
| // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fcall-graph-section -S \ | ||
| // RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s | ||
|
|
||
| // CHECK-DAG: define {{(dso_local)?}} void @foo({{.*}} !type [[F_TVOID:![0-9]+]] | ||
| void foo() { | ||
| } | ||
|
|
||
| // CHECK-DAG: define {{(dso_local)?}} void @bar({{.*}} !type [[F_TVOID]] | ||
| void bar() { | ||
| void (*fp)() = foo; | ||
| // ITANIUM: call {{.*}} [ "type"(metadata !"_ZTSFvE.generalized") ] | ||
| // MS: call {{.*}} [ "type"(metadata !"?6AX@Z.generalized") ] | ||
| fp(); | ||
| } | ||
|
|
||
| // CHECK-DAG: define {{(dso_local)?}} i32 @baz({{.*}} !type [[F_TPRIMITIVE:![0-9]+]] | ||
| int baz(char a, float b, double c) { | ||
| return 1; | ||
| } | ||
|
|
||
| // CHECK-DAG: define {{(dso_local)?}} ptr @qux({{.*}} !type [[F_TPTR:![0-9]+]] | ||
| int *qux(char *a, float *b, double *c) { | ||
| return 0; | ||
| } | ||
|
|
||
| // CHECK-DAG: define {{(dso_local)?}} void @corge({{.*}} !type [[F_TVOID]] | ||
| void corge() { | ||
| int (*fp_baz)(char, float, double) = baz; | ||
| // ITANIUM: call i32 {{.*}} [ "type"(metadata !"_ZTSFicfdE.generalized") ] | ||
| // MS: call i32 {{.*}} [ "type"(metadata !"?6AHDMN@Z.generalized") ] | ||
| fp_baz('a', .0f, .0); | ||
|
|
||
| int *(*fp_qux)(char *, float *, double *) = qux; | ||
| // ITANIUM: call ptr {{.*}} [ "type"(metadata !"_ZTSFPvS_S_S_E.generalized") ] | ||
| // MS: call ptr {{.*}} [ "type"(metadata !"?6APEAXPEAX00@Z.generalized") ] | ||
| fp_qux(0, 0, 0); | ||
| } | ||
|
|
||
| struct st1 { | ||
| int *(*fp)(char *, float *, double *); | ||
| }; | ||
|
|
||
| struct st2 { | ||
| struct st1 m; | ||
| }; | ||
|
|
||
| // CHECK-DAG: define {{(dso_local)?}} void @stparam({{.*}} !type [[F_TSTRUCT:![0-9]+]] | ||
| void stparam(struct st2 a, struct st2 *b) {} | ||
|
|
||
| // CHECK-DAG: define {{(dso_local)?}} void @stf({{.*}} !type [[F_TVOID]] | ||
| void stf() { | ||
| struct st1 St1; | ||
| St1.fp = qux; | ||
| // ITANIUM: call ptr {{.*}} [ "type"(metadata !"_ZTSFPvS_S_S_E.generalized") ] | ||
| // MS: call ptr {{.*}} [ "type"(metadata !"?6APEAXPEAX00@Z.generalized") ] | ||
| St1.fp(0, 0, 0); | ||
|
|
||
| struct st2 St2; | ||
| St2.m.fp = qux; | ||
| // ITANIUM: call ptr {{.*}} [ "type"(metadata !"_ZTSFPvS_S_S_E.generalized") ] | ||
| // MS: call ptr {{.*}} [ "type"(metadata !"?6APEAXPEAX00@Z.generalized") ] | ||
| St2.m.fp(0, 0, 0); | ||
|
|
||
| // ITANIUM: call void {{.*}} [ "type"(metadata !"_ZTSFv3st2PvE.generalized") ] | ||
| // MS: call void {{.*}} [ "type"(metadata !"?6AXUst2@@PEAX@Z.generalized") ] | ||
| void (*fp_stparam)(struct st2, struct st2 *) = stparam; | ||
| fp_stparam(St2, &St2); | ||
| } | ||
|
|
||
| // ITANIUM-DAG: [[F_TVOID]] = !{i64 0, !"_ZTSFvE.generalized"} | ||
| // MS-DAG: [[F_TVOID]] = !{i64 0, !"?6AX@Z.generalized"} | ||
|
|
||
| // ITANIUM-DAG: [[F_TPRIMITIVE]] = !{i64 0, !"_ZTSFicfdE.generalized"} | ||
| // MS-DAG: [[F_TPRIMITIVE]] = !{i64 0, !"?6AHDMN@Z.generalized"} | ||
|
|
||
| // ITANIUM-DAG: [[F_TPTR]] = !{i64 0, !"_ZTSFPvS_S_S_E.generalized"} | ||
| // MS-DAG: [[F_TPTR]] = !{i64 0, !"?6APEAXPEAX00@Z.generalized"} | ||
|
|
||
| // ITANIUM-DAG: [[F_TSTRUCT]] = !{i64 0, !"_ZTSFv3st2PvE.generalized"} | ||
| // MS-DAG: [[F_TSTRUCT]] = !{i64 0, !"?6AXUst2@@PEAX@Z.generalized"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| ;; Tests that call site type ids can be extracted and set from type operand | ||
| ;; bundles. | ||
|
|
||
| ;; Verify the exact typeId value to ensure it is not garbage but the value | ||
| ;; computed as the type id from the type operand bundle. | ||
| ; RUN: llc --call-graph-section -mtriple aarch64-linux-gnu < %s -stop-before=finalize-isel -o - | FileCheck %s | ||
|
|
||
| define dso_local void @foo(i8 signext %a) !type !3 { | ||
| entry: | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: name: main | ||
| define dso_local i32 @main() !type !4 { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| %fp = alloca ptr, align 8 | ||
| store i32 0, ptr %retval, align 4 | ||
| store ptr @foo, ptr %fp, align 8 | ||
| %0 = load ptr, ptr %fp, align 8 | ||
| ; CHECK: callSites: | ||
| ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId: | ||
| ; CHECK-NEXT: 7854600665770582568 } | ||
| call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ] | ||
| ret i32 0 | ||
| } | ||
|
|
||
| !3 = !{i64 0, !"_ZTSFvcE.generalized"} | ||
| !4 = !{i64 0, !"_ZTSFiE.generalized"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| ;; Tests that call site type ids can be extracted and set from type operand | ||
| ;; bundles. | ||
|
|
||
| ;; Verify the exact typeId value to ensure it is not garbage but the value | ||
| ;; computed as the type id from the type operand bundle. | ||
| ; RUN: llc --call-graph-section -mtriple arm-linux-gnu < %s -stop-before=finalize-isel -o - | FileCheck %s | ||
|
|
||
| define dso_local void @foo(i8 signext %a) !type !3 { | ||
| entry: | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: name: main | ||
| define dso_local i32 @main() !type !4 { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| %fp = alloca ptr, align 8 | ||
| store i32 0, ptr %retval, align 4 | ||
| store ptr @foo, ptr %fp, align 8 | ||
| %0 = load ptr, ptr %fp, align 8 | ||
| ; CHECK: callSites: | ||
| ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId: | ||
| ; CHECK-NEXT: 7854600665770582568 } | ||
| call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ] | ||
| ret i32 0 | ||
| } | ||
|
|
||
| !3 = !{i64 0, !"_ZTSFvcE.generalized"} | ||
| !4 = !{i64 0, !"_ZTSFiE.generalized"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| ;; Test MIR printer and parser for type id field in call site info. Test that | ||
| ;; it works well with/without --emit-call-site-info. | ||
|
|
||
| ;; Multiplex --call-graph-section and -emit-call-site-info as both utilize | ||
| ;; CallSiteInfo and callSites. | ||
|
|
||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| ;; Test printer and parser with --call-graph-section only. | ||
|
|
||
| ;; Test printer. | ||
| ;; Verify that fwdArgRegs is not set, typeId is set. | ||
| ;; Verify the exact typeId value to ensure it is not garbage but the value | ||
| ;; computed as the type id from the type operand bundle. | ||
| ; RUN: llc --call-graph-section %s -stop-before=finalize-isel -o %t1.mir | ||
| ; RUN: cat %t1.mir | FileCheck %s --check-prefix=PRINTER_CGS | ||
| ; PRINTER_CGS: name: main | ||
| ; PRINTER_CGS: callSites: | ||
| ; PRINTER_CGS-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId: | ||
| ; PRINTER_CGS-NEXT: 7854600665770582568 } | ||
|
|
||
|
|
||
| ;; Test parser. | ||
| ;; Verify that we get the same result. | ||
| ; RUN: llc --call-graph-section %t1.mir -run-pass=finalize-isel -o - \ | ||
| ; RUN: | FileCheck %s --check-prefix=PARSER_CGS | ||
| ; PARSER_CGS: name: main | ||
| ; PARSER_CGS: callSites: | ||
| ; PARSER_CGS-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId: | ||
| ; PARSER_CGS-NEXT: 7854600665770582568 } | ||
|
|
||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| ;; Test printer and parser with -emit-call-site-info only. | ||
|
|
||
| ;; Test printer. | ||
| ;; Verify that fwdArgRegs is set, typeId is not set. | ||
| ; RUN: llc -emit-call-site-info %s -stop-before=finalize-isel -o %t2.mir | ||
| ; RUN: cat %t2.mir | FileCheck %s --check-prefix=PRINTER_CSI | ||
| ; PRINTER_CSI: name: main | ||
| ; PRINTER_CSI: callSites: | ||
| ; PRINTER_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: | ||
| ; PRINTER_CSI-NEXT: { arg: 0, reg: '$edi' } | ||
| ; PRINTER_CSI-NOT: typeId: | ||
|
|
||
|
|
||
| ;; Test parser. | ||
| ;; Verify that we get the same result. | ||
| ; RUN: llc -emit-call-site-info %t2.mir -run-pass=finalize-isel -o - \ | ||
| ; RUN: | FileCheck %s --check-prefix=PARSER_CSI | ||
| ; PARSER_CSI: name: main | ||
| ; PARSER_CSI: callSites: | ||
| ; PARSER_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: | ||
| ; PARSER_CSI-NEXT: { arg: 0, reg: '$edi' } | ||
| ; PARSER_CSI-NOT: typeId: | ||
|
|
||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| ;; Test printer and parser with both -emit-call-site-info and --call-graph-section. | ||
|
|
||
| ;; Test printer. | ||
| ;; Verify both fwdArgRegs and typeId are set. | ||
| ;; Verify the exact typeId value to ensure it is not garbage but the value | ||
| ;; computed as the type id from the type operand bundle. | ||
| ; RUN: llc --call-graph-section -emit-call-site-info %s -stop-before=finalize-isel -o %t2.mir | ||
| ; RUN: cat %t2.mir | FileCheck %s --check-prefix=PRINTER_CGS_CSI | ||
| ; PRINTER_CGS_CSI: name: main | ||
| ; PRINTER_CGS_CSI: callSites: | ||
| ; PRINTER_CGS_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: | ||
| ; PRINTER_CGS_CSI-NEXT: { arg: 0, reg: '$edi' }, typeId: | ||
| ; PRINTER_CGS_CSI-NEXT: 7854600665770582568 } | ||
|
|
||
|
|
||
| ;; Test parser. | ||
| ;; Verify that we get the same result. | ||
| ; RUN: llc --call-graph-section -emit-call-site-info %t2.mir -run-pass=finalize-isel -o - \ | ||
| ; RUN: | FileCheck %s --check-prefix=PARSER_CGS_CSI | ||
| ; PARSER_CGS_CSI: name: main | ||
| ; PARSER_CGS_CSI: callSites: | ||
| ; PARSER_CGS_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: | ||
| ; PARSER_CGS_CSI-NEXT: { arg: 0, reg: '$edi' }, typeId: | ||
| ; PARSER_CGS_CSI-NEXT: 7854600665770582568 } | ||
|
|
||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
|
|
||
| ; Function Attrs: noinline nounwind optnone uwtable | ||
| define dso_local void @foo(i8 signext %a) !type !3 { | ||
| entry: | ||
| ret void | ||
| } | ||
|
|
||
| ; Function Attrs: noinline nounwind optnone uwtable | ||
| define dso_local i32 @main() !type !4 { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| %fp = alloca ptr, align 8 | ||
| store i32 0, ptr %retval, align 4 | ||
| store ptr @foo, ptr %fp, align 8 | ||
| %0 = load ptr, ptr %fp, align 8 | ||
| call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ] | ||
| ret i32 0 | ||
| } | ||
|
|
||
| !3 = !{i64 0, !"_ZTSFvcE.generalized"} | ||
| !4 = !{i64 0, !"_ZTSFiE.generalized"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # Test MIR printer and parser for type id field in callSites. It is used | ||
| # for propogating call site type identifiers to emit in the call graph section. | ||
|
|
||
| # RUN: llc --call-graph-section %s -run-pass=none -o - | FileCheck %s | ||
| # CHECK: name: main | ||
| # CHECK: callSites: | ||
| # CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId: | ||
| # CHECK-NEXT: 123456789 } | ||
|
|
||
| --- | | ||
| define dso_local void @foo(i8 signext %a) { | ||
| entry: | ||
| ret void | ||
| } | ||
|
|
||
| define dso_local i32 @main() { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| %fp = alloca ptr, align 8 | ||
| store i32 0, ptr %retval, align 4 | ||
| store ptr @foo, ptr %fp, align 8 | ||
| %0 = load ptr, ptr %fp, align 8 | ||
| call void %0(i8 signext 97) | ||
| ret i32 0 | ||
| } | ||
|
|
||
| ... | ||
| --- | ||
| name: foo | ||
| tracksRegLiveness: true | ||
| body: | | ||
| bb.0.entry: | ||
| RET 0 | ||
|
|
||
| ... | ||
| --- | ||
| name: main | ||
| tracksRegLiveness: true | ||
| stack: | ||
| - { id: 0, name: retval, type: default, offset: 0, size: 4, alignment: 4, | ||
| stack-id: default, callee-saved-register: '', callee-saved-restored: true, | ||
| debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } | ||
| - { id: 1, name: fp, type: default, offset: 0, size: 8, alignment: 8, | ||
| stack-id: default, callee-saved-register: '', callee-saved-restored: true, | ||
| debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } | ||
| callSites: | ||
| - { bb: 0, offset: 6, fwdArgRegs: [], typeId: | ||
| 123456789 } | ||
| body: | | ||
| bb.0.entry: | ||
| MOV32mi %stack.0.retval, 1, $noreg, 0, $noreg, 0 :: (store (s32) into %ir.retval) | ||
| MOV64mi32 %stack.1.fp, 1, $noreg, 0, $noreg, @foo :: (store (s64) into %ir.fp) | ||
| %0:gr64 = MOV32ri64 @foo | ||
| ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp | ||
| %1:gr32 = MOV32ri 97 | ||
| $edi = COPY %1 | ||
| CALL64r killed %0, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp | ||
| ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp | ||
| %2:gr32 = MOV32r0 implicit-def dead $eflags | ||
| $eax = COPY %2 | ||
| RET 0, $eax | ||
|
|
||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| ;; Tests that call site type ids can be extracted and set from type operand | ||
| ;; bundles. | ||
|
|
||
| ;; Verify the exact typeId value to ensure it is not garbage but the value | ||
| ;; computed as the type id from the type operand bundle. | ||
| ; RUN: llc --call-graph-section -mtriple=mips-linux-gnu < %s -stop-before=finalize-isel -o - | FileCheck %s | ||
|
|
||
| define dso_local void @foo(i8 signext %a) !type !3 { | ||
| entry: | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: name: main | ||
| define dso_local i32 @main() !type !4 { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| %fp = alloca ptr, align 8 | ||
| store i32 0, ptr %retval, align 4 | ||
| store ptr @foo, ptr %fp, align 8 | ||
| %0 = load ptr, ptr %fp, align 8 | ||
| ; CHECK: callSites: | ||
| ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId: | ||
| ; CHECK-NEXT: 7854600665770582568 } | ||
| call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ] | ||
| ret i32 0 | ||
| } | ||
|
|
||
| !3 = !{i64 0, !"_ZTSFvcE.generalized"} | ||
| !4 = !{i64 0, !"_ZTSFiE.generalized"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| ;; Tests that call site type ids can be extracted and set from type operand | ||
| ;; bundles. | ||
|
|
||
| ;; Verify the exact typeId value to ensure it is not garbage but the value | ||
| ;; computed as the type id from the type operand bundle. | ||
| ; RUN: llc --call-graph-section -mtriple=x86_64-unknown-linux < %s -stop-before=finalize-isel -o - | FileCheck %s | ||
|
|
||
| define dso_local void @foo(i8 signext %a) !type !3 { | ||
| entry: | ||
| ret void | ||
| } | ||
|
|
||
| ; CHECK: name: main | ||
| define dso_local i32 @main() !type !4 { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| %fp = alloca ptr, align 8 | ||
| store i32 0, ptr %retval, align 4 | ||
| store ptr @foo, ptr %fp, align 8 | ||
| %0 = load ptr, ptr %fp, align 8 | ||
| ; CHECK: callSites: | ||
| ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], typeId: | ||
| ; CHECK-NEXT: 7854600665770582568 } | ||
| call void %0(i8 signext 97) [ "type"(metadata !"_ZTSFvcE.generalized") ] | ||
| ret i32 0 | ||
| } | ||
|
|
||
| !3 = !{i64 0, !"_ZTSFvcE.generalized"} | ||
| !4 = !{i64 0, !"_ZTSFiE.generalized"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| ; Tests that we store the type identifiers in .callgraph section of the binary. | ||
|
|
||
| ; RUN: llc --call-graph-section -filetype=obj -o - < %s | \ | ||
| ; RUN: llvm-readelf -x .callgraph - | FileCheck %s | ||
|
|
||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| define dso_local void @foo() #0 !type !4 { | ||
| entry: | ||
| ret void | ||
| } | ||
|
|
||
| define dso_local i32 @bar(i8 signext %a) #0 !type !5 { | ||
| entry: | ||
| %a.addr = alloca i8, align 1 | ||
| store i8 %a, i8* %a.addr, align 1 | ||
| ret i32 0 | ||
| } | ||
|
|
||
| define dso_local i32* @baz(i8* %a) #0 !type !6 { | ||
| entry: | ||
| %a.addr = alloca i8*, align 8 | ||
| store i8* %a, i8** %a.addr, align 8 | ||
| ret i32* null | ||
| } | ||
|
|
||
| define dso_local i32 @main() #0 !type !7 { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| %fp_foo = alloca void (...)*, align 8 | ||
| %a = alloca i8, align 1 | ||
| %fp_bar = alloca i32 (i8)*, align 8 | ||
| %fp_baz = alloca i32* (i8*)*, align 8 | ||
| store i32 0, i32* %retval, align 4 | ||
| store void (...)* bitcast (void ()* @foo to void (...)*), void (...)** %fp_foo, align 8 | ||
| %0 = load void (...)*, void (...)** %fp_foo, align 8 | ||
| call void (...) %0() [ "type"(metadata !"_ZTSFvE.generalized") ] | ||
| store i32 (i8)* @bar, i32 (i8)** %fp_bar, align 8 | ||
| %1 = load i32 (i8)*, i32 (i8)** %fp_bar, align 8 | ||
| %2 = load i8, i8* %a, align 1 | ||
| %call = call i32 %1(i8 signext %2) [ "type"(metadata !"_ZTSFicE.generalized") ] | ||
| store i32* (i8*)* @baz, i32* (i8*)** %fp_baz, align 8 | ||
| %3 = load i32* (i8*)*, i32* (i8*)** %fp_baz, align 8 | ||
| %call1 = call i32* %3(i8* %a) [ "type"(metadata !"_ZTSFPvS_E.generalized") ] | ||
| call void @foo() [ "type"(metadata !"_ZTSFvE.generalized") ] | ||
| %4 = load i8, i8* %a, align 1 | ||
| %call2 = call i32 @bar(i8 signext %4) [ "type"(metadata !"_ZTSFicE.generalized") ] | ||
| %call3 = call i32* @baz(i8* %a) [ "type"(metadata !"_ZTSFPvS_E.generalized") ] | ||
| ret i32 0 | ||
| } | ||
|
|
||
| attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } | ||
|
|
||
| !llvm.module.flags = !{!0, !1, !2} | ||
| !llvm.ident = !{!3} | ||
|
|
||
| ; Check that the numeric type id (md5 hash) for the below type ids are emitted | ||
| ; to the callgraph section. | ||
|
|
||
| ; CHECK: Hex dump of section '.callgraph': | ||
|
|
||
| !0 = !{i32 1, !"wchar_size", i32 4} | ||
| !1 = !{i32 7, !"uwtable", i32 1} | ||
| !2 = !{i32 7, !"frame-pointer", i32 2} | ||
| !3 = !{!"clang version 13.0.0 (git@github.com:llvm/llvm-project.git 6d35f403b91c2f2c604e23763f699d580370ca96)"} | ||
| ; CHECK-DAG: 2444f731 f5eecb3e | ||
| !4 = !{i64 0, !"_ZTSFvE.generalized"} | ||
| ; CHECK-DAG: 5486bc59 814b8e30 | ||
| !5 = !{i64 0, !"_ZTSFicE.generalized"} | ||
| ; CHECK-DAG: 7ade6814 f897fd77 | ||
| !6 = !{i64 0, !"_ZTSFPvS_E.generalized"} | ||
| ; CHECK-DAG: caaf769a 600968fa | ||
| !7 = !{i64 0, !"_ZTSFiE.generalized"} |