Backport from GCC mainline.
[platform/upstream/linaro-gcc.git] / gcc / rtl-chkp.c
1 /* RTL manipulation functions exported by Pointer Bounds Checker.
2    Copyright (C) 2014-2016 Free Software Foundation, Inc.
3    Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "emit-rtl.h"
29 #include "expr.h"
30 #include "rtl-chkp.h"
31 #include "tree-chkp.h"
32
33 static hash_map<tree, rtx> *chkp_rtx_bounds_map;
34
35 /* Get bounds rtx associated with NODE via
36    chkp_set_rtl_bounds call.  */
37 rtx
38 chkp_get_rtl_bounds (tree node)
39 {
40   rtx *slot;
41
42   if (!chkp_rtx_bounds_map)
43     return NULL_RTX;
44
45   slot = chkp_rtx_bounds_map->get (node);
46   return slot ? *slot : NULL_RTX;
47 }
48
49 /* Associate bounds rtx VAL with NODE.  */
50 void
51 chkp_set_rtl_bounds (tree node, rtx val)
52 {
53   if (!chkp_rtx_bounds_map)
54     chkp_rtx_bounds_map = new hash_map<tree, rtx>;
55
56   chkp_rtx_bounds_map->put (node, val);
57 }
58
59 /* Reset all bounds stored via chkp_set_rtl_bounds.  */
60 void
61 chkp_reset_rtl_bounds ()
62 {
63   if (!chkp_rtx_bounds_map)
64     return;
65
66   delete chkp_rtx_bounds_map;
67   chkp_rtx_bounds_map = NULL;
68 }
69
70 /* Split SLOT identifying slot for function value or
71    argument into two parts SLOT_VAL and SLOT_BND.
72    First is the slot for regular value and the other one is
73    for bounds.  */
74 void
75 chkp_split_slot (rtx slot, rtx *slot_val, rtx *slot_bnd)
76 {
77   int i;
78   int val_num = 0;
79   int bnd_num = 0;
80   rtx *val_tmps;
81   rtx *bnd_tmps;
82
83   *slot_bnd = 0;
84
85   if (!slot
86       || GET_CODE (slot) != PARALLEL)
87     {
88       *slot_val = slot;
89       return;
90     }
91
92   val_tmps = XALLOCAVEC (rtx, XVECLEN (slot, 0));
93   bnd_tmps = XALLOCAVEC (rtx, XVECLEN (slot, 0));
94
95   for (i = 0; i < XVECLEN (slot, 0); i++)
96     {
97       rtx elem = XVECEXP (slot, 0, i);
98       rtx reg = GET_CODE (elem) == EXPR_LIST ? XEXP (elem, 0) : elem;
99
100       if (!reg)
101         continue;
102
103       if (POINTER_BOUNDS_MODE_P (GET_MODE (reg)) || CONST_INT_P (reg))
104         bnd_tmps[bnd_num++] = elem;
105       else
106         val_tmps[val_num++] = elem;
107     }
108
109   gcc_assert (val_num);
110
111   if (!bnd_num)
112     {
113       *slot_val = slot;
114       return;
115     }
116
117   if ((GET_CODE (val_tmps[0]) == EXPR_LIST) || (val_num > 1))
118     *slot_val = gen_rtx_PARALLEL (GET_MODE (slot),
119                                   gen_rtvec_v (val_num, val_tmps));
120   else
121     *slot_val = val_tmps[0];
122
123   if ((GET_CODE (bnd_tmps[0]) == EXPR_LIST) || (bnd_num > 1))
124     *slot_bnd = gen_rtx_PARALLEL (VOIDmode,
125                                   gen_rtvec_v (bnd_num, bnd_tmps));
126   else
127     *slot_bnd = bnd_tmps[0];
128 }
129
130 /* Join previously splitted to VAL and BND rtx for function
131    value or argument and return it.  */
132 rtx
133 chkp_join_splitted_slot (rtx val, rtx bnd)
134 {
135   rtx res;
136   int i, n = 0;
137
138   if (!bnd)
139     return val;
140
141   if (GET_CODE (val) == PARALLEL)
142     n += XVECLEN (val, 0);
143   else
144     n++;
145
146   if (GET_CODE (bnd) == PARALLEL)
147     n += XVECLEN (bnd, 0);
148   else
149     n++;
150
151   res = gen_rtx_PARALLEL (GET_MODE (val), rtvec_alloc (n));
152
153   n = 0;
154
155   if (GET_CODE (val) == PARALLEL)
156     for (i = 0; i < XVECLEN (val, 0); i++)
157       XVECEXP (res, 0, n++) = XVECEXP (val, 0, i);
158   else
159     XVECEXP (res, 0, n++) = val;
160
161   if (GET_CODE (bnd) == PARALLEL)
162     for (i = 0; i < XVECLEN (bnd, 0); i++)
163       XVECEXP (res, 0, n++) = XVECEXP (bnd, 0, i);
164   else
165     XVECEXP (res, 0, n++) = bnd;
166
167   return res;
168 }
169
170 /* If PAR is PARALLEL holding registers then transform
171    it into PARALLEL holding EXPR_LISTs of those regs
172    and zero constant (similar to how function value
173    on multiple registers looks like).  */
174 void
175 chkp_put_regs_to_expr_list (rtx par)
176 {
177   int n;
178
179   if (GET_CODE (par) != PARALLEL
180       || GET_CODE (XVECEXP (par, 0, 0)) == EXPR_LIST)
181     return;
182
183   for (n = 0; n < XVECLEN (par, 0); n++)
184     XVECEXP (par, 0, n) = gen_rtx_EXPR_LIST (VOIDmode,
185                                              XVECEXP (par, 0, n),
186                                              const0_rtx);
187 }
188
189 /*  Search rtx PAR describing function return value for an
190     item related to value at offset OFFS and return it.
191     Return NULL if item was not found.  */
192 rtx
193 chkp_get_value_with_offs (rtx par, rtx offs)
194 {
195   int n;
196
197   gcc_assert (GET_CODE (par) == PARALLEL);
198
199   for (n = 0; n < XVECLEN (par, 0); n++)
200     {
201       rtx par_offs = XEXP (XVECEXP (par, 0, n), 1);
202       if (INTVAL (offs) == INTVAL (par_offs))
203         return XEXP (XVECEXP (par, 0, n), 0);
204     }
205
206   return NULL;
207 }
208
209 /* Emit instructions to store BOUNDS for pointer VALUE
210    stored in MEM.
211    Function is used by expand to pass bounds for args
212    passed on stack.  */
213 void
214 chkp_emit_bounds_store (rtx bounds, rtx value, rtx mem)
215 {
216   gcc_assert (MEM_P (mem));
217
218   if (REG_P (bounds) || CONST_INT_P (bounds))
219     {
220       rtx ptr;
221
222       if (REG_P (value))
223         ptr = value;
224       else
225         {
226           rtx slot = adjust_address (value, Pmode, 0);
227           ptr = gen_reg_rtx (Pmode);
228           emit_move_insn (ptr, slot);
229         }
230
231       if (CONST_INT_P (bounds))
232         bounds = targetm.calls.load_bounds_for_arg (value, ptr, bounds);
233
234       targetm.calls.store_bounds_for_arg (ptr, mem,
235                                           bounds, NULL);
236     }
237   else
238     {
239       int i;
240
241       gcc_assert (GET_CODE (bounds) == PARALLEL);
242       gcc_assert (GET_CODE (value) == PARALLEL || MEM_P (value) || REG_P (value));
243
244       for (i = 0; i < XVECLEN (bounds, 0); i++)
245         {
246           rtx reg = XEXP (XVECEXP (bounds, 0, i), 0);
247           rtx offs = XEXP (XVECEXP (bounds, 0, i), 1);
248           rtx slot = adjust_address (mem, Pmode, INTVAL (offs));
249           rtx ptr;
250
251           if (GET_CODE (value) == PARALLEL)
252             ptr = chkp_get_value_with_offs (value, offs);
253           else if (MEM_P (value))
254             {
255               rtx tmp = adjust_address (value, Pmode, INTVAL (offs));
256               ptr = gen_reg_rtx (Pmode);
257               emit_move_insn (ptr, tmp);
258             }
259           else
260             ptr = gen_rtx_SUBREG (Pmode, value, INTVAL (offs));
261
262           targetm.calls.store_bounds_for_arg (ptr, slot, reg, NULL);
263         }
264     }
265 }
266
267 /* Emit code to copy bounds for structure VALUE of type TYPE
268    copied to SLOT.  */
269 void
270 chkp_copy_bounds_for_stack_parm (rtx slot, rtx value, tree type)
271 {
272   bitmap have_bound;
273   bitmap_iterator bi;
274   unsigned i;
275   rtx tmp = NULL, bnd;
276
277   gcc_assert (TYPE_SIZE (type));
278   gcc_assert (MEM_P (value));
279   gcc_assert (MEM_P (slot));
280   gcc_assert (RECORD_OR_UNION_TYPE_P (type));
281
282   bitmap_obstack_initialize (NULL);
283   have_bound = BITMAP_ALLOC (NULL);
284   chkp_find_bound_slots (type, have_bound);
285
286   EXECUTE_IF_SET_IN_BITMAP (have_bound, 0, i, bi)
287     {
288       rtx ptr = adjust_address (value, Pmode, i * POINTER_SIZE / 8);
289       rtx to = adjust_address (slot, Pmode, i * POINTER_SIZE / 8);
290
291       if (!tmp)
292         tmp = gen_reg_rtx (Pmode);
293
294       emit_move_insn (tmp, ptr);
295       bnd = targetm.calls.load_bounds_for_arg (ptr, tmp, NULL);
296       targetm.calls.store_bounds_for_arg (tmp, to, bnd, NULL);
297     }
298
299   BITMAP_FREE (have_bound);
300   bitmap_obstack_release (NULL);
301 }