xref: /illumos-gate/usr/src/tools/smatch/src/memops.c (revision d3b5f56344d8bfcdd6cfb82446af0e5e55ad9ebe)
1 /*
2  * memops - try to combine memory ops.
3  *
4  * Copyright (C) 2004 Linus Torvalds
5  */
6 
7 #include <string.h>
8 #include <stdarg.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <stddef.h>
12 #include <assert.h>
13 
14 #include "parse.h"
15 #include "expression.h"
16 #include "linearize.h"
17 #include "flow.h"
18 
19 static int find_dominating_parents(pseudo_t pseudo, struct instruction *insn,
20 	struct basic_block *bb, unsigned long generation, struct pseudo_list **dominators,
21 	int local)
22 {
23 	struct basic_block *parent;
24 
25 	FOR_EACH_PTR(bb->parents, parent) {
26 		struct instruction *one;
27 		struct instruction *br;
28 		pseudo_t phi;
29 
30 		FOR_EACH_PTR_REVERSE(parent->insns, one) {
31 			int dominance;
32 			if (!one->bb)
33 				continue;
34 			if (one == insn)
35 				goto no_dominance;
36 			dominance = dominates(pseudo, insn, one, local);
37 			if (dominance < 0) {
38 				if (one->opcode == OP_LOAD)
39 					continue;
40 				return 0;
41 			}
42 			if (!dominance)
43 				continue;
44 			goto found_dominator;
45 		} END_FOR_EACH_PTR_REVERSE(one);
46 no_dominance:
47 		if (parent->generation == generation)
48 			continue;
49 		parent->generation = generation;
50 
51 		if (!find_dominating_parents(pseudo, insn, parent, generation, dominators, local))
52 			return 0;
53 		continue;
54 
55 found_dominator:
56 		br = delete_last_instruction(&parent->insns);
57 		phi = alloc_phi(parent, one->target, one->size);
58 		phi->ident = phi->ident ? : one->target->ident;
59 		add_instruction(&parent->insns, br);
60 		use_pseudo(insn, phi, add_pseudo(dominators, phi));
61 	} END_FOR_EACH_PTR(parent);
62 	return 1;
63 }
64 
65 static int address_taken(pseudo_t pseudo)
66 {
67 	struct pseudo_user *pu;
68 	FOR_EACH_PTR(pseudo->users, pu) {
69 		struct instruction *insn = pu->insn;
70 		if (insn->bb && (insn->opcode != OP_LOAD && insn->opcode != OP_STORE))
71 			return 1;
72 	} END_FOR_EACH_PTR(pu);
73 	return 0;
74 }
75 
76 static int local_pseudo(pseudo_t pseudo)
77 {
78 	return pseudo->type == PSEUDO_SYM
79 		&& !(pseudo->sym->ctype.modifiers & (MOD_STATIC | MOD_NONLOCAL))
80 		&& !address_taken(pseudo);
81 }
82 
83 static void simplify_loads(struct basic_block *bb)
84 {
85 	struct instruction *insn;
86 
87 	FOR_EACH_PTR_REVERSE(bb->insns, insn) {
88 		if (!insn->bb)
89 			continue;
90 		if (insn->opcode == OP_LOAD) {
91 			struct instruction *dom;
92 			pseudo_t pseudo = insn->src;
93 			int local = local_pseudo(pseudo);
94 			struct pseudo_list *dominators;
95 			unsigned long generation;
96 
97 			/* Check for illegal offsets.. */
98 			check_access(insn);
99 
100 			if (insn->type->ctype.modifiers & MOD_VOLATILE)
101 				continue;
102 
103 			RECURSE_PTR_REVERSE(insn, dom) {
104 				int dominance;
105 				if (!dom->bb)
106 					continue;
107 				dominance = dominates(pseudo, insn, dom, local);
108 				if (dominance) {
109 					/* possible partial dominance? */
110 					if (dominance < 0)  {
111 						if (dom->opcode == OP_LOAD)
112 							continue;
113 						goto next_load;
114 					}
115 					/* Yeehaa! Found one! */
116 					convert_load_instruction(insn, dom->target);
117 					goto next_load;
118 				}
119 			} END_FOR_EACH_PTR_REVERSE(dom);
120 
121 			/* OK, go find the parents */
122 			generation = ++bb_generation;
123 			bb->generation = generation;
124 			dominators = NULL;
125 			if (find_dominating_parents(pseudo, insn, bb, generation, &dominators, local)) {
126 				/* This happens with initial assignments to structures etc.. */
127 				if (!dominators) {
128 					if (local) {
129 						assert(pseudo->type != PSEUDO_ARG);
130 						convert_load_instruction(insn, value_pseudo(insn->type, 0));
131 					}
132 					goto next_load;
133 				}
134 				rewrite_load_instruction(insn, dominators);
135 			}
136 		}
137 next_load:
138 		/* Do the next one */;
139 	} END_FOR_EACH_PTR_REVERSE(insn);
140 }
141 
142 static void kill_store(struct instruction *insn)
143 {
144 	if (insn) {
145 		insn->bb = NULL;
146 		insn->opcode = OP_SNOP;
147 		kill_use(&insn->target);
148 	}
149 }
150 
151 static void kill_dominated_stores(struct basic_block *bb)
152 {
153 	struct instruction *insn;
154 
155 	FOR_EACH_PTR_REVERSE(bb->insns, insn) {
156 		if (!insn->bb)
157 			continue;
158 		if (insn->opcode == OP_STORE) {
159 			struct instruction *dom;
160 			pseudo_t pseudo = insn->src;
161 			int local = local_pseudo(pseudo);
162 
163 			RECURSE_PTR_REVERSE(insn, dom) {
164 				int dominance;
165 				if (!dom->bb)
166 					continue;
167 				dominance = dominates(pseudo, insn, dom, local);
168 				if (dominance) {
169 					/* possible partial dominance? */
170 					if (dominance < 0)
171 						goto next_store;
172 					if (dom->opcode == OP_LOAD)
173 						goto next_store;
174 					/* Yeehaa! Found one! */
175 					kill_store(dom);
176 				}
177 			} END_FOR_EACH_PTR_REVERSE(dom);
178 
179 			/* OK, we should check the parents now */
180 		}
181 next_store:
182 		/* Do the next one */;
183 	} END_FOR_EACH_PTR_REVERSE(insn);
184 }
185 
186 void simplify_memops(struct entrypoint *ep)
187 {
188 	struct basic_block *bb;
189 
190 	FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
191 		simplify_loads(bb);
192 	} END_FOR_EACH_PTR_REVERSE(bb);
193 
194 	FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
195 		kill_dominated_stores(bb);
196 	} END_FOR_EACH_PTR_REVERSE(bb);
197 }
198