coan 4.2.4
integer_ops.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2004, 2006 Symbian Software Ltd.                        *
00003  *   All rights reserved.                                                  *
00004  *   Copyright (C) 2007-2011 Mike Kinghan, imk@strudl.org                  *
00005  *   All rights reserved.                                                  *
00006  *                                                                         *
00007  *   Contributed originally by Mike Kinghan, imk@strudl.org                *
00008  *                                                                         *
00009  *   Redistribution and use in source and binary forms, with or without    *
00010  *   modification, are permitted provided that the following conditions    *
00011  *   are met:                                                              *
00012  *                                                                         *
00013  *   Redistributions of source code must retain the above copyright        *
00014  *   notice, this list of conditions and the following disclaimer.         *
00015  *                                                                         *
00016  *   Redistributions in binary form must reproduce the above copyright     *
00017  *   notice, this list of conditions and the following disclaimer in the   *
00018  *   documentation and/or other materials provided with the distribution.  *
00019  *                                                                         *
00020  *   Neither the name of Symbian Software Ltd. nor the names of its        *
00021  *   contributors may be used to endorse or promote products derived from  *
00022  *   this software without specific prior written permission.              *
00023  *                                                                         *
00024  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   *
00025  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     *
00026  *   LIMITED TO, THE IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS    *
00027  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE        *
00028  *   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,   *
00029  *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  *
00030  *   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
00031  *   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    *
00032  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,*
00033  *   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
00034  *   THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH  *
00035  *   DAMAGE.                                                               *
00036  *                                                                         *
00037  **************************************************************************/
00038 
00039 #include "integer_ops.h"
00040 #include "report.h"
00041 
00049 
00050 /* Helpers */
00051 
00057 static int
00058 sign(int_spec_t const *int_spec)
00059 {
00060     switch(int_spec->type) {
00061     case INT_INT:
00062         return int_spec->val.i  < 0 ? -1 : 1;
00063     case INT_UINT:
00064         return 1;
00065     case INT_LONG:
00066         return int_spec->val.l  < 0L ? -1 : 1;
00067     case INT_ULONG:
00068         return 1;
00069     case INT_LLONG:
00070         return int_spec->val.ll  < 0LL ? -1 : 1;
00071     case INT_ULLONG:
00072         return 1;
00073     default:
00074         return 0;
00075     }
00076 }
00077 
00078 
00092 static void
00093 sign_extend(int_spec_t * converted, int_spec_t const * unconverted)
00094 {
00095     if (IS_SIGNED(unconverted->type) && sign(unconverted) == -1 &&
00096             RANK(converted->type) > RANK(unconverted->type)) {
00097         switch(converted->type) {
00098         case INT_LONG:
00099         case INT_ULONG:
00100             switch(unconverted->type) {
00101             case INT_INT:
00102                 converted->val.ul = unconverted->val.i;
00103                 break;
00104             default:
00105                 assert(false);
00106             }
00107             break;
00108         case INT_LLONG:
00109         case INT_ULLONG:
00110             switch(unconverted->type) {
00111             case INT_INT:
00112                 converted->val.ull = unconverted->val.i;
00113                 break;
00114             case INT_LONG:
00115                 converted->val.ull = unconverted->val.l;
00116                 break;
00117             default:
00118                 assert(false);
00119             }
00120             break;
00121         default:
00122             assert(false);
00123         }
00124     }
00125 }
00126 
00140 static void
00141 do_usual_conversions(int_spec_t const * l, int_spec_t const *r, int_spec_t *cl, int_spec_t *cr)
00142 {
00143     int_type lhs = l->type;
00144     int_type rhs = r->type;
00145     int_spec_t * post_sign_changed = NULL;
00146     int_spec_t const * pre_sign_changed = NULL;
00147 
00148     /* Initialise the converted operands with the unconverted operands */
00149     *cl = *l;
00150     *cr = *r;
00151 
00152     /* if both operands have the same type, then no further conversion is needed. */
00153     if (lhs == rhs) {
00154         return;
00155     }
00156     /* Otherwise, if both operands have signed integer types or both have unsigned
00157     integer types, the operand with the type of lesser integer conversion rank is
00158     converted to the type of the operand with greater rank. */
00159     if (IS_SIGNED(lhs) == IS_SIGNED(rhs)) {
00160         cl->type = cr->type = RANK(lhs) > RANK(rhs) ? lhs : rhs;
00161         return;
00162 
00163     }
00164     /* Otherwise, if the operand that has unsigned integer type has rank greater or
00165     equal to the rank of the type of the other operand, then the operand with
00166     signed integer type is converted to the type of the operand with unsigned
00167     integer type. */
00168     if (!IS_SIGNED(lhs) && RANK(lhs) >= RANK(rhs)) {
00169         post_sign_changed = cr;
00170         pre_sign_changed = r;
00171         cr->type = cl->type;
00172     }
00173     else if (!IS_SIGNED(rhs) && RANK(rhs) >= RANK(lhs)) {
00174         post_sign_changed = cl;
00175         pre_sign_changed = l;
00176         cl->type = cr->type;
00177     }
00178     /* Otherwise, if the type of the operand with signed integer type can represent
00179     all of the values of the type of the operand with unsigned integer type, then
00180     the operand with unsigned integer type is converted to the type of the
00181     operand with signed integer type. */
00182     else if (IS_SIGNED(lhs) && SIZEOF(lhs) > SIZEOF(rhs)) {
00183         post_sign_changed = cr;
00184         pre_sign_changed = r;
00185         cr->type = cl->type;
00186     }
00187     else if (IS_SIGNED(rhs) && SIZEOF(rhs) > SIZEOF(lhs)) {
00188         post_sign_changed = cl;
00189         pre_sign_changed = l;
00190         cl->type = cr->type;
00191     }
00192     /* Otherwise, both operands are converted to the unsigned integer type
00193     corresponding to the type of the operand with signed integer type. */
00194     else if (IS_SIGNED(lhs)) {
00195         post_sign_changed = cl;
00196         pre_sign_changed = l;
00197         cl->type = cr->type = MAKE_UNSIGNED(lhs);
00198 
00199     }
00200     else if (IS_SIGNED(rhs)) {
00201         post_sign_changed = cr;
00202         pre_sign_changed = r;
00203         cl->type = cr->type = MAKE_UNSIGNED(rhs);
00204     }
00205     if (post_sign_changed) {
00206         sign_extend(post_sign_changed,pre_sign_changed);
00207         if (sign(post_sign_changed) != sign(pre_sign_changed)) {
00208             char *orig = format_int(pre_sign_changed);
00209             char *converted = format_int(post_sign_changed);
00210             report(GRIPE_SIGN_CHANGED,NULL,"Integer %s changed to %s by the usual arithmetic conversions",
00211                    orig,converted);
00212             free(orig);
00213             free(converted);
00214         }
00215     }
00216 }
00217 
00226 static bool
00227 check_shift_validity(char const *direction, int_type type, int_spec_t const * shiftval)
00228 {
00229     bool ok = true;
00230     unsigned type_bits = SIZEOF(type) * 8;
00231     unsigned long long val = shiftval->val.ull;
00232     if (IS_SIGNED(shiftval->type)) {
00233         unsigned long long neg_bit =   (unsigned long long)1 << (type_bits - 1);
00234         if (val & neg_bit) {
00235             report(GRIPE_NEGATIVE_SHIFT,NULL,"Negative %s-shift has undefined behavior. "
00236                    "The expression will not be resolved",direction);
00237             ok = false;
00238         }
00239     }
00240     if (ok && val >= type_bits) {
00241         report(GRIPE_SHIFT_OVERFLOW,NULL,"Shifting a quantity passed its width has undefined behavior. The expression will not be resolved");
00242         ok = false;
00243     }
00244     return ok;
00245 }
00246 
00249 /* API*/
00250 
00251 int_spec_t
00252 lt(int_spec_t const * l, int_spec_t const *r)
00253 {
00254     int_spec_t result = {INT_UNION_INITOR,INT_INT};
00255     int_spec_t cl,cr;
00256     do_usual_conversions(l,r,&cl,&cr);
00257     result.type = cl.type;
00258     switch(result.type) {
00259     case INT_INT:
00260         result.val.i = cl.val.i < cr.val.i;
00261         break;
00262     case INT_UINT:
00263         result.val.i = cl.val.ui < cr.val.ui;
00264         break;
00265     case INT_LONG:
00266         result.val.i = cl.val.l < cr.val.l;
00267         break;
00268     case INT_ULONG:
00269         result.val.i = cl.val.ul < cr.val.ul;
00270         break;
00271     case INT_LLONG:
00272         result.val.i = cl.val.ll < cr.val.ll;
00273         break;
00274     case INT_ULLONG:
00275         result.val.i = cl.val.ull < cr.val.ull;
00276         break;
00277     default:
00278         assert(false);
00279     }
00280     return result;
00281 }
00282 
00283 int_spec_t
00284 gt(int_spec_t const * l, int_spec_t const *r)
00285 {
00286     return lt(r,l);
00287 }
00288 
00289 int_spec_t
00290 le(int_spec_t const * l, int_spec_t const *r)
00291 {
00292     int_spec_t result = INT_SPEC_INITOR;
00293     int_spec_t cl,cr;
00294     do_usual_conversions(l,r,&cl,&cr);
00295     result.type = cl.type;
00296     switch(result.type) {
00297     case INT_INT:
00298         result.val.i = cl.val.i <= cr.val.i;
00299         break;
00300     case INT_UINT:
00301         result.val.i = cl.val.ui <= cr.val.ui;
00302         break;
00303     case INT_LONG:
00304         result.val.i = cl.val.l <= cr.val.l;
00305         break;
00306     case INT_ULONG:
00307         result.val.i = cl.val.ul <= cr.val.ul;
00308         break;
00309     case INT_LLONG:
00310         result.val.i = cl.val.ll <= cr.val.ll;
00311         break;
00312     case INT_ULLONG:
00313         result.val.i = cl.val.ull <= cr.val.ull;
00314         break;
00315     default:
00316         assert(false);
00317     }
00318     return result;
00319 }
00320 
00321 int_spec_t
00322 ge(int_spec_t const * l, int_spec_t const *r)
00323 {
00324     return le(r,l);
00325 }
00326 
00327 int_spec_t
00328 eq(int_spec_t const * l, int_spec_t const *r)
00329 {
00330     int_spec_t result = {INT_UNION_INITOR,INT_INT};
00331     result.val.i = l->val.ll == r->val.ll;
00332     return result;
00333 }
00334 
00335 int_spec_t
00336 ne(int_spec_t const * l, int_spec_t const *r)
00337 {
00338     int_spec_t result = {INT_UNION_INITOR,INT_INT};
00339     result.val.i = l->val.ll != r->val.ll;
00340     return result;
00341 
00342 }
00343 
00344 int_spec_t
00345 bit_and(int_spec_t const * l, int_spec_t const *r)
00346 {
00347     int_spec_t result = INT_SPEC_INITOR;
00348     int_spec_t cl,cr;
00349     do_usual_conversions(l,r,&cl,&cr);
00350     result.type = cl.type;
00351     result.val.ll = cl.val.ll & cr.val.ll;
00352     return result;
00353 }
00354 
00355 int_spec_t
00356 bit_or(int_spec_t const * l, int_spec_t const *r)
00357 {
00358     int_spec_t result = INT_SPEC_INITOR;
00359     int_spec_t cl,cr;
00360     do_usual_conversions(l,r,&cl,&cr);
00361     result.type = cl.type;
00362     result.val.ll = cl.val.ll | cr.val.ll;
00363     return result;
00364 }
00365 
00366 int_spec_t
00367 bit_xor(int_spec_t const * l, int_spec_t const *r)
00368 {
00369     int_spec_t result = INT_SPEC_INITOR;
00370     int_spec_t cl,cr;
00371     do_usual_conversions(l,r,&cl,&cr);
00372     result.type = cl.type;
00373     result.val.ll = cl.val.ll ^ cr.val.ll;
00374     return result;
00375 }
00376 
00377 int_spec_t
00378 complement(int_spec_t const * int_spec)
00379 {
00380     int_spec_t result = INT_SPEC_INITOR;
00381     result.type = int_spec->type;
00382     switch(result.type) {
00383     case INT_INT:
00384     case INT_UINT:
00385         result.val.ui = ~int_spec->val.ui;
00386         break;
00387     case INT_LONG:
00388     case INT_ULONG:
00389         result.val.ul = ~int_spec->val.ul;
00390         break;
00391     case INT_LLONG:
00392     case INT_ULLONG:
00393         result.val.ull = ~int_spec->val.ull;
00394     default:
00395         assert(false);
00396     }
00397     return result;
00398 }
00399 
00400 int_spec_t
00401 minus(int_spec_t const * int_spec)
00402 {
00403     int_spec_t result = INT_SPEC_INITOR;
00404     result.type = int_spec->type;
00405     switch(result.type) {
00406     case INT_INT:
00407         result.val.i = -int_spec->val.i;
00408         break;
00409     case INT_UINT:
00410         result.val.ui = -int_spec->val.ui;
00411         break;
00412     case INT_LONG:
00413         result.val.l = -int_spec->val.l;
00414         break;
00415     case INT_ULONG:
00416         result.val.ul = -int_spec->val.ul;
00417         break;
00418     case INT_LLONG:
00419         result.val.ll = -int_spec->val.ll;
00420         break;
00421     case INT_ULLONG:
00422         result.val.ull = -int_spec->val.ull;
00423         break;
00424     default:
00425         assert(false);
00426     }
00427     return result;
00428 }
00429 
00430 int_spec_t
00431 lshift(int_spec_t const * l, int_spec_t const *r)
00432 {
00433     int_spec_t result = INT_SPEC_INITOR;
00434     int_type type = l->type;
00435     bool valid_shift = check_shift_validity("left",type,r);
00436     if (valid_shift) {
00437         result.type = type;
00438         switch(type) {
00439         case INT_INT:
00440             result.val.i = l->val.i << r->val.i;
00441             break;
00442         case INT_UINT:
00443             result.val.ui = l->val.ui << r->val.i;
00444             break;
00445         case INT_LONG:
00446             result.val.l = l->val.l << r->val.i;
00447             break;
00448         case INT_ULONG:
00449             result.val.ul = l->val.ul << r->val.i;
00450             break;
00451         case INT_LLONG:
00452             result.val.ll = l->val.ll << r->val.i;
00453             break;
00454         case INT_ULLONG:
00455             result.val.ull = l->val.ull << r->val.i;
00456             break;
00457         default:
00458             assert(false);
00459         }
00460     }
00461     return result;
00462 }
00463 
00464 int_spec_t
00465 rshift(int_spec_t const * l, int_spec_t const *r)
00466 {
00467     int_spec_t result = INT_SPEC_INITOR;
00468     int_type type = l->type;
00469     bool valid_shift = check_shift_validity("left",type,r);
00470     if (valid_shift) {
00471         result.type = type;
00472         switch(type) {
00473         case INT_INT:
00474             result.val.i = l->val.i >> r->val.i;
00475             break;
00476         case INT_UINT:
00477             result.val.ui = l->val.ui >> r->val.i;
00478             break;
00479         case INT_LONG:
00480             result.val.l = l->val.l >> r->val.i;
00481             break;
00482         case INT_ULONG:
00483             result.val.ul = l->val.ul >> r->val.i;
00484             break;
00485         case INT_LLONG:
00486             result.val.ll = l->val.ll >> r->val.i;
00487             break;
00488         case INT_ULLONG:
00489             result.val.ull = l->val.ull >> r->val.i;
00490             break;
00491         default:
00492             assert(false);
00493         }
00494     }
00495     return result;
00496 }
00497 
00498 int_spec_t
00499 add(int_spec_t const * l, int_spec_t const *r)
00500 {
00501     int_spec_t result = INT_SPEC_INITOR;
00502     int_spec_t cl,cr;
00503     do_usual_conversions(l,r,&cl,&cr);
00504     result.type = cl.type;
00505     switch(result.type) {
00506     case INT_INT:
00507         result.val.i = cl.val.i + cr.val.i;
00508         break;
00509     case INT_UINT:
00510         result.val.ui = cl.val.ui + cr.val.ui;
00511         break;
00512     case INT_LONG:
00513         result.val.l = cl.val.l + cr.val.l;
00514         break;
00515     case INT_ULONG:
00516         result.val.ul = cl.val.ul + cr.val.ul;
00517         break;
00518     case INT_LLONG:
00519         result.val.ll = cl.val.ll + cr.val.ll;
00520         break;
00521     case INT_ULLONG:
00522         result.val.ull = cl.val.ull + cr.val.ull;
00523         break;
00524     default:
00525         assert(false);
00526     }
00527     return result;
00528 }
00529 
00530 int_spec_t
00531 subtract(int_spec_t const * l, int_spec_t const *r)
00532 {
00533     int_spec_t result = INT_SPEC_INITOR;
00534     int_spec_t cl,cr;
00535     do_usual_conversions(l,r,&cl,&cr);
00536     result.type = cl.type;
00537     switch(result.type) {
00538     case INT_INT:
00539         result.val.i = cl.val.i - cr.val.i;
00540         break;
00541     case INT_UINT:
00542         result.val.ui = cl.val.ui - cr.val.ui;
00543         break;
00544     case INT_LONG:
00545         result.val.l = cl.val.l - cr.val.l;
00546         break;
00547     case INT_ULONG:
00548         result.val.ul = cl.val.ul - cr.val.ul;
00549         break;
00550     case INT_LLONG:
00551         result.val.ll = cl.val.ll - cr.val.ll;
00552         break;
00553     case INT_ULLONG:
00554         result.val.ull = cl.val.ull - cr.val.ull;
00555         break;
00556     default:
00557         assert(false);
00558     }
00559     return result;
00560 }
00561 
00562 int_spec_t
00563 multiply(int_spec_t const * l, int_spec_t const *r)
00564 {
00565     int_spec_t result = INT_SPEC_INITOR;
00566     int_spec_t cl,cr;
00567     do_usual_conversions(l,r,&cl,&cr);
00568     result.type = cl.type;
00569     switch(result.type) {
00570     case INT_INT:
00571         result.val.i = cl.val.i * cr.val.i;
00572         break;
00573     case INT_UINT:
00574         result.val.ui = cl.val.ui * cr.val.ui;
00575         break;
00576     case INT_LONG:
00577         result.val.l = cl.val.l * cr.val.l;
00578         break;
00579     case INT_ULONG:
00580         result.val.ul = cl.val.ul * cr.val.ul;
00581         break;
00582     case INT_LLONG:
00583         result.val.ll = cl.val.ll * cr.val.ll;
00584         break;
00585     case INT_ULLONG:
00586         result.val.ull = cl.val.ull * cr.val.ull;
00587         break;
00588     default:
00589         assert(false);
00590     }
00591     return result;
00592 }
00593 
00594 int_spec_t
00595 divide(int_spec_t const * l, int_spec_t const *r)
00596 {
00597     int_spec_t result = INT_SPEC_INITOR;
00598     int_spec_t cl,cr;
00599     do_usual_conversions(l,r,&cl,&cr);
00600     result.type = cl.type;
00601     switch(result.type) {
00602     case INT_INT:
00603         result.val.i = cl.val.i / cr.val.i;
00604         break;
00605     case INT_UINT:
00606         result.val.ui = cl.val.ui / cr.val.ui;
00607         break;
00608     case INT_LONG:
00609         result.val.l = cl.val.l / cr.val.l;
00610         break;
00611     case INT_ULONG:
00612         result.val.ul = cl.val.ul / cr.val.ul;
00613         break;
00614     case INT_LLONG:
00615         result.val.ll = cl.val.ll / cr.val.ll;
00616         break;
00617     case INT_ULLONG:
00618         result.val.ull = cl.val.ull / cr.val.ull;
00619         break;
00620     default:
00621         assert(false);
00622     }
00623     return result;
00624 }
00625 
00626 int_spec_t
00627 modulus(int_spec_t const * l, int_spec_t const *r)
00628 {
00629     int_spec_t result = INT_SPEC_INITOR;
00630     int_spec_t cl,cr;
00631     do_usual_conversions(l,r,&cl,&cr);
00632     result.type = cl.type;
00633     switch(result.type) {
00634     case INT_INT:
00635         result.val.i = cl.val.i % cr.val.i;
00636         break;
00637     case INT_UINT:
00638         result.val.ui = cl.val.ui % cr.val.ui;
00639         break;
00640     case INT_LONG:
00641         result.val.l = cl.val.l % cr.val.l;
00642         break;
00643     case INT_ULONG:
00644         result.val.ul = cl.val.ul % cr.val.ul;
00645         break;
00646     case INT_LLONG:
00647         result.val.ll = cl.val.ll % cr.val.ll;
00648         break;
00649     case INT_ULLONG:
00650         result.val.ull = cl.val.ull % cr.val.ull;
00651         break;
00652     default:
00653         assert(false);
00654     }
00655     return result;
00656 }
00657 
00663 int_spec_t
00664 boolean_and(int_spec_t const * l, int_spec_t const *r)
00665 {
00666     int_spec_t result = {INT_UNION_INITOR,INT_INT};
00667     result.val.i = l->val.ull && r->val.ull;
00668     return result;
00669 }
00670 
00676 int_spec_t
00677 boolean_or(int_spec_t const * l, int_spec_t const *r)
00678 {
00679     int_spec_t result = {INT_UNION_INITOR,INT_INT};
00680     result.val.i = l->val.ull || r->val.ull;
00681     return result;
00682 }
00683 
00684 
00689 int_spec_t
00690 negate(int_spec_t const * int_spec)
00691 {
00692     int_spec_t result = {INT_UNION_INITOR,INT_INT};
00693     result.val.i = !int_spec->val.ull;
00694     return result;
00695 }
00696 
00697 
00698 /* EOF*/
00699 
00700 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines