summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-02 21:31:57 +0000
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-02 21:31:57 +0000
commit9d651ea6c5f1828da09b9b759030e95bd25002cc (patch)
tree5e7dd3cafaad2526a4126abfd48740a3a4fbdac8
parent9adc3d5787f8b3221c6664aadc35783db15b69dc (diff)
downloadgcc-9d651ea6c5f1828da09b9b759030e95bd25002cc.tar.gz
gcc/
PR target/51931 * config/mips/mips-protos.h (mips_strip_unspec_address): Declare. * config/mips/mips.c (mips_strip_unspec_address): Make extern. (mips16_rewrite_pool_constant): Make a copy of the pool constant before adding to a PC-relative table. (mips16_lay_out_constants): Add a SPLIT_P parameter. (mips16_load_branch_target, mips16_split_long_branches): New functions. (mips_reorg): Update call to mips16_lay_out_constants. Call mips16_split_long_branches. * config/mips/predicates.md (pc_or_label_operand): Delete. * config/mips/mips.md (length): Add a calculation for MIPS16 branches. Move the extended_mips16 handling further down. (*branch_equality<mode>_mips16): Replace use pc_or_label_operand with explicit label_ref and pc. Follow the usual operand numbering. (*branch_equality<mode>_mips16_inverted): New pattern. (*jump_mips16): Add length attribute. (indirect_jump_and_restore_<mode>): New pattern. (consttable_int): Call mips_strip_unspec_address on the operand. gcc/testsuite/ PR target/51931 * gcc.c-torture/compile/20001226-1.c: Remove nomips16 attribute. * g++.dg/opt/longbranch1.C: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@190104 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog21
-rw-r--r--gcc/config/mips/mips-protos.h1
-rw-r--r--gcc/config/mips/mips.c129
-rw-r--r--gcc/config/mips/mips.md198
-rw-r--r--gcc/config/mips/predicates.md3
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/opt/longbranch1.C4
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20001226-1.c4
8 files changed, 313 insertions, 53 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 524ae209da8..61062b80561 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,26 @@
2012-08-02 Richard Sandiford <rdsandiford@googlemail.com>
+ PR target/51931
+ * config/mips/mips-protos.h (mips_strip_unspec_address): Declare.
+ * config/mips/mips.c (mips_strip_unspec_address): Make extern.
+ (mips16_rewrite_pool_constant): Make a copy of the pool constant
+ before adding to a PC-relative table.
+ (mips16_lay_out_constants): Add a SPLIT_P parameter.
+ (mips16_load_branch_target, mips16_split_long_branches): New functions.
+ (mips_reorg): Update call to mips16_lay_out_constants.
+ Call mips16_split_long_branches.
+ * config/mips/predicates.md (pc_or_label_operand): Delete.
+ * config/mips/mips.md (length): Add a calculation for MIPS16 branches.
+ Move the extended_mips16 handling further down.
+ (*branch_equality<mode>_mips16): Replace use pc_or_label_operand
+ with explicit label_ref and pc. Follow the usual operand numbering.
+ (*branch_equality<mode>_mips16_inverted): New pattern.
+ (*jump_mips16): Add length attribute.
+ (indirect_jump_and_restore_<mode>): New pattern.
+ (consttable_int): Call mips_strip_unspec_address on the operand.
+
+2012-08-02 Richard Sandiford <rdsandiford@googlemail.com>
+
* recog.c (split_insn): Copy the original SET_SRC before using
it as a note.
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index cba76b6672b..bae67a83041 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -190,6 +190,7 @@ extern rtx mips_pic_base_register (rtx);
extern rtx mips_got_load (rtx, rtx, enum mips_symbol_type);
extern bool mips_split_symbol (rtx, rtx, enum machine_mode, rtx *);
extern rtx mips_unspec_address (rtx, enum mips_symbol_type);
+extern rtx mips_strip_unspec_address (rtx);
extern void mips_move_integer (rtx, rtx, unsigned HOST_WIDE_INT);
extern bool mips_legitimize_move (enum machine_mode, rtx, rtx);
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index e9e4ec10c43..ef1cccdcbe7 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -2563,7 +2563,7 @@ mips_unspec_address (rtx address, enum mips_symbol_type symbol_type)
/* If OP is an UNSPEC address, return the address to which it refers,
otherwise return OP itself. */
-static rtx
+rtx
mips_strip_unspec_address (rtx op)
{
rtx base, offset;
@@ -14070,7 +14070,7 @@ mips16_rewrite_pool_constant (struct mips16_constant_pool *pool, rtx *x)
split_const (*x, &base, &offset);
if (GET_CODE (base) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (base))
{
- label = mips16_add_constant (pool, get_pool_constant (base),
+ label = mips16_add_constant (pool, copy_rtx (get_pool_constant (base)),
get_pool_mode (base));
base = gen_rtx_LABEL_REF (Pmode, label);
*x = mips_unspec_address_offset (base, offset, SYMBOL_PC_RELATIVE);
@@ -14126,10 +14126,11 @@ mips_cfg_in_reorg (void)
|| TARGET_RELAX_PIC_CALLS);
}
-/* Build MIPS16 constant pools. */
+/* Build MIPS16 constant pools. Split the instructions if SPLIT_P,
+ otherwise assume that they are already split. */
static void
-mips16_lay_out_constants (void)
+mips16_lay_out_constants (bool split_p)
{
struct mips16_constant_pool pool;
struct mips16_rewrite_pool_refs_info info;
@@ -14138,10 +14139,13 @@ mips16_lay_out_constants (void)
if (!TARGET_MIPS16_PCREL_LOADS)
return;
- if (mips_cfg_in_reorg ())
- split_all_insns ();
- else
- split_all_insns_noflow ();
+ if (split_p)
+ {
+ if (mips_cfg_in_reorg ())
+ split_all_insns ();
+ else
+ split_all_insns_noflow ();
+ }
barrier = 0;
memset (&pool, 0, sizeof (pool));
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
@@ -15490,6 +15494,110 @@ mips_df_reorg (void)
df_finish_pass (false);
}
+/* Emit code to load LABEL_REF SRC into MIPS16 register DEST. This is
+ called very late in mips_reorg, but the caller is required to run
+ mips16_lay_out_constants on the result. */
+
+static void
+mips16_load_branch_target (rtx dest, rtx src)
+{
+ if (TARGET_ABICALLS && !TARGET_ABSOLUTE_ABICALLS)
+ {
+ rtx page, low;
+
+ if (mips_cfun_has_cprestore_slot_p ())
+ mips_emit_move (dest, mips_cprestore_slot (dest, true));
+ else
+ mips_emit_move (dest, pic_offset_table_rtx);
+ page = mips_unspec_address (src, SYMBOL_GOTOFF_PAGE);
+ low = mips_unspec_address (src, SYMBOL_GOT_PAGE_OFST);
+ emit_insn (gen_rtx_SET (VOIDmode, dest,
+ PMODE_INSN (gen_unspec_got, (dest, page))));
+ emit_insn (gen_rtx_SET (VOIDmode, dest,
+ gen_rtx_LO_SUM (Pmode, dest, low)));
+ }
+ else
+ {
+ src = mips_unspec_address (src, SYMBOL_ABSOLUTE);
+ mips_emit_move (dest, src);
+ }
+}
+
+/* If we're compiling a MIPS16 function, look for and split any long branches.
+ This must be called after all other instruction modifications in
+ mips_reorg. */
+
+static void
+mips16_split_long_branches (void)
+{
+ bool something_changed;
+
+ if (!TARGET_MIPS16)
+ return;
+
+ /* Loop until the alignments for all targets are sufficient. */
+ do
+ {
+ rtx insn;
+
+ shorten_branches (get_insns ());
+ something_changed = false;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (JUMP_P (insn)
+ && USEFUL_INSN_P (insn)
+ && get_attr_length (insn) > 8)
+ {
+ rtx old_label, new_label, temp, saved_temp;
+ rtx target, jump, jump_sequence;
+
+ start_sequence ();
+
+ /* Free up a MIPS16 register by saving it in $1. */
+ saved_temp = gen_rtx_REG (Pmode, AT_REGNUM);
+ temp = gen_rtx_REG (Pmode, GP_REG_FIRST + 2);
+ emit_move_insn (saved_temp, temp);
+
+ /* Load the branch target into TEMP. */
+ old_label = JUMP_LABEL (insn);
+ target = gen_rtx_LABEL_REF (Pmode, old_label);
+ mips16_load_branch_target (temp, target);
+
+ /* Jump to the target and restore the register's
+ original value. */
+ jump = emit_jump_insn (PMODE_INSN (gen_indirect_jump_and_restore,
+ (temp, temp, saved_temp)));
+ JUMP_LABEL (jump) = old_label;
+ LABEL_NUSES (old_label)++;
+
+ /* Rewrite any symbolic references that are supposed to use
+ a PC-relative constant pool. */
+ mips16_lay_out_constants (false);
+
+ if (simplejump_p (insn))
+ /* We're going to replace INSN with a longer form. */
+ new_label = NULL_RTX;
+ else
+ {
+ /* Create a branch-around label for the original
+ instruction. */
+ new_label = gen_label_rtx ();
+ emit_label (new_label);
+ }
+
+ jump_sequence = get_insns ();
+ end_sequence ();
+
+ emit_insn_after (jump_sequence, insn);
+ if (new_label)
+ invert_jump (insn, new_label, false);
+ else
+ delete_insn (insn);
+ something_changed = true;
+ }
+ }
+ while (something_changed);
+}
+
/* Implement TARGET_MACHINE_DEPENDENT_REORG. */
static void
@@ -15500,7 +15608,7 @@ mips_reorg (void)
to date if the CFG is available. */
if (mips_cfg_in_reorg ())
compute_bb_for_insn ();
- mips16_lay_out_constants ();
+ mips16_lay_out_constants (true);
if (mips_cfg_in_reorg ())
{
mips_df_reorg ();
@@ -15519,6 +15627,7 @@ mips_reorg (void)
/* The expansion could invalidate some of the VR4130 alignment
optimizations, but this should be an extremely rare case anyhow. */
mips_reorg_process_insns ();
+ mips16_split_long_branches ();
}
/* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
@@ -15639,7 +15748,7 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
insn = get_insns ();
insn_locators_alloc ();
split_all_insns_noflow ();
- mips16_lay_out_constants ();
+ mips16_lay_out_constants (true);
shorten_branches (insn);
final_start_function (insn, file, 1);
final (insn, file, 1);
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index febe07799e6..759958ba460 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -402,11 +402,7 @@
;; Length of instruction in bytes.
(define_attr "length" ""
- (cond [(and (eq_attr "extended_mips16" "yes")
- (match_test "TARGET_MIPS16"))
- (const_int 8)
-
- ;; Direct branch instructions have a range of [-0x20000,0x1fffc],
+ (cond [;; Direct branch instructions have a range of [-0x20000,0x1fffc],
;; relative to the address of the delay slot. If a branch is
;; outside this range, we have a choice of two sequences.
;; For PIC, an out-of-range branch like:
@@ -431,14 +427,21 @@
;; using la/jr in this case too, but we do not do so at
;; present.
;;
- ;; Note that this value does not account for the delay slot
+ ;; The value we specify here does not account for the delay slot
;; instruction, whose length is added separately. If the RTL
;; pattern has no explicit delay slot, mips_adjust_insn_length
- ;; will add the length of the implicit nop. The values for
- ;; forward and backward branches will be different as well.
- (eq_attr "type" "branch")
+ ;; will add the length of the implicit nop. The range of
+ ;; [-0x20000, 0x1fffc] from the address of the delay slot
+ ;; therefore translates to a range of:
+ ;;
+ ;; [-(0x20000 - sizeof (branch)), 0x1fffc - sizeof (slot)]
+ ;; == [-0x1fffc, 0x1fff8]
+ ;;
+ ;; from the shorten_branches reference address.
+ (and (eq_attr "type" "branch")
+ (not (match_test "TARGET_MIPS16")))
(cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
- (le (minus (pc) (match_dup 0)) (const_int 131068)))
+ (le (minus (pc) (match_dup 0)) (const_int 131068)))
(const_int 4)
;; The non-PIC case: branch, first delay slot, and J.
@@ -453,6 +456,100 @@
;; of an insn.
(const_int MAX_PIC_BRANCH_LENGTH))
+ ;; An unextended MIPS16 branch has a range of [-0x100, 0xfe]
+ ;; from the address of the following instruction, which leads
+ ;; to a range of:
+ ;;
+ ;; [-(0x100 - sizeof (branch)), 0xfe]
+ ;; == [-0xfe, 0xfe]
+ ;;
+ ;; from the shorten_branches reference address. Extended branches
+ ;; likewise have a range of [-0x10000, 0xfffe] from the address
+ ;; of the following instruction, which leads to a range of:
+ ;;
+ ;; [-(0x10000 - sizeof (branch)), 0xfffe]
+ ;; == [-0xfffc, 0xfffe]
+ ;;
+ ;; from the reference address.
+ ;;
+ ;; When a branch is out of range, mips_reorg splits it into a form
+ ;; that uses in-range branches. There are four basic sequences:
+ ;;
+ ;; (1) Absolute addressing with a readable text segment
+ ;; (32-bit addresses):
+ ;;
+ ;; b... foo 2 bytes
+ ;; move $1,$2 2 bytes
+ ;; lw $2,label 2 bytes
+ ;; jr $2 2 bytes
+ ;; move $2,$1 2 bytes
+ ;; .align 2 0 or 2 bytes
+ ;; label:
+ ;; .word target 4 bytes
+ ;; foo:
+ ;; (16 bytes in the worst case)
+ ;;
+ ;; (2) Absolute addressing with a readable text segment
+ ;; (64-bit addresses):
+ ;;
+ ;; b... foo 2 bytes
+ ;; move $1,$2 2 bytes
+ ;; ld $2,label 2 bytes
+ ;; jr $2 2 bytes
+ ;; move $2,$1 2 bytes
+ ;; .align 3 0 to 6 bytes
+ ;; label:
+ ;; .dword target 8 bytes
+ ;; foo:
+ ;; (24 bytes in the worst case)
+ ;;
+ ;; (3) Absolute addressing without a readable text segment
+ ;; (which requires 32-bit addresses at present):
+ ;;
+ ;; b... foo 2 bytes
+ ;; move $1,$2 2 bytes
+ ;; lui $2,%hi(target) 4 bytes
+ ;; sll $2,8 2 bytes
+ ;; sll $2,8 2 bytes
+ ;; addiu $2,%lo(target) 4 bytes
+ ;; jr $2 2 bytes
+ ;; move $2,$1 2 bytes
+ ;; foo:
+ ;; (20 bytes)
+ ;;
+ ;; (4) PIC addressing (which requires 32-bit addresses at present):
+ ;;
+ ;; b... foo 2 bytes
+ ;; move $1,$2 2 bytes
+ ;; lw $2,cprestore 0, 2 or 4 bytes
+ ;; lw $2,%got(target)($2) 4 bytes
+ ;; addiu $2,%lo(target) 4 bytes
+ ;; jr $2 2 bytes
+ ;; move $2,$1 2 bytes
+ ;; foo:
+ ;; (20 bytes in the worst case)
+ ;;
+ ;; Note that the conditions test adjusted lengths, whereas the
+ ;; result is an unadjusted length, and is thus twice the true value.
+ (and (eq_attr "type" "branch")
+ (match_test "TARGET_MIPS16"))
+ (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254))
+ (le (minus (pc) (match_dup 0)) (const_int 254)))
+ (const_int 4)
+ (and (le (minus (match_dup 0) (pc)) (const_int 65534))
+ (le (minus (pc) (match_dup 0)) (const_int 65532)))
+ (const_int 8)
+ (and (match_test "TARGET_ABICALLS")
+ (not (match_test "TARGET_ABSOLUTE_ABICALLS")))
+ (const_int 40)
+ (match_test "Pmode == SImode")
+ (const_int 32)
+ ] (const_int 48))
+
+ (and (eq_attr "extended_mips16" "yes")
+ (match_test "TARGET_MIPS16"))
+ (const_int 8)
+
;; "Ghost" instructions occupy no space.
(eq_attr "type" "ghost")
(const_int 0)
@@ -5400,28 +5497,29 @@
(define_insn "*branch_equality<mode>_mips16"
[(set (pc)
(if_then_else
- (match_operator 0 "equality_operator"
- [(match_operand:GPR 1 "register_operand" "d,t")
+ (match_operator 1 "equality_operator"
+ [(match_operand:GPR 2 "register_operand" "d,t")
+ (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "TARGET_MIPS16"
+ "@
+ b%C1z\t%2,%0
+ bt%C1z\t%0"
+ [(set_attr "type" "branch")])
+
+(define_insn "*branch_equality<mode>_mips16_inverted"
+ [(set (pc)
+ (if_then_else
+ (match_operator 1 "equality_operator"
+ [(match_operand:GPR 2 "register_operand" "d,t")
(const_int 0)])
- (match_operand 2 "pc_or_label_operand" "")
- (match_operand 3 "pc_or_label_operand" "")))]
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
"TARGET_MIPS16"
-{
- if (operands[2] != pc_rtx)
- {
- if (which_alternative == 0)
- return "b%C0z\t%1,%2";
- else
- return "bt%C0z\t%2";
- }
- else
- {
- if (which_alternative == 0)
- return "b%N0z\t%1,%3";
- else
- return "bt%N0z\t%3";
- }
-}
+ "@
+ b%N1z\t%2,%0
+ bt%N1z\t%0"
[(set_attr "type" "branch")])
(define_expand "cbranch<mode>4"
@@ -5717,7 +5815,30 @@
(label_ref (match_operand 0 "" "")))]
"TARGET_MIPS16"
"b\t%l0"
- [(set_attr "type" "branch")])
+ [(set_attr "type" "branch")
+ (set (attr "length")
+ ;; This calculation is like the normal branch one, but the
+ ;; range of the unextended instruction is [-0x800, 0x7fe] rather
+ ;; than [-0x100, 0xfe]. This translates to a range of:
+ ;;
+ ;; [-(0x800 - sizeof (branch)), 0x7fe]
+ ;; == [-0x7fe, 0x7fe]
+ ;;
+ ;; from the shorten_branches reference address. Long-branch
+ ;; sequences will replace this one, so the minimum length
+ ;; is one instruction shorter than for conditional branches.
+ (cond [(and (le (minus (match_dup 0) (pc)) (const_int 2046))
+ (le (minus (pc) (match_dup 0)) (const_int 2046)))
+ (const_int 4)
+ (and (le (minus (match_dup 0) (pc)) (const_int 65534))
+ (le (minus (pc) (match_dup 0)) (const_int 65532)))
+ (const_int 8)
+ (and (match_test "TARGET_ABICALLS")
+ (not (match_test "TARGET_ABSOLUTE_ABICALLS")))
+ (const_int 36)
+ (match_test "Pmode == SImode")
+ (const_int 28)
+ ] (const_int 44)))])
(define_expand "indirect_jump"
[(set (pc) (match_operand 0 "register_operand"))]
@@ -5735,6 +5856,18 @@
[(set_attr "type" "jump")
(set_attr "mode" "none")])
+;; A combined jump-and-move instruction, used for MIPS16 long-branch
+;; sequences. Having a dedicated pattern is more convenient than
+;; creating a SEQUENCE for this special case.
+(define_insn "indirect_jump_and_restore_<mode>"
+ [(set (pc) (match_operand:P 1 "register_operand" "d"))
+ (set (match_operand:P 0 "register_operand" "=d")
+ (match_operand:P 2 "register_operand" "y"))]
+ ""
+ "%(%<jr\t%1\;move\t%0,%2%>%)"
+ [(set_attr "type" "multi")
+ (set_attr "extended_mips16" "yes")])
+
(define_expand "tablejump"
[(set (pc)
(match_operand 0 "register_operand"))
@@ -6549,7 +6682,8 @@
UNSPEC_CONSTTABLE_INT)]
"TARGET_MIPS16"
{
- assemble_integer (operands[0], INTVAL (operands[1]),
+ assemble_integer (mips_strip_unspec_address (operands[0]),
+ INTVAL (operands[1]),
BITS_PER_UNIT * INTVAL (operands[1]), 1);
return "";
}
diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md
index 97971e9a205..31c43a53ebb 100644
--- a/gcc/config/mips/predicates.md
+++ b/gcc/config/mips/predicates.md
@@ -139,9 +139,6 @@
(match_operand 0 "hilo_operand")
(match_operand 0 "register_operand")))
-(define_special_predicate "pc_or_label_operand"
- (match_code "pc,label_ref"))
-
(define_predicate "const_call_insn_operand"
(match_code "const,symbol_ref,label_ref")
{
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8ef8e789b38..78a829aaf26 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2012-08-02 Richard Sandiford <rdsandiford@googlemail.com>
+
+ PR target/51931
+ * gcc.c-torture/compile/20001226-1.c: Remove nomips16 attribute.
+ * g++.dg/opt/longbranch1.C: Likewise.
+
2012-08-02 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/53805
diff --git a/gcc/testsuite/g++.dg/opt/longbranch1.C b/gcc/testsuite/g++.dg/opt/longbranch1.C
index df545012cc7..a64a57aea2a 100644
--- a/gcc/testsuite/g++.dg/opt/longbranch1.C
+++ b/gcc/testsuite/g++.dg/opt/longbranch1.C
@@ -26,10 +26,6 @@
muchcode; muchcode; muchcode; muchcode; muchcode; muchcode; \
muchcode; muchcode; muchcode; muchcode; muchcode; muchcode
-#ifdef __mips
-/* See PR 51931. */
-__attribute__((nomips16))
-#endif
int
main (int argc, char **argv)
{
diff --git a/gcc/testsuite/gcc.c-torture/compile/20001226-1.c b/gcc/testsuite/gcc.c-torture/compile/20001226-1.c
index e833fb044c6..127c4daec45 100644
--- a/gcc/testsuite/gcc.c-torture/compile/20001226-1.c
+++ b/gcc/testsuite/gcc.c-torture/compile/20001226-1.c
@@ -21,10 +21,6 @@
#define C1024(x,y) C256(x,y) C256(x+16,y) C256(x+32,y) C256(x+48,y)
#define C4096(x,y) C1024(x,y) C1024(x,y+16) C1024(x,y+32) C1024(x,y+48)
-#ifdef __mips
-/* See PR 51931. */
-__attribute__((nomips16))
-#endif
unsigned foo(int x[64], int y[64])
{
C4096(x,y);