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