xref: /illumos-gate/usr/src/tools/smatch/src/simplify.c (revision c85f09cc)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Simplify - do instruction simplification before CSE
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * Copyright (C) 2004 Linus Torvalds
51f5207b7SJohn Levon  */
61f5207b7SJohn Levon 
7*c85f09ccSJohn Levon ///
8*c85f09ccSJohn Levon // Instruction simplification
9*c85f09ccSJohn Levon // --------------------------
10*c85f09ccSJohn Levon //
11*c85f09ccSJohn Levon // Notation
12*c85f09ccSJohn Levon // ^^^^^^^^
13*c85f09ccSJohn Levon // The following conventions are used to describe the simplications:
14*c85f09ccSJohn Levon // * Uppercase letters are reserved for constants:
15*c85f09ccSJohn Levon //   * `M` for a constant mask,
16*c85f09ccSJohn Levon //   * `S` for a constant shift,
17*c85f09ccSJohn Levon //   * `N` for a constant number of bits (usually other than a shift),
18*c85f09ccSJohn Levon //   * `C` or 'K' for others constants.
19*c85f09ccSJohn Levon // * Lowercase letters `a`, `b`, `x`, `y`, ... are used for non-constants
20*c85f09ccSJohn Levon //   or when it doesn't matter if the pseudo is a constant or not.
21*c85f09ccSJohn Levon // * Primes are used if needed to distinguish symbols (`M`, `M'`, ...).
22*c85f09ccSJohn Levon // * Expressions or sub-expressions involving only constants are
23*c85f09ccSJohn Levon //   understood to be evaluated.
24*c85f09ccSJohn Levon // * `$mask(N)` is used for `((1 << N) -1)`
25*c85f09ccSJohn Levon // * `$trunc(x, N)` is used for `(x & $mask(N))`
26*c85f09ccSJohn Levon // * Expressions like `(-1 << S)`, `(-1 >> S)` and others formulae are
27*c85f09ccSJohn Levon //   understood to be truncated to the size of the current instruction
28*c85f09ccSJohn Levon //   (needed, since in general this size is not the same as the one used
29*c85f09ccSJohn Levon //   by sparse for the evaluation of arithmetic operations).
30*c85f09ccSJohn Levon // * `TRUNC(x, N)` is used for a truncation *to* a size of `N` bits
31*c85f09ccSJohn Levon // * `ZEXT(x, N)` is used for a zero-extension *from* a size of `N` bits
32*c85f09ccSJohn Levon // * `OP(x, C)` is used to represent some generic operation using a constant,
33*c85f09ccSJohn Levon //   including when the constant is implicit (e.g. `TRUNC(x, N)`).
34*c85f09ccSJohn Levon // * `MASK(x, M)` is used to respresent a 'masking' instruction:
35*c85f09ccSJohn Levon //   - `AND(x, M)`
36*c85f09ccSJohn Levon //   - `LSR(x, S)`, with `M` = (-1 << S)
37*c85f09ccSJohn Levon //   - `SHL(x, S)`, with `M` = (-1 >> S)
38*c85f09ccSJohn Levon //   - `TRUNC(x, N)`, with `M` = $mask(N)
39*c85f09ccSJohn Levon //   - `ZEXT(x, N)`, with `M` = $mask(N)
40*c85f09ccSJohn Levon // * `SHIFT(x, S)` is used for `LSR(x, S)` or `SHL(x, S)`.
41*c85f09ccSJohn Levon 
421f5207b7SJohn Levon #include <assert.h>
431f5207b7SJohn Levon 
441f5207b7SJohn Levon #include "parse.h"
451f5207b7SJohn Levon #include "expression.h"
461f5207b7SJohn Levon #include "linearize.h"
471f5207b7SJohn Levon #include "flow.h"
481f5207b7SJohn Levon #include "symbol.h"
491f5207b7SJohn Levon 
50*c85f09ccSJohn Levon ///
51*c85f09ccSJohn Levon // Utilities
52*c85f09ccSJohn Levon // ^^^^^^^^^
53*c85f09ccSJohn Levon 
54*c85f09ccSJohn Levon ///
55*c85f09ccSJohn Levon // find the trivial parent for a phi-source
phi_parent(struct basic_block * source,pseudo_t pseudo)561f5207b7SJohn Levon static struct basic_block *phi_parent(struct basic_block *source, pseudo_t pseudo)
571f5207b7SJohn Levon {
581f5207b7SJohn Levon 	/* Can't go upwards if the pseudo is defined in the bb it came from.. */
591f5207b7SJohn Levon 	if (pseudo->type == PSEUDO_REG) {
601f5207b7SJohn Levon 		struct instruction *def = pseudo->def;
611f5207b7SJohn Levon 		if (def->bb == source)
621f5207b7SJohn Levon 			return source;
631f5207b7SJohn Levon 	}
641f5207b7SJohn Levon 	if (bb_list_size(source->children) != 1 || bb_list_size(source->parents) != 1)
651f5207b7SJohn Levon 		return source;
661f5207b7SJohn Levon 	return first_basic_block(source->parents);
671f5207b7SJohn Levon }
681f5207b7SJohn Levon 
69*c85f09ccSJohn Levon ///
70*c85f09ccSJohn Levon // copy the phi-node's phisrcs into to given array
71*c85f09ccSJohn Levon // @return: 0 if the the list contained the expected
72*c85f09ccSJohn Levon //	number of element, a positive number if there was
73*c85f09ccSJohn Levon //	more than expected and a negative one if less.
74*c85f09ccSJohn Levon //
75*c85f09ccSJohn Levon // :note: we can't reuse a function like linearize_ptr_list()
76*c85f09ccSJohn Levon //	because any VOIDs in the phi-list must be ignored here
77*c85f09ccSJohn Levon //	as in this context they mean 'entry has been removed'.
get_phisources(struct instruction * sources[],int nbr,struct instruction * insn)781f5207b7SJohn Levon static int get_phisources(struct instruction *sources[], int nbr, struct instruction *insn)
791f5207b7SJohn Levon {
801f5207b7SJohn Levon 	pseudo_t phi;
811f5207b7SJohn Levon 	int i = 0;
821f5207b7SJohn Levon 
831f5207b7SJohn Levon 	assert(insn->opcode == OP_PHI);
841f5207b7SJohn Levon 	FOR_EACH_PTR(insn->phi_list, phi) {
851f5207b7SJohn Levon 		struct instruction *def;
861f5207b7SJohn Levon 		if (phi == VOID)
871f5207b7SJohn Levon 			continue;
881f5207b7SJohn Levon 		if (i >= nbr)
891f5207b7SJohn Levon 			return 1;
901f5207b7SJohn Levon 		def = phi->def;
911f5207b7SJohn Levon 		assert(def->opcode == OP_PHISOURCE);
921f5207b7SJohn Levon 		sources[i++] = def;
931f5207b7SJohn Levon 	} END_FOR_EACH_PTR(phi);
941f5207b7SJohn Levon 	return i - nbr;
951f5207b7SJohn Levon }
961f5207b7SJohn Levon 
if_convert_phi(struct instruction * insn)971f5207b7SJohn Levon static int if_convert_phi(struct instruction *insn)
981f5207b7SJohn Levon {
991f5207b7SJohn Levon 	struct instruction *array[2];
1001f5207b7SJohn Levon 	struct basic_block *parents[3];
1011f5207b7SJohn Levon 	struct basic_block *bb, *bb1, *bb2, *source;
1021f5207b7SJohn Levon 	struct instruction *br;
1031f5207b7SJohn Levon 	pseudo_t p1, p2;
1041f5207b7SJohn Levon 
1051f5207b7SJohn Levon 	bb = insn->bb;
1061f5207b7SJohn Levon 	if (get_phisources(array, 2, insn))
1071f5207b7SJohn Levon 		return 0;
1081f5207b7SJohn Levon 	if (linearize_ptr_list((struct ptr_list *)bb->parents, (void **)parents, 3) != 2)
1091f5207b7SJohn Levon 		return 0;
110*c85f09ccSJohn Levon 	p1 = array[0]->phi_src;
1111f5207b7SJohn Levon 	bb1 = array[0]->bb;
112*c85f09ccSJohn Levon 	p2 = array[1]->phi_src;
1131f5207b7SJohn Levon 	bb2 = array[1]->bb;
1141f5207b7SJohn Levon 
1151f5207b7SJohn Levon 	/* Only try the simple "direct parents" case */
1161f5207b7SJohn Levon 	if ((bb1 != parents[0] || bb2 != parents[1]) &&
1171f5207b7SJohn Levon 	    (bb1 != parents[1] || bb2 != parents[0]))
1181f5207b7SJohn Levon 		return 0;
1191f5207b7SJohn Levon 
1201f5207b7SJohn Levon 	/*
1211f5207b7SJohn Levon 	 * See if we can find a common source for this..
1221f5207b7SJohn Levon 	 */
1231f5207b7SJohn Levon 	source = phi_parent(bb1, p1);
1241f5207b7SJohn Levon 	if (source != phi_parent(bb2, p2))
1251f5207b7SJohn Levon 		return 0;
1261f5207b7SJohn Levon 
1271f5207b7SJohn Levon 	/*
1281f5207b7SJohn Levon 	 * Cool. We now know that 'source' is the exclusive
1291f5207b7SJohn Levon 	 * parent of both phi-nodes, so the exit at the
1301f5207b7SJohn Levon 	 * end of it fully determines which one it is, and
1311f5207b7SJohn Levon 	 * we can turn it into a select.
1321f5207b7SJohn Levon 	 *
1331f5207b7SJohn Levon 	 * HOWEVER, right now we only handle regular
1341f5207b7SJohn Levon 	 * conditional branches. No multijumps or computed
1351f5207b7SJohn Levon 	 * stuff. Verify that here.
1361f5207b7SJohn Levon 	 */
1371f5207b7SJohn Levon 	br = last_instruction(source->insns);
1381f5207b7SJohn Levon 	if (!br || br->opcode != OP_CBR)
1391f5207b7SJohn Levon 		return 0;
1401f5207b7SJohn Levon 
1411f5207b7SJohn Levon 	assert(br->cond);
1421f5207b7SJohn Levon 	assert(br->bb_false);
1431f5207b7SJohn Levon 
1441f5207b7SJohn Levon 	/*
1451f5207b7SJohn Levon 	 * We're in business. Match up true/false with p1/p2.
1461f5207b7SJohn Levon 	 */
1471f5207b7SJohn Levon 	if (br->bb_true == bb2 || br->bb_false == bb1) {
1481f5207b7SJohn Levon 		pseudo_t p = p1;
1491f5207b7SJohn Levon 		p1 = p2;
1501f5207b7SJohn Levon 		p2 = p;
1511f5207b7SJohn Levon 	}
1521f5207b7SJohn Levon 
1531f5207b7SJohn Levon 	/*
1541f5207b7SJohn Levon 	 * OK, we can now replace that last
1551f5207b7SJohn Levon 	 *
1561f5207b7SJohn Levon 	 *	br cond, a, b
1571f5207b7SJohn Levon 	 *
1581f5207b7SJohn Levon 	 * with the sequence
1591f5207b7SJohn Levon 	 *
1601f5207b7SJohn Levon 	 *	setcc cond
1611f5207b7SJohn Levon 	 *	select pseudo, p1, p2
1621f5207b7SJohn Levon 	 *	br cond, a, b
1631f5207b7SJohn Levon 	 *
1641f5207b7SJohn Levon 	 * and remove the phi-node. If it then
1651f5207b7SJohn Levon 	 * turns out that 'a' or 'b' is entirely
1661f5207b7SJohn Levon 	 * empty (common case), and now no longer
1671f5207b7SJohn Levon 	 * a phi-source, we'll be able to simplify
1681f5207b7SJohn Levon 	 * the conditional branch too.
1691f5207b7SJohn Levon 	 */
1701f5207b7SJohn Levon 	insert_select(source, br, insn, p1, p2);
1711f5207b7SJohn Levon 	kill_instruction(insn);
1721f5207b7SJohn Levon 	return REPEAT_CSE;
1731f5207b7SJohn Levon }
1741f5207b7SJohn Levon 
175*c85f09ccSJohn Levon ///
176*c85f09ccSJohn Levon // detect trivial phi-nodes
177*c85f09ccSJohn Levon // @insn: the phi-node
178*c85f09ccSJohn Levon // @pseudo: the candidate resulting pseudo (NULL when starting)
179*c85f09ccSJohn Levon // @return: the unique result if the phi-node is trivial, NULL otherwise
180*c85f09ccSJohn Levon //
181*c85f09ccSJohn Levon // A phi-node is trivial if it has a single possible result:
182*c85f09ccSJohn Levon //	* all operands are the same
183*c85f09ccSJohn Levon //	* the operands are themselves defined by a chain or cycle of phi-nodes
184*c85f09ccSJohn Levon //		and the set of all operands involved contains a single value
185*c85f09ccSJohn Levon //		not defined by these phi-nodes
186*c85f09ccSJohn Levon //
187*c85f09ccSJohn Levon // Since the result is unique, these phi-nodes can be removed.
trivial_phi(pseudo_t pseudo,struct instruction * insn,struct pseudo_list ** list)188*c85f09ccSJohn Levon static pseudo_t trivial_phi(pseudo_t pseudo, struct instruction *insn, struct pseudo_list **list)
1891f5207b7SJohn Levon {
190*c85f09ccSJohn Levon 	pseudo_t target = insn->target;
1911f5207b7SJohn Levon 	pseudo_t phi;
1921f5207b7SJohn Levon 
193*c85f09ccSJohn Levon 	add_pseudo(list, target);
194*c85f09ccSJohn Levon 
1951f5207b7SJohn Levon 	FOR_EACH_PTR(insn->phi_list, phi) {
1961f5207b7SJohn Levon 		struct instruction *def;
197*c85f09ccSJohn Levon 		pseudo_t src;
198*c85f09ccSJohn Levon 
1991f5207b7SJohn Levon 		if (phi == VOID)
2001f5207b7SJohn Levon 			continue;
2011f5207b7SJohn Levon 		def = phi->def;
202*c85f09ccSJohn Levon 		if (!def->bb)
2031f5207b7SJohn Levon 			continue;
204*c85f09ccSJohn Levon 		src = def->phi_src; // bypass OP_PHISRC & get the real source
205*c85f09ccSJohn Levon 		if (src == VOID)
2061f5207b7SJohn Levon 			continue;
207*c85f09ccSJohn Levon 		if (!pseudo) {
208*c85f09ccSJohn Levon 			pseudo = src;
209*c85f09ccSJohn Levon 			continue;
210*c85f09ccSJohn Levon 		}
211*c85f09ccSJohn Levon 		if (src == pseudo)
212*c85f09ccSJohn Levon 			continue;
213*c85f09ccSJohn Levon 		if (src == target)
214*c85f09ccSJohn Levon 			continue;
215*c85f09ccSJohn Levon 		if (DEF_OPCODE(def, src) == OP_PHI) {
216*c85f09ccSJohn Levon 			if (pseudo_in_list(*list, src))
217*c85f09ccSJohn Levon 				continue;
218*c85f09ccSJohn Levon 			if ((pseudo = trivial_phi(pseudo, def, list)))
219*c85f09ccSJohn Levon 				continue;
2201f5207b7SJohn Levon 		}
221*c85f09ccSJohn Levon 		return NULL;
2221f5207b7SJohn Levon 	} END_FOR_EACH_PTR(phi);
2231f5207b7SJohn Levon 
224*c85f09ccSJohn Levon 	return pseudo ? pseudo : VOID;
225*c85f09ccSJohn Levon }
226*c85f09ccSJohn Levon 
clean_up_phi(struct instruction * insn)227*c85f09ccSJohn Levon static int clean_up_phi(struct instruction *insn)
228*c85f09ccSJohn Levon {
229*c85f09ccSJohn Levon 	struct pseudo_list *list = NULL;
230*c85f09ccSJohn Levon 	pseudo_t pseudo;
231*c85f09ccSJohn Levon 
232*c85f09ccSJohn Levon 	if ((pseudo = trivial_phi(NULL, insn, &list))) {
2331f5207b7SJohn Levon 		convert_instruction_target(insn, pseudo);
2341f5207b7SJohn Levon 		kill_instruction(insn);
2351f5207b7SJohn Levon 		return REPEAT_CSE;
2361f5207b7SJohn Levon 	}
2371f5207b7SJohn Levon 
2381f5207b7SJohn Levon 	return if_convert_phi(insn);
2391f5207b7SJohn Levon }
2401f5207b7SJohn Levon 
delete_pseudo_user_list_entry(struct pseudo_user_list ** list,pseudo_t * entry,int count)2411f5207b7SJohn Levon static int delete_pseudo_user_list_entry(struct pseudo_user_list **list, pseudo_t *entry, int count)
2421f5207b7SJohn Levon {
2431f5207b7SJohn Levon 	struct pseudo_user *pu;
2441f5207b7SJohn Levon 
2451f5207b7SJohn Levon 	FOR_EACH_PTR(*list, pu) {
2461f5207b7SJohn Levon 		if (pu->userp == entry) {
2471f5207b7SJohn Levon 			MARK_CURRENT_DELETED(pu);
2481f5207b7SJohn Levon 			if (!--count)
2491f5207b7SJohn Levon 				goto out;
2501f5207b7SJohn Levon 		}
2511f5207b7SJohn Levon 	} END_FOR_EACH_PTR(pu);
2521f5207b7SJohn Levon 	assert(count <= 0);
2531f5207b7SJohn Levon out:
254*c85f09ccSJohn Levon 	if (pseudo_user_list_empty(*list))
2551f5207b7SJohn Levon 		*list = NULL;
2561f5207b7SJohn Levon 	return count;
2571f5207b7SJohn Levon }
2581f5207b7SJohn Levon 
rem_usage(pseudo_t p,pseudo_t * usep,int kill)259*c85f09ccSJohn Levon static inline void rem_usage(pseudo_t p, pseudo_t *usep, int kill)
2601f5207b7SJohn Levon {
2611f5207b7SJohn Levon 	if (has_use_list(p)) {
262*c85f09ccSJohn Levon 		if (p->type == PSEUDO_SYM)
263*c85f09ccSJohn Levon 			repeat_phase |= REPEAT_SYMBOL_CLEANUP;
2641f5207b7SJohn Levon 		delete_pseudo_user_list_entry(&p->users, usep, 1);
265*c85f09ccSJohn Levon 		if (kill && !p->users)
2661f5207b7SJohn Levon 			kill_instruction(p->def);
2671f5207b7SJohn Levon 	}
2681f5207b7SJohn Levon }
2691f5207b7SJohn Levon 
remove_usage(pseudo_t p,pseudo_t * usep)270*c85f09ccSJohn Levon static inline void remove_usage(pseudo_t p, pseudo_t *usep)
271*c85f09ccSJohn Levon {
272*c85f09ccSJohn Levon 	rem_usage(p, usep, 1);
273*c85f09ccSJohn Levon }
274*c85f09ccSJohn Levon 
kill_use(pseudo_t * usep)2751f5207b7SJohn Levon void kill_use(pseudo_t *usep)
2761f5207b7SJohn Levon {
2771f5207b7SJohn Levon 	if (usep) {
2781f5207b7SJohn Levon 		pseudo_t p = *usep;
2791f5207b7SJohn Levon 		*usep = VOID;
280*c85f09ccSJohn Levon 		rem_usage(p, usep, 1);
2811f5207b7SJohn Levon 	}
2821f5207b7SJohn Levon }
2831f5207b7SJohn Levon 
284*c85f09ccSJohn Levon // Like kill_use() but do not (recursively) kill dead instructions
remove_use(pseudo_t * usep)285*c85f09ccSJohn Levon void remove_use(pseudo_t *usep)
286*c85f09ccSJohn Levon {
287*c85f09ccSJohn Levon 	pseudo_t p = *usep;
288*c85f09ccSJohn Levon 	*usep = VOID;
289*c85f09ccSJohn Levon 	rem_usage(p, usep, 0);
290*c85f09ccSJohn Levon }
291*c85f09ccSJohn Levon 
kill_use_list(struct pseudo_list * list)2921f5207b7SJohn Levon static void kill_use_list(struct pseudo_list *list)
2931f5207b7SJohn Levon {
2941f5207b7SJohn Levon 	pseudo_t p;
2951f5207b7SJohn Levon 	FOR_EACH_PTR(list, p) {
2961f5207b7SJohn Levon 		if (p == VOID)
2971f5207b7SJohn Levon 			continue;
2981f5207b7SJohn Levon 		kill_use(THIS_ADDRESS(p));
2991f5207b7SJohn Levon 	} END_FOR_EACH_PTR(p);
3001f5207b7SJohn Levon }
3011f5207b7SJohn Levon 
302*c85f09ccSJohn Levon ///
303*c85f09ccSJohn Levon // kill an instruction
304*c85f09ccSJohn Levon // @insn: the instruction to be killed
305*c85f09ccSJohn Levon // @force: if unset, the normal case, the instruction is not killed
306*c85f09ccSJohn Levon //	if not free of possible side-effect; if set the instruction
307*c85f09ccSJohn Levon //	is unconditionally killed.
308*c85f09ccSJohn Levon //
309*c85f09ccSJohn Levon // The killed instruction is removed from its BB and the usage
310*c85f09ccSJohn Levon // of all its operands are removed. The instruction is also
311*c85f09ccSJohn Levon // marked as killed by setting its ->bb to NULL.
kill_insn(struct instruction * insn,int force)312*c85f09ccSJohn Levon int kill_insn(struct instruction *insn, int force)
3131f5207b7SJohn Levon {
3141f5207b7SJohn Levon 	if (!insn || !insn->bb)
315*c85f09ccSJohn Levon 		return 0;
3161f5207b7SJohn Levon 
3171f5207b7SJohn Levon 	switch (insn->opcode) {
3181f5207b7SJohn Levon 	case OP_SEL:
3191f5207b7SJohn Levon 	case OP_RANGE:
3201f5207b7SJohn Levon 		kill_use(&insn->src3);
3211f5207b7SJohn Levon 		/* fall through */
3221f5207b7SJohn Levon 
3231f5207b7SJohn Levon 	case OP_BINARY ... OP_BINCMP_END:
3241f5207b7SJohn Levon 		kill_use(&insn->src2);
3251f5207b7SJohn Levon 		/* fall through */
3261f5207b7SJohn Levon 
327*c85f09ccSJohn Levon 	case OP_UNOP ... OP_UNOP_END:
3281f5207b7SJohn Levon 	case OP_SETVAL:
3291f5207b7SJohn Levon 	case OP_SLICE:
3301f5207b7SJohn Levon 		kill_use(&insn->src1);
3311f5207b7SJohn Levon 		break;
3321f5207b7SJohn Levon 
3331f5207b7SJohn Levon 	case OP_PHI:
3341f5207b7SJohn Levon 		kill_use_list(insn->phi_list);
3351f5207b7SJohn Levon 		break;
3361f5207b7SJohn Levon 	case OP_PHISOURCE:
3371f5207b7SJohn Levon 		kill_use(&insn->phi_src);
3381f5207b7SJohn Levon 		break;
3391f5207b7SJohn Levon 
3401f5207b7SJohn Levon 	case OP_SYMADDR:
341*c85f09ccSJohn Levon 		kill_use(&insn->src);
3421f5207b7SJohn Levon 		repeat_phase |= REPEAT_SYMBOL_CLEANUP;
3431f5207b7SJohn Levon 		break;
3441f5207b7SJohn Levon 
3451f5207b7SJohn Levon 	case OP_CBR:
346*c85f09ccSJohn Levon 	case OP_SWITCH:
3471f5207b7SJohn Levon 	case OP_COMPUTEDGOTO:
3481f5207b7SJohn Levon 		kill_use(&insn->cond);
3491f5207b7SJohn Levon 		break;
3501f5207b7SJohn Levon 
3511f5207b7SJohn Levon 	case OP_CALL:
3521f5207b7SJohn Levon 		if (!force) {
3531f5207b7SJohn Levon 			/* a "pure" function can be killed too */
3541f5207b7SJohn Levon 			if (!(insn->func->type == PSEUDO_SYM))
355*c85f09ccSJohn Levon 				return 0;
3561f5207b7SJohn Levon 			if (!(insn->func->sym->ctype.modifiers & MOD_PURE))
357*c85f09ccSJohn Levon 				return 0;
3581f5207b7SJohn Levon 		}
3591f5207b7SJohn Levon 		kill_use_list(insn->arguments);
3601f5207b7SJohn Levon 		if (insn->func->type == PSEUDO_REG)
3611f5207b7SJohn Levon 			kill_use(&insn->func);
3621f5207b7SJohn Levon 		break;
3631f5207b7SJohn Levon 
3641f5207b7SJohn Levon 	case OP_LOAD:
365*c85f09ccSJohn Levon 		if (!force && insn->is_volatile)
366*c85f09ccSJohn Levon 			return 0;
3671f5207b7SJohn Levon 		kill_use(&insn->src);
3681f5207b7SJohn Levon 		break;
3691f5207b7SJohn Levon 
3701f5207b7SJohn Levon 	case OP_STORE:
3711f5207b7SJohn Levon 		if (!force)
372*c85f09ccSJohn Levon 			return 0;
3731f5207b7SJohn Levon 		kill_use(&insn->src);
3741f5207b7SJohn Levon 		kill_use(&insn->target);
3751f5207b7SJohn Levon 		break;
3761f5207b7SJohn Levon 
3771f5207b7SJohn Levon 	case OP_ENTRY:
3781f5207b7SJohn Levon 		/* ignore */
379*c85f09ccSJohn Levon 		return 0;
3801f5207b7SJohn Levon 
3811f5207b7SJohn Levon 	case OP_BR:
382*c85f09ccSJohn Levon 	case OP_SETFVAL:
3831f5207b7SJohn Levon 	default:
3841f5207b7SJohn Levon 		break;
3851f5207b7SJohn Levon 	}
3861f5207b7SJohn Levon 
3871f5207b7SJohn Levon 	insn->bb = NULL;
388*c85f09ccSJohn Levon 	return repeat_phase |= REPEAT_CSE;
3891f5207b7SJohn Levon }
3901f5207b7SJohn Levon 
391*c85f09ccSJohn Levon ///
392*c85f09ccSJohn Levon // kill trivially dead instructions
dead_insn(struct instruction * insn,pseudo_t * src1,pseudo_t * src2,pseudo_t * src3)3931f5207b7SJohn Levon static int dead_insn(struct instruction *insn, pseudo_t *src1, pseudo_t *src2, pseudo_t *src3)
3941f5207b7SJohn Levon {
395*c85f09ccSJohn Levon 	if (has_users(insn->target))
396*c85f09ccSJohn Levon 		return 0;
3971f5207b7SJohn Levon 
3981f5207b7SJohn Levon 	insn->bb = NULL;
3991f5207b7SJohn Levon 	kill_use(src1);
4001f5207b7SJohn Levon 	kill_use(src2);
4011f5207b7SJohn Levon 	kill_use(src3);
4021f5207b7SJohn Levon 	return REPEAT_CSE;
4031f5207b7SJohn Levon }
4041f5207b7SJohn Levon 
has_target(struct instruction * insn)405*c85f09ccSJohn Levon static inline bool has_target(struct instruction *insn)
406*c85f09ccSJohn Levon {
407*c85f09ccSJohn Levon 	return opcode_table[insn->opcode].flags & OPF_TARGET;
408*c85f09ccSJohn Levon }
409*c85f09ccSJohn Levon 
remove_dead_insns(struct entrypoint * ep)410*c85f09ccSJohn Levon void remove_dead_insns(struct entrypoint *ep)
411*c85f09ccSJohn Levon {
412*c85f09ccSJohn Levon 	struct basic_block *bb;
413*c85f09ccSJohn Levon 
414*c85f09ccSJohn Levon 	FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
415*c85f09ccSJohn Levon 		struct instruction *insn;
416*c85f09ccSJohn Levon 		FOR_EACH_PTR_REVERSE(bb->insns, insn) {
417*c85f09ccSJohn Levon 			if (!insn->bb)
418*c85f09ccSJohn Levon 				continue;
419*c85f09ccSJohn Levon 			if (!has_target(insn))
420*c85f09ccSJohn Levon 				continue;
421*c85f09ccSJohn Levon 			if (!has_users(insn->target))
422*c85f09ccSJohn Levon 				kill_instruction(insn);
423*c85f09ccSJohn Levon 		} END_FOR_EACH_PTR_REVERSE(insn);
424*c85f09ccSJohn Levon 	} END_FOR_EACH_PTR_REVERSE(bb);
425*c85f09ccSJohn Levon }
426*c85f09ccSJohn Levon 
constant(pseudo_t pseudo)4271f5207b7SJohn Levon static inline int constant(pseudo_t pseudo)
4281f5207b7SJohn Levon {
4291f5207b7SJohn Levon 	return pseudo->type == PSEUDO_VAL;
4301f5207b7SJohn Levon }
4311f5207b7SJohn Levon 
432*c85f09ccSJohn Levon ///
433*c85f09ccSJohn Levon // replace the operand of an instruction
434*c85f09ccSJohn Levon // @insn: the instruction
435*c85f09ccSJohn Levon // @pp: the address of the instruction's operand
436*c85f09ccSJohn Levon // @new: the new value for the operand
437*c85f09ccSJohn Levon // @return: REPEAT_CSE.
replace_pseudo(struct instruction * insn,pseudo_t * pp,pseudo_t new)438*c85f09ccSJohn Levon static inline int replace_pseudo(struct instruction *insn, pseudo_t *pp, pseudo_t new)
439*c85f09ccSJohn Levon {
440*c85f09ccSJohn Levon 	pseudo_t old = *pp;
441*c85f09ccSJohn Levon 	use_pseudo(insn, new, pp);
442*c85f09ccSJohn Levon 	remove_usage(old, pp);
443*c85f09ccSJohn Levon 	return REPEAT_CSE;
444*c85f09ccSJohn Levon }
445*c85f09ccSJohn Levon 
replace_with_pseudo(struct instruction * insn,pseudo_t pseudo)4461f5207b7SJohn Levon static int replace_with_pseudo(struct instruction *insn, pseudo_t pseudo)
4471f5207b7SJohn Levon {
4481f5207b7SJohn Levon 	convert_instruction_target(insn, pseudo);
4491f5207b7SJohn Levon 
4501f5207b7SJohn Levon 	switch (insn->opcode) {
4511f5207b7SJohn Levon 	case OP_SEL:
4521f5207b7SJohn Levon 	case OP_RANGE:
4531f5207b7SJohn Levon 		kill_use(&insn->src3);
4541f5207b7SJohn Levon 	case OP_BINARY ... OP_BINCMP_END:
4551f5207b7SJohn Levon 		kill_use(&insn->src2);
456*c85f09ccSJohn Levon 	case OP_UNOP ... OP_UNOP_END:
4571f5207b7SJohn Levon 	case OP_SYMADDR:
4581f5207b7SJohn Levon 		kill_use(&insn->src1);
4591f5207b7SJohn Levon 		break;
4601f5207b7SJohn Levon 
4611f5207b7SJohn Levon 	default:
4621f5207b7SJohn Levon 		assert(0);
4631f5207b7SJohn Levon 	}
4641f5207b7SJohn Levon 	insn->bb = NULL;
4651f5207b7SJohn Levon 	return REPEAT_CSE;
4661f5207b7SJohn Levon }
4671f5207b7SJohn Levon 
def_opcode(pseudo_t p)468*c85f09ccSJohn Levon static inline int def_opcode(pseudo_t p)
469*c85f09ccSJohn Levon {
470*c85f09ccSJohn Levon 	if (p->type != PSEUDO_REG)
471*c85f09ccSJohn Levon 		return OP_BADOP;
472*c85f09ccSJohn Levon 	return p->def->opcode;
473*c85f09ccSJohn Levon }
474*c85f09ccSJohn Levon 
value_size(long long value)475*c85f09ccSJohn Levon static unsigned int value_size(long long value)
4761f5207b7SJohn Levon {
4771f5207b7SJohn Levon 	value >>= 8;
4781f5207b7SJohn Levon 	if (!value)
4791f5207b7SJohn Levon 		return 8;
4801f5207b7SJohn Levon 	value >>= 8;
4811f5207b7SJohn Levon 	if (!value)
4821f5207b7SJohn Levon 		return 16;
4831f5207b7SJohn Levon 	value >>= 16;
4841f5207b7SJohn Levon 	if (!value)
4851f5207b7SJohn Levon 		return 32;
4861f5207b7SJohn Levon 	return 64;
4871f5207b7SJohn Levon }
4881f5207b7SJohn Levon 
489*c85f09ccSJohn Levon ///
490*c85f09ccSJohn Levon // try to determine the maximum size of bits in a pseudo
491*c85f09ccSJohn Levon //
492*c85f09ccSJohn Levon // Right now this only follow casts and constant values, but we
493*c85f09ccSJohn Levon // could look at things like AND instructions, etc.
operand_size(struct instruction * insn,pseudo_t pseudo)4941f5207b7SJohn Levon static unsigned int operand_size(struct instruction *insn, pseudo_t pseudo)
4951f5207b7SJohn Levon {
4961f5207b7SJohn Levon 	unsigned int size = insn->size;
4971f5207b7SJohn Levon 
4981f5207b7SJohn Levon 	if (pseudo->type == PSEUDO_REG) {
4991f5207b7SJohn Levon 		struct instruction *src = pseudo->def;
500*c85f09ccSJohn Levon 		if (src && src->opcode == OP_ZEXT && src->orig_type) {
5011f5207b7SJohn Levon 			unsigned int orig_size = src->orig_type->bit_size;
5021f5207b7SJohn Levon 			if (orig_size < size)
5031f5207b7SJohn Levon 				size = orig_size;
5041f5207b7SJohn Levon 		}
5051f5207b7SJohn Levon 	}
5061f5207b7SJohn Levon 	if (pseudo->type == PSEUDO_VAL) {
5071f5207b7SJohn Levon 		unsigned int orig_size = value_size(pseudo->value);
5081f5207b7SJohn Levon 		if (orig_size < size)
5091f5207b7SJohn Levon 			size = orig_size;
5101f5207b7SJohn Levon 	}
5111f5207b7SJohn Levon 	return size;
5121f5207b7SJohn Levon }
5131f5207b7SJohn Levon 
eval_insn(struct instruction * insn)514*c85f09ccSJohn Levon static pseudo_t eval_insn(struct instruction *insn)
515*c85f09ccSJohn Levon {
516*c85f09ccSJohn Levon 	/* FIXME! Verify signs and sizes!! */
517*c85f09ccSJohn Levon 	unsigned int size = insn->size;
518*c85f09ccSJohn Levon 	long long left = insn->src1->value;
519*c85f09ccSJohn Levon 	long long right = insn->src2->value;
520*c85f09ccSJohn Levon 	unsigned long long ul, ur;
521*c85f09ccSJohn Levon 	long long res, mask, bits;
522*c85f09ccSJohn Levon 
523*c85f09ccSJohn Levon 	mask = 1ULL << (size-1);
524*c85f09ccSJohn Levon 	bits = mask | (mask-1);
525*c85f09ccSJohn Levon 
526*c85f09ccSJohn Levon 	if (left & mask)
527*c85f09ccSJohn Levon 		left |= ~bits;
528*c85f09ccSJohn Levon 	if (right & mask)
529*c85f09ccSJohn Levon 		right |= ~bits;
530*c85f09ccSJohn Levon 	ul = left & bits;
531*c85f09ccSJohn Levon 	ur = right & bits;
532*c85f09ccSJohn Levon 
533*c85f09ccSJohn Levon 	switch (insn->opcode) {
534*c85f09ccSJohn Levon 	case OP_ADD:
535*c85f09ccSJohn Levon 		res = left + right;
536*c85f09ccSJohn Levon 		break;
537*c85f09ccSJohn Levon 	case OP_SUB:
538*c85f09ccSJohn Levon 		res = left - right;
539*c85f09ccSJohn Levon 		break;
540*c85f09ccSJohn Levon 	case OP_MUL:
541*c85f09ccSJohn Levon 		res = ul * ur;
542*c85f09ccSJohn Levon 		break;
543*c85f09ccSJohn Levon 	case OP_DIVU:
544*c85f09ccSJohn Levon 		if (!ur)
545*c85f09ccSJohn Levon 			goto undef;
546*c85f09ccSJohn Levon 		res = ul / ur;
547*c85f09ccSJohn Levon 		break;
548*c85f09ccSJohn Levon 	case OP_DIVS:
549*c85f09ccSJohn Levon 		if (!right)
550*c85f09ccSJohn Levon 			goto undef;
551*c85f09ccSJohn Levon 		if (left == mask && right == -1)
552*c85f09ccSJohn Levon 			goto undef;
553*c85f09ccSJohn Levon 		res = left / right;
554*c85f09ccSJohn Levon 		break;
555*c85f09ccSJohn Levon 	case OP_MODU:
556*c85f09ccSJohn Levon 		if (!ur)
557*c85f09ccSJohn Levon 			goto undef;
558*c85f09ccSJohn Levon 		res = ul % ur;
559*c85f09ccSJohn Levon 		break;
560*c85f09ccSJohn Levon 	case OP_MODS:
561*c85f09ccSJohn Levon 		if (!right)
562*c85f09ccSJohn Levon 			goto undef;
563*c85f09ccSJohn Levon 		if (left == mask && right == -1)
564*c85f09ccSJohn Levon 			goto undef;
565*c85f09ccSJohn Levon 		res = left % right;
566*c85f09ccSJohn Levon 		break;
567*c85f09ccSJohn Levon 	case OP_SHL:
568*c85f09ccSJohn Levon 		if (ur >= size)
569*c85f09ccSJohn Levon 			goto undef;
570*c85f09ccSJohn Levon 		res = left << right;
571*c85f09ccSJohn Levon 		break;
572*c85f09ccSJohn Levon 	case OP_LSR:
573*c85f09ccSJohn Levon 		if (ur >= size)
574*c85f09ccSJohn Levon 			goto undef;
575*c85f09ccSJohn Levon 		res = ul >> ur;
576*c85f09ccSJohn Levon 		break;
577*c85f09ccSJohn Levon 	case OP_ASR:
578*c85f09ccSJohn Levon 		if (ur >= size)
579*c85f09ccSJohn Levon 			goto undef;
580*c85f09ccSJohn Levon 		res = left >> right;
581*c85f09ccSJohn Levon 		break;
582*c85f09ccSJohn Levon        /* Logical */
583*c85f09ccSJohn Levon 	case OP_AND:
584*c85f09ccSJohn Levon 		res = left & right;
585*c85f09ccSJohn Levon 		break;
586*c85f09ccSJohn Levon 	case OP_OR:
587*c85f09ccSJohn Levon 		res = left | right;
588*c85f09ccSJohn Levon 		break;
589*c85f09ccSJohn Levon 	case OP_XOR:
590*c85f09ccSJohn Levon 		res = left ^ right;
591*c85f09ccSJohn Levon 		break;
592*c85f09ccSJohn Levon 
593*c85f09ccSJohn Levon 	/* Binary comparison */
594*c85f09ccSJohn Levon 	case OP_SET_EQ:
595*c85f09ccSJohn Levon 		res = left == right;
596*c85f09ccSJohn Levon 		break;
597*c85f09ccSJohn Levon 	case OP_SET_NE:
598*c85f09ccSJohn Levon 		res = left != right;
599*c85f09ccSJohn Levon 		break;
600*c85f09ccSJohn Levon 	case OP_SET_LE:
601*c85f09ccSJohn Levon 		res = left <= right;
602*c85f09ccSJohn Levon 		break;
603*c85f09ccSJohn Levon 	case OP_SET_GE:
604*c85f09ccSJohn Levon 		res = left >= right;
605*c85f09ccSJohn Levon 		break;
606*c85f09ccSJohn Levon 	case OP_SET_LT:
607*c85f09ccSJohn Levon 		res = left < right;
608*c85f09ccSJohn Levon 		break;
609*c85f09ccSJohn Levon 	case OP_SET_GT:
610*c85f09ccSJohn Levon 		res = left > right;
611*c85f09ccSJohn Levon 		break;
612*c85f09ccSJohn Levon 	case OP_SET_B:
613*c85f09ccSJohn Levon 		res = ul < ur;
614*c85f09ccSJohn Levon 		break;
615*c85f09ccSJohn Levon 	case OP_SET_A:
616*c85f09ccSJohn Levon 		res = ul > ur;
617*c85f09ccSJohn Levon 		break;
618*c85f09ccSJohn Levon 	case OP_SET_BE:
619*c85f09ccSJohn Levon 		res = ul <= ur;
620*c85f09ccSJohn Levon 		break;
621*c85f09ccSJohn Levon 	case OP_SET_AE:
622*c85f09ccSJohn Levon 		res = ul >= ur;
623*c85f09ccSJohn Levon 		break;
624*c85f09ccSJohn Levon 	default:
625*c85f09ccSJohn Levon 		return NULL;
626*c85f09ccSJohn Levon 	}
627*c85f09ccSJohn Levon 	res &= bits;
628*c85f09ccSJohn Levon 
629*c85f09ccSJohn Levon 	return value_pseudo(res);
630*c85f09ccSJohn Levon 
631*c85f09ccSJohn Levon undef:
632*c85f09ccSJohn Levon 	return NULL;
633*c85f09ccSJohn Levon }
634*c85f09ccSJohn Levon 
635*c85f09ccSJohn Levon ///
636*c85f09ccSJohn Levon // Simplifications
637*c85f09ccSJohn Levon // ^^^^^^^^^^^^^^^
638*c85f09ccSJohn Levon 
639*c85f09ccSJohn Levon ///
640*c85f09ccSJohn Levon // try to simplify MASK(OR(AND(x, M'), b), M)
641*c85f09ccSJohn Levon // @insn: the masking instruction
642*c85f09ccSJohn Levon // @mask: the associated mask (M)
643*c85f09ccSJohn Levon // @ora: one of the OR's operands, guaranteed to be PSEUDO_REG
644*c85f09ccSJohn Levon // @orb: the other OR's operand
645*c85f09ccSJohn Levon // @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
simplify_mask_or_and(struct instruction * insn,unsigned long long mask,pseudo_t ora,pseudo_t orb)646*c85f09ccSJohn Levon static int simplify_mask_or_and(struct instruction *insn, unsigned long long mask,
647*c85f09ccSJohn Levon 	pseudo_t ora, pseudo_t orb)
648*c85f09ccSJohn Levon {
649*c85f09ccSJohn Levon 	unsigned long long omask, nmask;
650*c85f09ccSJohn Levon 	struct instruction *and = ora->def;
651*c85f09ccSJohn Levon 	pseudo_t src2 = and->src2;
652*c85f09ccSJohn Levon 
653*c85f09ccSJohn Levon 	if (and->opcode != OP_AND)
654*c85f09ccSJohn Levon 		return 0;
655*c85f09ccSJohn Levon 	if (!constant(src2))
656*c85f09ccSJohn Levon 		return 0;
657*c85f09ccSJohn Levon 	omask = src2->value;
658*c85f09ccSJohn Levon 	nmask = omask & mask;
659*c85f09ccSJohn Levon 	if (nmask == 0) {
660*c85f09ccSJohn Levon 		// if (M' & M) == 0: ((a & M') | b) -> b
661*c85f09ccSJohn Levon 		return replace_pseudo(insn, &insn->src1, orb);
662*c85f09ccSJohn Levon 	}
663*c85f09ccSJohn Levon 	if (multi_users(insn->src1))
664*c85f09ccSJohn Levon 		return 0;	// can't modify anything inside the OR
665*c85f09ccSJohn Levon 	if (nmask == mask) {
666*c85f09ccSJohn Levon 		struct instruction *or = insn->src1->def;
667*c85f09ccSJohn Levon 		pseudo_t *arg = (ora == or->src1) ? &or->src1 : &or->src2;
668*c85f09ccSJohn Levon 		// if (M' & M) == M: ((a & M') | b) -> (a | b)
669*c85f09ccSJohn Levon 		return replace_pseudo(or, arg, and->src1);
670*c85f09ccSJohn Levon 	}
671*c85f09ccSJohn Levon 	if (nmask != omask && !multi_users(ora)) {
672*c85f09ccSJohn Levon 		// if (M' & M) != M': AND(a, M') -> AND(a, (M' & M))
673*c85f09ccSJohn Levon 		and->src2 = value_pseudo(nmask);
674*c85f09ccSJohn Levon 		return REPEAT_CSE;
675*c85f09ccSJohn Levon 	}
676*c85f09ccSJohn Levon 	return 0;
677*c85f09ccSJohn Levon }
678*c85f09ccSJohn Levon 
679*c85f09ccSJohn Levon ///
680*c85f09ccSJohn Levon // try to simplify MASK(OR(a, b), M)
681*c85f09ccSJohn Levon // @insn: the masking instruction
682*c85f09ccSJohn Levon // @mask: the associated mask (M)
683*c85f09ccSJohn Levon // @or: the OR instruction
684*c85f09ccSJohn Levon // @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
simplify_mask_or(struct instruction * insn,unsigned long long mask,struct instruction * or)685*c85f09ccSJohn Levon static int simplify_mask_or(struct instruction *insn, unsigned long long mask, struct instruction *or)
686*c85f09ccSJohn Levon {
687*c85f09ccSJohn Levon 	pseudo_t src1 = or->src1;
688*c85f09ccSJohn Levon 	pseudo_t src2 = or->src2;
689*c85f09ccSJohn Levon 	int rc;
690*c85f09ccSJohn Levon 
691*c85f09ccSJohn Levon 	if (src1->type == PSEUDO_REG) {
692*c85f09ccSJohn Levon 		if ((rc = simplify_mask_or_and(insn, mask, src1, src2)))
693*c85f09ccSJohn Levon 			return rc;
694*c85f09ccSJohn Levon 	}
695*c85f09ccSJohn Levon 	if (src2->type == PSEUDO_REG) {
696*c85f09ccSJohn Levon 		if ((rc = simplify_mask_or_and(insn, mask, src2, src1)))
697*c85f09ccSJohn Levon 			return rc;
698*c85f09ccSJohn Levon 	} else if (src2->type == PSEUDO_VAL) {
699*c85f09ccSJohn Levon 		unsigned long long oval = src2->value;
700*c85f09ccSJohn Levon 		unsigned long long nval = oval & mask;
701*c85f09ccSJohn Levon 		// Try to simplify:
702*c85f09ccSJohn Levon 		//	MASK(OR(x, C), M)
703*c85f09ccSJohn Levon 		if (nval == 0) {
704*c85f09ccSJohn Levon 			// if (C & M) == 0: OR(x, C) -> x
705*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->src1, src1);
706*c85f09ccSJohn Levon 		}
707*c85f09ccSJohn Levon 		if (nval == mask) {
708*c85f09ccSJohn Levon 			// if (C & M) == M: OR(x, C) -> M
709*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->src1, value_pseudo(mask));
710*c85f09ccSJohn Levon 		}
711*c85f09ccSJohn Levon 		if (nval != oval && !multi_users(or->target)) {
712*c85f09ccSJohn Levon 			// if (C & M) != C: OR(x, C) -> OR(x, (C & M))
713*c85f09ccSJohn Levon 			return replace_pseudo(or, &or->src2, value_pseudo(nval));
714*c85f09ccSJohn Levon 		}
715*c85f09ccSJohn Levon 	}
716*c85f09ccSJohn Levon 	return 0;
717*c85f09ccSJohn Levon }
718*c85f09ccSJohn Levon 
719*c85f09ccSJohn Levon ///
720*c85f09ccSJohn Levon // try to simplify MASK(SHIFT(OR(a, b), S), M)
721*c85f09ccSJohn Levon // @sh: the shift instruction
722*c85f09ccSJohn Levon // @or: the OR instruction
723*c85f09ccSJohn Levon // @mask: the mask associated to MASK (M):
724*c85f09ccSJohn Levon // @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
simplify_mask_shift_or(struct instruction * sh,struct instruction * or,unsigned long long mask)725*c85f09ccSJohn Levon static int simplify_mask_shift_or(struct instruction *sh, struct instruction *or, unsigned long long mask)
726*c85f09ccSJohn Levon {
727*c85f09ccSJohn Levon 	unsigned long long smask = bits_mask(sh->size);
728*c85f09ccSJohn Levon 	int shift = sh->src2->value;
729*c85f09ccSJohn Levon 
730*c85f09ccSJohn Levon 	if (sh->opcode == OP_LSR)
731*c85f09ccSJohn Levon 		mask <<= shift;
732*c85f09ccSJohn Levon 	else
733*c85f09ccSJohn Levon 		mask >>= shift;
734*c85f09ccSJohn Levon 	return simplify_mask_or(sh, smask & mask, or);
735*c85f09ccSJohn Levon }
736*c85f09ccSJohn Levon 
simplify_mask_shift(struct instruction * sh,unsigned long long mask)737*c85f09ccSJohn Levon static int simplify_mask_shift(struct instruction *sh, unsigned long long mask)
7381f5207b7SJohn Levon {
739*c85f09ccSJohn Levon 	struct instruction *inner;
7401f5207b7SJohn Levon 
741*c85f09ccSJohn Levon 	if (!constant(sh->src2) || sh->tainted)
742*c85f09ccSJohn Levon 		return 0;
743*c85f09ccSJohn Levon 	switch (DEF_OPCODE(inner, sh->src1)) {
744*c85f09ccSJohn Levon 	case OP_OR:
745*c85f09ccSJohn Levon 		if (!multi_users(sh->target))
746*c85f09ccSJohn Levon 			return simplify_mask_shift_or(sh, inner, mask);
747*c85f09ccSJohn Levon 		break;
7481f5207b7SJohn Levon 	}
749*c85f09ccSJohn Levon 	return 0;
750*c85f09ccSJohn Levon }
751*c85f09ccSJohn Levon 
check_shift_count(struct instruction * insn,unsigned long long uval)752*c85f09ccSJohn Levon static long long check_shift_count(struct instruction *insn, unsigned long long uval)
753*c85f09ccSJohn Levon {
754*c85f09ccSJohn Levon 	unsigned int size = insn->size;
755*c85f09ccSJohn Levon 	long long sval = uval;
756*c85f09ccSJohn Levon 
757*c85f09ccSJohn Levon 	if (uval < size)
758*c85f09ccSJohn Levon 		return uval;
759*c85f09ccSJohn Levon 
760*c85f09ccSJohn Levon 	sval = sign_extend_safe(sval, size);
761*c85f09ccSJohn Levon 	sval = sign_extend_safe(sval, bits_in_int);
762*c85f09ccSJohn Levon 	if (sval < 0)
763*c85f09ccSJohn Levon 		insn->src2 = value_pseudo(sval);
764*c85f09ccSJohn Levon 	if (insn->tainted)
765*c85f09ccSJohn Levon 		return sval;
766*c85f09ccSJohn Levon 
767*c85f09ccSJohn Levon 	if (sval < 0 && Wshift_count_negative)
768*c85f09ccSJohn Levon 		warning(insn->pos, "shift count is negative (%lld)", sval);
769*c85f09ccSJohn Levon 	if (sval > 0 && Wshift_count_overflow) {
770*c85f09ccSJohn Levon 		struct symbol *ctype = insn->type;
771*c85f09ccSJohn Levon 		const char *tname;
772*c85f09ccSJohn Levon 		if (ctype->type == SYM_NODE)
773*c85f09ccSJohn Levon 			ctype = ctype->ctype.base_type;
774*c85f09ccSJohn Levon 		tname = show_typename(ctype);
775*c85f09ccSJohn Levon 		warning(insn->pos, "shift too big (%llu) for type %s", sval, tname);
776*c85f09ccSJohn Levon 	}
777*c85f09ccSJohn Levon 	insn->tainted = 1;
778*c85f09ccSJohn Levon 	return sval;
779*c85f09ccSJohn Levon }
780*c85f09ccSJohn Levon 
simplify_shift(struct instruction * insn,pseudo_t pseudo,long long value)781*c85f09ccSJohn Levon static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value)
782*c85f09ccSJohn Levon {
783*c85f09ccSJohn Levon 	struct instruction *def;
784*c85f09ccSJohn Levon 	unsigned long long mask, omask, nmask;
785*c85f09ccSJohn Levon 	unsigned long long nval;
786*c85f09ccSJohn Levon 	unsigned int size;
787*c85f09ccSJohn Levon 	pseudo_t src2;
788*c85f09ccSJohn Levon 
7891f5207b7SJohn Levon 	if (!value)
7901f5207b7SJohn Levon 		return replace_with_pseudo(insn, pseudo);
791*c85f09ccSJohn Levon 	value = check_shift_count(insn, value);
792*c85f09ccSJohn Levon 	if (value < 0)
793*c85f09ccSJohn Levon 		return 0;
794*c85f09ccSJohn Levon 
795*c85f09ccSJohn Levon 	size = insn->size;
796*c85f09ccSJohn Levon 	switch (insn->opcode) {
797*c85f09ccSJohn Levon 	case OP_ASR:
798*c85f09ccSJohn Levon 		if (value >= size)
799*c85f09ccSJohn Levon 			return 0;
800*c85f09ccSJohn Levon 		if (pseudo->type != PSEUDO_REG)
801*c85f09ccSJohn Levon 			break;
802*c85f09ccSJohn Levon 		def = pseudo->def;
803*c85f09ccSJohn Levon 		switch (def->opcode) {
804*c85f09ccSJohn Levon 		case OP_LSR:
805*c85f09ccSJohn Levon 		case OP_ASR:
806*c85f09ccSJohn Levon 			if (def == insn)	// cyclic DAG!
807*c85f09ccSJohn Levon 				break;
808*c85f09ccSJohn Levon 			src2 = def->src2;
809*c85f09ccSJohn Levon 			if (src2->type != PSEUDO_VAL)
810*c85f09ccSJohn Levon 				break;
811*c85f09ccSJohn Levon 			nval = src2->value;
812*c85f09ccSJohn Levon 			if (nval > insn->size || nval == 0)
813*c85f09ccSJohn Levon 				break;
814*c85f09ccSJohn Levon 			value += nval;
815*c85f09ccSJohn Levon 			if (def->opcode == OP_LSR)
816*c85f09ccSJohn Levon 				insn->opcode = OP_LSR;
817*c85f09ccSJohn Levon 			else if (value >= size)
818*c85f09ccSJohn Levon 				value = size - 1;
819*c85f09ccSJohn Levon 			goto new_value;
820*c85f09ccSJohn Levon 
821*c85f09ccSJohn Levon 		case OP_ZEXT:
822*c85f09ccSJohn Levon 			// transform:
823*c85f09ccSJohn Levon 			//	zext.N	%t <- (O) %a
824*c85f09ccSJohn Levon 			//	asr.N	%r <- %t, C
825*c85f09ccSJohn Levon 			// into
826*c85f09ccSJohn Levon 			//	zext.N	%t <- (O) %a
827*c85f09ccSJohn Levon 			//	lsr.N	%r <- %t, C
828*c85f09ccSJohn Levon 			insn->opcode = OP_LSR;
829*c85f09ccSJohn Levon 			return REPEAT_CSE;
830*c85f09ccSJohn Levon 		}
831*c85f09ccSJohn Levon 		break;
832*c85f09ccSJohn Levon 	case OP_LSR:
833*c85f09ccSJohn Levon 		size = operand_size(insn, pseudo);
834*c85f09ccSJohn Levon 		if (value >= size)
835*c85f09ccSJohn Levon 			goto zero;
836*c85f09ccSJohn Levon 		switch(DEF_OPCODE(def, pseudo)) {
837*c85f09ccSJohn Levon 		case OP_AND:
838*c85f09ccSJohn Levon 			// replace (A & M) >> S
839*c85f09ccSJohn Levon 			// by      (A >> S) & (M >> S)
840*c85f09ccSJohn Levon 			if (!constant(def->src2))
841*c85f09ccSJohn Levon 				break;
842*c85f09ccSJohn Levon 			mask = bits_mask(insn->size - value) << value;
843*c85f09ccSJohn Levon 			omask = def->src2->value;
844*c85f09ccSJohn Levon 			nmask = omask & mask;
845*c85f09ccSJohn Levon 			if (nmask == 0)
846*c85f09ccSJohn Levon 				return replace_with_pseudo(insn, value_pseudo(0));
847*c85f09ccSJohn Levon 			if (nmask == mask)
848*c85f09ccSJohn Levon 				return replace_pseudo(insn, &insn->src1, def->src1);
849*c85f09ccSJohn Levon 			if (nbr_users(pseudo) > 1)
850*c85f09ccSJohn Levon 				break;
851*c85f09ccSJohn Levon 			def->opcode = OP_LSR;
852*c85f09ccSJohn Levon 			def->src2 = insn->src2;
853*c85f09ccSJohn Levon 			insn->opcode = OP_AND;
854*c85f09ccSJohn Levon 			insn->src2 = value_pseudo(omask >> value);
855*c85f09ccSJohn Levon 			return REPEAT_CSE;
856*c85f09ccSJohn Levon 		case OP_LSR:
857*c85f09ccSJohn Levon 			goto case_shift_shift;
858*c85f09ccSJohn Levon 		case OP_OR:
859*c85f09ccSJohn Levon 			mask = bits_mask(size);
860*c85f09ccSJohn Levon 			return simplify_mask_shift_or(insn, def, mask);
861*c85f09ccSJohn Levon 		case OP_SHL:
862*c85f09ccSJohn Levon 			// replace ((x << S) >> S)
863*c85f09ccSJohn Levon 			// by      (x & (-1 >> S))
864*c85f09ccSJohn Levon 			if (def->src2 != insn->src2)
865*c85f09ccSJohn Levon 				break;
866*c85f09ccSJohn Levon 			mask = bits_mask(insn->size - value);
867*c85f09ccSJohn Levon 			goto replace_mask;
868*c85f09ccSJohn Levon 		}
869*c85f09ccSJohn Levon 		break;
870*c85f09ccSJohn Levon 	case OP_SHL:
871*c85f09ccSJohn Levon 		if (value >= size)
872*c85f09ccSJohn Levon 			goto zero;
873*c85f09ccSJohn Levon 		switch(DEF_OPCODE(def, pseudo)) {
874*c85f09ccSJohn Levon 		case OP_AND:
875*c85f09ccSJohn Levon 			// simplify (A & M) << S
876*c85f09ccSJohn Levon 			if (!constant(def->src2))
877*c85f09ccSJohn Levon 				break;
878*c85f09ccSJohn Levon 			mask = bits_mask(insn->size) >> value;
879*c85f09ccSJohn Levon 			omask = def->src2->value;
880*c85f09ccSJohn Levon 			nmask = omask & mask;
881*c85f09ccSJohn Levon 			if (nmask == 0)
882*c85f09ccSJohn Levon 				return replace_with_pseudo(insn, value_pseudo(0));
883*c85f09ccSJohn Levon 			if (nmask == mask)
884*c85f09ccSJohn Levon 				return replace_pseudo(insn, &insn->src1, def->src1);
885*c85f09ccSJohn Levon 			// do not simplify into ((A << S) & (M << S))
886*c85f09ccSJohn Levon 			break;
887*c85f09ccSJohn Levon 		case OP_LSR:
888*c85f09ccSJohn Levon 			// replace ((x >> S) << S)
889*c85f09ccSJohn Levon 			// by      (x & (-1 << S))
890*c85f09ccSJohn Levon 			if (def->src2 != insn->src2)
891*c85f09ccSJohn Levon 				break;
892*c85f09ccSJohn Levon 			mask = bits_mask(insn->size - value) << value;
893*c85f09ccSJohn Levon 			goto replace_mask;
894*c85f09ccSJohn Levon 		case OP_OR:
895*c85f09ccSJohn Levon 			mask = bits_mask(size);
896*c85f09ccSJohn Levon 			return simplify_mask_shift_or(insn, def, mask);
897*c85f09ccSJohn Levon 		case OP_SHL:
898*c85f09ccSJohn Levon 		case_shift_shift:		// also for LSR - LSR
899*c85f09ccSJohn Levon 			if (def == insn)	// cyclic DAG!
900*c85f09ccSJohn Levon 				break;
901*c85f09ccSJohn Levon 			src2 = def->src2;
902*c85f09ccSJohn Levon 			if (src2->type != PSEUDO_VAL)
903*c85f09ccSJohn Levon 				break;
904*c85f09ccSJohn Levon 			nval = src2->value;
905*c85f09ccSJohn Levon 			if (nval > insn->size)
906*c85f09ccSJohn Levon 				break;
907*c85f09ccSJohn Levon 			value += nval;
908*c85f09ccSJohn Levon 			goto new_value;
909*c85f09ccSJohn Levon 		}
910*c85f09ccSJohn Levon 		break;
911*c85f09ccSJohn Levon 	}
9121f5207b7SJohn Levon 	return 0;
913*c85f09ccSJohn Levon 
914*c85f09ccSJohn Levon new_value:
915*c85f09ccSJohn Levon 	if (value < size) {
916*c85f09ccSJohn Levon 		insn->src2 = value_pseudo(value);
917*c85f09ccSJohn Levon 		return replace_pseudo(insn, &insn->src1, pseudo->def->src1);
918*c85f09ccSJohn Levon 	}
919*c85f09ccSJohn Levon zero:
920*c85f09ccSJohn Levon 	return replace_with_pseudo(insn, value_pseudo(0));
921*c85f09ccSJohn Levon replace_mask:
922*c85f09ccSJohn Levon 	insn->opcode = OP_AND;
923*c85f09ccSJohn Levon 	insn->src2 = value_pseudo(mask);
924*c85f09ccSJohn Levon 	return replace_pseudo(insn, &insn->src1, def->src1);
9251f5207b7SJohn Levon }
9261f5207b7SJohn Levon 
simplify_mul_div(struct instruction * insn,long long value)9271f5207b7SJohn Levon static int simplify_mul_div(struct instruction *insn, long long value)
9281f5207b7SJohn Levon {
9291f5207b7SJohn Levon 	unsigned long long sbit = 1ULL << (insn->size - 1);
9301f5207b7SJohn Levon 	unsigned long long bits = sbit | (sbit - 1);
9311f5207b7SJohn Levon 
9321f5207b7SJohn Levon 	if (value == 1)
9331f5207b7SJohn Levon 		return replace_with_pseudo(insn, insn->src1);
9341f5207b7SJohn Levon 
9351f5207b7SJohn Levon 	switch (insn->opcode) {
936*c85f09ccSJohn Levon 	case OP_MUL:
9371f5207b7SJohn Levon 		if (value == 0)
9381f5207b7SJohn Levon 			return replace_with_pseudo(insn, insn->src2);
9391f5207b7SJohn Levon 	/* Fall through */
9401f5207b7SJohn Levon 	case OP_DIVS:
9411f5207b7SJohn Levon 		if (!(value & sbit))	// positive
9421f5207b7SJohn Levon 			break;
9431f5207b7SJohn Levon 
9441f5207b7SJohn Levon 		value |= ~bits;
9451f5207b7SJohn Levon 		if (value == -1) {
9461f5207b7SJohn Levon 			insn->opcode = OP_NEG;
9471f5207b7SJohn Levon 			return REPEAT_CSE;
9481f5207b7SJohn Levon 		}
9491f5207b7SJohn Levon 	}
9501f5207b7SJohn Levon 
9511f5207b7SJohn Levon 	return 0;
9521f5207b7SJohn Levon }
9531f5207b7SJohn Levon 
simplify_seteq_setne(struct instruction * insn,long long value)9541f5207b7SJohn Levon static int simplify_seteq_setne(struct instruction *insn, long long value)
9551f5207b7SJohn Levon {
9561f5207b7SJohn Levon 	pseudo_t old = insn->src1;
957*c85f09ccSJohn Levon 	struct instruction *def;
958*c85f09ccSJohn Levon 	unsigned osize;
9591f5207b7SJohn Levon 	int inverse;
9601f5207b7SJohn Levon 	int opcode;
9611f5207b7SJohn Levon 
9621f5207b7SJohn Levon 	if (value != 0 && value != 1)
9631f5207b7SJohn Levon 		return 0;
9641f5207b7SJohn Levon 
965*c85f09ccSJohn Levon 	if (old->type != PSEUDO_REG)
966*c85f09ccSJohn Levon 		return 0;
967*c85f09ccSJohn Levon 	def = old->def;
9681f5207b7SJohn Levon 	if (!def)
9691f5207b7SJohn Levon 		return 0;
9701f5207b7SJohn Levon 
9711f5207b7SJohn Levon 	inverse = (insn->opcode == OP_SET_NE) == value;
972*c85f09ccSJohn Levon 	if (!inverse && def->size == 1 && insn->size == 1) {
973*c85f09ccSJohn Levon 		// Replace:
974*c85f09ccSJohn Levon 		//	setne   %r <- %s, $0
975*c85f09ccSJohn Levon 		// or:
976*c85f09ccSJohn Levon 		//	seteq   %r <- %s, $1
977*c85f09ccSJohn Levon 		// by %s when boolean
978*c85f09ccSJohn Levon 		return replace_with_pseudo(insn, old);
979*c85f09ccSJohn Levon 	}
9801f5207b7SJohn Levon 	opcode = def->opcode;
9811f5207b7SJohn Levon 	switch (opcode) {
982*c85f09ccSJohn Levon 	case OP_AND:
983*c85f09ccSJohn Levon 		if (inverse)
984*c85f09ccSJohn Levon 			break;
985*c85f09ccSJohn Levon 		if (def->size != insn->size)
986*c85f09ccSJohn Levon 			break;
987*c85f09ccSJohn Levon 		if (def->src2->type != PSEUDO_VAL)
988*c85f09ccSJohn Levon 			break;
989*c85f09ccSJohn Levon 		if (def->src2->value != 1)
990*c85f09ccSJohn Levon 			break;
991*c85f09ccSJohn Levon 		return replace_with_pseudo(insn, old);
992*c85f09ccSJohn Levon 	case OP_FPCMP ... OP_BINCMP_END:
9931f5207b7SJohn Levon 		// Convert:
9941f5207b7SJohn Levon 		//	setcc.n	%t <- %a, %b
9951f5207b7SJohn Levon 		//	setne.m %r <- %t, $0
9961f5207b7SJohn Levon 		// into:
9971f5207b7SJohn Levon 		//	setcc.n	%t <- %a, %b
9981f5207b7SJohn Levon 		//	setcc.m %r <- %a, $b
9991f5207b7SJohn Levon 		// and similar for setne/eq ... 0/1
1000*c85f09ccSJohn Levon 		insn->opcode = inverse ? opcode_table[opcode].negate : opcode;
1001*c85f09ccSJohn Levon 		use_pseudo(insn, def->src1, &insn->src1);
1002*c85f09ccSJohn Levon 		use_pseudo(insn, def->src2, &insn->src2);
10031f5207b7SJohn Levon 		remove_usage(old, &insn->src1);
10041f5207b7SJohn Levon 		return REPEAT_CSE;
10051f5207b7SJohn Levon 
1006*c85f09ccSJohn Levon 	case OP_SEXT:
1007*c85f09ccSJohn Levon 		if (value && (def->orig_type->bit_size == 1))
1008*c85f09ccSJohn Levon 			break;
1009*c85f09ccSJohn Levon 		/* Fall through */
1010*c85f09ccSJohn Levon 	case OP_ZEXT:
1011*c85f09ccSJohn Levon 		// Convert:
1012*c85f09ccSJohn Levon 		//	*ext.m	%s <- (1) %a
1013*c85f09ccSJohn Levon 		//	setne.1 %r <- %s, $0
1014*c85f09ccSJohn Levon 		// into:
1015*c85f09ccSJohn Levon 		//	setne.1 %s <- %a, $0
1016*c85f09ccSJohn Levon 		// and same for setne/eq ... 0/1
1017*c85f09ccSJohn Levon 		return replace_pseudo(insn, &insn->src1, def->src);
1018*c85f09ccSJohn Levon 	case OP_TRUNC:
1019*c85f09ccSJohn Levon 		if (multi_users(old))
1020*c85f09ccSJohn Levon 			break;
1021*c85f09ccSJohn Levon 		// convert
1022*c85f09ccSJohn Levon 		//	trunc.n	%s <- (o) %a
1023*c85f09ccSJohn Levon 		//	setne.m %r <- %s, $0
1024*c85f09ccSJohn Levon 		// into:
1025*c85f09ccSJohn Levon 		//	and.o	%s <- %a, $((1 << o) - 1)
1026*c85f09ccSJohn Levon 		//	setne.m %r <- %s, $0
1027*c85f09ccSJohn Levon 		// and same for setne/eq ... 0/1
1028*c85f09ccSJohn Levon 		osize = def->size;
1029*c85f09ccSJohn Levon 		def->opcode = OP_AND;
1030*c85f09ccSJohn Levon 		def->type = def->orig_type;
1031*c85f09ccSJohn Levon 		def->size = def->type->bit_size;
1032*c85f09ccSJohn Levon 		def->src2 = value_pseudo(bits_mask(osize));
1033*c85f09ccSJohn Levon 		return REPEAT_CSE;
1034*c85f09ccSJohn Levon 	}
1035*c85f09ccSJohn Levon 	return 0;
1036*c85f09ccSJohn Levon }
1037*c85f09ccSJohn Levon 
simplify_constant_mask(struct instruction * insn,unsigned long long mask)1038*c85f09ccSJohn Levon static int simplify_constant_mask(struct instruction *insn, unsigned long long mask)
1039*c85f09ccSJohn Levon {
1040*c85f09ccSJohn Levon 	pseudo_t old = insn->src1;
1041*c85f09ccSJohn Levon 	unsigned long long omask;
1042*c85f09ccSJohn Levon 	unsigned long long nmask;
1043*c85f09ccSJohn Levon 	struct instruction *def;
1044*c85f09ccSJohn Levon 	int osize;
1045*c85f09ccSJohn Levon 
1046*c85f09ccSJohn Levon 	switch (DEF_OPCODE(def, old)) {
1047*c85f09ccSJohn Levon 	case OP_FPCMP ... OP_BINCMP_END:
1048*c85f09ccSJohn Levon 		osize = 1;
1049*c85f09ccSJohn Levon 		goto oldsize;
1050*c85f09ccSJohn Levon 	case OP_OR:
1051*c85f09ccSJohn Levon 		return simplify_mask_or(insn, mask, def);
1052*c85f09ccSJohn Levon 	case OP_LSR:
1053*c85f09ccSJohn Levon 	case OP_SHL:
1054*c85f09ccSJohn Levon 		return simplify_mask_shift(def, mask);
1055*c85f09ccSJohn Levon 	case OP_ZEXT:
1056*c85f09ccSJohn Levon 		osize = def->orig_type->bit_size;
1057*c85f09ccSJohn Levon 		/* fall through */
1058*c85f09ccSJohn Levon 	oldsize:
1059*c85f09ccSJohn Levon 		omask = (1ULL << osize) - 1;
1060*c85f09ccSJohn Levon 		nmask = mask & omask;
1061*c85f09ccSJohn Levon 		if (nmask == omask)
1062*c85f09ccSJohn Levon 			// the AND mask is redundant
1063*c85f09ccSJohn Levon 			return replace_with_pseudo(insn, old);
1064*c85f09ccSJohn Levon 		if (nmask != mask) {
1065*c85f09ccSJohn Levon 			// can use a smaller mask
1066*c85f09ccSJohn Levon 			insn->src2 = value_pseudo(nmask);
1067*c85f09ccSJohn Levon 			return REPEAT_CSE;
1068*c85f09ccSJohn Levon 		}
1069*c85f09ccSJohn Levon 		break;
10701f5207b7SJohn Levon 	}
1071*c85f09ccSJohn Levon 	return 0;
10721f5207b7SJohn Levon }
10731f5207b7SJohn Levon 
simplify_constant_rightside(struct instruction * insn)10741f5207b7SJohn Levon static int simplify_constant_rightside(struct instruction *insn)
10751f5207b7SJohn Levon {
10761f5207b7SJohn Levon 	long long value = insn->src2->value;
1077*c85f09ccSJohn Levon 	long long sbit = 1ULL << (insn->size - 1);
1078*c85f09ccSJohn Levon 	long long bits = sbit | (sbit - 1);
10791f5207b7SJohn Levon 
10801f5207b7SJohn Levon 	switch (insn->opcode) {
1081*c85f09ccSJohn Levon 	case OP_OR:
1082*c85f09ccSJohn Levon 		if ((value & bits) == bits)
10831f5207b7SJohn Levon 			return replace_with_pseudo(insn, insn->src2);
10841f5207b7SJohn Levon 		goto case_neutral_zero;
10851f5207b7SJohn Levon 
1086*c85f09ccSJohn Levon 	case OP_XOR:
1087*c85f09ccSJohn Levon 		if ((value & bits) == bits) {
1088*c85f09ccSJohn Levon 			insn->opcode = OP_NOT;
1089*c85f09ccSJohn Levon 			return REPEAT_CSE;
1090*c85f09ccSJohn Levon 		}
1091*c85f09ccSJohn Levon 		goto case_neutral_zero;
1092*c85f09ccSJohn Levon 
10931f5207b7SJohn Levon 	case OP_SUB:
10941f5207b7SJohn Levon 		if (value) {
10951f5207b7SJohn Levon 			insn->opcode = OP_ADD;
1096*c85f09ccSJohn Levon 			insn->src2 = value_pseudo(-value);
10971f5207b7SJohn Levon 			return REPEAT_CSE;
10981f5207b7SJohn Levon 		}
10991f5207b7SJohn Levon 	/* Fall through */
11001f5207b7SJohn Levon 	case OP_ADD:
11011f5207b7SJohn Levon 	case_neutral_zero:
11021f5207b7SJohn Levon 		if (!value)
11031f5207b7SJohn Levon 			return replace_with_pseudo(insn, insn->src1);
11041f5207b7SJohn Levon 		return 0;
11051f5207b7SJohn Levon 	case OP_ASR:
1106*c85f09ccSJohn Levon 	case OP_SHL:
1107*c85f09ccSJohn Levon 	case OP_LSR:
1108*c85f09ccSJohn Levon 		return simplify_shift(insn, insn->src1, value);
11091f5207b7SJohn Levon 
11101f5207b7SJohn Levon 	case OP_MODU: case OP_MODS:
11111f5207b7SJohn Levon 		if (value == 1)
1112*c85f09ccSJohn Levon 			return replace_with_pseudo(insn, value_pseudo(0));
11131f5207b7SJohn Levon 		return 0;
11141f5207b7SJohn Levon 
11151f5207b7SJohn Levon 	case OP_DIVU: case OP_DIVS:
1116*c85f09ccSJohn Levon 	case OP_MUL:
11171f5207b7SJohn Levon 		return simplify_mul_div(insn, value);
11181f5207b7SJohn Levon 
11191f5207b7SJohn Levon 	case OP_AND:
11201f5207b7SJohn Levon 		if (!value)
11211f5207b7SJohn Levon 			return replace_with_pseudo(insn, insn->src2);
1122*c85f09ccSJohn Levon 		if ((value & bits) == bits)
1123*c85f09ccSJohn Levon 			return replace_with_pseudo(insn, insn->src1);
1124*c85f09ccSJohn Levon 		return simplify_constant_mask(insn, value);
11251f5207b7SJohn Levon 
11261f5207b7SJohn Levon 	case OP_SET_NE:
11271f5207b7SJohn Levon 	case OP_SET_EQ:
11281f5207b7SJohn Levon 		return simplify_seteq_setne(insn, value);
11291f5207b7SJohn Levon 	}
11301f5207b7SJohn Levon 	return 0;
11311f5207b7SJohn Levon }
11321f5207b7SJohn Levon 
simplify_constant_leftside(struct instruction * insn)11331f5207b7SJohn Levon static int simplify_constant_leftside(struct instruction *insn)
11341f5207b7SJohn Levon {
11351f5207b7SJohn Levon 	long long value = insn->src1->value;
11361f5207b7SJohn Levon 
11371f5207b7SJohn Levon 	switch (insn->opcode) {
11381f5207b7SJohn Levon 	case OP_ADD: case OP_OR: case OP_XOR:
11391f5207b7SJohn Levon 		if (!value)
11401f5207b7SJohn Levon 			return replace_with_pseudo(insn, insn->src2);
11411f5207b7SJohn Levon 		return 0;
11421f5207b7SJohn Levon 
11431f5207b7SJohn Levon 	case OP_SHL:
11441f5207b7SJohn Levon 	case OP_LSR: case OP_ASR:
11451f5207b7SJohn Levon 	case OP_AND:
1146*c85f09ccSJohn Levon 	case OP_MUL:
11471f5207b7SJohn Levon 		if (!value)
11481f5207b7SJohn Levon 			return replace_with_pseudo(insn, insn->src1);
11491f5207b7SJohn Levon 		return 0;
11501f5207b7SJohn Levon 	}
11511f5207b7SJohn Levon 	return 0;
11521f5207b7SJohn Levon }
11531f5207b7SJohn Levon 
simplify_constant_binop(struct instruction * insn)11541f5207b7SJohn Levon static int simplify_constant_binop(struct instruction *insn)
11551f5207b7SJohn Levon {
1156*c85f09ccSJohn Levon 	pseudo_t res = eval_insn(insn);
11571f5207b7SJohn Levon 
1158*c85f09ccSJohn Levon 	if (!res)
11591f5207b7SJohn Levon 		return 0;
11601f5207b7SJohn Levon 
1161*c85f09ccSJohn Levon 	replace_with_pseudo(insn, res);
11621f5207b7SJohn Levon 	return REPEAT_CSE;
11631f5207b7SJohn Levon }
11641f5207b7SJohn Levon 
simplify_binop_same_args(struct instruction * insn,pseudo_t arg)11651f5207b7SJohn Levon static int simplify_binop_same_args(struct instruction *insn, pseudo_t arg)
11661f5207b7SJohn Levon {
11671f5207b7SJohn Levon 	switch (insn->opcode) {
11681f5207b7SJohn Levon 	case OP_SET_NE:
11691f5207b7SJohn Levon 	case OP_SET_LT: case OP_SET_GT:
11701f5207b7SJohn Levon 	case OP_SET_B:  case OP_SET_A:
11711f5207b7SJohn Levon 		if (Wtautological_compare)
11721f5207b7SJohn Levon 			warning(insn->pos, "self-comparison always evaluates to false");
11731f5207b7SJohn Levon 	case OP_SUB:
11741f5207b7SJohn Levon 	case OP_XOR:
1175*c85f09ccSJohn Levon 		return replace_with_pseudo(insn, value_pseudo(0));
11761f5207b7SJohn Levon 
11771f5207b7SJohn Levon 	case OP_SET_EQ:
11781f5207b7SJohn Levon 	case OP_SET_LE: case OP_SET_GE:
11791f5207b7SJohn Levon 	case OP_SET_BE: case OP_SET_AE:
11801f5207b7SJohn Levon 		if (Wtautological_compare)
11811f5207b7SJohn Levon 			warning(insn->pos, "self-comparison always evaluates to true");
1182*c85f09ccSJohn Levon 		return replace_with_pseudo(insn, value_pseudo(1));
11831f5207b7SJohn Levon 
11841f5207b7SJohn Levon 	case OP_AND:
11851f5207b7SJohn Levon 	case OP_OR:
11861f5207b7SJohn Levon 		return replace_with_pseudo(insn, arg);
11871f5207b7SJohn Levon 
11881f5207b7SJohn Levon 	default:
11891f5207b7SJohn Levon 		break;
11901f5207b7SJohn Levon 	}
11911f5207b7SJohn Levon 
11921f5207b7SJohn Levon 	return 0;
11931f5207b7SJohn Levon }
11941f5207b7SJohn Levon 
simplify_binop(struct instruction * insn)11951f5207b7SJohn Levon static int simplify_binop(struct instruction *insn)
11961f5207b7SJohn Levon {
11971f5207b7SJohn Levon 	if (dead_insn(insn, &insn->src1, &insn->src2, NULL))
11981f5207b7SJohn Levon 		return REPEAT_CSE;
11991f5207b7SJohn Levon 	if (constant(insn->src1)) {
12001f5207b7SJohn Levon 		if (constant(insn->src2))
12011f5207b7SJohn Levon 			return simplify_constant_binop(insn);
12021f5207b7SJohn Levon 		return simplify_constant_leftside(insn);
12031f5207b7SJohn Levon 	}
12041f5207b7SJohn Levon 	if (constant(insn->src2))
12051f5207b7SJohn Levon 		return simplify_constant_rightside(insn);
12061f5207b7SJohn Levon 	if (insn->src1 == insn->src2)
12071f5207b7SJohn Levon 		return simplify_binop_same_args(insn, insn->src1);
12081f5207b7SJohn Levon 	return 0;
12091f5207b7SJohn Levon }
12101f5207b7SJohn Levon 
switch_pseudo(struct instruction * insn1,pseudo_t * pp1,struct instruction * insn2,pseudo_t * pp2)12111f5207b7SJohn Levon static void switch_pseudo(struct instruction *insn1, pseudo_t *pp1, struct instruction *insn2, pseudo_t *pp2)
12121f5207b7SJohn Levon {
12131f5207b7SJohn Levon 	pseudo_t p1 = *pp1, p2 = *pp2;
12141f5207b7SJohn Levon 
12151f5207b7SJohn Levon 	use_pseudo(insn1, p2, pp1);
12161f5207b7SJohn Levon 	use_pseudo(insn2, p1, pp2);
12171f5207b7SJohn Levon 	remove_usage(p1, pp1);
12181f5207b7SJohn Levon 	remove_usage(p2, pp2);
12191f5207b7SJohn Levon }
12201f5207b7SJohn Levon 
canonical_order(pseudo_t p1,pseudo_t p2)12211f5207b7SJohn Levon static int canonical_order(pseudo_t p1, pseudo_t p2)
12221f5207b7SJohn Levon {
12231f5207b7SJohn Levon 	/* symbol/constants on the right */
12241f5207b7SJohn Levon 	if (p1->type == PSEUDO_VAL)
12251f5207b7SJohn Levon 		return p2->type == PSEUDO_VAL;
12261f5207b7SJohn Levon 
12271f5207b7SJohn Levon 	if (p1->type == PSEUDO_SYM)
12281f5207b7SJohn Levon 		return p2->type == PSEUDO_SYM || p2->type == PSEUDO_VAL;
12291f5207b7SJohn Levon 
12301f5207b7SJohn Levon 	return 1;
12311f5207b7SJohn Levon }
12321f5207b7SJohn Levon 
canonicalize_commutative(struct instruction * insn)1233*c85f09ccSJohn Levon static int canonicalize_commutative(struct instruction *insn)
12341f5207b7SJohn Levon {
1235*c85f09ccSJohn Levon 	if (canonical_order(insn->src1, insn->src2))
1236*c85f09ccSJohn Levon 		return 0;
1237*c85f09ccSJohn Levon 
1238*c85f09ccSJohn Levon 	switch_pseudo(insn, &insn->src1, insn, &insn->src2);
1239*c85f09ccSJohn Levon 	return repeat_phase |= REPEAT_CSE;
1240*c85f09ccSJohn Levon }
1241*c85f09ccSJohn Levon 
canonicalize_compare(struct instruction * insn)1242*c85f09ccSJohn Levon static int canonicalize_compare(struct instruction *insn)
1243*c85f09ccSJohn Levon {
1244*c85f09ccSJohn Levon 	if (canonical_order(insn->src1, insn->src2))
1245*c85f09ccSJohn Levon 		return 0;
1246*c85f09ccSJohn Levon 
1247*c85f09ccSJohn Levon 	switch_pseudo(insn, &insn->src1, insn, &insn->src2);
1248*c85f09ccSJohn Levon 	insn->opcode = opcode_table[insn->opcode].swap;
1249*c85f09ccSJohn Levon 	return repeat_phase |= REPEAT_CSE;
12501f5207b7SJohn Levon }
12511f5207b7SJohn Levon 
simple_pseudo(pseudo_t pseudo)12521f5207b7SJohn Levon static inline int simple_pseudo(pseudo_t pseudo)
12531f5207b7SJohn Levon {
12541f5207b7SJohn Levon 	return pseudo->type == PSEUDO_VAL || pseudo->type == PSEUDO_SYM;
12551f5207b7SJohn Levon }
12561f5207b7SJohn Levon 
simplify_associative_binop(struct instruction * insn)12571f5207b7SJohn Levon static int simplify_associative_binop(struct instruction *insn)
12581f5207b7SJohn Levon {
12591f5207b7SJohn Levon 	struct instruction *def;
12601f5207b7SJohn Levon 	pseudo_t pseudo = insn->src1;
12611f5207b7SJohn Levon 
12621f5207b7SJohn Levon 	if (!simple_pseudo(insn->src2))
12631f5207b7SJohn Levon 		return 0;
12641f5207b7SJohn Levon 	if (pseudo->type != PSEUDO_REG)
12651f5207b7SJohn Levon 		return 0;
12661f5207b7SJohn Levon 	def = pseudo->def;
12671f5207b7SJohn Levon 	if (def == insn)
12681f5207b7SJohn Levon 		return 0;
12691f5207b7SJohn Levon 	if (def->opcode != insn->opcode)
12701f5207b7SJohn Levon 		return 0;
12711f5207b7SJohn Levon 	if (!simple_pseudo(def->src2))
12721f5207b7SJohn Levon 		return 0;
1273*c85f09ccSJohn Levon 	if (multi_users(def->target))
12741f5207b7SJohn Levon 		return 0;
12751f5207b7SJohn Levon 	switch_pseudo(def, &def->src1, insn, &insn->src2);
12761f5207b7SJohn Levon 	return REPEAT_CSE;
12771f5207b7SJohn Levon }
12781f5207b7SJohn Levon 
simplify_constant_unop(struct instruction * insn)12791f5207b7SJohn Levon static int simplify_constant_unop(struct instruction *insn)
12801f5207b7SJohn Levon {
12811f5207b7SJohn Levon 	long long val = insn->src1->value;
12821f5207b7SJohn Levon 	long long res, mask;
12831f5207b7SJohn Levon 
12841f5207b7SJohn Levon 	switch (insn->opcode) {
12851f5207b7SJohn Levon 	case OP_NOT:
12861f5207b7SJohn Levon 		res = ~val;
12871f5207b7SJohn Levon 		break;
12881f5207b7SJohn Levon 	case OP_NEG:
12891f5207b7SJohn Levon 		res = -val;
12901f5207b7SJohn Levon 		break;
1291*c85f09ccSJohn Levon 	case OP_SEXT:
1292*c85f09ccSJohn Levon 		mask = 1ULL << (insn->orig_type->bit_size-1);
1293*c85f09ccSJohn Levon 		if (val & mask)
1294*c85f09ccSJohn Levon 			val |= ~(mask | (mask-1));
1295*c85f09ccSJohn Levon 		/* fall through */
1296*c85f09ccSJohn Levon 	case OP_ZEXT:
1297*c85f09ccSJohn Levon 	case OP_TRUNC:
1298*c85f09ccSJohn Levon 		res = val;
1299*c85f09ccSJohn Levon 		break;
13001f5207b7SJohn Levon 	default:
13011f5207b7SJohn Levon 		return 0;
13021f5207b7SJohn Levon 	}
13031f5207b7SJohn Levon 	mask = 1ULL << (insn->size-1);
13041f5207b7SJohn Levon 	res &= mask | (mask-1);
13051f5207b7SJohn Levon 
1306*c85f09ccSJohn Levon 	replace_with_pseudo(insn, value_pseudo(res));
13071f5207b7SJohn Levon 	return REPEAT_CSE;
13081f5207b7SJohn Levon }
13091f5207b7SJohn Levon 
simplify_unop(struct instruction * insn)13101f5207b7SJohn Levon static int simplify_unop(struct instruction *insn)
13111f5207b7SJohn Levon {
13121f5207b7SJohn Levon 	if (dead_insn(insn, &insn->src1, NULL, NULL))
13131f5207b7SJohn Levon 		return REPEAT_CSE;
13141f5207b7SJohn Levon 	if (constant(insn->src1))
13151f5207b7SJohn Levon 		return simplify_constant_unop(insn);
13161f5207b7SJohn Levon 
13171f5207b7SJohn Levon 	switch (insn->opcode) {
13181f5207b7SJohn Levon 		struct instruction *def;
13191f5207b7SJohn Levon 
13201f5207b7SJohn Levon 	case OP_NOT:
13211f5207b7SJohn Levon 		def = insn->src->def;
13221f5207b7SJohn Levon 		if (def && def->opcode == OP_NOT)
13231f5207b7SJohn Levon 			return replace_with_pseudo(insn, def->src);
13241f5207b7SJohn Levon 		break;
13251f5207b7SJohn Levon 	case OP_NEG:
13261f5207b7SJohn Levon 		def = insn->src->def;
13271f5207b7SJohn Levon 		if (def && def->opcode == OP_NEG)
13281f5207b7SJohn Levon 			return replace_with_pseudo(insn, def->src);
13291f5207b7SJohn Levon 		break;
13301f5207b7SJohn Levon 	default:
13311f5207b7SJohn Levon 		return 0;
13321f5207b7SJohn Levon 	}
13331f5207b7SJohn Levon 	return 0;
13341f5207b7SJohn Levon }
13351f5207b7SJohn Levon 
simplify_one_memop(struct instruction * insn,pseudo_t orig)13361f5207b7SJohn Levon static int simplify_one_memop(struct instruction *insn, pseudo_t orig)
13371f5207b7SJohn Levon {
13381f5207b7SJohn Levon 	pseudo_t addr = insn->src;
13391f5207b7SJohn Levon 	pseudo_t new, off;
13401f5207b7SJohn Levon 
13411f5207b7SJohn Levon 	if (addr->type == PSEUDO_REG) {
13421f5207b7SJohn Levon 		struct instruction *def = addr->def;
13431f5207b7SJohn Levon 		if (def->opcode == OP_SYMADDR && def->src) {
13441f5207b7SJohn Levon 			kill_use(&insn->src);
13451f5207b7SJohn Levon 			use_pseudo(insn, def->src, &insn->src);
13461f5207b7SJohn Levon 			return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
13471f5207b7SJohn Levon 		}
13481f5207b7SJohn Levon 		if (def->opcode == OP_ADD) {
13491f5207b7SJohn Levon 			new = def->src1;
13501f5207b7SJohn Levon 			off = def->src2;
13511f5207b7SJohn Levon 			if (constant(off))
13521f5207b7SJohn Levon 				goto offset;
13531f5207b7SJohn Levon 			new = off;
13541f5207b7SJohn Levon 			off = def->src1;
13551f5207b7SJohn Levon 			if (constant(off))
13561f5207b7SJohn Levon 				goto offset;
13571f5207b7SJohn Levon 			return 0;
13581f5207b7SJohn Levon 		}
13591f5207b7SJohn Levon 	}
13601f5207b7SJohn Levon 	return 0;
13611f5207b7SJohn Levon 
13621f5207b7SJohn Levon offset:
13631f5207b7SJohn Levon 	/* Invalid code */
1364*c85f09ccSJohn Levon 	if (new == orig || new == addr) {
13651f5207b7SJohn Levon 		if (new == VOID)
13661f5207b7SJohn Levon 			return 0;
13671f5207b7SJohn Levon 		/*
13681f5207b7SJohn Levon 		 * If some BB have been removed it is possible that this
13691f5207b7SJohn Levon 		 * memop is in fact part of a dead BB. In this case
13701f5207b7SJohn Levon 		 * we must not warn since nothing is wrong.
13711f5207b7SJohn Levon 		 * If not part of a dead BB this will be redone after
13721f5207b7SJohn Levon 		 * the BBs have been cleaned up.
13731f5207b7SJohn Levon 		 */
13741f5207b7SJohn Levon 		if (repeat_phase & REPEAT_CFG_CLEANUP)
13751f5207b7SJohn Levon 			return 0;
13761f5207b7SJohn Levon 		warning(insn->pos, "crazy programmer");
1377*c85f09ccSJohn Levon 		replace_pseudo(insn, &insn->src, VOID);
1378*c85f09ccSJohn Levon 		return 0;
13791f5207b7SJohn Levon 	}
13801f5207b7SJohn Levon 	insn->offset += off->value;
1381*c85f09ccSJohn Levon 	replace_pseudo(insn, &insn->src, new);
13821f5207b7SJohn Levon 	return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
13831f5207b7SJohn Levon }
13841f5207b7SJohn Levon 
1385*c85f09ccSJohn Levon ///
1386*c85f09ccSJohn Levon // simplify memops instructions
1387*c85f09ccSJohn Levon //
1388*c85f09ccSJohn Levon // :note: We walk the whole chain of adds/subs backwards.
1389*c85f09ccSJohn Levon //	That's not only more efficient, but it allows us to find loops.
simplify_memop(struct instruction * insn)13901f5207b7SJohn Levon static int simplify_memop(struct instruction *insn)
13911f5207b7SJohn Levon {
13921f5207b7SJohn Levon 	int one, ret = 0;
13931f5207b7SJohn Levon 	pseudo_t orig = insn->src;
13941f5207b7SJohn Levon 
13951f5207b7SJohn Levon 	do {
13961f5207b7SJohn Levon 		one = simplify_one_memop(insn, orig);
13971f5207b7SJohn Levon 		ret |= one;
13981f5207b7SJohn Levon 	} while (one);
13991f5207b7SJohn Levon 	return ret;
14001f5207b7SJohn Levon }
14011f5207b7SJohn Levon 
simplify_cast(struct instruction * insn)14021f5207b7SJohn Levon static int simplify_cast(struct instruction *insn)
14031f5207b7SJohn Levon {
1404*c85f09ccSJohn Levon 	unsigned long long mask;
1405*c85f09ccSJohn Levon 	struct instruction *def;
14061f5207b7SJohn Levon 	pseudo_t src;
1407*c85f09ccSJohn Levon 	pseudo_t val;
1408*c85f09ccSJohn Levon 	int osize;
1409*c85f09ccSJohn Levon 	int size;
14101f5207b7SJohn Levon 
14111f5207b7SJohn Levon 	if (dead_insn(insn, &insn->src, NULL, NULL))
14121f5207b7SJohn Levon 		return REPEAT_CSE;
14131f5207b7SJohn Levon 
14141f5207b7SJohn Levon 	src = insn->src;
14151f5207b7SJohn Levon 
14161f5207b7SJohn Levon 	/* A cast of a constant? */
1417*c85f09ccSJohn Levon 	if (constant(src))
1418*c85f09ccSJohn Levon 		return simplify_constant_unop(insn);
14191f5207b7SJohn Levon 
1420*c85f09ccSJohn Levon 	// can merge with the previous instruction?
1421*c85f09ccSJohn Levon 	size = insn->size;
1422*c85f09ccSJohn Levon 	def = src->def;
1423*c85f09ccSJohn Levon 	switch (def_opcode(src)) {
1424*c85f09ccSJohn Levon 	case OP_AND:
1425*c85f09ccSJohn Levon 		val = def->src2;
1426*c85f09ccSJohn Levon 		if (val->type != PSEUDO_VAL)
1427*c85f09ccSJohn Levon 			break;
1428*c85f09ccSJohn Levon 		/* A cast of a AND might be a no-op.. */
1429*c85f09ccSJohn Levon 		switch (insn->opcode) {
1430*c85f09ccSJohn Levon 		case OP_TRUNC:
1431*c85f09ccSJohn Levon 			if (multi_users(src))
1432*c85f09ccSJohn Levon 				break;
1433*c85f09ccSJohn Levon 			def->opcode = OP_TRUNC;
1434*c85f09ccSJohn Levon 			def->orig_type = def->type;
1435*c85f09ccSJohn Levon 			def->type = insn->type;
1436*c85f09ccSJohn Levon 			def->size = size;
1437*c85f09ccSJohn Levon 
1438*c85f09ccSJohn Levon 			insn->opcode = OP_AND;
1439*c85f09ccSJohn Levon 			mask = val->value;
1440*c85f09ccSJohn Levon 			mask &= (1ULL << size) - 1;
1441*c85f09ccSJohn Levon 			insn->src2 = value_pseudo(mask);
1442*c85f09ccSJohn Levon 			return REPEAT_CSE;
14431f5207b7SJohn Levon 
1444*c85f09ccSJohn Levon 		case OP_SEXT:
1445*c85f09ccSJohn Levon 			if (val->value & (1 << (def->size - 1)))
1446*c85f09ccSJohn Levon 				break;
1447*c85f09ccSJohn Levon 			// OK, sign bit is 0
1448*c85f09ccSJohn Levon 		case OP_ZEXT:
1449*c85f09ccSJohn Levon 			if (multi_users(src))
1450*c85f09ccSJohn Levon 				break;
1451*c85f09ccSJohn Levon 			// transform:
1452*c85f09ccSJohn Levon 			//	and.n	%b <- %a, M
1453*c85f09ccSJohn Levon 			//	*ext.m	%c <- (n) %b
1454*c85f09ccSJohn Levon 			// into:
1455*c85f09ccSJohn Levon 			//	zext.m	%b <- %a
1456*c85f09ccSJohn Levon 			//	and.m	%c <- %b, M
1457*c85f09ccSJohn Levon 			// For ZEXT, the mask will always be small
1458*c85f09ccSJohn Levon 			// enough. For SEXT, it can only be done if
1459*c85f09ccSJohn Levon 			// the mask force the sign bit to 0.
1460*c85f09ccSJohn Levon 			def->opcode = OP_ZEXT;
1461*c85f09ccSJohn Levon 			def->orig_type = insn->orig_type;
1462*c85f09ccSJohn Levon 			def->type = insn->type;
1463*c85f09ccSJohn Levon 			def->size = insn->size;
1464*c85f09ccSJohn Levon 			insn->opcode = OP_AND;
1465*c85f09ccSJohn Levon 			insn->src2 = val;
1466*c85f09ccSJohn Levon 			return REPEAT_CSE;
1467*c85f09ccSJohn Levon 		}
1468*c85f09ccSJohn Levon 		break;
1469*c85f09ccSJohn Levon 	case OP_FPCMP ... OP_BINCMP_END:
1470*c85f09ccSJohn Levon 		switch (insn->opcode) {
1471*c85f09ccSJohn Levon 		case OP_SEXT:
1472*c85f09ccSJohn Levon 			if (insn->size == 1)
1473*c85f09ccSJohn Levon 				break;
1474*c85f09ccSJohn Levon 			/* fall through */
1475*c85f09ccSJohn Levon 		case OP_ZEXT:
1476*c85f09ccSJohn Levon 		case OP_TRUNC:
1477*c85f09ccSJohn Levon 			// simplify:
1478*c85f09ccSJohn Levon 			//	setcc.n	%t <- %a, %b
1479*c85f09ccSJohn Levon 			//	zext.m	%r <- (n) %t
1480*c85f09ccSJohn Levon 			// into:
1481*c85f09ccSJohn Levon 			//	setcc.m	%r <- %a, %b
1482*c85f09ccSJohn Levon 			// and same for s/zext/trunc/
1483*c85f09ccSJohn Levon 			insn->opcode = def->opcode;
1484*c85f09ccSJohn Levon 			use_pseudo(insn, def->src2, &insn->src2);
1485*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->src1, def->src1);
1486*c85f09ccSJohn Levon 		}
1487*c85f09ccSJohn Levon 		break;
1488*c85f09ccSJohn Levon 	case OP_OR:
1489*c85f09ccSJohn Levon 		switch (insn->opcode) {
1490*c85f09ccSJohn Levon 		case OP_TRUNC:
1491*c85f09ccSJohn Levon 			mask = bits_mask(insn->size);
1492*c85f09ccSJohn Levon 			return simplify_mask_or(insn, mask, def);
1493*c85f09ccSJohn Levon 		}
1494*c85f09ccSJohn Levon 		break;
1495*c85f09ccSJohn Levon 	case OP_LSR:
1496*c85f09ccSJohn Levon 	case OP_SHL:
1497*c85f09ccSJohn Levon 		if (insn->opcode != OP_TRUNC)
1498*c85f09ccSJohn Levon 			break;
1499*c85f09ccSJohn Levon 		mask = bits_mask(insn->size);
1500*c85f09ccSJohn Levon 		return simplify_mask_shift(def, mask);
1501*c85f09ccSJohn Levon 	case OP_TRUNC:
1502*c85f09ccSJohn Levon 		switch (insn->opcode) {
1503*c85f09ccSJohn Levon 		case OP_TRUNC:
1504*c85f09ccSJohn Levon 			insn->orig_type = def->orig_type;
1505*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->src1, def->src);
1506*c85f09ccSJohn Levon 		case OP_ZEXT:
1507*c85f09ccSJohn Levon 			if (size != def->orig_type->bit_size)
1508*c85f09ccSJohn Levon 				break;
1509*c85f09ccSJohn Levon 			insn->opcode = OP_AND;
1510*c85f09ccSJohn Levon 			insn->src2 = value_pseudo((1ULL << def->size) - 1);
1511*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->src1, def->src);
1512*c85f09ccSJohn Levon 		}
1513*c85f09ccSJohn Levon 		break;
1514*c85f09ccSJohn Levon 	case OP_ZEXT:
1515*c85f09ccSJohn Levon 		switch (insn->opcode) {
1516*c85f09ccSJohn Levon 		case OP_SEXT:
1517*c85f09ccSJohn Levon 			insn->opcode = OP_ZEXT;
1518*c85f09ccSJohn Levon 			/* fall through */
1519*c85f09ccSJohn Levon 		case OP_ZEXT:
1520*c85f09ccSJohn Levon 			insn->orig_type = def->orig_type;
1521*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->src, def->src);
1522*c85f09ccSJohn Levon 		}
1523*c85f09ccSJohn Levon 		/* fall through */
1524*c85f09ccSJohn Levon 	case OP_SEXT:
1525*c85f09ccSJohn Levon 		switch (insn->opcode) {
1526*c85f09ccSJohn Levon 		case OP_TRUNC:
1527*c85f09ccSJohn Levon 			osize = def->orig_type->bit_size;
1528*c85f09ccSJohn Levon 			if (size == osize)
1529*c85f09ccSJohn Levon 				return replace_with_pseudo(insn, def->src);
1530*c85f09ccSJohn Levon 			if (size > osize)
1531*c85f09ccSJohn Levon 				insn->opcode = def->opcode;
1532*c85f09ccSJohn Levon 			insn->orig_type = def->orig_type;
1533*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->src, def->src);
1534*c85f09ccSJohn Levon 		}
1535*c85f09ccSJohn Levon 		switch (insn->opcode) {
1536*c85f09ccSJohn Levon 		case OP_SEXT:
1537*c85f09ccSJohn Levon 			insn->orig_type = def->orig_type;
1538*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->src, def->src);
1539*c85f09ccSJohn Levon 		}
1540*c85f09ccSJohn Levon 		break;
15411f5207b7SJohn Levon 	}
15421f5207b7SJohn Levon 
15431f5207b7SJohn Levon 	return 0;
15441f5207b7SJohn Levon }
15451f5207b7SJohn Levon 
simplify_select(struct instruction * insn)15461f5207b7SJohn Levon static int simplify_select(struct instruction *insn)
15471f5207b7SJohn Levon {
15481f5207b7SJohn Levon 	pseudo_t cond, src1, src2;
15491f5207b7SJohn Levon 
15501f5207b7SJohn Levon 	if (dead_insn(insn, &insn->src1, &insn->src2, &insn->src3))
15511f5207b7SJohn Levon 		return REPEAT_CSE;
15521f5207b7SJohn Levon 
15531f5207b7SJohn Levon 	cond = insn->src1;
15541f5207b7SJohn Levon 	src1 = insn->src2;
15551f5207b7SJohn Levon 	src2 = insn->src3;
15561f5207b7SJohn Levon 	if (constant(cond) || src1 == src2) {
15571f5207b7SJohn Levon 		pseudo_t *kill, take;
15581f5207b7SJohn Levon 		kill_use(&insn->src1);
15591f5207b7SJohn Levon 		take = cond->value ? src1 : src2;
15601f5207b7SJohn Levon 		kill = cond->value ? &insn->src3 : &insn->src2;
15611f5207b7SJohn Levon 		kill_use(kill);
15621f5207b7SJohn Levon 		replace_with_pseudo(insn, take);
15631f5207b7SJohn Levon 		return REPEAT_CSE;
15641f5207b7SJohn Levon 	}
15651f5207b7SJohn Levon 	if (constant(src1) && constant(src2)) {
15661f5207b7SJohn Levon 		long long val1 = src1->value;
15671f5207b7SJohn Levon 		long long val2 = src2->value;
15681f5207b7SJohn Levon 
15691f5207b7SJohn Levon 		/* The pair 0/1 is special - replace with SETNE/SETEQ */
15701f5207b7SJohn Levon 		if ((val1 | val2) == 1) {
15711f5207b7SJohn Levon 			int opcode = OP_SET_EQ;
15721f5207b7SJohn Levon 			if (val1) {
15731f5207b7SJohn Levon 				src1 = src2;
15741f5207b7SJohn Levon 				opcode = OP_SET_NE;
15751f5207b7SJohn Levon 			}
15761f5207b7SJohn Levon 			insn->opcode = opcode;
15771f5207b7SJohn Levon 			/* insn->src1 is already cond */
15781f5207b7SJohn Levon 			insn->src2 = src1; /* Zero */
15791f5207b7SJohn Levon 			return REPEAT_CSE;
15801f5207b7SJohn Levon 		}
15811f5207b7SJohn Levon 	}
1582*c85f09ccSJohn Levon 	if (cond == src2 && is_zero(src1)) {
1583*c85f09ccSJohn Levon 		kill_use(&insn->src1);
1584*c85f09ccSJohn Levon 		kill_use(&insn->src3);
1585*c85f09ccSJohn Levon 		replace_with_pseudo(insn, value_pseudo(0));
1586*c85f09ccSJohn Levon 		return REPEAT_CSE;
1587*c85f09ccSJohn Levon 	}
15881f5207b7SJohn Levon 	return 0;
15891f5207b7SJohn Levon }
15901f5207b7SJohn Levon 
is_in_range(pseudo_t src,long long low,long long high)15911f5207b7SJohn Levon static int is_in_range(pseudo_t src, long long low, long long high)
15921f5207b7SJohn Levon {
15931f5207b7SJohn Levon 	long long value;
15941f5207b7SJohn Levon 
15951f5207b7SJohn Levon 	switch (src->type) {
15961f5207b7SJohn Levon 	case PSEUDO_VAL:
15971f5207b7SJohn Levon 		value = src->value;
15981f5207b7SJohn Levon 		return value >= low && value <= high;
15991f5207b7SJohn Levon 	default:
16001f5207b7SJohn Levon 		return 0;
16011f5207b7SJohn Levon 	}
16021f5207b7SJohn Levon }
16031f5207b7SJohn Levon 
simplify_range(struct instruction * insn)16041f5207b7SJohn Levon static int simplify_range(struct instruction *insn)
16051f5207b7SJohn Levon {
16061f5207b7SJohn Levon 	pseudo_t src1, src2, src3;
16071f5207b7SJohn Levon 
16081f5207b7SJohn Levon 	src1 = insn->src1;
16091f5207b7SJohn Levon 	src2 = insn->src2;
16101f5207b7SJohn Levon 	src3 = insn->src3;
16111f5207b7SJohn Levon 	if (src2->type != PSEUDO_VAL || src3->type != PSEUDO_VAL)
16121f5207b7SJohn Levon 		return 0;
16131f5207b7SJohn Levon 	if (is_in_range(src1, src2->value, src3->value)) {
16141f5207b7SJohn Levon 		kill_instruction(insn);
16151f5207b7SJohn Levon 		return REPEAT_CSE;
16161f5207b7SJohn Levon 	}
16171f5207b7SJohn Levon 	return 0;
16181f5207b7SJohn Levon }
16191f5207b7SJohn Levon 
1620*c85f09ccSJohn Levon ///
1621*c85f09ccSJohn Levon // simplify SET_NE/EQ $0 + BR
simplify_cond_branch(struct instruction * br,struct instruction * def,pseudo_t newcond)1622*c85f09ccSJohn Levon static int simplify_cond_branch(struct instruction *br, struct instruction *def, pseudo_t newcond)
16231f5207b7SJohn Levon {
1624*c85f09ccSJohn Levon 	replace_pseudo(br, &br->cond, newcond);
16251f5207b7SJohn Levon 	if (def->opcode == OP_SET_EQ) {
1626*c85f09ccSJohn Levon 		struct basic_block *tmp = br->bb_true;
1627*c85f09ccSJohn Levon 		br->bb_true = br->bb_false;
1628*c85f09ccSJohn Levon 		br->bb_false = tmp;
16291f5207b7SJohn Levon 	}
16301f5207b7SJohn Levon 	return REPEAT_CSE;
16311f5207b7SJohn Levon }
16321f5207b7SJohn Levon 
simplify_branch(struct instruction * insn)16331f5207b7SJohn Levon static int simplify_branch(struct instruction *insn)
16341f5207b7SJohn Levon {
16351f5207b7SJohn Levon 	pseudo_t cond = insn->cond;
16361f5207b7SJohn Levon 
16371f5207b7SJohn Levon 	/* Constant conditional */
16381f5207b7SJohn Levon 	if (constant(cond)) {
16391f5207b7SJohn Levon 		insert_branch(insn->bb, insn, cond->value ? insn->bb_true : insn->bb_false);
16401f5207b7SJohn Levon 		return REPEAT_CSE;
16411f5207b7SJohn Levon 	}
16421f5207b7SJohn Levon 
16431f5207b7SJohn Levon 	/* Same target? */
16441f5207b7SJohn Levon 	if (insn->bb_true == insn->bb_false) {
16451f5207b7SJohn Levon 		struct basic_block *bb = insn->bb;
16461f5207b7SJohn Levon 		struct basic_block *target = insn->bb_false;
16471f5207b7SJohn Levon 		remove_bb_from_list(&target->parents, bb, 1);
16481f5207b7SJohn Levon 		remove_bb_from_list(&bb->children, target, 1);
16491f5207b7SJohn Levon 		insn->bb_false = NULL;
16501f5207b7SJohn Levon 		kill_use(&insn->cond);
16511f5207b7SJohn Levon 		insn->cond = NULL;
16521f5207b7SJohn Levon 		insn->opcode = OP_BR;
16531f5207b7SJohn Levon 		return REPEAT_CSE;
16541f5207b7SJohn Levon 	}
16551f5207b7SJohn Levon 
16561f5207b7SJohn Levon 	/* Conditional on a SETNE $0 or SETEQ $0 */
16571f5207b7SJohn Levon 	if (cond->type == PSEUDO_REG) {
16581f5207b7SJohn Levon 		struct instruction *def = cond->def;
16591f5207b7SJohn Levon 
16601f5207b7SJohn Levon 		if (def->opcode == OP_SET_NE || def->opcode == OP_SET_EQ) {
16611f5207b7SJohn Levon 			if (constant(def->src1) && !def->src1->value)
1662*c85f09ccSJohn Levon 				return simplify_cond_branch(insn, def, def->src2);
16631f5207b7SJohn Levon 			if (constant(def->src2) && !def->src2->value)
1664*c85f09ccSJohn Levon 				return simplify_cond_branch(insn, def, def->src1);
16651f5207b7SJohn Levon 		}
16661f5207b7SJohn Levon 		if (def->opcode == OP_SEL) {
16671f5207b7SJohn Levon 			if (constant(def->src2) && constant(def->src3)) {
16681f5207b7SJohn Levon 				long long val1 = def->src2->value;
16691f5207b7SJohn Levon 				long long val2 = def->src3->value;
16701f5207b7SJohn Levon 				if (!val1 && !val2) {
16711f5207b7SJohn Levon 					insert_branch(insn->bb, insn, insn->bb_false);
16721f5207b7SJohn Levon 					return REPEAT_CSE;
16731f5207b7SJohn Levon 				}
16741f5207b7SJohn Levon 				if (val1 && val2) {
16751f5207b7SJohn Levon 					insert_branch(insn->bb, insn, insn->bb_true);
16761f5207b7SJohn Levon 					return REPEAT_CSE;
16771f5207b7SJohn Levon 				}
16781f5207b7SJohn Levon 				if (val2) {
1679*c85f09ccSJohn Levon 					struct basic_block *tmp = insn->bb_true;
1680*c85f09ccSJohn Levon 					insn->bb_true = insn->bb_false;
1681*c85f09ccSJohn Levon 					insn->bb_false = tmp;
16821f5207b7SJohn Levon 				}
1683*c85f09ccSJohn Levon 				return replace_pseudo(insn, &insn->cond, def->src1);
16841f5207b7SJohn Levon 			}
16851f5207b7SJohn Levon 		}
1686*c85f09ccSJohn Levon 		if (def->opcode == OP_SEXT || def->opcode == OP_ZEXT)
1687*c85f09ccSJohn Levon 			return replace_pseudo(insn, &insn->cond, def->src);
16881f5207b7SJohn Levon 	}
16891f5207b7SJohn Levon 	return 0;
16901f5207b7SJohn Levon }
16911f5207b7SJohn Levon 
simplify_switch(struct instruction * insn)16921f5207b7SJohn Levon static int simplify_switch(struct instruction *insn)
16931f5207b7SJohn Levon {
16941f5207b7SJohn Levon 	pseudo_t cond = insn->cond;
16951f5207b7SJohn Levon 	long long val;
16961f5207b7SJohn Levon 	struct multijmp *jmp;
16971f5207b7SJohn Levon 
16981f5207b7SJohn Levon 	if (!constant(cond))
16991f5207b7SJohn Levon 		return 0;
17001f5207b7SJohn Levon 	val = insn->cond->value;
17011f5207b7SJohn Levon 
17021f5207b7SJohn Levon 	FOR_EACH_PTR(insn->multijmp_list, jmp) {
17031f5207b7SJohn Levon 		/* Default case */
17041f5207b7SJohn Levon 		if (jmp->begin > jmp->end)
17051f5207b7SJohn Levon 			goto found;
17061f5207b7SJohn Levon 		if (val >= jmp->begin && val <= jmp->end)
17071f5207b7SJohn Levon 			goto found;
17081f5207b7SJohn Levon 	} END_FOR_EACH_PTR(jmp);
17091f5207b7SJohn Levon 	warning(insn->pos, "Impossible case statement");
17101f5207b7SJohn Levon 	return 0;
17111f5207b7SJohn Levon 
17121f5207b7SJohn Levon found:
17131f5207b7SJohn Levon 	insert_branch(insn->bb, insn, jmp->target);
17141f5207b7SJohn Levon 	return REPEAT_CSE;
17151f5207b7SJohn Levon }
17161f5207b7SJohn Levon 
simplify_instruction(struct instruction * insn)17171f5207b7SJohn Levon int simplify_instruction(struct instruction *insn)
17181f5207b7SJohn Levon {
17191f5207b7SJohn Levon 	if (!insn->bb)
17201f5207b7SJohn Levon 		return 0;
17211f5207b7SJohn Levon 	switch (insn->opcode) {
1722*c85f09ccSJohn Levon 	case OP_ADD: case OP_MUL:
17231f5207b7SJohn Levon 	case OP_AND: case OP_OR: case OP_XOR:
1724*c85f09ccSJohn Levon 		canonicalize_commutative(insn);
17251f5207b7SJohn Levon 		if (simplify_binop(insn))
17261f5207b7SJohn Levon 			return REPEAT_CSE;
17271f5207b7SJohn Levon 		return simplify_associative_binop(insn);
17281f5207b7SJohn Levon 
17291f5207b7SJohn Levon 	case OP_SET_EQ: case OP_SET_NE:
1730*c85f09ccSJohn Levon 		canonicalize_commutative(insn);
1731*c85f09ccSJohn Levon 		return simplify_binop(insn);
17321f5207b7SJohn Levon 
1733*c85f09ccSJohn Levon 	case OP_SET_LE: case OP_SET_GE:
1734*c85f09ccSJohn Levon 	case OP_SET_LT: case OP_SET_GT:
1735*c85f09ccSJohn Levon 	case OP_SET_B:  case OP_SET_A:
1736*c85f09ccSJohn Levon 	case OP_SET_BE: case OP_SET_AE:
1737*c85f09ccSJohn Levon 		canonicalize_compare(insn);
1738*c85f09ccSJohn Levon 		/* fall through */
17391f5207b7SJohn Levon 	case OP_SUB:
17401f5207b7SJohn Levon 	case OP_DIVU: case OP_DIVS:
17411f5207b7SJohn Levon 	case OP_MODU: case OP_MODS:
17421f5207b7SJohn Levon 	case OP_SHL:
17431f5207b7SJohn Levon 	case OP_LSR: case OP_ASR:
17441f5207b7SJohn Levon 		return simplify_binop(insn);
17451f5207b7SJohn Levon 
1746*c85f09ccSJohn Levon 	case OP_NOT: case OP_NEG: case OP_FNEG:
17471f5207b7SJohn Levon 		return simplify_unop(insn);
1748*c85f09ccSJohn Levon 	case OP_LOAD:
1749*c85f09ccSJohn Levon 		if (!has_users(insn->target))
1750*c85f09ccSJohn Levon 			return kill_instruction(insn);
1751*c85f09ccSJohn Levon 		/* fall-through */
1752*c85f09ccSJohn Levon 	case OP_STORE:
17531f5207b7SJohn Levon 		return simplify_memop(insn);
17541f5207b7SJohn Levon 	case OP_SYMADDR:
1755*c85f09ccSJohn Levon 		if (dead_insn(insn, &insn->src, NULL, NULL))
17561f5207b7SJohn Levon 			return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
1757*c85f09ccSJohn Levon 		return replace_with_pseudo(insn, insn->src);
1758*c85f09ccSJohn Levon 	case OP_SEXT: case OP_ZEXT:
1759*c85f09ccSJohn Levon 	case OP_TRUNC:
17601f5207b7SJohn Levon 		return simplify_cast(insn);
1761*c85f09ccSJohn Levon 	case OP_FCVTU: case OP_FCVTS:
1762*c85f09ccSJohn Levon 	case OP_UCVTF: case OP_SCVTF:
1763*c85f09ccSJohn Levon 	case OP_FCVTF:
1764*c85f09ccSJohn Levon 	case OP_PTRCAST:
1765*c85f09ccSJohn Levon 		if (dead_insn(insn, &insn->src, NULL, NULL))
1766*c85f09ccSJohn Levon 			return REPEAT_CSE;
1767*c85f09ccSJohn Levon 		break;
1768*c85f09ccSJohn Levon 	case OP_UTPTR:
1769*c85f09ccSJohn Levon 	case OP_PTRTU:
1770*c85f09ccSJohn Levon 		return replace_with_pseudo(insn, insn->src);
1771*c85f09ccSJohn Levon 	case OP_SLICE:
1772*c85f09ccSJohn Levon 		if (dead_insn(insn, &insn->src, NULL, NULL))
1773*c85f09ccSJohn Levon 			return REPEAT_CSE;
1774*c85f09ccSJohn Levon 		break;
1775*c85f09ccSJohn Levon 	case OP_SETVAL:
1776*c85f09ccSJohn Levon 	case OP_SETFVAL:
1777*c85f09ccSJohn Levon 		if (dead_insn(insn, NULL, NULL, NULL))
1778*c85f09ccSJohn Levon 			return REPEAT_CSE;
1779*c85f09ccSJohn Levon 		break;
17801f5207b7SJohn Levon 	case OP_PHI:
17811f5207b7SJohn Levon 		if (dead_insn(insn, NULL, NULL, NULL)) {
17821f5207b7SJohn Levon 			kill_use_list(insn->phi_list);
17831f5207b7SJohn Levon 			return REPEAT_CSE;
17841f5207b7SJohn Levon 		}
17851f5207b7SJohn Levon 		return clean_up_phi(insn);
17861f5207b7SJohn Levon 	case OP_PHISOURCE:
17871f5207b7SJohn Levon 		if (dead_insn(insn, &insn->phi_src, NULL, NULL))
17881f5207b7SJohn Levon 			return REPEAT_CSE;
17891f5207b7SJohn Levon 		break;
17901f5207b7SJohn Levon 	case OP_SEL:
17911f5207b7SJohn Levon 		return simplify_select(insn);
17921f5207b7SJohn Levon 	case OP_CBR:
17931f5207b7SJohn Levon 		return simplify_branch(insn);
17941f5207b7SJohn Levon 	case OP_SWITCH:
17951f5207b7SJohn Levon 		return simplify_switch(insn);
17961f5207b7SJohn Levon 	case OP_RANGE:
17971f5207b7SJohn Levon 		return simplify_range(insn);
1798*c85f09ccSJohn Levon 	case OP_FADD:
1799*c85f09ccSJohn Levon 	case OP_FSUB:
1800*c85f09ccSJohn Levon 	case OP_FMUL:
1801*c85f09ccSJohn Levon 	case OP_FDIV:
1802*c85f09ccSJohn Levon 		if (dead_insn(insn, &insn->src1, &insn->src2, NULL))
1803*c85f09ccSJohn Levon 			return REPEAT_CSE;
1804*c85f09ccSJohn Levon 		break;
18051f5207b7SJohn Levon 	}
18061f5207b7SJohn Levon 	return 0;
18071f5207b7SJohn Levon }
1808