Skip to content

Commit d433b89

Browse files
committed
ir: generate init-expr in function
* support struct field-inits, struct normal-init * mark InitListExpr as CTC if all values are CTC (or empty list) * support non-global array inits (non-designators only) * use incremental offsets to reduce register pressure * TODO bit-field init without field-designator * TODO Compound Literals
1 parent 351adb6 commit d433b89

File tree

9 files changed

+283
-30
lines changed

9 files changed

+283
-30
lines changed

analyser/module_analyser_init.c2

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ fn bool Analyser.analyseStructFieldInit(Analyser* ma, StructTypeDecl* std, InitL
379379
const FieldInitInfo* fii = ma.getFieldInfo(std);
380380
// TODO get from global stack, dont allocate+free
381381
StructFieldInitChecker checker.init(fii.num_indexes);
382+
bool ctc = true;
382383

383384
u32 numValues = ile.getNumValues();
384385
Expr** values = ile.getValues();
@@ -417,6 +418,7 @@ fn bool Analyser.analyseStructFieldInit(Analyser* ma, StructTypeDecl* std, InitL
417418
if (!ok) goto out;
418419

419420
Expr* inner = fdi.getInit();
421+
ctc &= inner.isCtc();
420422
value.setType(inner.getType());
421423
if (fif.is_bitfield && inner.isCtv()) {
422424
if (!ctv_analyser.checkBitfield(ma.diags, fif.bitfield_width, fif.bitfield_signed, inner)) return false;
@@ -425,6 +427,7 @@ fn bool Analyser.analyseStructFieldInit(Analyser* ma, StructTypeDecl* std, InitL
425427

426428
expectedType.clearQuals();
427429
Expr* e = (Expr*)ile;
430+
if (ctc) e.setCtc();
428431
e.setType(expectedType);
429432
checker.free();
430433
return true;
@@ -445,6 +448,7 @@ fn bool Analyser.analyseInitListStruct(Analyser* ma, InitListExpr* ile, QualType
445448
// just init all values to 0
446449
if (numValues == 0) {
447450
e.setType(expectedType);
451+
e.setCtc();
448452
return true;
449453
}
450454

@@ -460,6 +464,7 @@ fn bool Analyser.analyseInitListStruct(Analyser* ma, InitListExpr* ile, QualType
460464
return ma.analyseStructFieldInit(std, ile, expectedType);
461465
}
462466

467+
bool ctc = true;
463468
const u32 num_members = std.getNumMembers();
464469
Decl** members = std.getMembers();
465470

@@ -496,9 +501,11 @@ fn bool Analyser.analyseInitListStruct(Analyser* ma, InitListExpr* ile, QualType
496501
if (!ctv_analyser.checkBitfield(ma.diags, ml.bitfield_width, ml.bitfield_signed, value)) return false;
497502
}
498503

504+
ctc &= value.isCtc();
499505
member_idx++;
500506
}
501507

508+
if (ctc) e.setCtc();
502509
expectedType.clearQuals();
503510
e.setType(expectedType);
504511
return true;

generator/ir/field_struct_layouter.c2

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ module ir_generator;
1717

1818
import ast;
1919
import ctv_analyser;
20+
import ir local;
21+
import ir_context;
2022

2123
import stdlib;
2224
import string;
@@ -75,27 +77,33 @@ fn void FieldStructLayouter.add(FieldStructLayouter* l,
7577
u32 offset = info.offset;
7678
while (idx) {
7779
FieldInit* fi = &l.inits[idx-1];
78-
if (offset > fi.info.offset) break;
80+
//if (offset > fi.info.offset) break;
81+
if (info.member_idx >= fi.info.member_idx) break;
7982
l.inits[idx] = *fi; // move up
8083
idx--;
8184
}
8285
l.inits[idx] = init;
8386
l.num_inits++;
8487
}
8588

89+
// Note: finalize is used for GLOBALS and does initialize padding
8690
fn void FieldStructLayouter.finalize(FieldStructLayouter* l) {
8791
u32 cur_offset = 0;
8892
bool have_bitfield = false;
8993
u8 bitfield_base_size = 0; // in bytes of whole field
9094
u64 bitfield_value = 0; // will be downsized to correct size later
9195

96+
// Iterator all members, check if there is an init, otherwise init to 0
97+
// Generate init for all fields
9298
for (u32 i=0; i<l.num_inits; i++) {
9399
const FieldInit* fi = &l.inits[i];
94100
const ast.Expr* e = fi.expr;
95101
ast.QualType qt = e.getType();
96102
u32 size = qt.getSize(false);
97103
// TODO dont get from type, already set is Layout
98104

105+
// TODO merge bit-fields and/or other CTV fields
106+
99107
//printf("[%d] off %d/%d bit %d\n", i, cur_offset, fi.info.offset, have_bitfield);
100108
u32 pad = fi.info.offset - cur_offset; // means offsets have changed
101109
if (pad) {
@@ -156,3 +164,99 @@ field:
156164
stdlib.free(l.inits);
157165
}
158166

167+
// Note: finalizeExpr is used for non-GLOBALS and does NOT initialize padding
168+
fn void FieldStructLayouter.finalizeExpr(FieldStructLayouter* l, const ast.StructTypeDecl* std, Ref base_ref) {
169+
bool have_bitfield = false;
170+
u8 bitfield_base_size = 0; // in bytes of whole field
171+
ir_context.Context* ctx = l.gen.ctx;
172+
173+
u32 num_members = std.getNumMembers();
174+
ast.StructLayout* layout = std.getLayout();
175+
176+
// TODO can also be {}, 0 inits
177+
//printf("num_inits %d num_members %d\n", l.num_inits, num_members);
178+
u32 init_idx = 0;
179+
u32 cur_offset = 0;
180+
const FieldInit* fi = &l.inits[init_idx];
181+
Ref dest_ref = base_ref;
182+
183+
for (u32 i = 0; i < num_members; i++) {
184+
const ast.StructMemberLayout* ml = &layout.members[i];
185+
//printf(" [%d|%d] offset %d size %d\n", i, init_idx, ml.offset, ml.size);
186+
187+
if (ml.is_bitfield) {
188+
//printf("member idx %d\n", fi.info.member_idx);
189+
if (init_idx < l.num_inits && fi.info.member_idx == i) {
190+
ir.Type t = size2type(ml.size);
191+
ast.Expr* e = fi.expr;
192+
Ref value_ref;
193+
if (e.isCtv()) {
194+
ast.Value value = ctv_analyser.get_value(e);
195+
value.mask(fi.info.bitfield_width);
196+
if (fi.info.bitfield_offset) value.left_shift2(fi.info.bitfield_offset);
197+
u64 v = value.as_u64();
198+
199+
// TODO handle 64-bit bitfields
200+
value_ref = ctx.addIntegerConstant((i64)v);
201+
} else {
202+
l.gen.emitExpr(&value_ref, e);
203+
// mask
204+
Ref mask_value = ctx.addIntegerConstant((1 << ml.bitfield_width) -1);
205+
value_ref = ctx.addBinaryInstr(InstrKind.And, mask_value, value_ref);
206+
// shift (if needed)
207+
if (ml.bitfield_offset) {
208+
Ref shift_value = ctx.addIntegerConstant(ml.bitfield_offset);
209+
value_ref = ctx.addBinaryInstr(InstrKind.Shl, shift_value, value_ref);
210+
}
211+
}
212+
if (!have_bitfield) { // generate SET
213+
ctx.addStoreInstr(t, value_ref, dest_ref);
214+
} else { // generate OR
215+
Ref bitfield_ref = ctx.addLoadInstr(t, dest_ref);
216+
bitfield_ref = ctx.addBinaryInstr(InstrKind.Or, bitfield_ref, value_ref);
217+
ctx.addStoreInstr(t, bitfield_ref, dest_ref);
218+
}
219+
220+
init_idx++;
221+
fi = &l.inits[init_idx];
222+
} else {
223+
// TODO init entire field to 0 if not initialized at all
224+
}
225+
226+
//printf(" [%d] bitfield w %d s %d\n", i, fi.info.bitfield_width, fi.info.bitfield_offset);
227+
// TODO if all bitfields CTV, merge (separate from whole InitListExpr CTC)
228+
// TODO need to increment offset if needed
229+
if (!have_bitfield) have_bitfield = true;
230+
continue;
231+
// if last member, always emit bitfields
232+
} else {
233+
if (have_bitfield) {
234+
// flush bitfield
235+
// TODO
236+
have_bitfield = false;
237+
}
238+
}
239+
240+
if (ml.offset != 0) {
241+
Ref offset_ref = ctx.addIntegerConstant(ml.offset - cur_offset);
242+
cur_offset = ml.offset;
243+
dest_ref = ctx.addBinaryInstr(InstrKind.Add, dest_ref, offset_ref);
244+
}
245+
246+
Ref value_ref;
247+
if (init_idx < l.num_inits && fi.info.member_idx == i) {
248+
//printf(" have init\n");
249+
l.gen.emitExpr(&value_ref, fi.expr);
250+
251+
init_idx++;
252+
fi = &l.inits[init_idx];
253+
} else {
254+
value_ref = ctx.addIntegerConstant(0);
255+
}
256+
257+
ctx.addStoreInstr(size2type(ml.size), value_ref, dest_ref);
258+
}
259+
260+
stdlib.free(l.inits);
261+
}
262+

generator/ir/ir_generator.c2

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ fn void Generator.emitInit(Generator* gen, const Expr* e, u32 size) {
299299
} else if (ile.isArray()) {
300300
gen.emitArrayInit(e);
301301
} else {
302-
gen.emitStructInit(e);
302+
gen.emitGlobalStructInit(e);
303303
}
304304
break;
305305
case FieldDesignatedInit:
@@ -347,7 +347,7 @@ fn void Generator.emitInit(Generator* gen, const Expr* e, u32 size) {
347347
}
348348
}
349349

350-
fn void Generator.emitStructInit(Generator* gen, const Expr* e) {
350+
fn void Generator.emitGlobalStructInit(Generator* gen, const Expr* e) {
351351
const InitListExpr* ile = cast<InitListExpr*>(e);
352352
u32 num_values = ile.getNumValues();
353353
const Expr** values = ile.getValues2();
@@ -357,7 +357,6 @@ fn void Generator.emitStructInit(Generator* gen, const Expr* e) {
357357
StructTypeDecl* std = st.getDecl();
358358

359359
if (ile.hasDesignators()) {
360-
// TODO have a stack of FieldStructLayouters? (for sub-structs)
361360
FieldStructLayouter layouter;
362361
layouter.init(gen, std.getSize(), std.getDesigMemberCount());
363362
for (u32 i=0; i<num_values; i++) {

generator/ir/ir_generator_expr.c2

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,3 +529,140 @@ fn void Generator.emitArraySubscript(Generator* gen, ir.Ref* result, const Expr*
529529
}
530530
}
531531

532+
// TODO handle larger structs
533+
fn ir.Type size2type(u32 size) {
534+
// TEMP always signed for now
535+
switch (size) {
536+
case 1:
537+
return ir.Type.I8;
538+
case 2:
539+
return ir.Type.I16;
540+
case 4:
541+
return ir.Type.I32;
542+
default:
543+
break;
544+
}
545+
return ir.Type.I64;
546+
}
547+
548+
fn void Generator.emitStructInitExpr(Generator* gen, const StackVar* var, const Expr* e) {
549+
const InitListExpr* ile = (InitListExpr*)e;
550+
551+
QualType qt = e.getType();
552+
StructType* st = qt.getStructType();
553+
StructTypeDecl* std = st.getDecl();
554+
555+
u32 num_values = ile.getNumValues();
556+
const Expr** values = ile.getValues2();
557+
558+
if (e.isCtc()) {
559+
// TODO if all members are CTC/CTV, generate a 'global' and copy that
560+
// Note: also includes empty list: { }
561+
}
562+
563+
if (ile.hasDesignators()) {
564+
FieldStructLayouter layouter;
565+
layouter.init(gen, std.getSize(), std.getDesigMemberCount());
566+
for (u32 i=0; i<num_values; i++) {
567+
FieldDesignatedInitExpr* fdi = cast<FieldDesignatedInitExpr*>(values[i]);
568+
const FieldInitField* fif = fdi.getMemberInfo();
569+
if (!fif.isZeroSizeBitfield()) {
570+
layouter.add(fif, fdi.getInit());
571+
}
572+
}
573+
layouter.finalizeExpr(std, var.ref);
574+
return;
575+
}
576+
577+
// TODO aggregate bit-fields
578+
u32 num_members = std.getNumMembers();
579+
const StructLayout* layout = std.getLayout();
580+
u32 i;
581+
u32 offset = 0;
582+
ir.Ref dest_ref = var.ref;
583+
for (i = 0; i < num_values; i++) {
584+
const StructMemberLayout* ml = &layout.members[i];
585+
ir.Ref value_ref;
586+
gen.emitExpr(&value_ref, values[i]);
587+
if (ml.offset != 0) {
588+
ir.Ref offset_ref = gen.ctx.addIntegerConstant(ml.offset - offset);
589+
offset = ml.offset;
590+
dest_ref = gen.ctx.addBinaryInstr(InstrKind.Add, dest_ref, offset_ref);
591+
}
592+
gen.ctx.addStoreInstr(size2type(ml.size), value_ref, dest_ref);
593+
594+
}
595+
596+
ir.Ref value_ref = gen.ctx.addIntegerConstant(0);
597+
while (i < num_members) {
598+
const StructMemberLayout* ml = &layout.members[i];
599+
if (ml.offset != 0) {
600+
ir.Ref offset_ref = gen.ctx.addIntegerConstant(ml.offset - offset);
601+
offset = ml.offset;
602+
dest_ref = gen.ctx.addBinaryInstr(InstrKind.Add, dest_ref, offset_ref);
603+
}
604+
gen.ctx.addStoreInstr(size2type(ml.size), value_ref, dest_ref);
605+
i++;
606+
}
607+
}
608+
609+
fn void Generator.emitArrayInitExpr(Generator* gen, const StackVar* var, const Expr* e) {
610+
const InitListExpr* ile = (InitListExpr*)e;
611+
ir_context.Context* ctx = gen.ctx;
612+
613+
if (e.isCtc()) {
614+
// TODO if all members are CTC/CTV, generate a 'global' and copy that
615+
}
616+
617+
if (ile.hasDesignators()) {
618+
assert(0); // TODO
619+
} else {
620+
const u32 elem_size = var.ir_type.size();
621+
ir.Ref dest_ref = var.ref;
622+
ir.Ref step_ref = ctx.addIntegerConstant(elem_size);
623+
u32 offset = 0;
624+
u32 num_values = ile.getNumValues();
625+
const Expr** values = ile.getValues2();
626+
for (u32 i = 0; i < num_values; i++) {
627+
if (i != 0) {
628+
dest_ref = ctx.addBinaryInstr(InstrKind.Add, dest_ref, step_ref);
629+
}
630+
631+
ir.Ref value_ref;
632+
gen.emitExpr(&value_ref, values[i]);
633+
ctx.addStoreInstr(var.ir_type, value_ref, dest_ref);
634+
635+
offset += elem_size;
636+
}
637+
638+
ir.Ref value_ref = ctx.addIntegerConstant(0);
639+
while (offset != var.size) {
640+
if (offset != 0) {
641+
dest_ref = ctx.addBinaryInstr(InstrKind.Add, dest_ref, step_ref);
642+
}
643+
ctx.addStoreInstr(var.ir_type, value_ref, dest_ref);
644+
offset += elem_size;
645+
}
646+
}
647+
}
648+
649+
fn void Generator.emitInitExpr(Generator* gen, const VarDecl* vd, const Expr* ie) {
650+
StackVar* var = gen.locals.find(vd);
651+
652+
if (ie.isInitList()) {
653+
// can be array (with/without designators), init (with/without field-init) (or combination)
654+
const InitListExpr* ile = (InitListExpr*)ie;
655+
if (ile.isArray()) {
656+
gen.emitArrayInitExpr(var, ie);
657+
} else {
658+
gen.emitStructInitExpr(var, ie);
659+
}
660+
} else {
661+
ir.Ref res;
662+
gen.emitExpr(&res, ie);
663+
if (!vd.hasInitCall()) { // otherwise already handled
664+
gen.ctx.addStoreInstr(var.ir_type, res, var.ref);
665+
}
666+
}
667+
}
668+

generator/ir/ir_generator_locals.c2

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ import string;
2323
public type StackVar struct {
2424
ir.Ref ref; // never changes
2525
ir.Type ir_type;
26-
// TODO remove width/align/size, only use ir_type?
27-
/*
28-
u32 width;
29-
u32 align;
30-
*/
3126
u32 size;
3227
}
3328

generator/ir/ir_generator_stmt.c2

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ module ir_generator;
1818
import ast local;
1919
import ir local;
2020
import ir_context;
21-
import ir_gen_locals local;
2221

2322
// returns true if more stmts can follow
2423
fn bool Generator.emitStmt(Generator* gen, const Stmt* s) {
@@ -101,12 +100,7 @@ fn bool Generator.emitStmt(Generator* gen, const Stmt* s) {
101100

102101
const Expr* ie = vd.getInit();
103102
if (ie) {
104-
StackVar* var = gen.locals.find(vd);
105-
ir.Ref res;
106-
gen.emitExpr(&res, ie);
107-
if (!vd.hasInitCall()) { // otherwise already handled
108-
gen.ctx.addStoreInstr(var.ir_type, res, var.ref);
109-
}
103+
gen.emitInitExpr(vd, ie);
110104
}
111105
}
112106
return true;

0 commit comments

Comments
 (0)