Index: lldb/trunk/include/lldb/Symbol/ClangASTContext.h =================================================================== --- lldb/trunk/include/lldb/Symbol/ClangASTContext.h +++ lldb/trunk/include/lldb/Symbol/ClangASTContext.h @@ -598,6 +598,8 @@ bool IsVoidType(lldb::opaque_compiler_type_t type) override; + bool CanPassInRegisters(const CompilerType &type) override; + bool SupportsLanguage(lldb::LanguageType language) override; static bool GetCXXClassName(const CompilerType &type, Index: lldb/trunk/include/lldb/Symbol/TypeSystem.h =================================================================== --- lldb/trunk/include/lldb/Symbol/TypeSystem.h +++ lldb/trunk/include/lldb/Symbol/TypeSystem.h @@ -181,6 +181,8 @@ virtual bool IsVoidType(lldb::opaque_compiler_type_t type) = 0; + virtual bool CanPassInRegisters(const CompilerType &type) = 0; + // TypeSystems can support more than one language virtual bool SupportsLanguage(lldb::LanguageType language) = 0; Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/Makefile =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/Makefile +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/Makefile @@ -1,5 +1,5 @@ LEVEL = ../../make -C_SOURCES := call-func.c +CXX_SOURCES := call-func.cpp include $(LEVEL)/Makefile.rules Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py @@ -57,7 +57,7 @@ frame = thread.GetFrameAtIndex(0) fun_name = frame.GetFunctionName() - self.assertTrue(fun_name == "outer_sint") + self.assertTrue(fun_name == "outer_sint(int)") return_value = thread.GetStopReturnValue() self.assertTrue(return_value.IsValid()) @@ -78,7 +78,7 @@ frame = thread.GetFrameAtIndex(1) fun_name = frame.GetFunctionName() - self.assertTrue(fun_name == "outer_sint") + self.assertTrue(fun_name == "outer_sint(int)") in_int = frame.FindVariable("value").GetValueAsSigned(error) self.assertTrue(error.Success()) @@ -98,7 +98,7 @@ # Now try some simple returns that have different types: inner_float_bkpt = self.target.BreakpointCreateByName( - "inner_float", exe) + "inner_float(float)", exe) self.assertTrue(inner_float_bkpt, VALID_BREAKPOINT) self.process.Continue() thread_list = lldbutil.get_threads_stopped_at_breakpoint( @@ -118,7 +118,7 @@ frame = thread.GetFrameAtIndex(0) fun_name = frame.GetFunctionName() - self.assertTrue(fun_name == "outer_float") + self.assertTrue(fun_name == "outer_float(float)") #return_value = thread.GetStopReturnValue() #self.assertTrue(return_value.IsValid()) @@ -190,6 +190,37 @@ self.return_and_test_struct_value("return_ext_vector_size_float32_4") self.return_and_test_struct_value("return_ext_vector_size_float32_8") + # limit the nested struct and class tests to only x86_64 + @skipIf(archs=no_match(['x86_64'])) + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778") + def test_for_cpp_support(self): + self.build() + exe = self.getBuildArtifact("a.out") + (self.target, self.process, thread, inner_sint_bkpt) = lldbutil.run_to_name_breakpoint(self, "inner_sint", exe_name = exe) + + error = lldb.SBError() + + self.target = self.dbg.CreateTarget(exe) + self.assertTrue(self.target, VALID_TARGET) + + main_bktp = self.target.BreakpointCreateByName("main", exe) + self.assertTrue(main_bktp, VALID_BREAKPOINT) + + self.process = self.target.LaunchSimple( + None, None, self.get_process_working_directory()) + self.assertEqual(len(lldbutil.get_threads_stopped_at_breakpoint( + self.process, main_bktp)), 1) + # nested struct tests + self.return_and_test_struct_value("return_nested_one_float_three_base") + self.return_and_test_struct_value("return_double_nested_one_float_one_nested") + self.return_and_test_struct_value("return_nested_float_struct") + # class test + self.return_and_test_struct_value("return_base_class_one_char") + self.return_and_test_struct_value("return_nested_class_float_and_base") + self.return_and_test_struct_value("return_double_nested_class_float_and_nested") + self.return_and_test_struct_value("return_base_class") + self.return_and_test_struct_value("return_derived_class") + def return_and_test_struct_value(self, func_name): """Pass in the name of the function to return from - takes in value, returns value.""" Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c @@ -1,407 +0,0 @@ -// Some convenient things to return: -static char *g_first_pointer = "I am the first"; -static char *g_second_pointer = "I am the second"; - -// First we have some simple functions that return standard types, ints, floats and doubles. -// We have a function calling a function in a few cases to test that if you stop in the -// inner function then do "up/fin" you get the return value from the outer-most frame. - -int -inner_sint (int value) -{ - return value; -} - -int -outer_sint (int value) -{ - int outer_value = 2 * inner_sint (value); - return outer_value; -} - -float -inner_float (float value) -{ - return value; -} - -float -outer_float (float value) -{ - float outer_value = 2 * inner_float(value); - return outer_value; -} - -double -return_double (double value) -{ - return value; -} - -long double -return_long_double (long double value) -{ - return value; -} - -char * -return_pointer (char *value) -{ - return value; -} - -struct one_int -{ - int one_field; -}; - -struct one_int -return_one_int (struct one_int value) -{ - return value; -} - -struct two_int -{ - int first_field; - int second_field; -}; - -struct two_int -return_two_int (struct two_int value) -{ - return value; -} - -struct three_int -{ - int first_field; - int second_field; - int third_field; -}; - -struct three_int -return_three_int (struct three_int value) -{ - return value; -} - -struct four_int -{ - int first_field; - int second_field; - int third_field; - int fourth_field; -}; - -struct four_int -return_four_int (struct four_int value) -{ - return value; -} - -struct five_int -{ - int first_field; - int second_field; - int third_field; - int fourth_field; - int fifth_field; -}; - -struct five_int -return_five_int (struct five_int value) -{ - return value; -} - -struct one_int_one_double -{ - int first_field; - double second_field; -}; - -struct one_int_one_double -return_one_int_one_double (struct one_int_one_double value) -{ - return value; -} - -struct one_int_one_double_one_int -{ - int one_field; - double second_field; - int third_field; -}; - -struct one_int_one_double_one_int -return_one_int_one_double_one_int (struct one_int_one_double_one_int value) -{ - return value; -} - -struct one_short_one_double_one_short -{ - int one_field; - double second_field; - int third_field; -}; - -struct one_short_one_double_one_short -return_one_short_one_double_one_short (struct one_short_one_double_one_short value) -{ - return value; -} - -struct three_short_one_float -{ - short one_field; - short second_field; - short third_field; - float fourth_field; -}; - -struct three_short_one_float -return_three_short_one_float (struct three_short_one_float value) -{ - return value; -} - -struct one_int_one_float_one_int -{ - int one_field; - float second_field; - int third_field; -}; - -struct one_int_one_float_one_int -return_one_int_one_float_one_int (struct one_int_one_float_one_int value) -{ - return value; -} - -struct one_float_one_int_one_float -{ - float one_field; - int second_field; - float third_field; -}; - -struct one_float_one_int_one_float -return_one_float_one_int_one_float (struct one_float_one_int_one_float value) -{ - return value; -} - -struct one_double_two_float -{ - double one_field; - float second_field; - float third_field; -}; - -struct one_double_two_float -return_one_double_two_float (struct one_double_two_float value) -{ - return value; -} - -struct two_double -{ - double first_field; - double second_field; -}; - -struct two_double -return_two_double (struct two_double value) -{ - return value; -} - -struct two_float -{ - float first_field; - float second_field; -}; - -struct two_float -return_two_float (struct two_float value) -{ - return value; -} - -struct one_int_one_double_packed -{ - int first_field; - double second_field; -} __attribute__((__packed__)); - -struct one_int_one_double_packed -return_one_int_one_double_packed (struct one_int_one_double_packed value) -{ - return value; -} - -struct one_int_one_long -{ - int first_field; - long second_field; -}; - -struct one_int_one_long -return_one_int_one_long (struct one_int_one_long value) -{ - return value; -} - -struct one_pointer -{ - char *first_field; -}; - -struct one_pointer -return_one_pointer (struct one_pointer value) -{ - return value; -} - -struct two_pointer -{ - char *first_field; - char *second_field; -}; - -struct two_pointer -return_two_pointer (struct two_pointer value) -{ - return value; -} - -struct one_float_one_pointer -{ - float first_field; - char *second_field; -}; - -struct one_float_one_pointer -return_one_float_one_pointer (struct one_float_one_pointer value) -{ - return value; -} - -struct one_int_one_pointer -{ - int first_field; - char *second_field; -}; - -struct one_int_one_pointer -return_one_int_one_pointer (struct one_int_one_pointer value) -{ - return value; -} - -typedef float vector_size_float32_8 __attribute__((__vector_size__(8))); -typedef float vector_size_float32_16 __attribute__((__vector_size__(16))); -typedef float vector_size_float32_32 __attribute__((__vector_size__(32))); - -typedef float ext_vector_size_float32_2 __attribute__((ext_vector_type(2))); -typedef float ext_vector_size_float32_4 __attribute__((ext_vector_type(4))); -typedef float ext_vector_size_float32_8 __attribute__((ext_vector_type(8))); - -vector_size_float32_8 -return_vector_size_float32_8 (vector_size_float32_8 value) -{ - return value; -} - -vector_size_float32_16 -return_vector_size_float32_16 (vector_size_float32_16 value) -{ - return value; -} - -vector_size_float32_32 -return_vector_size_float32_32 (vector_size_float32_32 value) -{ - return value; -} - -ext_vector_size_float32_2 -return_ext_vector_size_float32_2 (ext_vector_size_float32_2 value) -{ - return value; -} - -ext_vector_size_float32_4 -return_ext_vector_size_float32_4 (ext_vector_size_float32_4 value) -{ - return value; -} - -ext_vector_size_float32_8 -return_ext_vector_size_float32_8 (ext_vector_size_float32_8 value) -{ - return value; -} - -int -main () -{ - int first_int = 123456; - int second_int = 234567; - - outer_sint (first_int); - outer_sint (second_int); - - float first_float_value = 12.34; - float second_float_value = 23.45; - - outer_float (first_float_value); - outer_float (second_float_value); - - double double_value = -23.45; - - return_double (double_value); - - return_pointer(g_first_pointer); - - long double long_double_value = -3456789.987654321; - - return_long_double (long_double_value); - - // Okay, now the structures: - return_one_int ((struct one_int) {10}); - return_two_int ((struct two_int) {10, 20}); - return_three_int ((struct three_int) {10, 20, 30}); - return_four_int ((struct four_int) {10, 20, 30, 40}); - return_five_int ((struct five_int) {10, 20, 30, 40, 50}); - - return_two_double ((struct two_double) {10.0, 20.0}); - return_one_double_two_float ((struct one_double_two_float) {10.0, 20.0, 30.0}); - return_one_int_one_float_one_int ((struct one_int_one_float_one_int) {10, 20.0, 30}); - - return_one_pointer ((struct one_pointer) {g_first_pointer}); - return_two_pointer ((struct two_pointer) {g_first_pointer, g_second_pointer}); - return_one_float_one_pointer ((struct one_float_one_pointer) {10.0, g_first_pointer}); - return_one_int_one_pointer ((struct one_int_one_pointer) {10, g_first_pointer}); - return_three_short_one_float ((struct three_short_one_float) {10, 20, 30, 40.0}); - - return_one_int_one_double ((struct one_int_one_double) {10, 20.0}); - return_one_int_one_double_one_int ((struct one_int_one_double_one_int) {10, 20.0, 30}); - return_one_short_one_double_one_short ((struct one_short_one_double_one_short) {10, 20.0, 30}); - return_one_float_one_int_one_float ((struct one_float_one_int_one_float) {10.0, 20, 30.0}); - return_two_float ((struct two_float) { 10.0, 20.0}); - return_one_int_one_double_packed ((struct one_int_one_double_packed) {10, 20.0}); - return_one_int_one_long ((struct one_int_one_long) {10, 20}); - - return_vector_size_float32_8 (( vector_size_float32_8 ){1.5, 2.25}); - return_vector_size_float32_16 (( vector_size_float32_16 ){1.5, 2.25, 4.125, 8.0625}); - return_vector_size_float32_32 (( vector_size_float32_32 ){1.5, 2.25, 4.125, 8.0625, 7.89, 8.52, 6.31, 9.12}); - - return_ext_vector_size_float32_2 ((ext_vector_size_float32_2){ 16.5, 32.25}); - return_ext_vector_size_float32_4 ((ext_vector_size_float32_4){ 16.5, 32.25, 64.125, 128.0625}); - return_ext_vector_size_float32_8 ((ext_vector_size_float32_8){ 16.5, 32.25, 64.125, 128.0625, 1.59, 3.57, 8.63, 9.12 }); - - return 0; -} Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp @@ -0,0 +1,607 @@ +// Some convenient things to return: +static char *g_first_pointer = "I am the first"; +static char *g_second_pointer = "I am the second"; + +// First we have some simple functions that return standard types, ints, floats and doubles. +// We have a function calling a function in a few cases to test that if you stop in the +// inner function then do "up/fin" you get the return value from the outer-most frame. + +int +inner_sint (int value) +{ + return value; +} + +int +outer_sint (int value) +{ + int outer_value = 2 * inner_sint (value); + return outer_value; +} + +float +inner_float (float value) +{ + return value; +} + +float +outer_float (float value) +{ + float outer_value = 2 * inner_float(value); + return outer_value; +} + +double +return_double (double value) +{ + return value; +} + +long double +return_long_double (long double value) +{ + return value; +} + +char * +return_pointer (char *value) +{ + return value; +} + +struct one_int +{ + int one_field; +}; + +struct one_int +return_one_int (struct one_int value) +{ + return value; +} + +struct two_int +{ + int first_field; + int second_field; +}; + +struct two_int +return_two_int (struct two_int value) +{ + return value; +} + +struct three_int +{ + int first_field; + int second_field; + int third_field; +}; + +struct three_int +return_three_int (struct three_int value) +{ + return value; +} + +struct four_int +{ + int first_field; + int second_field; + int third_field; + int fourth_field; +}; + +struct four_int +return_four_int (struct four_int value) +{ + return value; +} + +struct five_int +{ + int first_field; + int second_field; + int third_field; + int fourth_field; + int fifth_field; +}; + +struct five_int +return_five_int (struct five_int value) +{ + return value; +} + +struct one_int_one_double +{ + int first_field; + double second_field; +}; + +struct one_int_one_double +return_one_int_one_double (struct one_int_one_double value) +{ + return value; +} + +struct one_int_one_double_one_int +{ + int one_field; + double second_field; + int third_field; +}; + +struct one_int_one_double_one_int +return_one_int_one_double_one_int (struct one_int_one_double_one_int value) +{ + return value; +} + +struct one_short_one_double_one_short +{ + int one_field; + double second_field; + int third_field; +}; + +struct one_short_one_double_one_short +return_one_short_one_double_one_short (struct one_short_one_double_one_short value) +{ + return value; +} + +struct three_short_one_float +{ + short one_field; + short second_field; + short third_field; + float fourth_field; +}; + +struct three_short_one_float +return_three_short_one_float (struct three_short_one_float value) +{ + return value; +} + +struct one_int_one_float_one_int +{ + int one_field; + float second_field; + int third_field; +}; + +struct one_int_one_float_one_int +return_one_int_one_float_one_int (struct one_int_one_float_one_int value) +{ + return value; +} + +struct one_float_one_int_one_float +{ + float one_field; + int second_field; + float third_field; +}; + +struct one_float_one_int_one_float +return_one_float_one_int_one_float (struct one_float_one_int_one_float value) +{ + return value; +} + +struct one_double_two_float +{ + double one_field; + float second_field; + float third_field; +}; + +struct one_double_two_float +return_one_double_two_float (struct one_double_two_float value) +{ + return value; +} + +struct two_double +{ + double first_field; + double second_field; +}; + +struct two_double +return_two_double (struct two_double value) +{ + return value; +} + +struct two_float +{ + float first_field; + float second_field; +}; + +struct two_float +return_two_float (struct two_float value) +{ + return value; +} + +struct one_int_one_double_packed +{ + int first_field; + double second_field; +} __attribute__((__packed__)); + +struct one_int_one_double_packed +return_one_int_one_double_packed (struct one_int_one_double_packed value) +{ + return value; +} + +struct one_int_one_long +{ + int first_field; + long second_field; +}; + +struct one_int_one_long +return_one_int_one_long (struct one_int_one_long value) +{ + return value; +} + +struct one_pointer +{ + char *first_field; +}; + +struct one_pointer +return_one_pointer (struct one_pointer value) +{ + return value; +} + +struct two_pointer +{ + char *first_field; + char *second_field; +}; + +struct two_pointer +return_two_pointer (struct two_pointer value) +{ + return value; +} + +struct one_float_one_pointer +{ + float first_field; + char *second_field; +}; + +struct one_float_one_pointer +return_one_float_one_pointer (struct one_float_one_pointer value) +{ + return value; +} + +struct one_int_one_pointer +{ + int first_field; + char *second_field; +}; + +struct one_int_one_pointer +return_one_int_one_pointer (struct one_int_one_pointer value) +{ + return value; +} + +struct base_one_char { + char c; +}; + +struct nested_one_float_three_base { + float f; + struct base_one_char b1; + struct base_one_char b2; + struct base_one_char b3; +}; // returned in RAX for both SysV and Windows + +struct nested_one_float_three_base +return_nested_one_float_three_base (struct nested_one_float_three_base value) +{ + return value; +} + +struct double_nested_one_float_one_nested { + float f; + struct nested_one_float_three_base ns; +}; // SysV-ABI: returned in XMM0 + RAX +// Windows-ABI: returned in memory + +struct double_nested_one_float_one_nested +return_double_nested_one_float_one_nested(struct double_nested_one_float_one_nested value) +{ + return value; +} + +struct base_float_struct { + float f1; + float f2; +}; + +struct nested_float_struct { + double d; + struct base_float_struct bfs; +}; // SysV-ABI: return in xmm0 + xmm1 +// Windows-ABI: returned in memory + +struct nested_float_struct +return_nested_float_struct (struct nested_float_struct value) +{ + return value; +} + +struct six_double_three_int { + double d1; // 8 + double d2; // 8 + int i1; // 4 + double d3; // 8 + double d4; // 8 + int i2; // 4 + double d5; // 8 + double d6; // 8 + int i3; // 4 +}; // returned in memeory on both SysV and Windows + +struct six_double_three_int +return_six_double_three_int (struct six_double_three_int value) { + return value; +} + +typedef float vector_size_float32_8 __attribute__((__vector_size__(8))); +typedef float vector_size_float32_16 __attribute__((__vector_size__(16))); +typedef float vector_size_float32_32 __attribute__((__vector_size__(32))); + +typedef float ext_vector_size_float32_2 __attribute__((ext_vector_type(2))); +typedef float ext_vector_size_float32_4 __attribute__((ext_vector_type(4))); +typedef float ext_vector_size_float32_8 __attribute__((ext_vector_type(8))); + +vector_size_float32_8 +return_vector_size_float32_8 (vector_size_float32_8 value) +{ + return value; +} + +vector_size_float32_16 +return_vector_size_float32_16 (vector_size_float32_16 value) +{ + return value; +} + +vector_size_float32_32 +return_vector_size_float32_32 (vector_size_float32_32 value) +{ + return value; +} + +ext_vector_size_float32_2 +return_ext_vector_size_float32_2 (ext_vector_size_float32_2 value) +{ + return value; +} + +ext_vector_size_float32_4 +return_ext_vector_size_float32_4 (ext_vector_size_float32_4 value) +{ + return value; +} + +ext_vector_size_float32_8 +return_ext_vector_size_float32_8 (ext_vector_size_float32_8 value) +{ + return value; +} + +class base_class_one_char { +public: + char c = '!'; +}; // returned in RAX for both ABI + +base_class_one_char +return_base_class_one_char(base_class_one_char value) { + return value; +} + +class nested_class_float_and_base { +public: + float f = 0.1; + base_class_one_char b; +}; // returned in RAX for both ABI + +nested_class_float_and_base +return_nested_class_float_and_base(nested_class_float_and_base value) { + return value; +} + +class double_nested_class_float_and_nested { +public: + float f = 0.2; + nested_class_float_and_base n; +}; // SysV-ABI: returned in XMM0 + RAX +// Windows-ABI: returned in memory + +double_nested_class_float_and_nested +return_double_nested_class_float_and_nested( + double_nested_class_float_and_nested value) { + return value; +} + +class base_class { +public: + base_class() { + c = 'a'; + c2 = 'b'; + } +private: + char c; +protected: + char c2; +}; // returned in RAX for both ABI + +base_class +return_base_class(base_class value) { + return value; +} + +class sub_class : base_class { +public: + sub_class() { + c2 = '&'; + i = 10; + } +private: + int i; +}; // size 8; should be returned in RAX +// Since it's in register, lldb won't be able to get the +// fields in base class, expected to fail. + +sub_class +return_sub_class(sub_class value) { + return value; +} + +class abstract_class { +public: + virtual char getChar() = 0; +private: + int i = 8; +protected: + char c = '!'; +}; + +class derived_class : abstract_class { +public: + derived_class() { + c = '?'; + } + char getChar() { + return this->c; + } +private: + char c2 = '$'; +}; // size: 16; contains non POD member, returned in memory + +derived_class +return_derived_class(derived_class value) { + return value; +} + +int +main () +{ + int first_int = 123456; + int second_int = 234567; + + outer_sint (first_int); + outer_sint (second_int); + + float first_float_value = 12.34; + float second_float_value = 23.45; + + outer_float (first_float_value); + outer_float (second_float_value); + + double double_value = -23.45; + + return_double (double_value); + + return_pointer(g_first_pointer); + + long double long_double_value = -3456789.987654321; + + return_long_double (long_double_value); + + // Okay, now the structures: + return_one_int ((struct one_int) {10}); + return_two_int ((struct two_int) {10, 20}); + return_three_int ((struct three_int) {10, 20, 30}); + return_four_int ((struct four_int) {10, 20, 30, 40}); + return_five_int ((struct five_int) {10, 20, 30, 40, 50}); + + return_two_double ((struct two_double) {10.0, 20.0}); + return_one_double_two_float ((struct one_double_two_float) {10.0, 20.0, 30.0}); + return_one_int_one_float_one_int ((struct one_int_one_float_one_int) {10, 20.0, 30}); + + return_one_pointer ((struct one_pointer) {g_first_pointer}); + return_two_pointer ((struct two_pointer) {g_first_pointer, g_second_pointer}); + return_one_float_one_pointer ((struct one_float_one_pointer) {10.0, g_first_pointer}); + return_one_int_one_pointer ((struct one_int_one_pointer) {10, g_first_pointer}); + return_three_short_one_float ((struct three_short_one_float) {10, 20, 30, 40.0}); + + return_one_int_one_double ((struct one_int_one_double) {10, 20.0}); + return_one_int_one_double_one_int ((struct one_int_one_double_one_int) {10, 20.0, 30}); + return_one_short_one_double_one_short ((struct one_short_one_double_one_short) {10, 20.0, 30}); + return_one_float_one_int_one_float ((struct one_float_one_int_one_float) {10.0, 20, 30.0}); + return_two_float ((struct two_float) { 10.0, 20.0}); + return_one_int_one_double_packed ((struct one_int_one_double_packed) {10, 20.0}); + return_one_int_one_long ((struct one_int_one_long) {10, 20}); + + return_nested_one_float_three_base((struct nested_one_float_three_base) { + 10.0, + (struct base_one_char) { + 'x' + }, + (struct base_one_char) { + 'y' + }, + (struct base_one_char) { + 'z' + } + }); + return_double_nested_one_float_one_nested((struct double_nested_one_float_one_nested) { + 10.0, + (struct nested_one_float_three_base) { + 20.0, + (struct base_one_char) { + 'x' + }, + (struct base_one_char) { + 'y' + }, + (struct base_one_char) { + 'z' + } + }}); + return_nested_float_struct((struct nested_float_struct) { + 10.0, + (struct base_float_struct) { + 20.0, + 30.0 + }}); + return_six_double_three_int((struct six_double_three_int) { + 10.0, 20.0, 1, 30.0, 40.0, 2, 50.0, 60.0, 3}); + + return_base_class_one_char(base_class_one_char()); + return_nested_class_float_and_base(nested_class_float_and_base()); + return_double_nested_class_float_and_nested(double_nested_class_float_and_nested()); + return_base_class(base_class()); + // this is expected to fail + return_sub_class(sub_class()); + return_derived_class(derived_class()); + + return_vector_size_float32_8 (( vector_size_float32_8 ){1.5, 2.25}); + return_vector_size_float32_16 (( vector_size_float32_16 ){1.5, 2.25, 4.125, 8.0625}); + return_vector_size_float32_32 (( vector_size_float32_32 ){1.5, 2.25, 4.125, 8.0625, 7.89, 8.52, 6.31, 9.12}); + + return_ext_vector_size_float32_2 ((ext_vector_size_float32_2){ 16.5, 32.25}); + return_ext_vector_size_float32_4 ((ext_vector_size_float32_4){ 16.5, 32.25, 64.125, 128.0625}); + return_ext_vector_size_float32_8 ((ext_vector_size_float32_8){ 16.5, 32.25, 64.125, 128.0625, 1.59, 3.57, 8.63, 9.12 }); + + return 0; +} Index: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/trivial_abi/TestTrivialABI.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/trivial_abi/TestTrivialABI.py +++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/trivial_abi/TestTrivialABI.py @@ -28,7 +28,8 @@ self.expr_test(True) @skipUnlessSupportedTypeAttribute("trivial_abi") - @expectedFailureAll(bugnumber="llvm.org/pr36870") + # fixed for SysV-x86_64 ABI, but not Windows-x86_64 + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr36870") def test_call_nontrivial(self): """Test that we can print a variable & call a function on the same class w/o the trivial ABI marker.""" self.build() Index: lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp =================================================================== --- lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp @@ -30,6 +30,8 @@ #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" +#include + using namespace lldb; using namespace lldb_private; @@ -1558,6 +1560,55 @@ return return_valobj_sp; } +// The compiler will flatten the nested aggregate type into single +// layer and push the value to stack +// This helper function will flatten an aggregate type +// and return true if it can be returned in register(s) by value +// return false if the aggregate is in memory +static bool FlattenAggregateType( + Thread &thread, ExecutionContext &exe_ctx, + CompilerType &return_compiler_type, + uint32_t data_byte_offset, + std::vector &aggregate_field_offsets, + std::vector &aggregate_compiler_types) { + + const uint32_t num_children = return_compiler_type.GetNumFields(); + for (uint32_t idx = 0; idx < num_children; ++idx) { + std::string name; + bool is_signed; + uint32_t count; + bool is_complex; + + uint64_t field_bit_offset = 0; + CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( + idx, name, &field_bit_offset, nullptr, nullptr); + llvm::Optional field_bit_width = + field_compiler_type.GetBitSize(&thread); + + // if we don't know the size of the field (e.g. invalid type), exit + if (!field_bit_width || *field_bit_width == 0) { + return false; + } + + uint32_t field_byte_offset = field_bit_offset / 8 + data_byte_offset; + + const uint32_t field_type_flags = field_compiler_type.GetTypeInfo(); + if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || + field_compiler_type.IsPointerType() || + field_compiler_type.IsFloatingPointType(count, is_complex)) { + aggregate_field_offsets.push_back(field_byte_offset); + aggregate_compiler_types.push_back(field_compiler_type); + } else if (field_type_flags & eTypeHasChildren) { + if (!FlattenAggregateType(thread, exe_ctx, field_compiler_type, + field_byte_offset, aggregate_field_offsets, + aggregate_compiler_types)) { + return false; + } + } + } + return true; +} + ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( Thread &thread, CompilerType &return_compiler_type) const { ValueObjectSP return_valobj_sp; @@ -1580,10 +1631,17 @@ if (return_compiler_type.IsAggregateType()) { Target *target = exe_ctx.GetTargetPtr(); bool is_memory = true; - if (*bit_width <= 128) { - ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder(); + std::vector aggregate_field_offsets; + std::vector aggregate_compiler_types; + if (return_compiler_type.GetTypeSystem()->CanPassInRegisters( + return_compiler_type) && + *bit_width <= 128 && + FlattenAggregateType(thread, exe_ctx, return_compiler_type, + 0, aggregate_field_offsets, + aggregate_compiler_types)) { + ByteOrder byte_order = target->GetArchitecture().GetByteOrder(); DataBufferSP data_sp(new DataBufferHeap(16, 0)); - DataExtractor return_ext(data_sp, target_byte_order, + DataExtractor return_ext(data_sp, byte_order, target->GetArchitecture().GetAddressByteSize()); const RegisterInfo *rax_info = @@ -1613,36 +1671,27 @@ uint32_t integer_bytes = 0; // Tracks how much of the rax/rds registers we've consumed so far - const uint32_t num_children = return_compiler_type.GetNumFields(); + // in case of the returned type is a subclass of non-abstract-base class + // it will have a padding to skip the base content + if (aggregate_field_offsets.size()) { + fp_bytes = aggregate_field_offsets[0]; + integer_bytes = aggregate_field_offsets[0]; + } + + const uint32_t num_children = aggregate_compiler_types.size(); // Since we are in the small struct regime, assume we are not in memory. is_memory = false; - for (uint32_t idx = 0; idx < num_children; idx++) { - std::string name; - uint64_t field_bit_offset = 0; bool is_signed; - bool is_complex; uint32_t count; + bool is_complex; - CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( - idx, name, &field_bit_offset, nullptr, nullptr); - llvm::Optional field_bit_width = - field_compiler_type.GetBitSize(&thread); - - // if we don't know the size of the field (e.g. invalid type), just - // bail out - if (!field_bit_width || *field_bit_width == 0) - break; - - // If there are any unaligned fields, this is stored in memory. - if (field_bit_offset % *field_bit_width != 0) { - is_memory = true; - break; - } + CompilerType field_compiler_type = aggregate_compiler_types[idx]; + uint32_t field_byte_width = (uint32_t) (*field_compiler_type.GetByteSize(&thread)); + uint32_t field_byte_offset = aggregate_field_offsets[idx]; - uint32_t field_byte_width = *field_bit_width / 8; - uint32_t field_byte_offset = field_bit_offset / 8; + uint32_t field_bit_width = field_byte_width * 8; DataExtractor *copy_from_extractor = nullptr; uint32_t copy_from_offset = 0; @@ -1674,10 +1723,10 @@ } } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { // Structs with long doubles are always passed in memory. - if (*field_bit_width == 128) { + if (field_bit_width == 128) { is_memory = true; break; - } else if (*field_bit_width == 64) { + } else if (field_bit_width == 64) { // These have to be in a single xmm register. if (fp_bytes == 0) copy_from_extractor = &xmm0_data; @@ -1686,7 +1735,7 @@ copy_from_offset = 0; fp_bytes += field_byte_width; - } else if (*field_bit_width == 32) { + } else if (field_bit_width == 32) { // This one is kind of complicated. If we are in an "eightbyte" // with another float, we'll be stuffed into an xmm register with // it. If we are in an "eightbyte" with one or more ints, then we @@ -1695,18 +1744,15 @@ if (field_byte_offset % 8 == 0) { // We are at the beginning of one of the eightbytes, so check the // next element (if any) - if (idx == num_children - 1) + if (idx == num_children - 1) { in_gpr = false; - else { - uint64_t next_field_bit_offset = 0; + } else { CompilerType next_field_compiler_type = - return_compiler_type.GetFieldAtIndex(idx + 1, name, - &next_field_bit_offset, - nullptr, nullptr); + aggregate_compiler_types[idx + 1]; if (next_field_compiler_type.IsIntegerOrEnumerationType( - is_signed)) + is_signed)) { in_gpr = true; - else { + } else { copy_from_offset = 0; in_gpr = false; } @@ -1715,18 +1761,15 @@ // We are inside of an eightbyte, so see if the field before us // is floating point: This could happen if somebody put padding // in the structure. - if (idx == 0) + if (idx == 0) { in_gpr = false; - else { - uint64_t prev_field_bit_offset = 0; + } else { CompilerType prev_field_compiler_type = - return_compiler_type.GetFieldAtIndex(idx - 1, name, - &prev_field_bit_offset, - nullptr, nullptr); + aggregate_compiler_types[idx - 1]; if (prev_field_compiler_type.IsIntegerOrEnumerationType( - is_signed)) + is_signed)) { in_gpr = true; - else { + } else { copy_from_offset = 4; in_gpr = false; } @@ -1759,7 +1802,6 @@ } } } - // These two tests are just sanity checks. If I somehow get the type // calculation wrong above it is better to just return nothing than to // assert or crash. @@ -1768,13 +1810,11 @@ if (copy_from_offset + field_byte_width > copy_from_extractor->GetByteSize()) return return_valobj_sp; - copy_from_extractor->CopyByteOrderedData( copy_from_offset, field_byte_width, data_sp->GetBytes() + field_byte_offset, field_byte_width, - target_byte_order); + byte_order); } - if (!is_memory) { // The result is in our data buffer. Let's make a variable object out // of it: Index: lldb/trunk/source/Symbol/ClangASTContext.cpp =================================================================== --- lldb/trunk/source/Symbol/ClangASTContext.cpp +++ lldb/trunk/source/Symbol/ClangASTContext.cpp @@ -3911,6 +3911,14 @@ return GetCanonicalQualType(type)->isVoidType(); } +bool ClangASTContext::CanPassInRegisters(const CompilerType &type) { + if (auto *record_decl = + ClangASTContext::GetAsRecordDecl(type)) { + return record_decl->canPassInRegisters(); + } + return false; +} + bool ClangASTContext::SupportsLanguage(lldb::LanguageType language) { return ClangASTContextSupportsLanguage(language); }