Skip to content

Commit cdd443a

Browse files
committed
Extend CSE to support more binary operations
- Add comprehensive CSE support for arithmetic, bitwise, logical, and comparison operations - Support commutative operation detection (add, mul, and, or, xor, eq, neq) - Maintain existing array access pattern optimization (add + read) - Add safety checks to prevent CSE with global variables
1 parent 41fed6b commit cdd443a

File tree

1 file changed

+117
-59
lines changed

1 file changed

+117
-59
lines changed

src/ssa.c

Lines changed: 117 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,82 +1238,140 @@ void ssa_build(void)
12381238
unwind_phi();
12391239
}
12401240

1241+
/* Check if operation can be subject to CSE */
1242+
bool is_cse_candidate(insn_t *insn)
1243+
{
1244+
switch (insn->opcode) {
1245+
case OP_add:
1246+
case OP_sub:
1247+
case OP_mul:
1248+
case OP_div:
1249+
case OP_mod:
1250+
case OP_lshift:
1251+
case OP_rshift:
1252+
case OP_bit_and:
1253+
case OP_bit_or:
1254+
case OP_bit_xor:
1255+
case OP_log_and:
1256+
case OP_log_or:
1257+
case OP_eq:
1258+
case OP_neq:
1259+
case OP_lt:
1260+
case OP_leq:
1261+
case OP_gt:
1262+
case OP_geq:
1263+
return true;
1264+
default:
1265+
return false;
1266+
}
1267+
}
1268+
12411269
/* Common Subexpression Elimination (CSE) */
1242-
/* TODO: release detached insns node */
1270+
/* Enhanced to support general binary operations */
12431271
bool cse(insn_t *insn, basic_block_t *bb)
12441272
{
1245-
if (insn->opcode != OP_read)
1246-
return false;
1273+
/* Handle array access pattern: add + read */
1274+
if (insn->opcode == OP_read) {
1275+
insn_t *prev = insn->prev;
1276+
if (!prev)
1277+
return false;
1278+
if (prev->opcode != OP_add)
1279+
return false;
1280+
if (prev->rd != insn->rs1)
1281+
return false;
12471282

1248-
insn_t *prev = insn->prev;
1249-
if (!prev)
1250-
return false;
1251-
if (prev->opcode != OP_add)
1283+
var_t *def = insn->rd, *base = prev->rs1, *idx = prev->rs2;
1284+
if (base->is_global || idx->is_global)
1285+
return false;
1286+
1287+
/* Look for identical add+read patterns */
1288+
for (use_chain_t *user = base->users_head; user; user = user->next) {
1289+
insn_t *i = user->insn;
1290+
if (i == prev)
1291+
continue;
1292+
if (i->opcode != OP_add)
1293+
continue;
1294+
if (!i->next)
1295+
continue;
1296+
if (i->next->opcode != OP_read)
1297+
continue;
1298+
if (i->rs1 != base || i->rs2 != idx)
1299+
continue;
1300+
1301+
/* Check dominance */
1302+
basic_block_t *i_bb = i->belong_to;
1303+
bool check_dom = false;
1304+
for (;; i_bb = i_bb->idom) {
1305+
if (i_bb == bb) {
1306+
check_dom = true;
1307+
break;
1308+
}
1309+
if (i_bb == i_bb->idom)
1310+
break;
1311+
}
1312+
if (!check_dom)
1313+
continue;
1314+
1315+
/* Replace with assignment */
1316+
i->next->opcode = OP_assign;
1317+
i->next->rs1 = def;
1318+
if (i->prev) {
1319+
i->prev->next = i->next;
1320+
i->next->prev = i->prev;
1321+
} else {
1322+
i->belong_to->insn_list.head = i->next;
1323+
i->next->prev = NULL;
1324+
}
1325+
}
1326+
return true;
1327+
}
1328+
1329+
/* Handle general binary operations */
1330+
if (!is_cse_candidate(insn))
12521331
return false;
1253-
if (prev->rd != insn->rs1)
1332+
1333+
if (!insn->rs1 || !insn->rs2 || !insn->rd)
12541334
return false;
12551335

1256-
var_t *def = insn->rd, *base = prev->rs1, *idx = prev->rs2;
1257-
if (base->is_global || idx->is_global)
1336+
/* Don't CSE operations with global variables */
1337+
if (insn->rs1->is_global || insn->rs2->is_global)
12581338
return false;
12591339

1260-
use_chain_t *rs1_delete_user = NULL;
1261-
use_chain_t *rs2_delete_user = NULL;
1262-
for (use_chain_t *user = base->users_head; user; user = user->next) {
1263-
insn_t *i = user->insn;
1340+
/* Look for identical binary operations */
1341+
for (insn_t *other = bb->insn_list.head; other; other = other->next) {
1342+
if (other == insn)
1343+
break; /* Only consider earlier instructions */
12641344

1265-
/* Delete the use chain nodes found in the last loop */
1266-
if (rs1_delete_user) {
1267-
use_chain_delete(rs1_delete_user, rs1_delete_user->insn->rs1);
1268-
rs1_delete_user = NULL;
1269-
}
1270-
if (rs2_delete_user) {
1271-
use_chain_delete(rs2_delete_user, rs2_delete_user->insn->rs2);
1272-
rs2_delete_user = NULL;
1273-
}
1274-
if (i == prev)
1275-
continue;
1276-
if (i->opcode != OP_add)
1277-
continue;
1278-
if (!i->next)
1345+
if (other->opcode != insn->opcode)
12791346
continue;
1280-
if (i->next->opcode != OP_read)
1347+
if (!other->rs1 || !other->rs2 || !other->rd)
12811348
continue;
1282-
if (i->rs1 != base || i->rs2 != idx)
1283-
continue;
1284-
basic_block_t *i_bb = i->belong_to;
1285-
bool check_dom = 0;
1286-
/* Check if the instructions are under the same dominate tree */
1287-
for (;; i_bb = i_bb->idom) {
1288-
if (i_bb == bb) {
1289-
check_dom = true;
1290-
break;
1349+
1350+
/* Check if operands match */
1351+
bool operands_match = false;
1352+
if (other->rs1 == insn->rs1 && other->rs2 == insn->rs2) {
1353+
operands_match = true;
1354+
} else if (insn->opcode == OP_add || insn->opcode == OP_mul ||
1355+
insn->opcode == OP_bit_and || insn->opcode == OP_bit_or ||
1356+
insn->opcode == OP_bit_xor || insn->opcode == OP_log_and ||
1357+
insn->opcode == OP_log_or || insn->opcode == OP_eq ||
1358+
insn->opcode == OP_neq) {
1359+
/* Commutative operations */
1360+
if (other->rs1 == insn->rs2 && other->rs2 == insn->rs1) {
1361+
operands_match = true;
12911362
}
1292-
if (i_bb == i_bb->idom)
1293-
break;
12941363
}
1295-
if (!check_dom)
1296-
continue;
12971364

1298-
i->next->opcode = OP_assign;
1299-
i->next->rs1 = def;
1300-
if (i->prev) {
1301-
i->prev->next = i->next;
1302-
i->next->prev = i->prev;
1303-
} else {
1304-
i->belong_to->insn_list.head = i->next;
1305-
i->next->prev = NULL;
1365+
if (operands_match) {
1366+
/* Replace current instruction with assignment */
1367+
insn->opcode = OP_assign;
1368+
insn->rs1 = other->rd;
1369+
insn->rs2 = NULL;
1370+
return true;
13061371
}
1307-
i->next->opcode = OP_assign;
1308-
i->next->rs1 = def;
1309-
/* Prepare information for deleting use chain nodes */
1310-
rs1_delete_user = user;
1311-
for (rs2_delete_user = i->rs2->users_head;
1312-
rs2_delete_user->insn != rs1_delete_user->insn;
1313-
rs2_delete_user = rs2_delete_user->next)
1314-
;
13151372
}
1316-
return true;
1373+
1374+
return false;
13171375
}
13181376

13191377
bool mark_const(insn_t *insn)

0 commit comments

Comments
 (0)