[Lldb-commits] [lldb] r362543 - [ABI] Fix SystemV ABI to handle nested aggregate type returned in register

Alex Langford via lldb-commits lldb-commits at lists.llvm.org
Tue Jun 4 12:30:00 PDT 2019


Author: xiaobai
Date: Tue Jun  4 12:29:59 2019
New Revision: 362543

URL: http://llvm.org/viewvc/llvm-project?rev=362543&view=rev
Log:
[ABI] Fix SystemV ABI to handle nested aggregate type returned in register

Add a function to flatten the nested aggregate type

Differential Revision: https://reviews.llvm.org/D62702

Patch by Wanyi Ye <kusmour at gmail.com>

Added:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp
      - copied, changed from r362510, lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c
Removed:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c
Modified:
    lldb/trunk/include/lldb/Symbol/ClangASTContext.h
    lldb/trunk/include/lldb/Symbol/TypeSystem.h
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
    lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/trivial_abi/TestTrivialABI.py
    lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
    lldb/trunk/source/Symbol/ClangASTContext.cpp

Modified: lldb/trunk/include/lldb/Symbol/ClangASTContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ClangASTContext.h?rev=362543&r1=362542&r2=362543&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/ClangASTContext.h (original)
+++ lldb/trunk/include/lldb/Symbol/ClangASTContext.h Tue Jun  4 12:29:59 2019
@@ -598,6 +598,8 @@ public:
 
   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,

Modified: lldb/trunk/include/lldb/Symbol/TypeSystem.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/TypeSystem.h?rev=362543&r1=362542&r2=362543&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/TypeSystem.h (original)
+++ lldb/trunk/include/lldb/Symbol/TypeSystem.h Tue Jun  4 12:29:59 2019
@@ -181,6 +181,8 @@ public:
 
   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;
 

Modified: lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/Makefile?rev=362543&r1=362542&r2=362543&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/Makefile (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/Makefile Tue Jun  4 12:29:59 2019
@@ -1,5 +1,5 @@
 LEVEL = ../../make
 
-C_SOURCES := call-func.c
+CXX_SOURCES := call-func.cpp
 
 include $(LEVEL)/Makefile.rules

Modified: lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py?rev=362543&r1=362542&r2=362543&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py Tue Jun  4 12:29:59 2019
@@ -57,7 +57,7 @@ class ReturnValueTestCase(TestBase):
 
         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 @@ class ReturnValueTestCase(TestBase):
 
         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 @@ class ReturnValueTestCase(TestBase):
 
         # 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 @@ class ReturnValueTestCase(TestBase):
 
         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 @@ class ReturnValueTestCase(TestBase):
         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."""
 

Removed: lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c?rev=362542&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c (removed)
@@ -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; 
-}

Copied: lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp (from r362510, lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c)
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp?p2=lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp&p1=lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c&r1=362510&r2=362543&rev=362543&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp Tue Jun  4 12:29:59 2019
@@ -301,6 +301,69 @@ return_one_int_one_pointer (struct one_i
   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)));
@@ -345,6 +408,100 @@ return_ext_vector_size_float32_8 (ext_ve
     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 ()
 {
@@ -395,6 +552,49 @@ main ()
   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});

Modified: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/trivial_abi/TestTrivialABI.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/trivial_abi/TestTrivialABI.py?rev=362543&r1=362542&r2=362543&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/trivial_abi/TestTrivialABI.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/trivial_abi/TestTrivialABI.py Tue Jun  4 12:29:59 2019
@@ -28,7 +28,8 @@ class TestTrivialABI(TestBase):
         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()

Modified: lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp?rev=362543&r1=362542&r2=362543&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp Tue Jun  4 12:29:59 2019
@@ -30,6 +30,8 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/Status.h"
 
+#include <vector>
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -1558,6 +1560,55 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
   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<uint32_t> &aggregate_field_offsets,
+    std::vector<CompilerType> &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<uint64_t> 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 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
   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<uint32_t> aggregate_field_offsets;
+    std::vector<CompilerType> 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 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
       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<uint64_t> 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 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
           }
         } 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 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
 
             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 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
             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 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
               // 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 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
             }
           }
         }
-
         // 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 @@ ValueObjectSP ABISysV_x86_64::GetReturnV
         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:

Modified: lldb/trunk/source/Symbol/ClangASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTContext.cpp?rev=362543&r1=362542&r2=362543&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/ClangASTContext.cpp (original)
+++ lldb/trunk/source/Symbol/ClangASTContext.cpp Tue Jun  4 12:29:59 2019
@@ -3911,6 +3911,14 @@ bool ClangASTContext::IsVoidType(lldb::o
   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);
 }




More information about the lldb-commits mailing list