Skip to content

Commit

Permalink
Add @PACKED attribute for structs. Closes #32.
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiayang committed Oct 20, 2019
1 parent cbaca99 commit 8402c46
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 24 deletions.
30 changes: 24 additions & 6 deletions build/ultratiny.flx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

export ultratiny

import libc as _
import std::math

// import libc as _
// import std::math
/*
@compiler_support["raii_trait::drop"] trait Drop { fn deinit() }
@compiler_support["raii_trait::copy"] trait Copy { fn copy(other: &self) }
@compiler_support["raii_trait::move"] trait Move { fn move(other: &mut self) }
Expand Down Expand Up @@ -49,12 +49,30 @@ fn stuff2() -> Bar
{
return Bar(x: 57)
}
*/

ffi fn printf(fmt: &i8, ...) -> i32

struct Thicc
{
x: i64
y: i8
}

@packed struct Flat
{
x: i64
y: i8
}

@entry fn main()
{
let q = stuff()
let p = stuff2()
printf("q = %d\n", q)
// let q = stuff()
// let p = stuff2()
// printf("q = %d\n", q)
let x = Flat(x: 3, y: 20)

printf("%d, %d, %d\n", sizeof(x), sizeof(Thicc), sizeof(Flat))
}


Expand Down
44 changes: 31 additions & 13 deletions source/fir/Types/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1005,28 +1005,44 @@ namespace fir



static size_t getAggregateSize(const std::vector<Type*>& tys)
static size_t getAggregateSize(const std::vector<Type*>& tys, bool packed = false)
{
size_t ptr = 0;
size_t aln = 0;

for(auto ty : tys)
if(packed)
{
auto a = getAlignmentOfType(ty);
iceAssert(a > 0);
// gg
// return util::foldl(0, tys, [](Type* a, Type* b) -> size_t {
// return getSizeOfType(a) + getSizeOfType(b);
// });

if(ptr % a > 0)
ptr += (a - (ptr % a));
size_t ret = 0;
for(const auto& t : tys)
ret += getSizeOfType(t);

ptr += getSizeOfType(ty);
aln = std::max(aln, a);
return ret;
}
else
{
for(auto ty : tys)
{
auto a = getAlignmentOfType(ty);
iceAssert(a > 0);

iceAssert(aln > 0);
if(ptr % aln > 0)
ptr += (aln - (ptr % aln));
if(ptr % a > 0)
ptr += (a - (ptr % a));

return ptr;
ptr += getSizeOfType(ty);
aln = std::max(aln, a);
}

iceAssert(aln > 0);
if(ptr % aln > 0)
ptr += (aln - (ptr % aln));

return ptr;
}
}

size_t getSizeOfType(Type* type)
Expand Down Expand Up @@ -1058,6 +1074,7 @@ namespace fir
}
else if(type->isClassType() || type->isStructType() || type->isTupleType())
{
bool packed = false;
std::vector<Type*> tys;

if(type->isClassType())
Expand All @@ -1067,14 +1084,15 @@ namespace fir
}
else if(type->isStructType())
{
packed = type->toStructType()->isPackedStruct();
tys = type->toStructType()->getElements();
}
else
{
tys = type->toTupleType()->getElements();
}

return getAggregateSize(tys);
return getAggregateSize(tys, packed);
}
else if(type->isUnionType() )
{
Expand Down
6 changes: 6 additions & 0 deletions source/frontend/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,12 @@ namespace lexer
tok.text = "@entry";
read = 6;
}
else if(hasPrefix(stream, "@packed"))
{
tok.type = TokenType::Attr_Packed;
tok.text = "@packed";
read = 7;
}
else if(hasPrefix(stream, "@raw"))
{
tok.type = TokenType::Attr_Raw;
Expand Down
6 changes: 5 additions & 1 deletion source/frontend/parser/expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ namespace parser
if((attrs.flags & FN_ENTRYPOINT) && !(allowed.flags & FN_ENTRYPOINT))
error(ret, "unsupported attribute '@entry' on %s", ret->readableName);

if((attrs.flags & PACKED) && !(allowed.flags & PACKED))
error(ret, "unsupported attribute '@packed' on %s", ret->readableName);


// here let's check the arguments and stuff for default attributes.
// note: due to poor API design on my part, if there is no attribute with that name then ::get()
// returns an empty UA, which has a blank name -- so we check that instead.
Expand Down Expand Up @@ -155,7 +159,7 @@ namespace parser
return enforceAttrs(parseUnion(st, attrs.has(attr::RAW), /* nameless: */ false), AttribSet::of(attr::RAW));

case TT::Struct:
return enforceAttrs(parseStruct(st, /* nameless: */ false));
return enforceAttrs(parseStruct(st, /* nameless: */ false), AttribSet::of(attr::PACKED));

case TT::Class:
return enforceAttrs(parseClass(st));
Expand Down
15 changes: 12 additions & 3 deletions source/frontend/parser/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,14 @@ namespace parser
{
using UA = AttribSet::UserAttrib;

if(st.front() <= TT::Attr_ATTRS_BEGIN || st.front() >= TT::Attr_ATTRS_END)
if(st.front() != TT::At && (st.front() <= TT::Attr_ATTRS_BEGIN || st.front() >= TT::Attr_ATTRS_END))
return AttribSet::of(attr::NONE);

auto parseUA = [](State& st) -> UA {

iceAssert(st.front() == TT::At);
st.pop();

auto ret = UA(st.eat().str(), {});

if(st.front() == TT::LSquare)
Expand Down Expand Up @@ -142,23 +145,29 @@ namespace parser


AttribSet ret;
while(st.front() > TT::Attr_ATTRS_BEGIN && st.front() < TT::Attr_ATTRS_END)
while(true)
{
// i would love me some static reflection right now
switch(st.front())
{
case TT::Attr_Raw: ret.set(attr::RAW); st.pop(); break;
case TT::Attr_Packed: ret.set(attr::PACKED); st.pop(); break;
case TT::Attr_NoMangle: ret.set(attr::NO_MANGLE); st.pop(); break;
case TT::Attr_EntryFn: ret.set(attr::FN_ENTRYPOINT); st.pop(); break;
case TT::Attr_Platform: unexpected(st.loc(), "@platform definition");
case TT::Attr_Operator: unexpected(st.loc(), "@operator declaration");

default:
case TT::At:
ret.add(parseUA(st));
break;

default:
goto out;
}
}

// sue me
out:
return ret;
}

Expand Down
1 change: 1 addition & 0 deletions source/include/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ namespace lexer
Attr_ATTRS_BEGIN,

Attr_Raw,
Attr_Packed,
Attr_EntryFn,
Attr_NoMangle,
Attr_Operator,
Expand Down
1 change: 1 addition & 0 deletions source/include/stcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace attr
constexpr FlagTy FN_ENTRYPOINT = 0x1;
constexpr FlagTy NO_MANGLE = 0x2;
constexpr FlagTy RAW = 0x4;
constexpr FlagTy PACKED = 0x8;
}

struct AttribSet
Expand Down
12 changes: 12 additions & 0 deletions source/include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ namespace util
}


template <typename T, typename U, class FoldOp>
U foldl(const U& i, const std::vector<T>& xs, FoldOp fn)
{
auto ret = i;
for(const auto& x : xs)
ret = fn(ret, x);

return ret;
}



template <typename T, class UnaryOp, typename K = typename std::result_of<UnaryOp(T)>::type>
std::vector<K> map(const std::vector<T>& input, UnaryOp fn)
{
Expand Down
2 changes: 1 addition & 1 deletion source/typecheck/structs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ TCResult ast::StructDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type
for(auto m : this->methods)
m->parentType = this, m->realScope = this->realScope + defn->id.name;

auto str = fir::StructType::createWithoutBody(defn->id);
auto str = fir::StructType::createWithoutBody(defn->id, /* isPacked: */ this->attrs.has(attr::PACKED));
defn->type = str;

fs->checkForShadowingOrConflictingDefinition(defn, [](sst::TypecheckState* fs, sst::Defn* other) -> bool { return true; });
Expand Down

0 comments on commit 8402c46

Please sign in to comment.