xref: /netbsd-src/external/lgpl3/gmp/dist/mpz/ior.c (revision 8450a7c42673d65e3b1f6560d3b6ecd317a6cbe8)
1 /* mpz_ior -- Logical inclusive or.
2 
3 Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012, 2013 Free
4 Software Foundation, Inc.
5 
6 This file is part of the GNU MP Library.
7 
8 The GNU MP Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The GNU MP Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
20 
21 #include "gmp.h"
22 #include "gmp-impl.h"
23 
24 void
25 mpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
26 {
27   mp_srcptr op1_ptr, op2_ptr;
28   mp_size_t op1_size, op2_size;
29   mp_ptr res_ptr;
30   mp_size_t res_size;
31   mp_size_t i;
32   TMP_DECL;
33 
34   TMP_MARK;
35   op1_size = SIZ(op1);
36   op2_size = SIZ(op2);
37 
38   op1_ptr = PTR(op1);
39   op2_ptr = PTR(op2);
40   res_ptr = PTR(res);
41 
42   if (op1_size >= 0)
43     {
44       if (op2_size >= 0)
45 	{
46 	  if (op1_size >= op2_size)
47 	    {
48 	      if (ALLOC(res) < op1_size)
49 		{
50 		  _mpz_realloc (res, op1_size);
51 		  /* No overlapping possible: op1_ptr = PTR(op1); */
52 		  op2_ptr = PTR(op2);
53 		  res_ptr = PTR(res);
54 		}
55 
56 	      if (res_ptr != op1_ptr)
57 		MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
58 			  op1_size - op2_size);
59 	      if (LIKELY (op2_size != 0))
60 		mpn_ior_n (res_ptr, op1_ptr, op2_ptr, op2_size);
61 	      res_size = op1_size;
62 	    }
63 	  else
64 	    {
65 	      if (ALLOC(res) < op2_size)
66 		{
67 		  _mpz_realloc (res, op2_size);
68 		  op1_ptr = PTR(op1);
69 		  /* No overlapping possible: op2_ptr = PTR(op2); */
70 		  res_ptr = PTR(res);
71 		}
72 
73 	      if (res_ptr != op2_ptr)
74 		MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
75 			  op2_size - op1_size);
76 	      if (LIKELY (op1_size != 0))
77 		mpn_ior_n (res_ptr, op1_ptr, op2_ptr, op1_size);
78 	      res_size = op2_size;
79 	    }
80 
81 	  SIZ(res) = res_size;
82 	  return;
83 	}
84       else /* op2_size < 0 */
85 	{
86 	  /* Fall through to the code at the end of the function.  */
87 	}
88     }
89   else
90     {
91       if (op2_size < 0)
92 	{
93 	  mp_ptr opx, opy;
94 	  mp_limb_t cy;
95 
96 	  /* Both operands are negative, so will be the result.
97 	     -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) =
98 	     = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 =
99 	     = ((OP1 - 1) & (OP2 - 1)) + 1      */
100 
101 	  op1_size = -op1_size;
102 	  op2_size = -op2_size;
103 
104 	  res_size = MIN (op1_size, op2_size);
105 
106 	  /* Possible optimization: Decrease mpn_sub precision,
107 	     as we won't use the entire res of both.  */
108 	  TMP_ALLOC_LIMBS_2 (opx, res_size, opy, res_size);
109 	  mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1);
110 	  op1_ptr = opx;
111 
112 	  mpn_sub_1 (opy, op2_ptr, res_size, (mp_limb_t) 1);
113 	  op2_ptr = opy;
114 
115 	  /* First loop finds the size of the result.  */
116 	  for (i = res_size - 1; i >= 0; i--)
117 	    if ((op1_ptr[i] & op2_ptr[i]) != 0)
118 	      break;
119 	  res_size = i + 1;
120 
121 	  if (res_size != 0)
122 	    {
123 	      res_ptr = MPZ_REALLOC (res, res_size + 1);
124 
125 	      /* Second loop computes the real result.  */
126 	      mpn_and_n (res_ptr, op1_ptr, op2_ptr, res_size);
127 
128 	      cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
129 	      if (cy)
130 		{
131 		  res_ptr[res_size] = cy;
132 		  res_size++;
133 		}
134 	    }
135 	  else
136 	    {
137 	      res_ptr[0] = 1;
138 	      res_size = 1;
139 	    }
140 
141 	  SIZ(res) = -res_size;
142 	  TMP_FREE;
143 	  return;
144 	}
145       else
146 	{
147 	  /* We should compute -OP1 | OP2.  Swap OP1 and OP2 and fall
148 	     through to the code that handles OP1 | -OP2.  */
149 	  MPZ_SRCPTR_SWAP (op1, op2);
150 	  MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
151 	}
152     }
153 
154   {
155     mp_ptr opx;
156     mp_limb_t cy;
157     mp_size_t res_alloc;
158     mp_size_t count;
159 
160     /* Operand 2 negative, so will be the result.
161        -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) =
162        = ~(OP1 | ~(OP2 - 1)) + 1 =
163        = (~OP1 & (OP2 - 1)) + 1      */
164 
165     op2_size = -op2_size;
166 
167     res_alloc = op2_size;
168 
169     opx = TMP_ALLOC_LIMBS (op2_size);
170     mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
171     op2_ptr = opx;
172     op2_size -= op2_ptr[op2_size - 1] == 0;
173 
174     if (ALLOC(res) < res_alloc)
175       {
176 	_mpz_realloc (res, res_alloc);
177 	op1_ptr = PTR(op1);
178 	/* op2_ptr points to temporary space.  */
179 	res_ptr = PTR(res);
180       }
181 
182     if (op1_size >= op2_size)
183       {
184 	/* We can just ignore the part of OP1 that stretches above OP2,
185 	   because the result limbs are zero there.  */
186 
187 	/* First loop finds the size of the result.  */
188 	for (i = op2_size - 1; i >= 0; i--)
189 	  if ((~op1_ptr[i] & op2_ptr[i]) != 0)
190 	    break;
191 	res_size = i + 1;
192 	count = res_size;
193       }
194     else
195       {
196 	res_size = op2_size;
197 
198 	/* Copy the part of OP2 that stretches above OP1, to RES.  */
199 	MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
200 	count = op1_size;
201       }
202 
203     if (res_size != 0)
204       {
205 	/* Second loop computes the real result.  */
206 	if (LIKELY (count != 0))
207 	  mpn_andn_n (res_ptr, op2_ptr, op1_ptr, count);
208 
209 	cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
210 	if (cy)
211 	  {
212 	    res_ptr[res_size] = cy;
213 	    res_size++;
214 	  }
215       }
216     else
217       {
218 	res_ptr[0] = 1;
219 	res_size = 1;
220       }
221 
222     SIZ(res) = -res_size;
223   }
224   TMP_FREE;
225 }
226