From eec7150fac18f3ad915d762548b317e35d4b55b6 Mon Sep 17 00:00:00 2001 From: liu-yaxue Date: Thu, 26 Dec 2024 20:53:31 +0800 Subject: [PATCH] Description: Implemented the struct return value logic in aarch64. Made modification in llvm and lldb, only influence -O0 compile option. issue: https://gitee.com/openharmony/third_party_llvm-project/issues/IBIHF3 Test: step out from stl and self-defined return value functions, and the rteurn value shows correctly. Signed-off-by: liu-yaxue --- .../Plugins/ABI/AArch64/ABISysV_arm64.cpp | 45 +++- lldb/test/API/ohos/stl_return_value/Makefile | 3 + .../stl_return_value/TestSTLReturnValue.py | 95 +++++++++ lldb/test/API/ohos/stl_return_value/main.cpp | 72 +++++++ .../AArch64/GISel/AArch64CallLowering.cpp | 44 ++++ .../GlobalISel/call-lowering-sret-stack.ll | 180 ++++++++++++++++ .../GlobalISel/call-lowering-sret-string.ll | 201 ++++++++++++++++++ 7 files changed, 635 insertions(+), 5 deletions(-) create mode 100644 lldb/test/API/ohos/stl_return_value/Makefile create mode 100644 lldb/test/API/ohos/stl_return_value/TestSTLReturnValue.py create mode 100644 lldb/test/API/ohos/stl_return_value/main.cpp create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-sret-stack.ll create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-sret-string.ll diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index 3e87fd196e01..4bf80791272b 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectMemory.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -467,7 +468,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( bool is_return_value, // false => parameter, true => return value uint32_t &NGRN, // NGRN (see ABI documentation) uint32_t &NSRN, // NSRN (see ABI documentation) - DataExtractor &data) { + DataExtractor &data, + bool &is_sret) { // OHOS_LOCAL llvm::Optional byte_size = value_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); @@ -566,7 +568,28 @@ static bool LoadValueFromConsecutiveGPRRegisters( // does. It looks like all the users of this ABI currently choose not to // do that, and so we can't reconstruct stack based returns on exit // from the function. - return false; + // OHOS_LOCAL begin + // ohos supports to write the sret argument into x0. + if (exe_ctx.GetProcessRef().GetTarget().GetArchitecture().GetTriple().isOpenHOS()) { + Log *log = GetLog(LLDBLog::Expressions); + const RegisterInfo *x0_reg_info = reg_ctx->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + if (x0_reg_info == nullptr) { + LLDB_LOGF(log, "Failed to get register information for x0."); + return false; + } + lldb::addr_t return_value_addr = + reg_ctx->ReadRegisterAsUnsigned(x0_reg_info, LLDB_INVALID_ADDRESS); + if (return_value_addr == LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, "Failed to read the return value address from x0."); + return false; + } + is_sret = true; + return true; + } else { + return false; + } + // OHOS_LOCAL end } else { // We are assuming we are stopped at the first instruction in a function // and that the ABI is being respected so all parameters appear where @@ -776,11 +799,23 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( uint32_t NGRN = 0; // Search ABI docs for NGRN uint32_t NSRN = 0; // Search ABI docs for NSRN const bool is_return_value = true; + // OHOS_LOCAL begin + bool is_sret = false; if (LoadValueFromConsecutiveGPRRegisters( exe_ctx, reg_ctx, return_compiler_type, is_return_value, NGRN, NSRN, - data)) { - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); + data, is_sret)) { + if (is_sret) { + const RegisterInfo *x0_reg_info = reg_ctx->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + lldb::addr_t return_value_addr = reg_ctx->ReadRegisterAsUnsigned( + x0_reg_info, LLDB_INVALID_ADDRESS); + return_valobj_sp = ValueObjectMemory::Create( + &thread, "", Address(return_value_addr, nullptr), return_compiler_type); + } else { + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), data); + } + // OHOS_LOCAL end } } return return_valobj_sp; diff --git a/lldb/test/API/ohos/stl_return_value/Makefile b/lldb/test/API/ohos/stl_return_value/Makefile new file mode 100644 index 000000000000..99998b20bcb0 --- /dev/null +++ b/lldb/test/API/ohos/stl_return_value/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/ohos/stl_return_value/TestSTLReturnValue.py b/lldb/test/API/ohos/stl_return_value/TestSTLReturnValue.py new file mode 100644 index 000000000000..d2f34dc89c1c --- /dev/null +++ b/lldb/test/API/ohos/stl_return_value/TestSTLReturnValue.py @@ -0,0 +1,95 @@ +from __future__ import print_function + +import unittest2 +import os +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.decorators import * + +class TestSTLReturnValue(TestBase): + def test_stack_return_value(self): + """Test some expressions involving STL data types.""" + self.build() + (_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// Set stack break point at this line.", lldb.SBFileSpec("main.cpp")) + self.runCmd("finish") + frame0 = thread.GetFrameAtIndex(0) + th = frame0.GetThread() + value = th.GetStopReturnValue() + self.assertTrue(value.IsValid()) + + child_value = value.GetChildMemberWithName("c") + self.assertEqual(int(child_value.GetChildAtIndex(0).GetValue()), 1) + self.assertEqual(int(child_value.GetChildAtIndex(1).GetValue()), 2) + self.assertEqual(int(child_value.GetChildAtIndex(2).GetValue()), 3) + + def test_string_return_value(self): + """Test some expressions involving STL data types.""" + self.build() + (_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// Set string break point at this line.", lldb.SBFileSpec("main.cpp")) + self.runCmd("finish") + frame0 = thread.GetFrameAtIndex(0) + th = frame0.GetThread() + value = th.GetStopReturnValue() + self.assertTrue(value.IsValid()) + self.assertEqual(value.GetSummary(), '"Hello"') + + def test_map_return_value(self): + """Test some expressions involving STL data types.""" + self.build() + (_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// Set map break point at this line.", lldb.SBFileSpec("main.cpp")) + self.runCmd("finish") + frame0 = thread.GetFrameAtIndex(0) + th = frame0.GetThread() + value = th.GetStopReturnValue() + self.assertTrue(value.IsValid()) + self.assertEqual(value.GetChildAtIndex(0).GetChildAtIndex(0).GetSummary(), '"A"') + self.assertEqual(int(value.GetChildAtIndex(0).GetChildAtIndex(1).GetValue()), 100) + self.assertEqual(value.GetChildAtIndex(1).GetChildAtIndex(0).GetSummary(), '"B"') + self.assertEqual(int(value.GetChildAtIndex(1).GetChildAtIndex(1).GetValue()), 50) + self.assertEqual(value.GetChildAtIndex(2).GetChildAtIndex(0).GetSummary(), '"C"') + self.assertEqual(int(value.GetChildAtIndex(2).GetChildAtIndex(1).GetValue()), 0) + + def test_class_return_value(self): + """Test some expressions involving STL data types.""" + self.build() + (_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// Set class break point at this line.", lldb.SBFileSpec("main.cpp")) + self.runCmd("finish") + frame0 = thread.GetFrameAtIndex(0) + th = frame0.GetThread() + value = th.GetStopReturnValue() + self.assertTrue(value.IsValid()) + self.assertEqual(value.GetChildAtIndex(0).GetName(), "a") + self.assertEqual(int(value.GetChildAtIndex(0).GetValue()), 0) + self.assertEqual(value.GetChildMemberWithName("s").GetSummary(), '"Hello"') + child_vec = value.GetChildMemberWithName("vec") + self.assertEqual(int(child_vec.GetChildAtIndex(0).GetValue()), 1) + self.assertEqual(int(child_vec.GetChildAtIndex(1).GetValue()), 2) + self.assertEqual(int(child_vec.GetChildAtIndex(2).GetValue()), 3) + child_list = value.GetChildMemberWithName("l") + self.assertEqual(int(child_list.GetChildAtIndex(0).GetValue()), 1) + self.assertEqual(int(child_list.GetChildAtIndex(1).GetValue()), 1) + self.assertEqual(int(child_list.GetChildAtIndex(2).GetValue()), 1) + + def test_child_class_return_value(self): + """Test some expressions involving STL data types.""" + self.build() + (_, _, thread, _) = lldbutil.run_to_source_breakpoint(self, "// Set child_class break point at this line.", lldb.SBFileSpec("main.cpp")) + self.runCmd("finish") + frame0 = thread.GetFrameAtIndex(0) + th = frame0.GetThread() + value = th.GetStopReturnValue() + self.assertTrue(value.IsValid()) + self.assertEqual(value.GetChildAtIndex(0).GetName(), "father") + child_value = value.GetChildAtIndex(0) + self.assertEqual(child_value.GetChildAtIndex(0).GetName(), "a") + self.assertEqual(int(child_value.GetChildAtIndex(0).GetValue()), 0) + self.assertEqual(child_value.GetChildMemberWithName("s").GetSummary(), '"Hello"') + child_vec = child_value.GetChildMemberWithName("vec") + self.assertEqual(int(child_vec.GetChildAtIndex(0).GetValue()), 1) + self.assertEqual(int(child_vec.GetChildAtIndex(1).GetValue()), 2) + self.assertEqual(int(child_vec.GetChildAtIndex(2).GetValue()), 3) + child_list = child_value.GetChildMemberWithName("l") + self.assertEqual(int(child_list.GetChildAtIndex(0).GetValue()), 1) + self.assertEqual(int(child_list.GetChildAtIndex(1).GetValue()), 1) + self.assertEqual(int(child_list.GetChildAtIndex(2).GetValue()), 1) diff --git a/lldb/test/API/ohos/stl_return_value/main.cpp b/lldb/test/API/ohos/stl_return_value/main.cpp new file mode 100644 index 000000000000..c7181572d9ac --- /dev/null +++ b/lldb/test/API/ohos/stl_return_value/main.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +using namespace std; + +stack getstack() { + stack st; // Set stack break point at this line. + st.push(1); + st.push(2); + st.push(3); + return st; +} + +string getstring() { + string str = "Hello"; // Set string break point at this line. + return str; +} + +map getmap() { + map mp; // Set map break point at this line. + mp["A"] = 100; + mp["B"] = 50; + mp["C"] = 0; + return mp; +} + +class father { +public: + father() {}; + vector returnvec() { return this->vec; } + list returnlists() { return this->l; } + string getstring() { return s; } + int getint() { return a; } + +protected: + int a = 0; + string s = "Hello"; + vector vec{1, 2, 3}; + list l{1, 1, 1}; +}; + +class son : public father { +public: + son() {}; + vector returnvec() { return this->vec; } + list returnlists() { return this->l; } + string getstring() { return s; } + int getint() { return a; } +}; + +father getclass() { + father fa; // Set class break point at this line. + return fa; +} + +son get_son_class() { + son s; // Set child_class break point at this line. + return s; +} + +int main() { + stack stack1; + stack1 = getstack(); + string str = getstring(); + map mp = getmap(); + father fa = getclass(); + son s = get_son_class(); + return 0; +} + diff --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp index ff597e6605b0..2c0f5fd5c3d9 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp @@ -463,6 +463,29 @@ bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, MIRBuilder, CC, F.isVarArg()); } + // OHOS_LOCAL begin + MachineFunction &MF = MIRBuilder.getMF(); + const Function &F = MF.getFunction(); + if (MF.getTarget().getTargetTriple().isOpenHOS()) { + LLVM_DEBUG(dbgs() << "Checking for struct return attribute in lowerReturn\n"); + if (F.hasStructRetAttr()) { + LLVM_DEBUG(dbgs() << "lowerReturn has struct return attribute\n"); + AArch64FunctionInfo *FuncInfo = MF.getInfo(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + OutgoingArgHandler Handler(MIRBuilder, MRI, MIB); + Register SRetReg = FuncInfo->getSRetReturnReg(); + unsigned RetValReg = AArch64::X0; + if (MRI.isPhysRegUsed(RetValReg)) { + LLVM_DEBUG(dbgs() << "Register x0 is already used.\n"); + } + Handler.assignValueToReg(SRetReg, RetValReg, + CCValAssign::getReg(0, MVT::getIntegerVT(64), RetValReg, + MVT::getIntegerVT(64), CCValAssign::LocInfo::Full)); + } else { + LLVM_DEBUG(dbgs() << "lowerReturn does not have struct return attribute\n"); + } + } + // OHOS_LOCAL end if (SwiftErrorVReg) { MIB.addUse(AArch64::X21, RegState::Implicit); MIRBuilder.buildCopy(AArch64::X21, SwiftErrorVReg); @@ -659,6 +682,27 @@ bool AArch64CallLowering::lowerFormalArguments( handleMustTailForwardedRegisters(MIRBuilder, AssignFn); + // OHOS_LOCAL begin + if (MF.getTarget().getTargetTriple().isOpenHOS()) { + LLVM_DEBUG(dbgs() << "Checking for struct return attribute in lowerFormalArguments\n"); + if (F.hasStructRetAttr()) { + LLVM_DEBUG(dbgs() << "lowerFormalArguments has struct return attribute\n"); + for (unsigned i = 0; i < SplitArgs.size(); ++i) { + if (SplitArgs[i].Flags[0].isSRet()) { + Register Reg = MF.getRegInfo().createVirtualRegister(&AArch64::GPR64RegClass); + FuncInfo->setSRetReturnReg(Reg); + for (unsigned Part = 0; Part < SplitArgs[i].Flags.size(); ++Part) { + MIRBuilder.buildCopy(Reg, SplitArgs[i].Regs[Part]); + } + } else { + LLVM_DEBUG(dbgs() << "lowerFormalArguments does not have struct return attribute\n"); + } + } + } else { + LLVM_DEBUG(dbgs() << "lowerFormalArguments does not have struct return attribute\n"); + } + } + // OHOS_LOCAL end // Move back to the end of the basic block. MIRBuilder.setMBB(MBB); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-sret-stack.ll b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-sret-stack.ll new file mode 100644 index 000000000000..f21d2263d2f5 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-sret-stack.ll @@ -0,0 +1,180 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=aarch64-linux-ohos -global-isel -O0 -verify-machineinstrs -frame-pointer=all < %s | FileCheck %s + +%"class.std::__h::stack" = type { %"class.std::__h::deque" } +%"class.std::__h::deque" = type { %"class.std::__h::__deque_base" } +%"class.std::__h::__deque_base" = type { %"struct.std::__h::__split_buffer", i64, %"class.std::__h::__compressed_pair.1" } +%"struct.std::__h::__split_buffer" = type { ptr, ptr, ptr, %"class.std::__h::__compressed_pair" } +%"class.std::__h::__compressed_pair" = type { %"struct.std::__h::__compressed_pair_elem" } +%"struct.std::__h::__compressed_pair_elem" = type { ptr } +%"class.std::__h::__compressed_pair.1" = type { %"struct.std::__h::__compressed_pair_elem.2" } +%"struct.std::__h::__compressed_pair_elem.2" = type { i64 } +%"class.std::__h::__deque_iterator" = type { ptr, ptr } +%"struct.std::__h::integral_constant" = type { i8 } +%"struct.std::__h::is_trivially_destructible" = type { i8 } +%"struct.std::__h::integral_constant.7" = type { i8 } +%"struct.std::__h::__default_init_tag" = type { i8 } +%"struct.std::__h::__split_buffer.8" = type { ptr, ptr, ptr, %"class.std::__h::__compressed_pair.9" } +%"class.std::__h::__compressed_pair.9" = type { %"struct.std::__h::__compressed_pair_elem", %"struct.std::__h::__compressed_pair_elem.10" } +%"struct.std::__h::__compressed_pair_elem.10" = type { ptr } +%"class.std::__h::unique_ptr" = type { %"class.std::__h::__compressed_pair.11" } +%"class.std::__h::__compressed_pair.11" = type { %"struct.std::__h::__compressed_pair_elem.12", %"struct.std::__h::__compressed_pair_elem.13" } +%"struct.std::__h::__compressed_pair_elem.12" = type { ptr } +%"struct.std::__h::__compressed_pair_elem.13" = type { %"class.std::__h::__allocator_destructor" } +%"class.std::__h::__allocator_destructor" = type { ptr, i64 } +%"class.std::__h::move_iterator" = type { ptr } +%"struct.std::__h::__less" = type { i8 } +%"struct.std::__h::__allocation_result" = type { ptr, i64 } +%"struct.std::__h::pair" = type { ptr, ptr } +%"struct.std::__h::__split_buffer &>::_ConstructTransaction" = type { ptr, ptr, ptr } +%"struct.std::__h::random_access_iterator_tag" = type { i8 } + +@_ZTISt20bad_array_new_length = external constant ptr + +; Function Attrs: mustprogress noinline optnone +define dso_local void @_Z8getstackv(ptr noalias sret(%"class.std::__h::stack") align 8 %0) #0 personality ptr @__gxx_personality_v0 { +; CHECK-LABEL: _Z8getstackv: +; CHECK: .Lfunc_begin0: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: .cfi_personality 0, __gxx_personality_v0 +; CHECK-NEXT: .cfi_lsda 0, .Lexception0 +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: sub sp, sp, #80 +; CHECK-NEXT: .cfi_def_cfa_offset 80 +; CHECK-NEXT: stp x29, x30, [sp, #64] // 16-byte Folded Spill +; CHECK-NEXT: add x29, sp, #64 +; CHECK-NEXT: .cfi_def_cfa w29, 16 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w29, -16 +; CHECK-NEXT: mov x0, x8 +; CHECK-NEXT: str x0, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: mov x8, x0 +; CHECK-NEXT: str x8, [sp] // 8-byte Folded Spill +; CHECK-NEXT: mov x8, x0 +; CHECK-NEXT: stur x8, [x29, #-8] +; CHECK-NEXT: mov w8, wzr +; CHECK-NEXT: mov w9, #1 +; CHECK-NEXT: str w9, [sp, #12] // 4-byte Folded Spill +; CHECK-NEXT: and w8, w8, #0x1 +; CHECK-NEXT: and w8, w8, w9 +; CHECK-NEXT: sturb w8, [x29, #-9] +; CHECK-NEXT: bl _ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEEC2B6v15004Ev +; CHECK-NEXT: ldr w8, [sp, #12] // 4-byte Folded Reload +; CHECK-NEXT: ldr x0, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: sub x1, x29, #16 +; CHECK-NEXT: stur w8, [x29, #-16] +; CHECK-NEXT: .Ltmp0: +; CHECK-NEXT: bl _ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEE4pushB6v15004EOi +; CHECK-NEXT: .Ltmp1: +; CHECK-NEXT: b .LBB0_1 +; CHECK-NEXT: .LBB0_1: +; CHECK-NEXT: ldr x0, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: add x1, sp, #32 +; CHECK-NEXT: mov w8, #2 +; CHECK-NEXT: str w8, [sp, #32] +; CHECK-NEXT: .Ltmp2: +; CHECK-NEXT: bl _ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEE4pushB6v15004EOi +; CHECK-NEXT: .Ltmp3: +; CHECK-NEXT: b .LBB0_2 +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: ldr x0, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: add x1, sp, #28 +; CHECK-NEXT: mov w8, #3 +; CHECK-NEXT: str w8, [sp, #28] +; CHECK-NEXT: .Ltmp4: +; CHECK-NEXT: bl _ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEE4pushB6v15004EOi +; CHECK-NEXT: .Ltmp5: +; CHECK-NEXT: b .LBB0_3 +; CHECK-NEXT: .LBB0_3: +; CHECK-NEXT: mov w8, #1 +; CHECK-NEXT: and w8, w8, #0x1 +; CHECK-NEXT: and w8, w8, #0x1 +; CHECK-NEXT: sturb w8, [x29, #-9] +; CHECK-NEXT: ldurb w8, [x29, #-9] +; CHECK-NEXT: tbnz w8, #0, .LBB0_6 +; CHECK-NEXT: b .LBB0_5 +; CHECK-NEXT: .LBB0_4: +; CHECK-NEXT: .Ltmp6: +; CHECK-NEXT: mov x9, x0 +; CHECK-NEXT: ldr x0, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: mov w8, w1 +; CHECK-NEXT: stur x9, [x29, #-24] +; CHECK-NEXT: stur w8, [x29, #-28] +; CHECK-NEXT: bl _ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEED2Ev +; CHECK-NEXT: b .LBB0_7 +; CHECK-NEXT: .LBB0_5: +; CHECK-NEXT: ldr x0, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: bl _ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEED2Ev +; CHECK-NEXT: b .LBB0_6 +; CHECK-NEXT: .LBB0_6: +; CHECK-NEXT: ldr x0, [sp] // 8-byte Folded Reload +; CHECK-NEXT: ldp x29, x30, [sp, #64] // 16-byte Folded Reload +; CHECK-NEXT: add sp, sp, #80 +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB0_7: +; CHECK-NEXT: ldur x0, [x29, #-24] +; CHECK-NEXT: bl _Unwind_Resume + %2 = alloca ptr, align 8 + %3 = alloca i1, align 1 + %4 = alloca i32, align 4 + %5 = alloca ptr, align 8 + %6 = alloca i32, align 4 + %7 = alloca i32, align 4 + %8 = alloca i32, align 4 + store ptr %0, ptr %2, align 8 + store i1 false, ptr %3, align 1 + call void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEEC2B6v15004Ev(ptr noundef nonnull align 8 dereferenceable(48) %0) #11 + store i32 1, ptr %4, align 4 + invoke void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEE4pushB6v15004EOi(ptr noundef nonnull align 8 dereferenceable(48) %0, ptr noundef nonnull align 4 dereferenceable(4) %4) + to label %9 unwind label %13 + +9: ; preds = %1 + store i32 2, ptr %7, align 4 + invoke void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEE4pushB6v15004EOi(ptr noundef nonnull align 8 dereferenceable(48) %0, ptr noundef nonnull align 4 dereferenceable(4) %7) + to label %10 unwind label %13 + +10: ; preds = %9 + store i32 3, ptr %8, align 4 + invoke void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEE4pushB6v15004EOi(ptr noundef nonnull align 8 dereferenceable(48) %0, ptr noundef nonnull align 4 dereferenceable(4) %8) + to label %11 unwind label %13 + +11: ; preds = %10 + store i1 true, ptr %3, align 1 + %12 = load i1, ptr %3, align 1 + br i1 %12, label %18, label %17 + +13: ; preds = %10, %9, %1 + %14 = landingpad { ptr, i32 } + cleanup + %15 = extractvalue { ptr, i32 } %14, 0 + store ptr %15, ptr %5, align 8 + %16 = extractvalue { ptr, i32 } %14, 1 + store i32 %16, ptr %6, align 4 + call void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEED2Ev(ptr noundef nonnull align 8 dereferenceable(48) %0) #11 + br label %19 + +17: ; preds = %11 + call void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEED2Ev(ptr noundef nonnull align 8 dereferenceable(48) %0) #11 + br label %18 + +18: ; preds = %17, %11 + ret void + +19: ; preds = %13 + %20 = load ptr, ptr %5, align 8 + %21 = load i32, ptr %6, align 4 + %22 = insertvalue { ptr, i32 } undef, ptr %20, 0 + %23 = insertvalue { ptr, i32 } %22, i32 %21, 1 + resume { ptr, i32 } %23 +} + +declare void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEEC2B6v15004Ev(ptr noundef nonnull align 8 dereferenceable(48) %0) unnamed_addr #1 align 2 + +declare void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEE4pushB6v15004EOi(ptr noundef nonnull align 8 dereferenceable(48) %0, ptr noundef nonnull align 4 dereferenceable(4) %1) #0 align 2 + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: noinline nounwind optnone +declare dso_local void @_ZNSt3__h5stackIiNS_5dequeIiNS_9allocatorIiEEEEED2Ev(ptr noundef nonnull align 8 dereferenceable(48) %0) unnamed_addr #1 align 2 + +declare void @__cxa_end_catch() diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-sret-string.ll b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-sret-string.ll new file mode 100644 index 000000000000..01639848e37e --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-sret-string.ll @@ -0,0 +1,201 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=aarch64-linux-ohos -global-isel -O0 -verify-machineinstrs -frame-pointer=all < %s | FileCheck %s + +%"class.std::__h::basic_string" = type { %"class.std::__h::__compressed_pair" } +%"class.std::__h::__compressed_pair" = type { %"struct.std::__h::__compressed_pair_elem" } +%"struct.std::__h::__compressed_pair_elem" = type { %"struct.std::__h::basic_string::__rep" } +%"struct.std::__h::basic_string::__rep" = type { %union.anon } +%union.anon = type { %"struct.std::__h::basic_string::__long" } +%"struct.std::__h::basic_string::__long" = type { %struct.anon, i64, ptr } +%struct.anon = type { i64 } +%"struct.std::__h::__default_init_tag" = type { i8 } +%"struct.std::__h::basic_string::__short" = type { %struct.anon.0, [0 x i8], [23 x i8] } +%struct.anon.0 = type { i8 } + +@.str = private unnamed_addr constant [14 x i8] c"Hello, World!\00", align 1 +@.str.1 = private unnamed_addr constant [4 x i8] c"str\00", align 1 + +; Function Attrs: mustprogress noinline optnone +define dso_local void @_Z12ReturnStringv(ptr noalias sret(%"class.std::__h::basic_string") align 8 %0) #0 { +; CHECK-LABEL: _Z12ReturnStringv: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #48 +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: stp x29, x30, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: add x29, sp, #32 +; CHECK-NEXT: .cfi_def_cfa w29, 16 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w29, -16 +; CHECK-NEXT: mov x0, x8 +; CHECK-NEXT: str x0, [sp] // 8-byte Folded Spill +; CHECK-NEXT: mov x8, x0 +; CHECK-NEXT: str x8, [sp, #8] // 8-byte Folded Spill +; CHECK-NEXT: mov x8, x0 +; CHECK-NEXT: stur x8, [x29, #-8] +; CHECK-NEXT: mov w8, wzr +; CHECK-NEXT: mov w9, #1 +; CHECK-NEXT: str w9, [sp, #16] // 4-byte Folded Spill +; CHECK-NEXT: and w8, w8, #0x1 +; CHECK-NEXT: and w8, w8, #0x1 +; CHECK-NEXT: sturb w8, [x29, #-9] +; CHECK-NEXT: adrp x1, .L.str +; CHECK-NEXT: add x1, x1, :lo12:.L.str +; CHECK-NEXT: bl _ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2B6v15004IDnEEPKc +; CHECK-NEXT: ldr w9, [sp, #16] // 4-byte Folded Reload +; CHECK-NEXT: and w8, w9, #0x1 +; CHECK-NEXT: and w8, w8, w9 +; CHECK-NEXT: sturb w8, [x29, #-9] +; CHECK-NEXT: ldurb w8, [x29, #-9] +; CHECK-NEXT: tbnz w8, #0, .LBB0_2 +; CHECK-NEXT: b .LBB0_1 +; CHECK-NEXT: .LBB0_1: +; CHECK-NEXT: ldr x0, [sp] // 8-byte Folded Reload +; CHECK-NEXT: bl _ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev +; CHECK-NEXT: b .LBB0_2 +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: ldr x0, [sp, #8] // 8-byte Folded Reload +; CHECK-NEXT: ldp x29, x30, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: add sp, sp, #48 +; CHECK-NEXT: ret + %2 = alloca ptr, align 8 + %3 = alloca i1, align 1 + store ptr %0, ptr %2, align 8 + store i1 false, ptr %3, align 1 + call void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2B6v15004IDnEEPKc(ptr noundef nonnull align 8 dereferenceable(24) %0, ptr noundef @.str) + store i1 true, ptr %3, align 1 + %4 = load i1, ptr %3, align 1 + br i1 %4, label %6, label %5 + +5: ; preds = %1 + call void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(ptr noundef nonnull align 8 dereferenceable(24) %0) #8 + br label %6 + +6: ; preds = %5, %1 + ret void +} + +; Function Attrs: noinline optnone +declare dso_local void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2B6v15004IDnEEPKc(ptr noundef nonnull align 8 dereferenceable(24) %0, ptr noundef %1) unnamed_addr #1 align 2 + +; Function Attrs: nounwind +declare void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(ptr noundef nonnull align 8 dereferenceable(24)) unnamed_addr #2 + +; Function Attrs: mustprogress noinline norecurse optnone +define dso_local noundef i32 @main() #3 personality ptr @__gxx_personality_v0 { +; CHECK-LABEL: main: +; CHECK: .Lfunc_begin0: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: .cfi_personality 0, __gxx_personality_v0 +; CHECK-NEXT: .cfi_lsda 0, .Lexception0 +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: sub sp, sp, #96 +; CHECK-NEXT: .cfi_def_cfa_offset 96 +; CHECK-NEXT: stp x29, x30, [sp, #80] // 16-byte Folded Spill +; CHECK-NEXT: add x29, sp, #80 +; CHECK-NEXT: .cfi_def_cfa w29, 16 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w29, -16 +; CHECK-NEXT: stur wzr, [x29, #-4] +; CHECK-NEXT: sub x0, x29, #32 +; CHECK-NEXT: adrp x1, .L.str.1 +; CHECK-NEXT: add x1, x1, :lo12:.L.str.1 +; CHECK-NEXT: bl _ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2B6v15004IDnEEPKc +; CHECK-NEXT: .Ltmp0: +; CHECK-NEXT: add x8, sp, #24 +; CHECK-NEXT: bl _Z12ReturnStringv +; CHECK-NEXT: .Ltmp1: +; CHECK-NEXT: b .LBB1_1 +; CHECK-NEXT: .LBB1_1: +; CHECK-NEXT: .Ltmp3: +; CHECK-NEXT: sub x0, x29, #32 +; CHECK-NEXT: add x1, sp, #24 +; CHECK-NEXT: bl _ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLB6v15004ERKS5_ +; CHECK-NEXT: .Ltmp4: +; CHECK-NEXT: b .LBB1_2 +; CHECK-NEXT: .LBB1_2: +; CHECK-NEXT: add x0, sp, #24 +; CHECK-NEXT: bl _ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev +; CHECK-NEXT: stur wzr, [x29, #-4] +; CHECK-NEXT: sub x0, x29, #32 +; CHECK-NEXT: bl _ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev +; CHECK-NEXT: ldur w0, [x29, #-4] +; CHECK-NEXT: ldp x29, x30, [sp, #80] // 16-byte Folded Reload +; CHECK-NEXT: add sp, sp, #96 +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB1_3: +; CHECK-NEXT: .Ltmp2: +; CHECK-NEXT: mov w8, w1 +; CHECK-NEXT: str x0, [sp, #16] +; CHECK-NEXT: str w8, [sp, #12] +; CHECK-NEXT: b .LBB1_5 +; CHECK-NEXT: .LBB1_4: +; CHECK-NEXT: .Ltmp5: +; CHECK-NEXT: mov w8, w1 +; CHECK-NEXT: str x0, [sp, #16] +; CHECK-NEXT: str w8, [sp, #12] +; CHECK-NEXT: add x0, sp, #24 +; CHECK-NEXT: bl _ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev +; CHECK-NEXT: b .LBB1_5 +; CHECK-NEXT: .LBB1_5: +; CHECK-NEXT: sub x0, x29, #32 +; CHECK-NEXT: bl _ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev +; CHECK-NEXT: b .LBB1_6 +; CHECK-NEXT: .LBB1_6: +; CHECK-NEXT: ldr x0, [sp, #16] +; CHECK-NEXT: bl _Unwind_Resume + %1 = alloca i32, align 4 + %2 = alloca %"class.std::__h::basic_string", align 8 + %3 = alloca %"class.std::__h::basic_string", align 8 + %4 = alloca ptr, align 8 + %5 = alloca i32, align 4 + store i32 0, ptr %1, align 4 + call void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2B6v15004IDnEEPKc(ptr noundef nonnull align 8 dereferenceable(24) %2, ptr noundef @.str.1) + invoke void @_Z12ReturnStringv(ptr sret(%"class.std::__h::basic_string") align 8 %3) + to label %6 unwind label %10 + +6: ; preds = %0 + %7 = invoke noundef nonnull align 8 dereferenceable(24) ptr @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLB6v15004ERKS5_(ptr noundef nonnull align 8 dereferenceable(24) %2, ptr noundef nonnull align 8 dereferenceable(24) %3) + to label %8 unwind label %14 + +8: ; preds = %6 + call void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(ptr noundef nonnull align 8 dereferenceable(24) %3) #8 + store i32 0, ptr %1, align 4 + call void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(ptr noundef nonnull align 8 dereferenceable(24) %2) #8 + %9 = load i32, ptr %1, align 4 + ret i32 %9 + +10: ; preds = %0 + %11 = landingpad { ptr, i32 } + cleanup + %12 = extractvalue { ptr, i32 } %11, 0 + store ptr %12, ptr %4, align 8 + %13 = extractvalue { ptr, i32 } %11, 1 + store i32 %13, ptr %5, align 4 + br label %18 + +14: ; preds = %6 + %15 = landingpad { ptr, i32 } + cleanup + %16 = extractvalue { ptr, i32 } %15, 0 + store ptr %16, ptr %4, align 8 + %17 = extractvalue { ptr, i32 } %15, 1 + store i32 %17, ptr %5, align 4 + call void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(ptr noundef nonnull align 8 dereferenceable(24) %3) #8 + br label %18 + +18: ; preds = %14, %10 + call void @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev(ptr noundef nonnull align 8 dereferenceable(24) %2) #8 + br label %19 + +19: ; preds = %18 + %20 = load ptr, ptr %4, align 8 + %21 = load i32, ptr %5, align 4 + %22 = insertvalue { ptr, i32 } undef, ptr %20, 0 + %23 = insertvalue { ptr, i32 } %22, i32 %21, 1 + resume { ptr, i32 } %23 +} + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: mustprogress noinline optnone +declare noundef nonnull align 8 dereferenceable(24) ptr @_ZNSt3__h12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLB6v15004ERKS5_(ptr noundef nonnull align 8 dereferenceable(24) %0, ptr noundef nonnull align 8 dereferenceable(24) %1) #0 align 2 -- Gitee