// 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