Skip to content

Commit 3ebbc50

Browse files
committed
cleanup sanity checks in backend
1 parent c499da5 commit 3ebbc50

6 files changed

Lines changed: 156 additions & 55 deletions

File tree

BE/Base/sanity.cc

Lines changed: 127 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,127 @@
11
#include "BE/Base/sanity.h"
22

33
#include <set>
4+
#include <vector>
45

56
#include "BE/Base/cfg.h"
7+
#include "BE/Base/ir.h"
68
#include "BE/Base/serialize.h"
79

810
namespace cwerg::base {
911

10-
void BblCheck(Bbl bbl, Fun fun) {
12+
class FunArgState {
13+
public:
14+
FunArgState() = default;
15+
16+
void HandleProlog(Fun fun) {
17+
FillPopArgs(FunNumInputTypes(fun), FunInputTypes(fun));
18+
}
19+
20+
void HandleIns(Ins ins, Bbl bbl, Fun fun) {
21+
switch (InsOPC(ins)) {
22+
case OPC::POPARG: {
23+
if (num_pop_args_ == 0) {
24+
CHECK(false, "too many pop args in " << Name(fun));
25+
}
26+
DK expected = pop_args_[num_pop_args_ - 1];
27+
--num_pop_args_;
28+
DK actual = RegOrConstKind(InsOperand(ins, 0));
29+
CHECK(expected == actual, "unexpected pop arg type in "
30+
<< Name(fun) << ": expected "
31+
<< EnumToString(expected) << " got "
32+
<< EnumToString(actual));
33+
break;
34+
}
35+
case OPC::PUSHARG: {
36+
CHECK(num_pop_args_ == 0, "orphan pop args in " << Name(fun));
37+
DK dk = RegOrConstKind(InsOperand(ins, 0));
38+
CHECK(num_push_args_ < MAX_PARAMETERS,
39+
"too many push args in " << Name(fun));
40+
push_args_[num_push_args_] = dk;
41+
++num_push_args_;
42+
break;
43+
}
44+
case OPC::RET:
45+
CHECK(num_pop_args_ == 0, "orphan pop args " << Name(fun));
46+
ConsumePushArgs(FunNumOutputTypes(fun), FunOutputTypes(fun),
47+
Fun(HandleInvalid), fun);
48+
break;
49+
case OPC::JSR:
50+
case OPC::BSR:
51+
case OPC::SYSCALL: {
52+
Fun callee = InsCallee(ins);
53+
CHECK(num_pop_args_ == 0, "orphan pop args in " << Name(fun));
54+
ConsumePushArgs(FunNumInputTypes(callee), FunInputTypes(callee), callee,
55+
fun);
56+
FillPopArgs(FunNumOutputTypes(callee), FunOutputTypes(callee));
57+
if (FunBblList::IsEmpty(callee)) {
58+
CHECK(FunKind(callee) == FUN_KIND::BUILTIN ||
59+
FunKind(callee) == FUN_KIND::SIGNATURE,
60+
"undefined function " << Name(callee) << " in " << Name(fun));
61+
}
62+
break;
63+
}
64+
default:
65+
CHECK(num_pop_args_ == 0, "orphan pop args " << Name(fun));
66+
CHECK(num_push_args_ == 0, "orphan push args " << Name(fun));
67+
break;
68+
}
69+
}
70+
71+
private:
72+
void ConsumePushArgs(int n, DK* dks, Fun callee, Fun caller) {
73+
if (num_push_args_ != n) {
74+
if (callee == HandleInvalid) {
75+
CHECK(false, "In " << Name(caller) << "epilog: expected " << n
76+
<< " push args, got " << num_push_args_);
77+
} else {
78+
CHECK(false, "In " << Name(caller) << " calling " << Name(callee)
79+
<< ": expected " << n << " push args, got "
80+
<< num_push_args_);
81+
}
82+
}
83+
for (int i = 0; i < n; i++) {
84+
if (push_args_[i] != dks[n - 1 - i]) {
85+
if (callee == HandleInvalid) {
86+
CHECK(false, "In caller " << Name(caller) << " epilog: expected push arg "
87+
<< i << " to be "
88+
<< EnumToString(dks[n - 1 - i]) << " got "
89+
<< EnumToString(push_args_[i]));
90+
} else {
91+
CHECK(false, "In caller " << Name(caller) << " calling "
92+
<< Name(callee) << ": expected push arg "
93+
<< i << " to be "
94+
<< EnumToString(dks[n - 1 - i]) << " got "
95+
<< EnumToString(push_args_[i]));
96+
}
97+
}
98+
}
99+
num_push_args_ = 0;
100+
}
101+
102+
void FillPopArgs(int n, DK* dks) {
103+
for (int i = 0; i < n; i++) {
104+
DK dk = dks[n - i - 1];
105+
pop_args_[i] = dk;
106+
}
107+
num_pop_args_ = n;
108+
}
109+
110+
void FillPushArgs(int n, DK* dks) {
111+
for (int i = 0; i < n; i++) {
112+
DK dk = dks[n - i - 1];
113+
push_args_[i] = dk;
114+
}
115+
num_push_args_ = n;
116+
}
117+
118+
DK pop_args_[MAX_PARAMETERS];
119+
DK push_args_[MAX_PARAMETERS];
120+
int num_pop_args_ = 0;
121+
int num_push_args_ = 0;
122+
};
123+
124+
void BblCheck(Bbl bbl, Fun fun, FunArgState* state, bool check_push_pop) {
11125
uint32_t count = 0;
12126
for (Ins ins : BblInsIter(bbl)) {
13127
Ins prev = BblInsList::Prev(ins);
@@ -32,20 +146,18 @@ void BblCheck(Bbl bbl, Fun fun) {
32146
CHECK(false, "bbl corruption in " << Name(fun) << " at pos " << count);
33147
}
34148
}
35-
36-
if (InsOpcode(ins).IsCall()) {
37-
Fun callee = InsCallee(ins);
38-
if (FunBblList::IsEmpty(callee)) {
39-
CHECK(FunKind(callee) == FUN_KIND::BUILTIN ||
40-
FunKind(callee) == FUN_KIND::SIGNATURE,
41-
"undefined function " << Name(callee) << " in " << Name(fun));
42-
}
149+
if (check_push_pop) {
150+
state->HandleIns(ins, bbl, fun);
43151
}
44152
++count;
45153
}
46154
}
47155

48-
void FunCheck(Fun fun) {
156+
void FunCheck(Fun fun, bool check_cfg, bool check_push_pop,
157+
bool check_fallthroughs) {
158+
FunArgState state;
159+
state.HandleProlog(fun);
160+
49161
std::set<Bbl> bbls;
50162
for (Bbl bbl : FunBblIter(fun)) {
51163
bbls.insert(bbl);
@@ -98,37 +210,14 @@ void FunCheck(Fun fun) {
98210
Bbl pred = EdgPredBbl(edg);
99211
Bbl succ = EdgSuccBbl(edg);
100212
CHECK(bbls.find(pred) != bbls.end(),
101-
"bad " << Name(pred) << " -> " << Name(succ));
213+
"bad 1 " << Name(pred) << " -> " << Name(succ) << " " << Name(fun));
102214
CHECK(bbls.find(succ) != bbls.end(),
103-
"bad " << Name(pred) << " -> " << Name(succ));
104-
CHECK(pred == bbl,
105-
"bad " << Name(bbl) << ": " << Name(pred) << " -> " << Name(succ));
106-
}
107-
108-
BblCheck(bbl, fun);
109-
}
110-
}
111-
112-
void UnitCheck(Unit unit) {
113-
for (Fun fun : UnitFunIter(unit)) {
114-
Fun prev = UnitFunList::Prev(fun);
115-
Fun next = UnitFunList::Next(fun);
116-
117-
if (UnitFunList::IsSentinel(prev)) {
118-
CHECK(prev == unit, "");
119-
CHECK(UnitFunList::Head(unit) == fun, "");
120-
} else {
121-
CHECK(UnitFunList::Next(prev) == fun, "");
122-
}
123-
124-
if (UnitFunList::IsSentinel(next)) {
125-
CHECK(next == unit, "");
126-
CHECK(UnitFunList::Tail(unit) == fun, "");
127-
} else {
128-
CHECK(UnitFunList::Prev(next) == fun, "");
215+
"bad 2 " << Name(pred) << " -> " << Name(succ) << " " << Name(fun));
216+
CHECK(pred == bbl, "bad 3 " << Name(bbl) << ": " << Name(pred) << " -> "
217+
<< Name(succ) << " " << Name(fun));
129218
}
130219

131-
FunCheck(fun);
220+
BblCheck(bbl, fun, &state, check_push_pop);
132221
}
133222
}
134223

BE/Base/sanity.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55

66
namespace cwerg::base {
77

8-
extern void BblCheck(Bbl bbl, Fun fun);
9-
10-
extern void FunCheck(Fun fun);
11-
12-
extern void UnitCheck(Unit unit);
8+
extern void FunCheck(Fun fun, bool check_cfg, bool check_push_pop, bool check_fallthroughs);
139

1410
} // namespace cwerg::base

BE/CodeGenA32/codegen.cc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,28 +220,33 @@ a32::A32Unit EmitUnitAsBinary(base::Unit unit) {
220220
return out;
221221
}
222222

223-
void LegalizeAll(Unit unit, bool verbose, std::ostream* fout) {
223+
std::vector<Fun> GetSeeds(Unit unit) {
224224
std::vector<Fun> seeds;
225225
Fun fun = UnitFunFind(unit, StrNew("main"));
226226
if (!fun.isnull()) seeds.push_back(fun);
227227
fun = UnitFunFind(unit, StrNew("_start"));
228228
if (!fun.isnull()) seeds.push_back(fun);
229+
return seeds;
230+
}
231+
232+
void LegalizeAll(Unit unit, bool verbose, std::ostream* fout) {
233+
std::vector<Fun> seeds = GetSeeds(unit);
229234
if (!seeds.empty()) UnitRemoveUnreachableCode(unit, seeds);
235+
//
230236
for (Fun fun : UnitFunIter(unit)) {
231-
FunCheck(fun);
237+
FunCheck(fun, false, true, false);
232238
if (FunKind(fun) == FUN_KIND::NORMAL) {
233239
FunCfgInit(fun);
234240
FunOptBasic(fun, true);
235241
}
236242

237-
FunCheck(fun);
238243
PhaseLegalization(fun, unit, fout);
239244
}
240245
}
241246

242247
void RegAllocGlobal(Unit unit, bool verbose, std::ostream* fout) {
243248
for (Fun fun : UnitFunIter(unit)) {
244-
FunCheck(fun);
249+
FunCheck(fun, false, false, false);
245250
PhaseGlobalRegAlloc(fun, unit, fout);
246251
}
247252
}

BE/CodeGenA64/legalize.cc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,29 +363,33 @@ void PhaseFinalizeStackAndLocalRegAlloc(Fun fun, Unit unit,
363363
FunMoveEliminationCpu(fun, &inss);
364364
}
365365

366-
void LegalizeAll(Unit unit, bool verbose, std::ostream* fout) {
366+
std::vector<Fun> GetSeeds(Unit unit) {
367367
std::vector<Fun> seeds;
368368
Fun fun = UnitFunFind(unit, StrNew("main"));
369369
if (!fun.isnull()) seeds.push_back(fun);
370370
fun = UnitFunFind(unit, StrNew("_start"));
371371
if (!fun.isnull()) seeds.push_back(fun);
372+
return seeds;
373+
}
374+
375+
void LegalizeAll(Unit unit, bool verbose, std::ostream* fout) {
376+
std::vector<Fun> seeds = GetSeeds(unit);
372377
if (!seeds.empty()) UnitRemoveUnreachableCode(unit, seeds);
373378
for (Fun fun : UnitFunIter(unit)) {
374-
FunCheck(fun);
379+
FunCheck(fun, false, true, false);
375380
if (FunKind(fun) == FUN_KIND::NORMAL) {
376381
FunCfgInit(fun);
377382
FunOptBasic(fun, true);
378383
}
379384

380-
FunCheck(fun);
381385
PhaseLegalizationStep1(fun, unit, fout);
382386
PhaseLegalizationStep2(fun, unit, fout);
383387
}
384388
}
385389

386390
void RegAllocGlobal(Unit unit, bool verbose, std::ostream* fout) {
387391
for (Fun fun : UnitFunIter(unit)) {
388-
FunCheck(fun);
392+
FunCheck(fun, false, false, false);
389393
PhaseGlobalRegAlloc(fun, unit, fout);
390394
}
391395
}

BE/CodeGenX64/legalize.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -532,15 +532,21 @@ void PhaseFinalizeStackAndLocalRegAlloc(Fun fun, Unit unit,
532532
FunMoveEliminationCpu(fun, &inss);
533533
}
534534

535-
void OptimizeAll(Unit unit, bool verbose, std::ostream* fout) {
535+
std::vector<Fun> GetSeeds(Unit unit) {
536536
std::vector<Fun> seeds;
537537
Fun fun = UnitFunFind(unit, StrNew("main"));
538538
if (!fun.isnull()) seeds.push_back(fun);
539539
fun = UnitFunFind(unit, StrNew("_start"));
540540
if (!fun.isnull()) seeds.push_back(fun);
541+
return seeds;
542+
}
543+
544+
545+
void OptimizeAll(Unit unit, bool verbose, std::ostream* fout) {
546+
std::vector<Fun> seeds = GetSeeds(unit);
541547
if (!seeds.empty()) UnitRemoveUnreachableCode(unit, seeds);
542548
for (Fun fun : UnitFunIter(unit)) {
543-
FunCheck(fun);
549+
FunCheck(fun, false, true, false);
544550
if (FunKind(fun) == FUN_KIND::NORMAL) {
545551
FunCfgInit(fun);
546552
FunOptBasic(fun, true);
@@ -550,14 +556,14 @@ void OptimizeAll(Unit unit, bool verbose, std::ostream* fout) {
550556

551557
void LegalizeAll(Unit unit, bool verbose, std::ostream* fout) {
552558
for (Fun fun : UnitFunIter(unit)) {
553-
FunCheck(fun);
559+
FunCheck(fun, false, true, false);
554560
PhaseLegalization(fun, unit, fout);
555561
}
556562
}
557563

558564
void RegAllocGlobal(Unit unit, bool verbose, std::ostream* fout) {
559565
for (Fun fun : UnitFunIter(unit)) {
560-
FunCheck(fun);
566+
// we cannot run FunCheck once push-/poparg conversion has happened
561567
PhaseGlobalRegAlloc(fun, unit, fout);
562568
}
563569
}

BE/CodeGenX64/legalize.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ def OptimizeAll(unit, opt_stats):
282282

283283
def LegalizeAll(unit, opt_stats):
284284
for fun in unit.funs:
285+
sanity.FunCheck(fun, unit, check_cfg=False, check_push_pop=True, check_fallthroughs=False)
285286
PhaseLegalization(fun, unit, opt_stats)
286287

287288

0 commit comments

Comments
 (0)