2015-06-11 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / cilk-common.c
blob594ab5c5783def06f1664efadf34532a46750d52
1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2 This file contains the CilkPlus Intrinsics
3 Copyright (C) 2013-2015 Free Software Foundation, Inc.
4 Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
5 Intel Corporation
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3, or (at your option)
12 any later version.
14 GCC is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "input.h"
27 #include "alias.h"
28 #include "symtab.h"
29 #include "options.h"
30 #include "tree.h"
31 #include "fold-const.h"
32 #include "stringpool.h"
33 #include "stor-layout.h"
34 #include "langhooks.h"
35 #include "tm.h"
36 #include "hard-reg-set.h"
37 #include "function.h"
38 #include "rtl.h"
39 #include "flags.h"
40 #include "insn-config.h"
41 #include "expmed.h"
42 #include "dojump.h"
43 #include "explow.h"
44 #include "calls.h"
45 #include "emit-rtl.h"
46 #include "varasm.h"
47 #include "stmt.h"
48 #include "expr.h"
49 #include "insn-codes.h"
50 #include "optabs.h"
51 #include "recog.h"
52 #include "tree-iterator.h"
53 #include "gimplify.h"
54 #include "cilk.h"
56 /* This structure holds all the important fields of the internal structures,
57 internal built-in functions, and Cilk-specific data types. Explanation of
58 all the these fielsd are given in cilk.h. */
59 tree cilk_trees[(int) CILK_TI_MAX];
61 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
62 (e.g. X.y).
63 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
64 about these fields, refer to cilk_trees structure in cilk.h and
65 cilk_init_builtins function in this file. Returns a TREE that is the type
66 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
67 to true then the returning field is set as volatile. */
69 tree
70 cilk_dot (tree frame, int field_number, bool volatil)
72 tree field = cilk_trees[field_number];
73 field = fold_build3 (COMPONENT_REF, TREE_TYPE (field), frame, field,
74 NULL_TREE);
75 TREE_THIS_VOLATILE (field) = volatil;
76 return field;
79 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
80 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
81 FIELD_NUMBER. Returns a tree that is the type of the field represented
82 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
83 field is set as volatile. */
85 tree
86 cilk_arrow (tree frame_ptr, int field_number, bool volatil)
88 return cilk_dot (build_simple_mem_ref (frame_ptr),
89 field_number, volatil);
93 /* This function will add FIELD of type TYPE to a defined built-in
94 structure. *NAME is the name of the field to be added. */
96 static tree
97 add_field (const char *name, tree type, tree fields)
99 tree t = get_identifier (name);
100 tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, t, type);
101 TREE_CHAIN (field) = fields;
102 return field;
105 /* This function will define a built-in function of NAME, of type FNTYPE and
106 register it under the built-in function code CODE. If PUBLISH is set then
107 the declaration is pushed into the declaration list. CODE is the index
108 to the cilk_trees array. *NAME is the name of the function to be added. */
110 static tree
111 install_builtin (const char *name, tree fntype, enum built_in_function code,
112 bool publish)
114 tree fndecl = build_fn_decl (name, fntype);
115 DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
116 DECL_FUNCTION_CODE (fndecl) = code;
117 if (publish)
119 tree t = lang_hooks.decls.pushdecl (fndecl);
120 if (t)
121 fndecl = t;
123 set_builtin_decl (code, fndecl, true);
124 return fndecl;
127 /* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
129 static tree
130 declare_cilk_for_builtin (const char *name, tree type,
131 enum built_in_function code)
133 tree cb, ft, fn;
135 cb = build_function_type_list (void_type_node,
136 ptr_type_node, type, type,
137 NULL_TREE);
138 cb = build_pointer_type (cb);
139 ft = build_function_type_list (void_type_node,
140 cb, ptr_type_node, type,
141 integer_type_node, NULL_TREE);
142 fn = install_builtin (name, ft, code, false);
143 TREE_NOTHROW (fn) = 0;
145 return fn;
148 /* Creates and initializes all the built-in Cilk keywords functions and three
149 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
150 Detailed information about __cilkrts_stack_frame and
151 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
152 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
154 void
155 cilk_init_builtins (void)
157 /* Now build the following __cilkrts_pedigree struct:
158 struct __cilkrts_pedigree {
159 uint64_t rank;
160 struct __cilkrts_pedigree *parent;
161 } */
163 tree pedigree_type = lang_hooks.types.make_type (RECORD_TYPE);
164 tree pedigree_ptr = build_pointer_type (pedigree_type);
165 tree field = add_field ("rank", uint64_type_node, NULL_TREE);
166 cilk_trees[CILK_TI_PEDIGREE_RANK] = field;
167 field = add_field ("parent", pedigree_ptr, field);
168 cilk_trees[CILK_TI_PEDIGREE_PARENT] = field;
169 finish_builtin_struct (pedigree_type, "__cilkrts_pedigree_GCC", field,
170 NULL_TREE);
171 lang_hooks.types.register_builtin_type (pedigree_type,
172 "__cilkrts_pedigree_t");
173 cilk_pedigree_type_decl = pedigree_type;
175 /* Build the Cilk Stack Frame:
176 struct __cilkrts_stack_frame {
177 uint32_t flags;
178 uint32_t size;
179 struct __cilkrts_stack_frame *call_parent;
180 __cilkrts_worker *worker;
181 void *except_data;
182 void *ctx[4];
183 uint32_t mxcsr;
184 uint16_t fpcsr;
185 uint16_t reserved;
186 __cilkrts_pedigree pedigree;
187 }; */
189 tree frame = lang_hooks.types.make_type (RECORD_TYPE);
190 tree frame_ptr = build_pointer_type (frame);
191 tree worker_type = lang_hooks.types.make_type (RECORD_TYPE);
192 tree worker_ptr = build_pointer_type (worker_type);
193 tree s_type_node = build_int_cst (size_type_node, 4);
195 tree flags = add_field ("flags", uint32_type_node, NULL_TREE);
196 tree size = add_field ("size", uint32_type_node, flags);
197 tree parent = add_field ("call_parent", frame_ptr, size);
198 tree worker = add_field ("worker", worker_ptr, parent);
199 tree except = add_field ("except_data", frame_ptr, worker);
200 tree context = add_field ("ctx",
201 build_array_type (ptr_type_node,
202 build_index_type (s_type_node)),
203 except);
204 tree mxcsr = add_field ("mxcsr", uint32_type_node, context);
205 tree fpcsr = add_field ("fpcsr", uint16_type_node, mxcsr);
206 tree reserved = add_field ("reserved", uint16_type_node, fpcsr);
207 tree pedigree = add_field ("pedigree", pedigree_type, reserved);
209 /* Now add them to a common structure whose fields are #defined to something
210 that is used at a later stage. */
211 cilk_trees[CILK_TI_FRAME_FLAGS] = flags;
212 cilk_trees[CILK_TI_FRAME_PARENT] = parent;
213 cilk_trees[CILK_TI_FRAME_WORKER] = worker;
214 cilk_trees[CILK_TI_FRAME_EXCEPTION] = except;
215 cilk_trees[CILK_TI_FRAME_CONTEXT] = context;
216 /* We don't care about reserved, so no need to store it in cilk_trees. */
217 cilk_trees[CILK_TI_FRAME_PEDIGREE] = pedigree;
218 TREE_ADDRESSABLE (frame) = 1;
220 finish_builtin_struct (frame, "__cilkrts_st_frame_GCC", pedigree, NULL_TREE);
221 cilk_frame_type_decl = frame;
222 lang_hooks.types.register_builtin_type (frame, "__cilkrts_frame_t");
224 cilk_frame_ptr_type_decl = build_qualified_type (frame_ptr,
225 TYPE_QUAL_VOLATILE);
226 /* Now let's do the following worker struct:
228 struct __cilkrts_worker {
229 __cilkrts_stack_frame *volatile *volatile tail;
230 __cilkrts_stack_frame *volatile *volatile head;
231 __cilkrts_stack_frame *volatile *volatile exc;
232 __cilkrts_stack_frame *volatile *volatile protected_tail;
233 __cilkrts_stack_frame *volatile *ltq_limit;
234 int32_t self;
235 global_state_t *g;
236 local_state *l;
237 cilkred_map *reducer_map;
238 __cilkrts_stack_frame *current_stack_frame;
239 void *reserved;
240 __cilkrts_worker_sysdep_state *sysdep;
241 __cilkrts_pedigree pedigree;
242 } */
244 tree fptr_volatil_type = build_qualified_type (frame_ptr, TYPE_QUAL_VOLATILE);
245 tree fptr_volatile_ptr = build_pointer_type (fptr_volatil_type);
246 tree fptr_vol_ptr_vol = build_qualified_type (fptr_volatile_ptr,
247 TYPE_QUAL_VOLATILE);
248 tree g = lang_hooks.types.make_type (RECORD_TYPE);
249 finish_builtin_struct (g, "__cilkrts_global_state", NULL_TREE, NULL_TREE);
250 tree l = lang_hooks.types.make_type (RECORD_TYPE);
251 finish_builtin_struct (l, "__cilkrts_local_state", NULL_TREE, NULL_TREE);
252 tree sysdep_t = lang_hooks.types.make_type (RECORD_TYPE);
253 finish_builtin_struct (sysdep_t, "__cilkrts_worker_sysdep_state", NULL_TREE,
254 NULL_TREE);
256 field = add_field ("tail", fptr_vol_ptr_vol, NULL_TREE);
257 cilk_trees[CILK_TI_WORKER_TAIL] = field;
258 field = add_field ("head", fptr_vol_ptr_vol, field);
259 field = add_field ("exc", fptr_vol_ptr_vol, field);
260 field = add_field ("protected_tail", fptr_vol_ptr_vol, field);
261 field = add_field ("ltq_limit", fptr_volatile_ptr, field);
262 field = add_field ("self", integer_type_node, field);
263 field = add_field ("g", build_pointer_type (g), field);
264 field = add_field ("l", build_pointer_type (g), field);
265 field = add_field ("reducer_map", ptr_type_node, field);
266 field = add_field ("current_stack_frame", frame_ptr, field);
267 cilk_trees[CILK_TI_WORKER_CUR] = field;
268 field = add_field ("saved_protected_tail", fptr_volatile_ptr, field);
269 field = add_field ("sysdep", build_pointer_type (sysdep_t), field);
270 field = add_field ("pedigree", pedigree_type, field);
271 cilk_trees[CILK_TI_WORKER_PEDIGREE] = field;
272 finish_builtin_struct (worker_type, "__cilkrts_worker_GCC", field,
273 NULL_TREE);
275 tree fptr_arglist = tree_cons (NULL_TREE, frame_ptr, void_list_node);
276 tree fptr_fun = build_function_type (void_type_node, fptr_arglist);
278 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
279 cilk_enter_fndecl = install_builtin ("__cilkrts_enter_frame_1", fptr_fun,
280 BUILT_IN_CILK_ENTER_FRAME, false);
282 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
283 cilk_enter_fast_fndecl =
284 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun,
285 BUILT_IN_CILK_ENTER_FRAME_FAST, false);
287 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
288 cilk_pop_fndecl = install_builtin ("__cilkrts_pop_frame", fptr_fun,
289 BUILT_IN_CILK_POP_FRAME, false);
291 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
292 cilk_leave_fndecl = install_builtin ("__cilkrts_leave_frame", fptr_fun,
293 BUILT_IN_CILK_LEAVE_FRAME, false);
295 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
296 cilk_sync_fndecl = install_builtin ("__cilkrts_sync", fptr_fun,
297 BUILT_IN_CILK_SYNC, false);
299 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
300 cilk_detach_fndecl = install_builtin ("__cilkrts_detach", fptr_fun,
301 BUILT_IN_CILK_DETACH, false);
303 /* __cilkrts_rethrow (struct stack_frame *); */
304 cilk_rethrow_fndecl = install_builtin ("__cilkrts_rethrow", fptr_fun,
305 BUILT_IN_CILK_RETHROW, false);
306 TREE_NOTHROW (cilk_rethrow_fndecl) = 0;
308 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
309 cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state",
310 fptr_fun, BUILT_IN_CILK_SAVE_FP,
311 false);
312 /* __cilkrts_cilk_for_32 (...); */
313 cilk_for_32_fndecl = declare_cilk_for_builtin ("__cilkrts_cilk_for_32",
314 unsigned_intSI_type_node,
315 BUILT_IN_CILK_FOR_32);
316 /* __cilkrts_cilk_for_64 (...); */
317 cilk_for_64_fndecl = declare_cilk_for_builtin ("__cilkrts_cilk_for_64",
318 unsigned_intDI_type_node,
319 BUILT_IN_CILK_FOR_64);
322 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
324 static tree
325 get_frame_arg (tree call)
327 tree arg, argtype;
329 gcc_assert (call_expr_nargs (call) >= 1);
331 arg = CALL_EXPR_ARG (call, 0);
332 argtype = TREE_TYPE (arg);
333 gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
335 argtype = TREE_TYPE (argtype);
337 /* If it is passed in as an address, then just use the value directly
338 since the function is inlined. */
339 if (TREE_CODE (arg) == ADDR_EXPR)
340 return TREE_OPERAND (arg, 0);
341 return arg;
344 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
346 void
347 expand_builtin_cilk_pop_frame (tree exp)
349 tree frame = get_frame_arg (exp);
350 tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
352 tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
353 build_int_cst (TREE_TYPE (parent), 0));
354 expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
356 /* During LTO, the is_cilk_function flag gets cleared.
357 If __cilkrts_pop_frame is called, then this definitely must be a
358 cilk function. */
359 if (cfun)
360 cfun->is_cilk_function = 1;
363 /* Expands the cilk_detach function call stored in EXP. */
365 void
366 expand_builtin_cilk_detach (tree exp)
368 rtx_insn *insn;
369 tree fptr = get_frame_arg (exp);
371 if (fptr == NULL_TREE)
372 return;
374 tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
375 tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
376 tree tail = cilk_arrow (worker, CILK_TI_WORKER_TAIL, 1);
378 rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
379 if (GET_CODE (wreg) != REG)
380 wreg = copy_to_reg (wreg);
381 rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
383 /* TMP <- WORKER.TAIL
384 *TMP <- PARENT
385 TMP <- TMP + 1
386 WORKER.TAIL <- TMP */
388 HOST_WIDE_INT worker_tail_offset =
389 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) +
390 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) /
391 BITS_PER_UNIT;
392 rtx tmem0 = gen_rtx_MEM (Pmode,
393 plus_constant (Pmode, wreg, worker_tail_offset));
394 set_mem_attributes (tmem0, tail, 0);
395 MEM_NOTRAP_P (tmem0) = 1;
396 gcc_assert (MEM_VOLATILE_P (tmem0));
397 rtx treg = copy_to_mode_reg (Pmode, tmem0);
398 rtx tmem1 = gen_rtx_MEM (Pmode, treg);
399 set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
400 MEM_NOTRAP_P (tmem1) = 1;
401 emit_move_insn (tmem1, preg);
402 emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
404 /* There is a release barrier (st8.rel, membar #StoreStore,
405 sfence, lwsync, etc.) between the two stores. On x86
406 normal volatile stores have proper semantics; the sfence
407 would only be needed for nontemporal stores (which we
408 could generate using the storent optab, for no benefit
409 in this case).
411 The predicate may return false even for a REG if this is
412 the limited release operation that only stores 0. */
413 enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode);
414 if (icode != CODE_FOR_nothing
415 && insn_data[icode].operand[1].predicate (treg, Pmode)
416 && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
417 emit_insn (insn);
418 else
419 emit_move_insn (tmem0, treg);
421 /* The memory barrier inserted above should not prevent
422 the load of flags from being moved before the stores,
423 but in practice it does because it is implemented with
424 unspec_volatile. In-order RISC machines should
425 explicitly load flags earlier. */
427 tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
428 expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
429 build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
430 build_int_cst (TREE_TYPE (flags),
431 CILK_FRAME_DETACHED))),
432 const0_rtx, VOIDmode, EXPAND_NORMAL);
435 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
437 tree
438 cilk_call_setjmp (tree frame)
440 tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
441 c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
442 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
445 /* This function will expand the _Cilk_sync keyword. */
447 static tree
448 expand_cilk_sync (void)
450 tree frame = cfun->cilk_frame_decl;
452 /* Cilk_sync is converted to the following code:
454 sf.pedigree = sf.worker->pedigree;
455 if (frame.flags & CILK_FRAME_UNSYNCHED)
457 __cilkrts_save_fp_state (&sf);
458 if (!builtin_setjmp (sf.ctx)
459 __cilkrts_sync (&sf);
460 else
461 if (sf.flags & CILK_FRAME_EXCEPTING)
462 __cilkrts_rethrow (&sf);
464 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
466 tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
468 tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
469 build_int_cst (TREE_TYPE (flags),
470 CILK_FRAME_UNSYNCHED));
472 unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
473 build_int_cst (TREE_TYPE (unsynched), 0));
475 tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
477 /* Check if exception (0x10) bit is set in the sf->flags. */
478 tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
479 build_int_cst (TREE_TYPE (flags),
480 CILK_FRAME_EXCEPTING));
481 except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
482 build_int_cst (TREE_TYPE (except_flag), 0));
484 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
485 tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
486 build_call_expr (cilk_rethrow_fndecl, 1,
487 frame_addr),
488 build_empty_stmt (EXPR_LOCATION (unsynched)));
490 tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
491 tree setjmp_expr = cilk_call_setjmp (frame);
492 setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
493 build_int_cst (TREE_TYPE (setjmp_expr), 0));
495 setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
496 sync_expr, except_cond);
497 tree sync_list = alloc_stmt_list ();
498 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
499 frame_addr), &sync_list);
500 append_to_statement_list (setjmp_expr, &sync_list);
501 tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
502 build_empty_stmt (EXPR_LOCATION (unsynched)));
503 tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
504 tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
505 tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
506 tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
507 parent_pedigree, worker_pedigree);
508 tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree),
509 CILK_TI_PEDIGREE_RANK, false);
510 tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
511 w_ped_rank,
512 build_one_cst (TREE_TYPE (w_ped_rank)));
513 incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
514 incr_ped_rank);
515 tree ret_sync_exp = alloc_stmt_list ();
516 append_to_statement_list (assign_pedigree, &ret_sync_exp);
517 append_to_statement_list (sync, &ret_sync_exp);
518 append_to_statement_list (incr_ped_rank, &ret_sync_exp);
519 return ret_sync_exp;
522 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
523 when finished. */
525 void
526 gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
528 tree sync_expr = expand_cilk_sync ();
529 *expr_p = NULL_TREE;
530 gimplify_and_add (sync_expr, pre_p);