Skip to content

Commit

Permalink
Implement packed structures (RFC 32)
Browse files Browse the repository at this point in the history
This change adds program annotations allowing programmers to declare
packed structures, i.e. structures without implementation-specific
padding between members.

Closes #1523.
  • Loading branch information
Benoit Vey committed Jan 26, 2017
1 parent 9739cad commit 08d9657
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
9 changes: 8 additions & 1 deletion src/libponyc/codegen/gentype.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ static bool make_struct(compile_t* c, reach_type_t* t)
{
LLVMTypeRef type;
int extra = 0;
bool packed = false;

switch(t->underlying)
{
Expand All @@ -421,12 +422,18 @@ static bool make_struct(compile_t* c, reach_type_t* t)
break;

case TK_STRUCT:
{
// Pointer and Maybe will have no structure.
if(t->structure == NULL)
return true;

type = t->structure;
ast_t* def = (ast_t*)ast_data(t->ast);
if(ast_has_annotation(def, "packed"))
packed = true;

break;
}

case TK_PRIMITIVE:
// Machine words will have a primitive.
Expand Down Expand Up @@ -481,7 +488,7 @@ static bool make_struct(compile_t* c, reach_type_t* t)
}
}

LLVMStructSetBody(type, elements, t->field_count + extra, false);
LLVMStructSetBody(type, elements, t->field_count + extra, packed);
ponyint_pool_free_size(buf_size, elements);
return true;
}
Expand Down
105 changes: 105 additions & 0 deletions test/libponyc/codegen.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <gtest/gtest.h>
#include <platform.h>

#include <reach/reach.h>

#include "util.h"

#ifdef _MSC_VER
// Stop MSVC from complaining about conversions from LLVMBool to bool.
# pragma warning(disable:4800)
#endif

#define TEST_COMPILE(src) DO(test_compile(src, "ir"))


class CodegenTest : public PassTest
{};


TEST_F(CodegenTest, PackedStructIsPacked)
{
const char* src =
"struct \\packed\\ Foo\n"
" var a: U8 = 0\n"
" var b: U32 = 0\n"

"actor Main\n"
" new create(env: Env) =>\n"
" Foo";

TEST_COMPILE(src);

reach_t* reach = compile->reach;
reach_type_t* foo = reach_type_name(reach, "Foo");
ASSERT_TRUE(foo != NULL);

LLVMTypeRef type = foo->structure;
ASSERT_TRUE(LLVMIsPackedStruct(type));
}


TEST_F(CodegenTest, NonPackedStructIsntPacked)
{
const char* src =
"struct Foo\n"
" var a: U8 = 0\n"
" var b: U32 = 0\n"

"actor Main\n"
" new create(env: Env) =>\n"
" Foo";

TEST_COMPILE(src);

reach_t* reach = compile->reach;
reach_type_t* foo = reach_type_name(reach, "Foo");
ASSERT_TRUE(foo != NULL);

LLVMTypeRef type = foo->structure;
ASSERT_TRUE(!LLVMIsPackedStruct(type));
}


TEST_F(CodegenTest, ClassCannotBePacked)
{
const char* src =
"class \\packed\\ Foo\n"
" var a: U8 = 0\n"
" var b: U32 = 0\n"

"actor Main\n"
" new create(env: Env) =>\n"
" Foo";

TEST_COMPILE(src);

reach_t* reach = compile->reach;
reach_type_t* foo = reach_type_name(reach, "Foo");
ASSERT_TRUE(foo != NULL);

LLVMTypeRef type = foo->structure;
ASSERT_TRUE(!LLVMIsPackedStruct(type));
}


TEST_F(CodegenTest, ActorCannotBePacked)
{
const char* src =
"actor \\packed\\ Foo\n"
" var a: U8 = 0\n"
" var b: U32 = 0\n"

"actor Main\n"
" new create(env: Env) =>\n"
" Foo";

TEST_COMPILE(src);

reach_t* reach = compile->reach;
reach_type_t* foo = reach_type_name(reach, "Foo");
ASSERT_TRUE(foo != NULL);

LLVMTypeRef type = foo->structure;
ASSERT_TRUE(!LLVMIsPackedStruct(type));
}

0 comments on commit 08d9657

Please sign in to comment.