Skip to content

Commit b5b537c

Browse files
committed
ir: simplement simple if-stmt
* only support compare not-equal-zero (RV64) * rv64 * arm64 (invert compare to avoid extra jump)
1 parent 7805001 commit b5b537c

File tree

6 files changed

+105
-28
lines changed

6 files changed

+105
-28
lines changed

ir/arch_arm64/arch_arm64.c2

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,28 @@ import string_buffer;
2121

2222
type Arm64_InstrKind enum u8 {
2323
Add,
24+
Branch,
25+
Beq,
26+
Bne,
27+
Cmp,
28+
Mov,
2429
Mul,
2530
Lsl,
2631
Ret,
2732
Sub,
2833
}
2934

3035
const char*[] instr_names = {
31-
[Arm64_InstrKind.Add] = "add",
32-
[Arm64_InstrKind.Lsl] = "lsl",
33-
[Arm64_InstrKind.Mul] = "mul",
34-
[Arm64_InstrKind.Ret] = "ret",
35-
[Arm64_InstrKind.Sub] = "sub",
36+
[Arm64_InstrKind.Add] = "add",
37+
[Arm64_InstrKind.Branch] = "b",
38+
[Arm64_InstrKind.Beq] = "beq",
39+
[Arm64_InstrKind.Bne] = "bne",
40+
[Arm64_InstrKind.Cmp] = "cmp",
41+
[Arm64_InstrKind.Lsl] = "lsl",
42+
[Arm64_InstrKind.Mul] = "mul",
43+
[Arm64_InstrKind.Mov] = "mov",
44+
[Arm64_InstrKind.Ret] = "ret",
45+
[Arm64_InstrKind.Sub] = "sub",
3646
}
3747

3848
/*
@@ -126,6 +136,15 @@ fn void instructionSelection(Tools* t, ir.FunctionInfo* f) {
126136
break;
127137
// Comparisons
128138
case CmpNe:
139+
assert(j+1 != last);
140+
Instr* next = &instrs[j+1];
141+
ii.setArch(Arm64_InstrKind.Cmp);
142+
ii.instrBits.has_result = 0;
143+
assert(next.getKind() == JmpIf);
144+
// invert, assert true block is next
145+
next.setArch(Arm64_InstrKind.Beq);
146+
next.args[0].init(Block, b.dests[1]);
147+
next.args[1].clear();
129148
break;
130149
case CmpEq:
131150
break;
@@ -163,6 +182,8 @@ fn void instructionSelection(Tools* t, ir.FunctionInfo* f) {
163182
break;
164183
// Jump instructions
165184
case Jmp:
185+
ii.setArch(Arm64_InstrKind.Branch);
186+
ii.args[0].init(Block, b.dests[0]);
166187
break;
167188
case JmpIf:
168189
break;
@@ -319,30 +340,34 @@ fn void generateAsm(string_buffer.Buf* out, const char* name, const FunctionInfo
319340
out.add(":\n");
320341
u32 num_blocks = fi.blocks.getCount();
321342
const Block* blocks = fi.blocks.get(0);
322-
const Instr* instrs = fi.instructions.get(0);
343+
Instr* instrs = fi.instructions.get(0);
323344

324345
for (u32 blk_id = 0; blk_id < num_blocks; blk_id++) {
325346
const Block* b = &blocks[blk_id];
326-
out.print("# %s.%d:\n", b.getKindName(), blk_id);
347+
if (blk_id == 0) out.add("# ");
348+
out.print(".BB%d_%d:\n", fi.id, blk_id);
327349
u32 last = b.instr.start + b.instr.count;
328350
u32 num_arg = 0;
329351
for (u32 j = b.instr.start; j < last; j++) {
330-
const Instr* ii = &instrs[j];
352+
Instr* ii = &instrs[j];
331353
bool first = true;
332354
if (ii.isNone()) continue;
333-
assert(ii.isArch());
355+
if (!ii.isArch()) {
356+
assert(ii.isCopy());
357+
ii.setArch(Arm64_InstrKind.Mov);
358+
}
334359
out.print("\t%-8s", instr_names[ii.instrBits.arch_instr]);
335360
if (ii.hasResult()) {
336361
assert(ii.hasRegister());
337362
out.print("%s", reg_names[ii.getRegister()]);
338363
first = false;
339364
}
340365
for (u32 i = 0; i < 2; i++) {
341-
if (ii.args[0].isNone()) break;
366+
if (ii.args[i].isNone()) break;
342367
if (!first) {
343368
out.add(", ");
344-
first = false;
345369
}
370+
first = false;
346371
const Ref* r = &ii.args[i];
347372
switch (r.getKind()) {
348373
case None:
@@ -382,9 +407,7 @@ fn void generateAsm(string_buffer.Buf* out, const char* name, const FunctionInfo
382407
out.print("%s", reg_names[r.value]);
383408
break;
384409
case Block:
385-
assert(0); // TODO
386-
//Block* b = ph.blocks.get((u32)r.value);
387-
//out.print("@%s.%d", b.getKindName(), r.value);
410+
out.print(".BB%d_%d", fi.id, r.value);
388411
break;
389412
case PhiClause:
390413
case CallNumArgs:

ir/arch_rv64/arch_rv64.c2

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ type RV64_InstrKind enum u8 {
2323
Add,
2424
AddIw,
2525
And,
26+
Beqz,
27+
Bnez,
2628
Divw,
29+
Jump,
30+
Li,
2731
Mul,
2832
Or,
2933
Remw,
@@ -39,8 +43,12 @@ const char*[] instr_names = {
3943
[RV64_InstrKind.Add] = "add",
4044
[RV64_InstrKind.AddIw] = "addiw",
4145
[RV64_InstrKind.And] = "and",
42-
[RV64_InstrKind.Divw] = "divw",
46+
[RV64_InstrKind.Beqz] = "beqz",
47+
[RV64_InstrKind.Bnez] = "bnez",
48+
[RV64_InstrKind.Divw] = "divw",
49+
[RV64_InstrKind.Jump] = "j",
4350
[RV64_InstrKind.Mul] = "mul",
51+
[RV64_InstrKind.Li] = "li",
4452
[RV64_InstrKind.Or] = "or",
4553
[RV64_InstrKind.Remw] = "remw",
4654
[RV64_InstrKind.Ret] = "ret",
@@ -150,6 +158,21 @@ fn void instructionSelection(Tools* t, ir.FunctionInfo* f) {
150158
break;
151159
// Comparisons
152160
case CmpNe:
161+
// combine Cmp + JmpIf into one beq(z) + jump
162+
assert(j+1 != last);
163+
Instr* next = &instrs[j+1];
164+
assert(next.getKind() == JmpIf);
165+
if (ii.args[1].isZero()) {
166+
// change cmp ne + jmp_if -> beqz (then) + j (else)
167+
ii.setArch(RV64_InstrKind.Bnez);
168+
ii.instrBits.has_result = 0;
169+
ii.args[1].init(Block, b.dests[0]);
170+
} else {
171+
assert(0); // TODO
172+
}
173+
next.setArch(RV64_InstrKind.Jump);
174+
next.args[0].init(Block, b.dests[1]);
175+
next.args[1].clear();
153176
break;
154177
case CmpEq:
155178
break;
@@ -167,6 +190,12 @@ fn void instructionSelection(Tools* t, ir.FunctionInfo* f) {
167190
case Load2:
168191
break;
169192
case Load4:
193+
if (ii.args[0].isConstant()) {
194+
ii.setArch(RV64_InstrKind.Li);
195+
// TODO if zero, use 'zero', skip copy
196+
} else {
197+
// TODO mov?
198+
}
170199
break;
171200
case Load8:
172201
break;
@@ -187,8 +216,11 @@ fn void instructionSelection(Tools* t, ir.FunctionInfo* f) {
187216
break;
188217
// Jump instructions
189218
case Jmp:
219+
ii.setArch(RV64_InstrKind.Jump);
220+
ii.args[0].init(Block, b.dests[0]);
190221
break;
191222
case JmpIf:
223+
assert(0); // should be removed already
192224
break;
193225
case Ret:
194226
ii.setArch(RV64_InstrKind.Ret);
@@ -198,6 +230,7 @@ fn void instructionSelection(Tools* t, ir.FunctionInfo* f) {
198230
case Call:
199231
break;
200232
case Copy:
233+
// NOTE: leave copies in for now, can be removed during register allocation
201234
break;
202235
// Pseudo instructions (must be converted before converting to ASM)
203236
case Arch:
@@ -229,30 +262,38 @@ fn void generateAsm(string_buffer.Buf* out, const char* name, const FunctionInfo
229262
out.add(":\n");
230263
u32 num_blocks = fi.blocks.getCount();
231264
const Block* blocks = fi.blocks.get(0);
232-
const Instr* instrs = fi.instructions.get(0);
265+
Instr* instrs = fi.instructions.get(0);
233266

234267
for (u32 blk_id = 0; blk_id < num_blocks; blk_id++) {
235268
const Block* b = &blocks[blk_id];
236-
out.print("# %s.%d:\n", b.getKindName(), blk_id);
269+
if (blk_id == 0) out.add("# ");
270+
out.print(".BB%d_%d:\n", fi.id, blk_id);
237271
u32 last = b.instr.start + b.instr.count;
238272
u32 num_arg = 0;
239273
for (u32 j = b.instr.start; j < last; j++) {
240-
const Instr* ii = &instrs[j];
274+
Instr* ii = &instrs[j];
241275
bool first = true;
242276
if (ii.isNone()) continue;
243-
assert(ii.isArch());
277+
if (!ii.isArch()) {
278+
assert(ii.isCopy());
279+
if (ii.args[0].isValue()) {
280+
ii.setArch(RV64_InstrKind.Li);
281+
} else {
282+
assert(0); // TODO
283+
}
284+
}
244285
out.print("\t%-8s", instr_names[ii.instrBits.arch_instr]);
245286
if (ii.hasResult()) {
246287
assert(ii.hasRegister());
247288
out.print("%s", reg_names[ii.getRegister()]);
248289
first = false;
249290
}
250291
for (u32 i = 0; i < 2; i++) {
251-
if (ii.args[0].isNone()) break;
292+
if (ii.args[i].isNone()) break;
252293
if (!first) {
253294
out.add(", ");
254-
first = false;
255295
}
296+
first = false;
256297
const Ref* r = &ii.args[i];
257298
switch (r.getKind()) {
258299
case None:
@@ -292,9 +333,7 @@ fn void generateAsm(string_buffer.Buf* out, const char* name, const FunctionInfo
292333
out.print("%s", reg_names[r.value]);
293334
break;
294335
case Block:
295-
assert(0); // TODO
296-
//Block* b = ph.blocks.get((u32)r.value);
297-
//out.print("@%s.%d", b.getKindName(), r.value);
336+
out.print(".BB%d_%d", fi.id, r.value);
298337
break;
299338
case PhiClause:
300339
case CallNumArgs:

ir/context.c2

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ public fn void Context.startFunc(Context* c, SymbolId id) {
176176
stdio.printf("startFunc(%d) cur %d\n", id, b.cur_func);
177177
#endif
178178
assert(b.tmp_info == nil);
179-
b.tmp_info = FunctionInfo.create(8, 16, 16);
179+
b.tmp_info = FunctionInfo.create(id, 8, 16, 16);
180180
assert(b.cur_func == 0);
181181
b.cur_func = id;
182182
b.num_scopes = 0;
@@ -633,6 +633,7 @@ fn void Context.finalizeFunction(Context* c, SymbolId id) {
633633
// TODO can be multi-threaded after this point (ready for inlining)
634634
if (c.single_thread) {
635635
t.convert_fn();
636+
//dump_function(fi, "TODO");
636637
} else {
637638
c.queue.add(fi);
638639
}

ir/context_output.c2

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import file_utils;
2121
import console;
2222
import string_buffer;
2323

24+
import stdio;
25+
2426
public fn void Context.writeOutput(Context* c, const char* output_dir, const char* target_name) {
2527
// generate create Makefile
2628
string_buffer.Buf* out = string_buffer.create(4096, false, 0);
@@ -43,13 +45,15 @@ public fn void Context.writeOutput(Context* c, const char* output_dir, const cha
4345

4446
// generate ASM
4547
assert(c.target.generateAsm);
48+
u32 block_start = 0;
4649
u32 num_symbols = c.symbols.getCount();
4750
const Symbol* symbols = c.symbols.get(0);
4851
for (u32 i = 0; i < num_symbols; i++) {
4952
const Symbol* s = &symbols[i];
5053
if (s.is_function) {
5154
const ir.FunctionInfo* fi = s.f.info;
5255
c.target.generateAsm(out, c.pool.idx2str(s.name), fi, s.is_external);
56+
block_start += fi.blocks.getCount();
5357
}
5458
// TODO emit other symbols as well
5559

@@ -59,6 +63,10 @@ public fn void Context.writeOutput(Context* c, const char* output_dir, const cha
5963
out.add("\t.ident \"C2C\"\n");
6064
//.section TODO
6165

66+
if (1) {
67+
stdio.puts(out.data());
68+
}
69+
6270
c.write(output_dir, "output.s", out);
6371
out.free();
6472
}

ir/function_info.c2

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ public type FunctionInfo struct {
2727
u8 num_args;
2828
// args[0][low bits] is return type (None if no return value)
2929
u8[1 + constants.MaxCallArgs/2] args; // stores 2 ir.Types per u8, first low, then high bits
30+
u32 id;
3031
}
31-
static_assert(80, sizeof(FunctionInfo));
32+
static_assert(88, sizeof(FunctionInfo));
3233

33-
public fn FunctionInfo* FunctionInfo.create(u32 num_blks, u32 num_instr, u32 num_refs) {
34+
public fn FunctionInfo* FunctionInfo.create(u32 id, u32 num_blks, u32 num_instr, u32 num_refs) {
3435
FunctionInfo* fi = stdlib.malloc(sizeof(FunctionInfo));
36+
fi.id = id;
3537
fi.blocks.init(num_blks);
3638
fi.instructions.init(num_instr);
3739
fi.cases.init();

ir/ref.c2

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public type RefKind enum u8 {
2929
Double, // constant_idx
3030
Text, // idx into string pool, for comment
3131
Register, // nr (0,1,..)
32-
Block, // only used by Switch to store join_blk in args[1]
32+
Block, // only used by Switch to store join_blk in args[1], and for Arch jump/branch instructions
3333
PhiClause, // only for Phi instructions. args[0]=start, args[1]=count
3434
CallNumArgs, // only for Call instructions
3535
}
@@ -113,6 +113,10 @@ public fn bool Ref.isConstant(const Ref* r) @(unused) {
113113
return r.kind >= RefKind.Value && r.kind <= RefKind.Double;
114114
}
115115

116+
public fn bool Ref.isZero(const Ref* r) {
117+
return r.kind == RefKind.Value && r.value == 0;
118+
}
119+
116120
public fn const char* Ref.getKindName(const Ref* r) {
117121
return r.getKind().str();
118122
}

0 commit comments

Comments
 (0)