Skip to content

Commit

Permalink
[ABI] Fix SystemV ABI to handle nested aggregate type returned in reg…
Browse files Browse the repository at this point in the history
…ister

Add a function to flatten the nested aggregate type

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

Patch by Wanyi Ye <kusmour@gmail.com>

llvm-svn: 362543
  • Loading branch information
bulbazord committed Jun 4, 2019
1 parent 2e207d4 commit a03e2b2
Show file tree
Hide file tree
Showing 8 changed files with 338 additions and 54 deletions.
2 changes: 2 additions & 0 deletions lldb/include/lldb/Symbol/ClangASTContext.h
Expand Up @@ -598,6 +598,8 @@ class ClangASTContext : public TypeSystem {

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,
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Symbol/TypeSystem.h
Expand Up @@ -181,6 +181,8 @@ class TypeSystem : public PluginInterface {

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;

Expand Down
@@ -1,5 +1,5 @@
LEVEL = ../../make

C_SOURCES := call-func.c
CXX_SOURCES := call-func.cpp

include $(LEVEL)/Makefile.rules
Expand Up @@ -57,7 +57,7 @@ def test_with_python(self):

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())
Expand All @@ -78,7 +78,7 @@ def test_with_python(self):

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())

Expand All @@ -98,7 +98,7 @@ def test_with_python(self):

# 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(
Expand All @@ -118,7 +118,7 @@ def test_with_python(self):

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())
Expand Down Expand Up @@ -190,6 +190,37 @@ def test_vector_values(self):
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."""

Expand Down
Expand Up @@ -301,6 +301,69 @@ 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)));
Expand Down Expand Up @@ -345,6 +408,100 @@ 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 ()
{
Expand Down Expand Up @@ -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});
Expand Down
Expand Up @@ -28,7 +28,8 @@ def test_call_trivial(self):
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()
Expand Down

0 comments on commit a03e2b2

Please sign in to comment.