summaryrefslogtreecommitdiff
path: root/Notes/CodegenCEmbeddedTags.diff
blob: 62fea1cb11c6c1e126d7b315d8906a67c58e168e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 9af87d47..bcf296db 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -1385,12 +1385,22 @@ namespace {
 
         void emit_enum_path(const TypeRepr* repr, const TypeRepr::FieldPath& path)
         {
-            if( TU_TEST1(repr->variants, Values, .field.index == path.index) )
+            if( TU_TEST1(repr->variants, Values, .field.index == path.index) || path.index == ~0u )
             {
-                m_of << ".TAG";
+                // TODO: The tag can be within the union
+                if( repr->fields.size() >= 2 )
+                {
+                    m_of << ".DATA.var_tag.TAG";
+                }
+                else
+                {
+                    m_of << ".TAG";
+                }
+                return ;
             }
             else
             {
+                // TODO: Support for non-zero offsets?
                 m_of << ".DATA.var_" << path.index;
             }
             const auto* ty = &repr->fields[path.index].ty;
@@ -1458,55 +1468,44 @@ namespace {
                 assert(1 + union_fields.size() + 1 >= repr->fields.size());
                 // Make the union!
                 // NOTE: The way the structure generation works is that enum variants are always first, so the field index = the variant index
-                // TODO: 
-                if( !this->type_is_bad_zst(repr->fields[0].ty) || ::std::any_of(union_fields.begin(), union_fields.end(), [this,repr](auto x){ return !this->type_is_bad_zst(repr->fields[x].ty); }) )
+                m_of << "\tunion {\n";
+                bool is_tagged = (1 + union_fields.size() < repr->fields.size());
+                // > First field
+                for(size_t idx = 0; idx < repr->fields.size()-(is_tagged ? 1 : 0); idx ++)
                 {
-                    m_of << "\tunion {\n";
-                    // > First field
-                    {
-                        m_of << "\t\t";
-                        const auto& ty = repr->fields[0].ty;
-                        if( this->type_is_bad_zst(ty) ) {
-                            m_of << "// ZST: " << ty << "\n";
-                        }
-                        else {
-                            emit_ctype( ty, FMT_CB(ss, ss << "var_0") );
-                            m_of << ";\n";
-                            //sized_fields ++;
-                        }
+                    m_of << "\t\tstruct {";
+                    const auto& ty = repr->fields[idx].ty;
+                    if( this->type_is_bad_zst(ty) ) {
+                        m_of << "/* ZST: " << ty << "*/";
                     }
-                    // > All others
-                    for(auto idx : union_fields)
+                    else {
+                        emit_ctype( ty, FMT_CB(os, os << "d") );
+                        m_of << ";";
+                        //sized_fields ++;
+                    }
+                    if( is_tagged )
                     {
-                        m_of << "\t\t";
-
-                        const auto& ty = repr->fields[idx].ty;
-                        if( this->type_is_bad_zst(ty) ) {
-                            m_of << "// ZST: " << ty << "\n";
-                        }
-                        else {
-                            emit_ctype( ty, FMT_CB(ss, ss << "var_" << idx) );
-                            m_of << ";\n";
-                            //sized_fields ++;
+                        auto padbytes = repr->fields.back().offset - Target_GetSizeOf(ty);
+                        if( padbytes > 0 )
+                        {
+                            m_of << "char pad[" << padbytes << "];";
                         }
+                        emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); m_of << ";";
                     }
-                    m_of << "\t} DATA;\n";
+                    m_of << "} var_" << idx << "\n";
                 }
-
-                if( repr->fields.size() == 1 + union_fields.size() )
+                // NOTE: The tag can be placed within variants (overlapping with padding bytes)
+                if( !is_tagged )
                 {
                     // No tag, the tag is in one of the fields.
                     DEBUG("Untagged, nonzero or other");
                 }
                 else
                 {
-                    //assert(repr->fields.back().offset != repr->fields.front().offset);
                     DEBUG("Tag present at offset " << repr->fields.back().offset << " - " << repr->fields.back().ty);
-
-                    m_of << "\t";
-                    emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG"));
-                    m_of << ";\n";
+                    m_of << "\t\tstruct { char pad[" << repr->fields.back().offset << "]; "; emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); m_of << "; } var_tag;\n";
                 }
+                m_of << "\t} DATA;\n";
             }
             else if( repr->fields.size() == 1 )
             {
@@ -1591,7 +1590,7 @@ namespace {
                 {
                     auto var_lv =::MIR::LValue::new_Downcast(mv$(self), 0);
 
-                    m_of << "\tswitch(rv->TAG) {\n";
+                    m_of << "\tswitch((*rv)";emit_enum_path(repr, {~0u}); m_of << ") {\n";
                     for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++)
                     {
                         m_of << "\tcase " << e->values[var_idx] << ":\n";
@@ -1652,7 +1651,7 @@ namespace {
             {
             case TypeRepr::VariantMode::TAGDEAD:    throw "";
             TU_ARM(repr->variants, Values, ve) {
-                m_of << " .TAG = "; emit_enum_variant_val(repr, var_idx); m_of << ",";
+                m_of << " .DATA = { .var_tag = { .TAG = "; emit_enum_variant_val(repr, var_idx); m_of << " }},";
                 } break;
             TU_ARM(repr->variants, NonZero, ve) {
                 } break;
@@ -1949,7 +1948,7 @@ namespace {
                         emit_literal(ity, *e.val, params);
                         m_of << " }, ";
                     }
-                    m_of << ".TAG = "; emit_enum_variant_val(repr, e.idx);
+                    emit_enum_path(repr, {~0u}); m_of << " = "; emit_enum_variant_val(repr, e.idx);
                     m_of << "}";
                 }
                 ),
@@ -3292,11 +3291,11 @@ namespace {
                         }
                         else if( enm_p->is_value() )
                         {
-                            emit_lvalue(e.dst); m_of << ".TAG = "; emit_enum_variant_val(repr, ve.index);
+                            emit_lvalue(e.dst); emit_enum_path(repr, {~0u}); m_of << " = "; emit_enum_variant_val(repr, ve.index);
                         }
                         else
                         {
-                            emit_lvalue(e.dst); m_of << ".TAG = "; emit_enum_variant_val(repr, ve.index);
+                            emit_lvalue(e.dst); emit_enum_path(repr, {~0u}); m_of << " = "; emit_enum_variant_val(repr, ve.index);
 
                             ::HIR::TypeRef  tmp;
                             const auto& vty = mir_res.get_param_type(tmp, ve.val);
@@ -3542,7 +3541,7 @@ namespace {
             if (ve.type.m_data.is_Primitive() && ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum())
             {
                 emit_lvalue(ve.val);
-                m_of << ".TAG";
+                m_of << ".TAG"; // TODO: Fix for tag locations? (may not be needed for value-only enums)
                 special = true;
             }
             if (!special)
@@ -3605,7 +3604,7 @@ namespace {
                 case ::HIR::CoreType::Str:
                     MIR_BUG(mir_res, "Unsized tag?!");
                 }
-                m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n";
+                m_of << indent << "switch("; emit_lvalue(val); emit_enum_path(repr, {~0u}); m_of << ") {\n";
                 for(size_t j = 0; j < n_arms; j ++)
                 {
                     // TODO: Get type of this field and check if it's signed.