blob: af2bcc7098e2817b61361c649274fb92872a97fc [file] [edit]
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
// All 17 cases from clang/test/CodeGenCXX/trivial_abi.cpp, adapted for
// x86_64-unknown-linux-gnu with CIR/LLVM/OGCG checks.
struct __attribute__((trivial_abi)) Small {
int *p;
Small();
~Small();
Small(const Small &) noexcept;
Small &operator=(const Small &);
};
struct __attribute__((trivial_abi)) Large {
int *p;
int a[128];
Large();
~Large();
Large(const Large &) noexcept;
Large &operator=(const Large &);
};
struct Trivial { int a; };
struct NonTrivial {
NonTrivial();
~NonTrivial();
int a;
};
// --- Case 17: PR42961 lambda returning Small via __invoke ---
// CIR emits lambda internals before user functions, so this CIR check
// must come first to match CIR emission order.
Small (*fp)() = []() -> Small { return Small(); };
// CIR-LABEL: cir.func {{.*}} @{{.*}}__invokeEv
// CIR: cir.call @{{.*}}clEv
// LLVM-LABEL: define {{.*}} @{{.*}}__invokeEv
// LLVM: call {{.*}} @{{.*}}clEv
// --- Case 1: D0::m0 thunk returning trivial_abi Small ---
struct B0 { virtual Small m0(); };
struct B1 { virtual Small m0(); };
struct D0 : B0, B1 { Small m0() override; };
Small D0::m0() { return {}; }
// CIR-LABEL: cir.func {{.*}} @_ZThn8_N2D02m0Ev
// CIR: cir.call @_ZN2D02m0Ev
// LLVM-LABEL: define {{.*}} @_ZN2D02m0Ev(
// LLVM-LABEL: define {{.*}} @_ZThn8_N2D02m0Ev(
// LLVM: getelementptr i8, ptr {{.*}}, i64 -8
// LLVM: call {{.*}} @_ZN2D02m0Ev(
// OGCG-LABEL: define {{.*}} @_ZN2D02m0Ev(
// OGCG-LABEL: define {{.*}} @_ZThn8_N2D02m0Ev(
// OGCG: getelementptr inbounds i8, ptr {{.*}}, i64 -8
// OGCG: {{.*}}call {{.*}} @_ZN2D02m0Ev(
// --- Case 2: testParamSmall ---
void testParamSmall(Small a) noexcept {}
// CIR-LABEL: cir.func {{.*}} @_Z14testParamSmall5Small
// CIR: cir.return
// LLVM-LABEL: define {{.*}} void @_Z14testParamSmall5Small(
// LLVM: ret void
// OGCG-LABEL: define {{.*}} void @_Z14testParamSmall5Small(ptr %a.coerce)
// OGCG: call {{.*}} @_ZN5SmallD1Ev(
// OGCG: ret void
// --- Case 3: testReturnSmall ---
Small testReturnSmall() {
Small t;
return t;
}
// CIR-LABEL: cir.func {{.*}} @_Z15testReturnSmallv
// CIR: cir.call @_ZN5SmallC1Ev
// LLVM-LABEL: define {{.*}} @_Z15testReturnSmallv(
// LLVM: call void @_ZN5SmallC1Ev(
// OGCG-LABEL: define {{.*}} ptr @_Z15testReturnSmallv(
// OGCG: call {{.*}} @_ZN5SmallC1Ev(
// --- Case 4: testCallSmall0 (local copy + callee-destructed param) ---
void testCallSmall0() {
Small t;
testParamSmall(t);
}
// CIR-LABEL: cir.func {{.*}} @_Z14testCallSmall0v
// CIR: cir.call @_ZN5SmallC1Ev
// CIR: cir.call @_ZN5SmallC1ERKS_
// CIR: cir.call @_Z14testParamSmall5Small
// LLVM-LABEL: define {{.*}} void @_Z14testCallSmall0v(
// LLVM: call void @_ZN5SmallC1Ev(
// LLVM: call void @_ZN5SmallC1ERKS_(
// LLVM: call void @_Z14testParamSmall5Small(
// OGCG-LABEL: define {{.*}} void @_Z14testCallSmall0v(
// OGCG: call {{.*}} @_ZN5SmallC1Ev(
// OGCG: call {{.*}} @_ZN5SmallC1ERKS_(
// OGCG: call void @_Z14testParamSmall5Small(
// --- Case 5: testCallSmall1 (pass returned value directly) ---
void testCallSmall1() {
testParamSmall(testReturnSmall());
}
// CIR-LABEL: cir.func {{.*}} @_Z14testCallSmall1v
// CIR: cir.call @_Z15testReturnSmallv
// CIR: cir.call @_Z14testParamSmall5Small
// LLVM-LABEL: define {{.*}} void @_Z14testCallSmall1v(
// LLVM: call {{.*}} @_Z15testReturnSmallv(
// LLVM: call void @_Z14testParamSmall5Small(
// OGCG-LABEL: define {{.*}} void @_Z14testCallSmall1v(
// OGCG: call {{.*}} @_Z15testReturnSmallv()
// OGCG: call void @_Z14testParamSmall5Small(
// --- Case 6: testIgnoredSmall (discard return, must destruct) ---
void testIgnoredSmall() {
testReturnSmall();
}
// CIR-LABEL: cir.func {{.*}} @_Z16testIgnoredSmallv
// CIR: cir.call @_Z15testReturnSmallv
// CIR: cir.call @_ZN5SmallD1Ev
// LLVM-LABEL: define {{.*}} void @_Z16testIgnoredSmallv(
// LLVM: call {{.*}} @_Z15testReturnSmallv(
// LLVM: call void @_ZN5SmallD1Ev(
// OGCG-LABEL: define {{.*}} void @_Z16testIgnoredSmallv(
// OGCG: call {{.*}} @_Z15testReturnSmallv()
// OGCG: call {{.*}} @_ZN5SmallD1Ev(
// --- Case 7: testParamLarge ---
void testParamLarge(Large a) noexcept {}
// CIR-LABEL: cir.func {{.*}} @_Z14testParamLarge5Large
// CIR: cir.return
// LLVM-LABEL: define {{.*}} void @_Z14testParamLarge5Large(
// LLVM: ret void
// OGCG-LABEL: define {{.*}} void @_Z14testParamLarge5Large(ptr noundef byval(%struct.Large) align 8 %a)
// OGCG: call {{.*}} @_ZN5LargeD1Ev(
// OGCG: ret void
// --- Case 8: testReturnLarge ---
Large testReturnLarge() {
Large t;
return t;
}
// CIR-LABEL: cir.func {{.*}} @_Z15testReturnLargev
// CIR: cir.call @_ZN5LargeC1Ev
// LLVM-LABEL: define {{.*}} @_Z15testReturnLargev(
// LLVM: call void @_ZN5LargeC1Ev(
// OGCG-LABEL: define {{.*}} void @_Z15testReturnLargev(ptr {{.*}}sret(%struct.Large)
// OGCG: call {{.*}} @_ZN5LargeC1Ev(
// --- Case 9: testCallLarge0 (local copy + callee-destructed param) ---
void testCallLarge0() {
Large t;
testParamLarge(t);
}
// CIR-LABEL: cir.func {{.*}} @_Z14testCallLarge0v
// CIR: cir.call @_ZN5LargeC1Ev
// CIR: cir.call @_ZN5LargeC1ERKS_
// CIR: cir.call @_Z14testParamLarge5Large
// LLVM-LABEL: define {{.*}} void @_Z14testCallLarge0v(
// LLVM: call void @_ZN5LargeC1Ev(
// LLVM: call void @_ZN5LargeC1ERKS_(
// LLVM: call void @_Z14testParamLarge5Large(
// OGCG-LABEL: define {{.*}} void @_Z14testCallLarge0v(
// OGCG: call {{.*}} @_ZN5LargeC1Ev(
// OGCG: call {{.*}} @_ZN5LargeC1ERKS_(
// OGCG: call void @_Z14testParamLarge5Large(
// --- Case 10: testCallLarge1 (pass returned value directly) ---
void testCallLarge1() {
testParamLarge(testReturnLarge());
}
// CIR-LABEL: cir.func {{.*}} @_Z14testCallLarge1v
// CIR: cir.call @_Z15testReturnLargev
// CIR: cir.call @_Z14testParamLarge5Large
// LLVM-LABEL: define {{.*}} void @_Z14testCallLarge1v(
// LLVM: call {{.*}} @_Z15testReturnLargev(
// LLVM: call void @_Z14testParamLarge5Large(
// OGCG-LABEL: define {{.*}} void @_Z14testCallLarge1v(
// OGCG: call void @_Z15testReturnLargev(
// OGCG: call void @_Z14testParamLarge5Large(
// --- Case 11: testIgnoredLarge (discard return, must destruct) ---
void testIgnoredLarge() {
testReturnLarge();
}
// CIR-LABEL: cir.func {{.*}} @_Z16testIgnoredLargev
// CIR: cir.call @_Z15testReturnLargev
// CIR: cir.call @_ZN5LargeD1Ev
// LLVM-LABEL: define {{.*}} void @_Z16testIgnoredLargev(
// LLVM: call {{.*}} @_Z15testReturnLargev(
// LLVM: call void @_ZN5LargeD1Ev(
// OGCG-LABEL: define {{.*}} void @_Z16testIgnoredLargev(
// OGCG: call void @_Z15testReturnLargev(
// OGCG: call {{.*}} @_ZN5LargeD1Ev(
// --- Case 12: testReturnHasTrivial ---
Trivial testReturnHasTrivial() {
Trivial t;
return t;
}
// CIR-LABEL: cir.func {{.*}} @_Z20testReturnHasTrivialv
// CIR: cir.return
// LLVM-LABEL: define {{.*}} @_Z20testReturnHasTrivialv(
// LLVM: ret
// OGCG-LABEL: define {{.*}} i32 @_Z20testReturnHasTrivialv(
// OGCG: ret i32
// --- Case 13: testReturnHasNonTrivial ---
NonTrivial testReturnHasNonTrivial() {
NonTrivial t;
return t;
}
// CIR-LABEL: cir.func {{.*}} @_Z23testReturnHasNonTrivialv
// CIR: cir.call @_ZN10NonTrivialC1Ev
// LLVM-LABEL: define {{.*}} @_Z23testReturnHasNonTrivialv(
// LLVM: call void @_ZN10NonTrivialC1Ev(
// OGCG-LABEL: define {{.*}} void @_Z23testReturnHasNonTrivialv(ptr {{.*}}sret(%struct.NonTrivial)
// OGCG: call {{.*}} @_ZN10NonTrivialC1Ev(
// --- Case 14: testExceptionSmall ---
// CIR does not emit invoke/landingpad; the non-unwinding call sequence
// is tested here. OGCG verifies the full EH path.
void calleeExceptionSmall(Small, Small);
void testExceptionSmall() {
calleeExceptionSmall(Small(), Small());
}
// CIR-LABEL: cir.func {{.*}} @_Z18testExceptionSmallv
// CIR: cir.call @_ZN5SmallC1Ev
// CIR: cir.call @_ZN5SmallC1Ev
// CIR: cir.call @_Z20calleeExceptionSmall5SmallS_
// LLVM-LABEL: define {{.*}} void @_Z18testExceptionSmallv(
// LLVM: call void @_ZN5SmallC1Ev(
// LLVM: call void @_ZN5SmallC1Ev(
// LLVM: call void @_Z20calleeExceptionSmall5SmallS_(
// OGCG-LABEL: define {{.*}} void @_Z18testExceptionSmallv()
// OGCG: call {{.*}} @_ZN5SmallC1Ev(
// OGCG: call {{.*}} @_ZN5SmallC1Ev(
// OGCG: call void @_Z20calleeExceptionSmall5SmallS_(
// --- Case 15: testExceptionLarge ---
void calleeExceptionLarge(Large, Large);
void testExceptionLarge() {
calleeExceptionLarge(Large(), Large());
}
// CIR-LABEL: cir.func {{.*}} @_Z18testExceptionLargev
// CIR: cir.call @_ZN5LargeC1Ev
// CIR: cir.call @_ZN5LargeC1Ev
// CIR: cir.call @_Z20calleeExceptionLarge5LargeS_
// LLVM-LABEL: define {{.*}} void @_Z18testExceptionLargev(
// LLVM: call void @_ZN5LargeC1Ev(
// LLVM: call void @_ZN5LargeC1Ev(
// LLVM: call void @_Z20calleeExceptionLarge5LargeS_(
// OGCG-LABEL: define {{.*}} void @_Z18testExceptionLargev()
// OGCG: call {{.*}} @_ZN5LargeC1Ev(
// OGCG: call {{.*}} @_ZN5LargeC1Ev(
// OGCG: call void @_Z20calleeExceptionLarge5LargeS_(
// --- Case 16: GH93040 packed trivial_abi with placement new ---
void* operator new(unsigned long, void*);
namespace GH93040 {
struct [[clang::trivial_abi]] S {
char a;
int x;
__attribute((aligned(2))) char y;
S();
} __attribute((packed));
S f();
void g(S* s) { new(s) S(f()); }
}
// CIR-LABEL: cir.func {{.*}} @_ZN7GH930401gEPNS_1SE
// CIR: cir.call @_ZN7GH930401fEv
// LLVM-LABEL: define {{.*}} void @_ZN7GH930401gEPNS_1SE(
// LLVM: call {{.*}} @_ZN7GH930401fEv(
// OGCG-LABEL: define {{.*}} void @_ZN7GH930401gEPNS_1SE(
// OGCG: call void @_ZN7GH930401fEv(ptr {{.*}}sret(
// Lambda __invoke comes last in OGCG (internal linkage).
// OGCG-LABEL: define {{.*}} @{{.*}}__invokeEv
// OGCG: call {{.*}} @{{.*}}clEv