Skip to content

Commit e7267e4

Browse files
committed
Extend CSE to support more binary operations
- Add CSE support for OP_add and OP_mul with commutativity - Add CSE support for OP_sub and OP_div without commutativity
1 parent 95c5cb4 commit e7267e4

File tree

1 file changed

+130
-62
lines changed

1 file changed

+130
-62
lines changed

src/ssa.c

Lines changed: 130 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,78 +1225,146 @@ void ssa_build(void)
12251225
/* TODO: release detached insns node */
12261226
bool cse(insn_t *insn, basic_block_t *bb)
12271227
{
1228-
if (insn->opcode != OP_read)
1229-
return false;
1228+
/* Handle memory reads */
1229+
if (insn->opcode == OP_read) {
1230+
insn_t *prev = insn->prev;
1231+
if (!prev)
1232+
return false;
1233+
if (prev->opcode != OP_add)
1234+
return false;
1235+
if (prev->rd != insn->rs1)
1236+
return false;
12301237

1231-
insn_t *prev = insn->prev;
1232-
if (!prev)
1233-
return false;
1234-
if (prev->opcode != OP_add)
1235-
return false;
1236-
if (prev->rd != insn->rs1)
1237-
return false;
1238+
var_t *def = insn->rd, *base = prev->rs1, *idx = prev->rs2;
1239+
if (base->is_global || idx->is_global)
1240+
return false;
12381241

1239-
var_t *def = insn->rd, *base = prev->rs1, *idx = prev->rs2;
1240-
if (base->is_global || idx->is_global)
1241-
return false;
1242+
use_chain_t *rs1_delete_user = NULL, *rs2_delete_user = NULL;
1243+
for (use_chain_t *user = base->users_head; user; user = user->next) {
1244+
insn_t *i = user->insn;
1245+
1246+
/* Delete the use chain nodes found in the last loop */
1247+
if (rs1_delete_user) {
1248+
use_chain_delete(rs1_delete_user, rs1_delete_user->insn->rs1);
1249+
rs1_delete_user = NULL;
1250+
}
1251+
if (rs2_delete_user) {
1252+
use_chain_delete(rs2_delete_user, rs2_delete_user->insn->rs2);
1253+
rs2_delete_user = NULL;
1254+
}
1255+
if (i == prev)
1256+
continue;
1257+
if (i->opcode != OP_add)
1258+
continue;
1259+
if (!i->next)
1260+
continue;
1261+
if (i->next->opcode != OP_read)
1262+
continue;
1263+
if (i->rs1 != base || i->rs2 != idx)
1264+
continue;
12421265

1243-
use_chain_t *rs1_delete_user = NULL;
1244-
use_chain_t *rs2_delete_user = NULL;
1245-
for (use_chain_t *user = base->users_head; user; user = user->next) {
1246-
insn_t *i = user->insn;
1266+
basic_block_t *i_bb = i->belong_to;
1267+
bool check_dom = 0;
1268+
/* Check if the instructions are under the same dominate tree */
1269+
for (;; i_bb = i_bb->idom) {
1270+
if (i_bb == bb) {
1271+
check_dom = true;
1272+
break;
1273+
}
1274+
if (i_bb == i_bb->idom)
1275+
break;
1276+
}
1277+
if (!check_dom)
1278+
continue;
12471279

1248-
/* Delete the use chain nodes found in the last loop */
1249-
if (rs1_delete_user) {
1250-
use_chain_delete(rs1_delete_user, rs1_delete_user->insn->rs1);
1251-
rs1_delete_user = NULL;
1252-
}
1253-
if (rs2_delete_user) {
1254-
use_chain_delete(rs2_delete_user, rs2_delete_user->insn->rs2);
1255-
rs2_delete_user = NULL;
1280+
i->next->opcode = OP_assign;
1281+
i->next->rs1 = def;
1282+
if (i->prev) {
1283+
i->prev->next = i->next;
1284+
i->next->prev = i->prev;
1285+
} else {
1286+
i->belong_to->insn_list.head = i->next;
1287+
i->next->prev = NULL;
1288+
}
1289+
i->next->opcode = OP_assign;
1290+
i->next->rs1 = def;
1291+
/* Prepare information for deleting use chain nodes */
1292+
rs1_delete_user = user;
1293+
for (rs2_delete_user = i->rs2->users_head;
1294+
rs2_delete_user->insn != rs1_delete_user->insn;
1295+
rs2_delete_user = rs2_delete_user->next)
1296+
;
12561297
}
1257-
if (i == prev)
1258-
continue;
1259-
if (i->opcode != OP_add)
1260-
continue;
1261-
if (!i->next)
1262-
continue;
1263-
if (i->next->opcode != OP_read)
1264-
continue;
1265-
if (i->rs1 != base || i->rs2 != idx)
1266-
continue;
1267-
basic_block_t *i_bb = i->belong_to;
1268-
bool check_dom = 0;
1269-
/* Check if the instructions are under the same dominate tree */
1270-
for (;; i_bb = i_bb->idom) {
1271-
if (i_bb == bb) {
1272-
check_dom = true;
1273-
break;
1298+
return true;
1299+
}
1300+
1301+
/* Handle non-commutative binary operations (OP_sub, OP_div) */
1302+
if (insn->opcode == OP_sub || insn->opcode == OP_div) {
1303+
if (!insn->rs1 || !insn->rs2 || !insn->rd)
1304+
return false;
1305+
1306+
/* Don't CSE operations with global variables (safety) */
1307+
if (insn->rs1->is_global || insn->rs2->is_global)
1308+
return false;
1309+
1310+
/* Look for identical expressions in the same basic block */
1311+
for (insn_t *candidate = bb->insn_list.head;
1312+
candidate && candidate != insn; candidate = candidate->next) {
1313+
if (candidate->opcode != insn->opcode || !candidate->rd)
1314+
continue;
1315+
1316+
if (!candidate->rs1 || !candidate->rs2)
1317+
continue;
1318+
1319+
/* Check for exact match only (no commutativity for sub/div) */
1320+
if (candidate->rs1 == insn->rs1 && candidate->rs2 == insn->rs2) {
1321+
insn->opcode = OP_assign;
1322+
insn->rs1 = candidate->rd;
1323+
insn->rs2 = NULL;
1324+
return true;
12741325
}
1275-
if (i_bb == i_bb->idom)
1276-
break;
12771326
}
1278-
if (!check_dom)
1279-
continue;
1327+
return false;
1328+
}
12801329

1281-
i->next->opcode = OP_assign;
1282-
i->next->rs1 = def;
1283-
if (i->prev) {
1284-
i->prev->next = i->next;
1285-
i->next->prev = i->prev;
1286-
} else {
1287-
i->belong_to->insn_list.head = i->next;
1288-
i->next->prev = NULL;
1330+
/* Handle commutative binary operations (OP_add, OP_mul) */
1331+
if (insn->opcode == OP_add || insn->opcode == OP_mul) {
1332+
if (!insn->rs1 || !insn->rs2 || !insn->rd)
1333+
return false;
1334+
1335+
/* Don't CSE operations with global variables (safety) */
1336+
if (insn->rs1->is_global || insn->rs2->is_global)
1337+
return false;
1338+
1339+
/* Look for identical expressions in the same basic block */
1340+
for (insn_t *candidate = bb->insn_list.head;
1341+
candidate && candidate != insn; candidate = candidate->next) {
1342+
if (candidate->opcode != insn->opcode || !candidate->rd)
1343+
continue;
1344+
1345+
if (!candidate->rs1 || !candidate->rs2)
1346+
continue;
1347+
1348+
/* Check for exact match: a op b */
1349+
if (candidate->rs1 == insn->rs1 && candidate->rs2 == insn->rs2) {
1350+
insn->opcode = OP_assign;
1351+
insn->rs1 = candidate->rd;
1352+
insn->rs2 = NULL;
1353+
return true;
1354+
}
1355+
1356+
/* Check for commutative match: b op a = a op b */
1357+
if (candidate->rs1 == insn->rs2 && candidate->rs2 == insn->rs1) {
1358+
insn->opcode = OP_assign;
1359+
insn->rs1 = candidate->rd;
1360+
insn->rs2 = NULL;
1361+
return true;
1362+
}
12891363
}
1290-
i->next->opcode = OP_assign;
1291-
i->next->rs1 = def;
1292-
/* Prepare information for deleting use chain nodes */
1293-
rs1_delete_user = user;
1294-
for (rs2_delete_user = i->rs2->users_head;
1295-
rs2_delete_user->insn != rs1_delete_user->insn;
1296-
rs2_delete_user = rs2_delete_user->next)
1297-
;
1364+
return false;
12981365
}
1299-
return true;
1366+
1367+
return false;
13001368
}
13011369

13021370
bool mark_const(insn_t *insn)

0 commit comments

Comments
 (0)