161049Sdfr/* mpz_ior -- Logical inclusive or.
261049Sdfr
361049SdfrCopyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012, 2013,
461049Sdfr2015-2018 Free Software Foundation, Inc.
561049Sdfr
661049SdfrThis file is part of the GNU MP Library.
761049Sdfr
861049SdfrThe GNU MP Library is free software; you can redistribute it and/or modify
961049Sdfrit under the terms of either:
1061049Sdfr
1161049Sdfr  * the GNU Lesser General Public License as published by the Free
1261049Sdfr    Software Foundation; either version 3 of the License, or (at your
1361049Sdfr    option) any later version.
1461049Sdfr
1561049Sdfror
1661049Sdfr
1761049Sdfr  * the GNU General Public License as published by the Free Software
1861049Sdfr    Foundation; either version 2 of the License, or (at your option) any
1961049Sdfr    later version.
2061049Sdfr
2161049Sdfror both in parallel, as here.
2261049Sdfr
2361049SdfrThe GNU MP Library is distributed in the hope that it will be useful, but
2461049SdfrWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2561049Sdfror FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
2661049Sdfrfor more details.
2761049Sdfr
2861049SdfrYou should have received copies of the GNU General Public License and the
2961049SdfrGNU Lesser General Public License along with the GNU MP Library.  If not,
3061049Sdfrsee https://www.gnu.org/licenses/.  */
31262065Savg
3261049Sdfr#include "gmp-impl.h"
3361049Sdfr
3461049Sdfrvoid
3561049Sdfrmpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
3661049Sdfr{
3761049Sdfr  mp_srcptr op1_ptr, op2_ptr;
3884306Sru  mp_size_t op1_size, op2_size;
3988509Sdavidc  mp_ptr res_ptr;
4088509Sdavidc  mp_size_t res_size;
4184306Sru  mp_size_t i;
4284306Sru
4361049Sdfr  op1_size = SIZ(op1);
44136971Sbms  op2_size = SIZ(op2);
4561049Sdfr
4661049Sdfr  if (op1_size < op2_size)
4761049Sdfr    {
4861049Sdfr      MPZ_SRCPTR_SWAP (op1, op2);
4961049Sdfr      MP_SIZE_T_SWAP (op1_size, op2_size);
50145740Ssam    }
51145740Ssam
52136971Sbms  op1_ptr = PTR(op1);
5361049Sdfr  res_ptr = PTR(res);
5461049Sdfr
55221060Skib  if (op2_size >= 0)
56248649Swill    {
57248649Swill      if (res_ptr != op1_ptr)
58248649Swill	{
59248649Swill	  res_ptr = MPZ_REALLOC (res, op1_size);
60248649Swill	  /* No overlapping possible: op1_ptr = PTR(op1); */
61248649Swill	  MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
62248649Swill		    op1_size - op2_size);
63221060Skib	}
6461049Sdfr      if (LIKELY (op2_size != 0))
6561049Sdfr	mpn_ior_n (res_ptr, op1_ptr, PTR(op2), op2_size);
66179214Sgonzo
67179778Sgonzo      SIZ(res) = op1_size;
68179778Sgonzo    }
69248649Swill  else
70248649Swill    {
7161049Sdfr      mp_ptr opx;
72248649Swill      TMP_DECL;
73248649Swill
7461049Sdfr      TMP_MARK;
7561049Sdfr      if (op1_size < 0)
7661049Sdfr	{
77124066Sscottl	  mp_ptr opy;
78124066Sscottl
79215011Smdf	  /* Both operands are negative, so will be the result.
80221060Skib	     -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) =
81221060Skib	     = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 =
82215011Smdf	     = ((OP1 - 1) & (OP2 - 1)) + 1      */
83221060Skib
84221060Skib	  res_size = -op1_size;
8561049Sdfr
86146412Sglebius	  /* Possible optimization: Decrease mpn_sub precision,
87221060Skib	     as we won't use the entire res of both.  */
88221060Skib	  TMP_ALLOC_LIMBS_2 (opx, res_size, opy, res_size);
89262065Savg	  mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1);
90262065Savg	  op1_ptr = opx;
91262065Savg
92262065Savg	  mpn_sub_1 (opy, PTR(op2), res_size, (mp_limb_t) 1);
93262065Savg	  op2_ptr = opy;
94262065Savg
95196295Spjd	  /* First loop finds the size of the result.  */
96196295Spjd	  for (i = res_size; --i >= 0;)
97213739Smdf	    if ((op1_ptr[i] & op2_ptr[i]) != 0)
98213813Smdf	      break;
99221060Skib	  res_size = i + 1;
100228715Sjhb
10161049Sdfr	  res_ptr = MPZ_NEWALLOC (res, res_size + 1);
10288509Sdavidc
103179778Sgonzo	  if (res_size != 0)
104133305Sjmg	    {
105179778Sgonzo	      /* Second loop computes the real result.  */
106221060Skib	      mpn_and_n (res_ptr, op1_ptr, op2_ptr, res_size);
10761049Sdfr
10861049Sdfr	      res_ptr[res_size] = 0;
10961049Sdfr	      MPN_INCR_U (res_ptr, res_size + 1, 1);
11061049Sdfr	      res_size += res_ptr[res_size];
11161049Sdfr	    }
11261049Sdfr	  else
11361049Sdfr	    {
11461049Sdfr	      res_ptr[0] = 1;
11561049Sdfr	      res_size = 1;
116145740Ssam	    }
11761049Sdfr
11861049Sdfr	  SIZ(res) = -res_size;
119145740Ssam	}
12061049Sdfr      else
121145740Ssam	{
122145740Ssam	  mp_limb_t cy;
12361049Sdfr	  mp_size_t count;
124145740Ssam
125145740Ssam	  /* Operand 2 negative, so will be the result.
126145740Ssam	     -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) =
12761049Sdfr	     = ~(OP1 | ~(OP2 - 1)) + 1 =
128145740Ssam	     = (~OP1 & (OP2 - 1)) + 1      */
129145740Ssam
130145740Ssam	  op2_size = -op2_size;
13161049Sdfr
13261049Sdfr	  res_ptr = MPZ_REALLOC (res, op2_size);
133145740Ssam	  op1_ptr = PTR(op1);
134145740Ssam
135145740Ssam	  opx = TMP_ALLOC_LIMBS (op2_size);
136233648Seadler	  mpn_sub_1 (opx, PTR(op2), op2_size, (mp_limb_t) 1);
137233648Seadler	  op2_ptr = opx;
138179778Sgonzo	  op2_size -= op2_ptr[op2_size - 1] == 0;
139179778Sgonzo
14061049Sdfr	  if (op1_size >= op2_size)
14161049Sdfr	    {
14261049Sdfr	      /* We can just ignore the part of OP1 that stretches above OP2,
143196358Spjd		 because the result limbs are zero there.  */
144145740Ssam
145145740Ssam	      /* First loop finds the size of the result.  */
14661049Sdfr	      for (i = op2_size; --i >= 0;)
147248649Swill		if ((~op1_ptr[i] & op2_ptr[i]) != 0)
148248649Swill		  break;
149248649Swill	      res_size = i + 1;
150248649Swill	      count = res_size;
151248649Swill	    }
152248649Swill	  else
153248649Swill	    {
154248649Swill	      res_size = op2_size;
155248649Swill
156248649Swill	      /* Copy the part of OP2 that stretches above OP1, to RES.  */
157248649Swill	      MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
158248649Swill	      count = op1_size;
159248649Swill	    }
160248649Swill
161248649Swill	  if (res_size != 0)
162248649Swill	    {
163248649Swill	      /* Second loop computes the real result.  */
16461049Sdfr	      if (LIKELY (count != 0))
16561049Sdfr		mpn_andn_n (res_ptr, op2_ptr, op1_ptr, count);
16661049Sdfr
16761049Sdfr	      cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
16861049Sdfr	      if (cy)
16961049Sdfr		{
17061049Sdfr		  res_ptr[res_size] = cy;
171225570Sadrian		  ++res_size;
17261049Sdfr		}
17361049Sdfr	    }
17461049Sdfr	  else
17561049Sdfr	    {
17661049Sdfr	      res_ptr[0] = 1;
17761049Sdfr	      res_size = 1;
17861049Sdfr	    }
17969052Sru
18061049Sdfr	  SIZ(res) = -res_size;
18161049Sdfr	}
182124066Sscottl      TMP_FREE;
183124066Sscottl    }
184124066Sscottl}
185124066Sscottl