Skip to content

Commit fb89ec1

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 8921b9b commit fb89ec1

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
@@ -1220,78 +1220,146 @@ void ssa_build(void)
12201220
/* TODO: release detached insns node */
12211221
bool cse(insn_t *insn, basic_block_t *bb)
12221222
{
1223-
if (insn->opcode != OP_read)
1224-
return false;
1223+
/* Handle memory reads */
1224+
if (insn->opcode == OP_read) {
1225+
insn_t *prev = insn->prev;
1226+
if (!prev)
1227+
return false;
1228+
if (prev->opcode != OP_add)
1229+
return false;
1230+
if (prev->rd != insn->rs1)
1231+
return false;
12251232

1226-
insn_t *prev = insn->prev;
1227-
if (!prev)
1228-
return false;
1229-
if (prev->opcode != OP_add)
1230-
return false;
1231-
if (prev->rd != insn->rs1)
1232-
return false;
1233+
var_t *def = insn->rd, *base = prev->rs1, *idx = prev->rs2;
1234+
if (base->is_global || idx->is_global)
1235+
return false;
12331236

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

1238-
use_chain_t *rs1_delete_user = NULL;
1239-
use_chain_t *rs2_delete_user = NULL;
1240-
for (use_chain_t *user = base->users_head; user; user = user->next) {
1241-
insn_t *i = user->insn;
1261+
basic_block_t *i_bb = i->belong_to;
1262+
bool check_dom = 0;
1263+
/* Check if the instructions are under the same dominate tree */
1264+
for (;; i_bb = i_bb->idom) {
1265+
if (i_bb == bb) {
1266+
check_dom = true;
1267+
break;
1268+
}
1269+
if (i_bb == i_bb->idom)
1270+
break;
1271+
}
1272+
if (!check_dom)
1273+
continue;
12421274

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

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

12971365
bool mark_const(insn_t *insn)

0 commit comments

Comments
 (0)