kusmour updated this revision to Diff 202574.
kusmour marked an inline comment as done.
kusmour added a comment.
small update :)
Repository:
rLLDB LLDB
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D62702/new/
https://reviews.llvm.org/D62702
Files:
lldb/include/lldb/Symbol/ClangASTContext.h
lldb/include/lldb/Symbol/TypeSystem.h
lldb/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
lldb/packages/Python/lldbsuite/test/functionalities/return-value/call-func.c
lldb/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp
lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
lldb/source/Symbol/ClangASTContext.cpp
Index: lldb/source/Symbol/ClangASTContext.cpp
===================================================================
--- lldb/source/Symbol/ClangASTContext.cpp
+++ lldb/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);
}
Index: lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
===================================================================
--- lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ lldb/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 <vector>
+
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<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 @@
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,40 +1671,33 @@
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;
+ const uint32_t field_type_flags = field_compiler_type.GetTypeInfo();
+
if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) ||
field_compiler_type.IsPointerType()) {
if (integer_bytes < 8) {
@@ -1674,10 +1725,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 +1737,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 +1746,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 +1763,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 +1804,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 +1812,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/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp
+++ lldb/packages/Python/lldbsuite/test/functionalities/return-value/call-func.cpp
@@ -301,6 +301,50 @@
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;
+}; // This should be returned in RAX
+
+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;
+}; // This should be returned in XMM0 + RAX
+
+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;
+}; // This should be return in xmm0 + xmm1
+
+struct nested_float_struct
+return_nested_float_struct (struct nested_float_struct 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 +389,100 @@
return value;
}
+class base_class_one_char {
+public:
+ char c = '!';
+}; // returned in RAX
+
+base_class_one_char
+return_base_class_one_char(base_class_one_char value) {
+ return value;
+}
+
+class nested_class_float_and_base {
+public:
+ // int i = 0;
+ float f = 0.1;
+ base_class_one_char b;
+}; // This should be returned in RAX
+
+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;
+}; // This should be returned in XMM0 + RAX
+
+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;
+};
+
+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; should be returned in memeory
+
+derived_class
+return_derived_class(derived_class value) {
+ return value;
+}
+
int
main ()
{
@@ -395,6 +533,47 @@
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_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});
Index: lldb/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
+++ lldb/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())
@@ -154,6 +154,16 @@
# about alignment when reading DWARF for packed types.
#self.return_and_test_struct_value ("return_one_int_one_double_packed")
self.return_and_test_struct_value("return_one_int_one_long")
+ # 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")
@expectedFailureAll(oslist=["freebsd"], archs=["i386"])
@expectedFailureAll(oslist=["macosx"], archs=["i386"], bugnumber="<rdar://problem/28719652>")
Index: lldb/include/lldb/Symbol/TypeSystem.h
===================================================================
--- lldb/include/lldb/Symbol/TypeSystem.h
+++ lldb/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/include/lldb/Symbol/ClangASTContext.h
===================================================================
--- lldb/include/lldb/Symbol/ClangASTContext.h
+++ lldb/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,
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits