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