Sync with 5.4.0
[deliverable/titan.core.git] / compiler2 / Int.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "../common/dbgnew.hh"
9 #include "Int.hh"
10 #include "string.hh"
11 #include "error.h"
12 #include "Setting.hh"
13
14 #include <openssl/crypto.h>
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <math.h>
20
21 // We cannot check without using a "./configure" script or such if we have
22 // llabs() or not. Define our own function instead.
23 inline long long ll_abs(long long x) { return ((x >= 0) ? (x) : (-x)); }
24
25 namespace Common {
26
27 string Int2string(const Int& i)
28 {
29 char *s = NULL;
30 s = mprintf("%lld", i);
31 string str(s);
32 Free(s);
33 return str;
34 }
35
36 Int string2Int(const char *s, const Location& loc)
37 {
38 errno = 0;
39 Int i = strtoll(s, NULL, 10);
40 switch (errno) {
41 case ERANGE: {
42 if (loc.get_filename() != NULL) {
43 loc.error("Overflow when converting `%s' to integer value: %s", s,
44 strerror(errno));
45 } else {
46 FATAL_ERROR("Overflow when converting `%s' to integer value: %s", s,
47 strerror(errno));
48 }
49 break; }
50 case 0:
51 break;
52 default:
53 FATAL_ERROR("Unexpected error when converting `%s' to integer: %s", s,
54 strerror(errno));
55 }
56 return i;
57 }
58
59 int_val_t::int_val_t() : native_flag(true)
60 {
61 val.openssl = NULL;
62 }
63
64 int_val_t::int_val_t(const int_val_t& v)
65 {
66 native_flag = v.is_native();
67 if (native_flag) val.native = v.get_val();
68 else val.openssl = BN_dup(v.get_val_openssl());
69 }
70
71 int_val_t::int_val_t(const char *s, const Location& loc)
72 {
73 BIGNUM *n = NULL;
74 if (!BN_dec2bn(&n, *s == '+' ? s + 1 : s))
75 loc.error("Unexpected error when converting `%s' to integer", s);
76 if (BN_num_bits(n) > (int)sizeof(long long) * 8 - 1) {
77 native_flag = false;
78 val.openssl = n;
79 } else {
80 native_flag = true;
81 val.native = string2Int(s, loc);
82 BN_free(n);
83 }
84 }
85
86 int_val_t::~int_val_t()
87 {
88 if (!native_flag) BN_free(val.openssl);
89 }
90
91 string int_val_t::t_str() const
92 {
93 char *tmp = NULL;
94 if (native_flag) {
95 tmp = mprintf("%lld", val.native);
96 string s(tmp);
97 Free(tmp);
98 return s;
99 } else {
100 if (!(tmp = BN_bn2dec(val.openssl)))
101 FATAL_ERROR("int_val_t::t_str()");
102 string s(tmp);
103 OPENSSL_free(tmp);
104 return s;
105 }
106 }
107
108 BIGNUM *int_val_t::to_openssl() const
109 {
110 BIGNUM *big = NULL;
111 if (native_flag) {
112 string str = Int2string(val.native);
113 if (!BN_dec2bn(&big, str.c_str())) FATAL_ERROR("int_val_t::to_openssl()");
114 } else {
115 big = BN_dup(val.openssl);
116 if (!big) FATAL_ERROR("int_val_t::to_openssl()");
117 }
118 return big;
119 }
120
121 bool int_val_t::operator==(Int right) const
122 {
123 if (!native_flag) return false;
124 return val.native == right;
125 }
126
127 bool int_val_t::operator==(const int_val_t& v) const
128 {
129 if (native_flag != v.is_native()) return false;
130 if (native_flag) return val.native == v.get_val();
131 return !BN_cmp(val.openssl, v.get_val_openssl());
132 }
133
134 bool int_val_t::operator<(const int_val_t& v) const
135 {
136 if (native_flag) {
137 if (v.is_native()) {
138 return val.native < v.get_val();
139 } else {
140 BIGNUM *this_big = to_openssl();
141 if (!this_big) FATAL_ERROR("int_val_t::operator<(int_val_t& v)");
142 int this_equ = BN_cmp(this_big, v.get_val_openssl());
143 BN_free(this_big);
144 return this_equ == -1;
145 }
146 } else {
147 if (v.is_native()) {
148 BIGNUM *v_big = v.to_openssl();
149 if (!v_big) FATAL_ERROR("int_val_t::operator<(int_val_t& v)");
150 int v_equ = BN_cmp(val.openssl, v_big);
151 BN_free(v_big);
152 return v_equ == -1;
153 } else {
154 return BN_cmp(val.openssl, v.val.openssl) == -1;
155 }
156 }
157 }
158
159 int_val_t int_val_t::operator-() const
160 {
161 if (native_flag) {
162 if (val.native == LLONG_MIN) {
163 BIGNUM *result = int_val_t(LLONG_MIN).to_openssl();
164 BN_set_negative(result, 0);
165 return int_val_t(result);
166 } else {
167 return int_val_t(-val.native);
168 }
169 } else {
170 BIGNUM *llong_max_plus_one = int_val_t(LLONG_MIN).to_openssl();
171 BN_set_negative(llong_max_plus_one, 0);
172 int cmp = BN_cmp(val.openssl, llong_max_plus_one);
173 BN_free(llong_max_plus_one);
174 if (cmp == 0) {
175 return int_val_t(LLONG_MIN);
176 } else {
177 BIGNUM *result = BN_dup(val.openssl);
178 BN_set_negative(result, !BN_is_negative(result));
179 return int_val_t(result);
180 }
181 }
182 }
183
184 int_val_t int_val_t::operator+(const int_val_t& right) const
185 {
186 // a + b = a add b
187 // a + -b = a sub b
188 // -a + b = b sub a
189 // -a + -b = -(a add b)
190 // Use only inline functions and BN_* directly. Call out for operator- in
191 // the beginning.
192 bool a_neg = is_negative();
193 bool b_neg = right.is_negative();
194 bool r_neg = a_neg && b_neg;
195 if (!a_neg && b_neg) return operator-(-right);
196 if (a_neg && !b_neg) return right.operator-(-(*this));
197 if (native_flag) {
198 long long result_;
199 if (right.is_native()) {
200 unsigned long long result = val.native + right.get_val();
201 result_ = val.native + right.get_val();
202 if (static_cast<long long>(result) != result_ ||
203 (!r_neg && result_ < 0) || (r_neg && result_ > 0)) {
204 // We can safely assume that the sum of two non-negative long long
205 // values fit in an unsigned long long. limits.h says:
206 // # ifndef ULLONG_MAX
207 // # define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
208 // # endif
209 // This is the most complicated case. We cannot be sure that
210 // sizeof(BN_ULONG) == sizeof(long long). First convert the long long
211 // to string and feed BN_dec2bn.
212 BIGNUM *left_ = to_openssl();
213 BIGNUM *right_ = right.to_openssl();
214 BN_add(left_, left_, right_);
215 BN_free(right_);
216 return int_val_t(left_);
217 } else {
218 return int_val_t(result_);
219 }
220 } else {
221 // long long (>= 0) + BIGNUM == BIGNUM.
222 BIGNUM *result = BN_new();
223 BIGNUM *left_ = to_openssl();
224 BN_add(result, left_, right.get_val_openssl());
225 return int_val_t(result);
226 }
227 } else {
228 // BIGNUM + long long (>= 0) == BIGNUM.
229 BIGNUM *result = BN_new();
230 BIGNUM *right_;
231 right_ = right.is_native() ? right.to_openssl() : right.get_val_openssl();
232 BN_add(result, val.openssl, right_);
233 if (right.is_native())
234 BN_free(right_);
235 return int_val_t(result);
236 }
237 }
238
239 int_val_t int_val_t::operator-(const int_val_t& right) const
240 {
241 // a - b = a sub b
242 // -a - b = -(a add b)
243 // a - -b = a add b
244 // -a - -b = -a add b = b sub a
245 bool a_neg = is_negative();
246 bool b_neg = right.is_negative();
247 if (!a_neg && b_neg) return operator+(-right);
248 if (a_neg && !b_neg) return -right.operator+(-(*this));
249 if (native_flag) {
250 if (right.is_native()) {
251 // Since both operands are non-negative the most negative result of a
252 // subtraction can be -LLONG_MAX and according to limits.h:
253 // # ifndef LLONG_MIN
254 // # define LLONG_MIN (-LLONG_MAX-1)
255 // # endif
256 return int_val_t(val.native - right.get_val());
257 } else {
258 BIGNUM *left_bn = to_openssl();
259 BN_sub(left_bn, left_bn, right.get_val_openssl());
260 // The result can be small enough to fit in long long. The same is true
261 // for division. Back conversion is a really costly operation using
262 // strings all the time. TODO Improve it.
263 if (BN_num_bits(left_bn) <= (int)sizeof(long long) * 8 - 1) {
264 char *result_str = BN_bn2dec(left_bn);
265 Int result_ll = string2Int(result_str, Location());
266 OPENSSL_free(result_str);
267 BN_free(left_bn);
268 return int_val_t(result_ll);
269 } else {
270 return int_val_t(left_bn);
271 }
272 }
273 } else {
274 BIGNUM *result = BN_new();
275 BIGNUM *right_bn;
276 right_bn = right.is_native() ? right.to_openssl() :
277 right.get_val_openssl();
278 BN_sub(result, val.openssl, right_bn);
279 if (right.is_native()) BN_free(right_bn);
280 if (BN_num_bits(result) <= (int)sizeof(long long) * 8 - 1) {
281 char *result_str = BN_bn2dec(result);
282 Int result_ll = string2Int(result_str, Location());
283 OPENSSL_free(result_str);
284 return int_val_t(result_ll);
285 } else {
286 return int_val_t(result);
287 }
288 }
289 }
290
291 int_val_t int_val_t::operator*(const int_val_t& right) const
292 {
293 if ((native_flag && val.native == 0LL) ||
294 (right.native_flag && right.val.native == 0LL))
295 return int_val_t(0LL);
296 if (native_flag) {
297 if (right.native_flag) {
298 // 2^15 is used as a simple heuristic.
299 // TODO: Improve.
300 if (ll_abs(val.native) < 32768LL && ll_abs(right.val.native) < 32768LL) {
301 return int_val_t(val.native * right.val.native);
302 } else {
303 BIGNUM *left_bn = to_openssl();
304 BIGNUM *right_bn = right.to_openssl();
305 BN_CTX *ctx = BN_CTX_new();
306 BN_CTX_init(ctx);
307 BN_mul(left_bn, left_bn, right_bn, ctx);
308 BN_CTX_free(ctx);
309 BN_free(right_bn);
310 if (BN_num_bits(left_bn) < (int)sizeof(long long) * 8) {
311 BN_free(left_bn);
312 return int_val_t(val.native * right.val.native);
313 } else {
314 return int_val_t(left_bn);
315 }
316 }
317 } else {
318 BIGNUM *this_bn = to_openssl();
319 BN_CTX *ctx = BN_CTX_new();
320 BN_CTX_init(ctx);
321 BN_mul(this_bn, this_bn, right.get_val_openssl(), ctx);
322 BN_CTX_free(ctx);
323 return int_val_t(this_bn);
324 }
325 } else {
326 BIGNUM *result = BN_new();
327 BIGNUM *right_bn;
328 BN_CTX *ctx = BN_CTX_new();
329 BN_CTX_init(ctx);
330 right_bn = right.native_flag ? right.to_openssl()
331 : right.get_val_openssl();
332 BN_mul(result, val.openssl, right_bn, ctx);
333 BN_CTX_free(ctx);
334 if (right.native_flag) BN_free(right_bn);
335 return int_val_t(result);
336 }
337 }
338
339 int_val_t int_val_t::operator/(const int_val_t& right) const
340 {
341 if (native_flag && val.native == 0LL)
342 return int_val_t(0LL);
343 if (right.is_native() && right.get_val() == 0LL)
344 FATAL_ERROR("Division by zero after semantic check");
345 if (native_flag) {
346 if (right.native_flag) {
347 return int_val_t(val.native / right.get_val());
348 } else {
349 BIGNUM *left_bn = to_openssl();
350 BN_CTX *ctx = BN_CTX_new();
351 BN_CTX_init(ctx);
352 BN_div(left_bn, NULL, left_bn, right.get_val_openssl(), ctx);
353 BN_CTX_free(ctx);
354 if (BN_num_bits(left_bn) <= (int)sizeof(long long) * 8 - 1) {
355 char *result_str = BN_bn2dec(left_bn);
356 Int result_ll = string2Int(result_str, Location());
357 OPENSSL_free(result_str);
358 BN_free(left_bn);
359 return int_val_t(result_ll);
360 } else {
361 return int_val_t(left_bn);
362 }
363 }
364 } else {
365 BIGNUM *result = BN_new();
366 BIGNUM *right_bn;
367 BN_CTX *ctx = BN_CTX_new();
368 BN_CTX_init(ctx);
369 right_bn = right.is_native() ? right.to_openssl() :
370 right.get_val_openssl();
371 BN_div(result, NULL, val.openssl, right_bn, ctx);
372 BN_CTX_free(ctx);
373 if (BN_num_bits(result) <= (int)sizeof(long long) * 8 - 1) {
374 char *result_str = BN_bn2dec(result);
375 Int result_ll = string2Int(result_str, Location());
376 OPENSSL_free(result_str);
377 return int_val_t(result_ll);
378 } else {
379 if (right.is_native())
380 BN_free(right_bn);
381 return int_val_t(result);
382 }
383 }
384 }
385
386 int_val_t int_val_t::operator&(Int right) const
387 {
388 // TODO Right can be int_val_t. Now it works only if right fits in
389 // BN_ULONG. If it's not true right must be converted to BIGNUM and the
390 // bits should be set with BN_is_bit_set/BN_set_bit.
391 BN_ULONG right_bn_ulong = (BN_ULONG)right;
392 if (right != (long long)right_bn_ulong)
393 FATAL_ERROR("Bitmask is too big");
394 if (native_flag) {
395 return int_val_t(val.native & right);
396 } else {
397 BIGNUM *tmp = BN_dup(val.openssl);
398 BN_mask_bits(tmp, sizeof(BN_ULONG) * 8);
399 BN_ULONG word = BN_get_word(tmp);
400 BN_free(tmp);
401 return int_val_t(word & right_bn_ulong);
402 }
403 }
404
405 int_val_t int_val_t::operator>>(Int right) const
406 {
407 if (native_flag) {
408 // Shifting right (or left) with a number greater or equal to the bits of
409 // the type of the left operand has an undefined behaviour.
410 // http://bytes.com/groups/c/495137-right-shift-weird-result-why
411 Int shifted_value = right >= static_cast<Int>(sizeof(Int) * 8) ? 0 :
412 val.native >> right;
413 return int_val_t(shifted_value);
414 } else {
415 BIGNUM *result = BN_new();
416 BN_rshift(result, val.openssl, right);
417 if (BN_num_bits(result) < (int)sizeof(long long) * 8 - 1) {
418 char *result_str = BN_bn2dec(result);
419 Int result_ll = string2Int(result_str, Location());
420 OPENSSL_free(result_str);
421 BN_free(result);
422 return int_val_t(result_ll);
423 } else {
424 return int_val_t(result);
425 }
426 }
427 }
428
429 const Int& int_val_t::get_val() const
430 {
431 if (!native_flag) FATAL_ERROR("Invalid conversion of a large integer value");
432 return val.native;
433 }
434
435 BIGNUM *int_val_t::get_val_openssl() const
436 {
437 if (native_flag) FATAL_ERROR("Invalid conversion of a large integer value");
438 return val.openssl;
439 }
440
441 Real int_val_t::to_real() const
442 {
443 if (native_flag) {
444 return (double)val.native;
445 } else {
446 char *result_str = BN_bn2dec(val.openssl);
447 Real result = 0.0;
448 // Use fixed-point notation. The mantissa is usually at most 52-bits.
449 // Bigger integer values will be rounded.
450 if (sscanf(result_str, "%lf", &result) != 1)
451 FATAL_ERROR("Conversion of integer value `%s' to float failed",
452 result_str); // No deallocation, it'll crash anyway...
453 OPENSSL_free(result_str);
454 return result;
455 }
456 }
457
458 int_val_t& int_val_t::operator=(const int_val_t& right)
459 {
460 if (!native_flag) BN_free(val.openssl);
461 native_flag = right.native_flag;
462 if (native_flag) val.native = right.get_val();
463 else val.openssl = BN_dup(right.get_val_openssl());
464 return *this;
465 }
466
467 int_val_t& int_val_t::operator<<=(Int right)
468 {
469 // It makes no sense to support negative operands. GCC returns constant "0"
470 // with "warning: left shift count is negative" for these shifts.
471 // BN_set_word is not enough since sizeof(BN_ULONG) != sizeof(long long).
472 // In TTCN-3 <<= right means >>= -right.
473 if (right < 0) FATAL_ERROR("The second operand of bitwise shift operators "
474 "cannot be negative");
475 if (right == 0) return *this;
476 if (native_flag) {
477 BIGNUM *result = BN_new();
478 BN_dec2bn(&result, Int2string(val.native).c_str());
479 BN_lshift(result, result, right);
480 if (BN_num_bits(result) > (int)sizeof(long long) * 8 - 1) {
481 val.openssl = result;
482 native_flag = false;
483 } else {
484 val.native <<= right;
485 BN_free(result);
486 }
487 } else {
488 BN_lshift(val.openssl, val.openssl, right);
489 }
490 return *this;
491 }
492
493 int_val_t& int_val_t::operator>>=(Int right)
494 {
495 if (right < 0) FATAL_ERROR("The second operand of bitwise shift operators "
496 "cannot be negative");
497 if (right == 0) return *this;
498 if (native_flag) {
499 val.native >>= right;
500 } else {
501 BN_rshift(val.openssl, val.openssl, right);
502 if (BN_num_bits(val.openssl) <= (int)sizeof(long long) * 8 - 1) {
503 char *result_str = BN_bn2dec(val.openssl);
504 Int result_ll = string2Int(result_str, Location());
505 OPENSSL_free(result_str);
506 native_flag = true;
507 BN_free(val.openssl);
508 val.native = result_ll;
509 }
510 }
511 return *this;
512 }
513
514 int_val_t& int_val_t::operator+=(Int right)
515 {
516 // Unfortunately we have to check the sign of the "right" operand and
517 // perform addition or subtraction accordingly.
518 if (right == 0) return *this;
519 bool neg = right < 0;
520 if (native_flag) {
521 BIGNUM *result = BN_new();
522 BN_set_word(result, (BN_ULONG)val.native);
523 if (neg) BN_sub_word(result, (BN_ULONG)right);
524 else BN_add_word(result, (BN_ULONG)right);
525 if (BN_num_bits(result) > (int)sizeof(long long) * 8 - 1) {
526 val.openssl = result;
527 native_flag = false;
528 } else {
529 val.native += right;
530 BN_free(result);
531 }
532 } else {
533 if (neg) BN_sub_word(val.openssl, (BN_ULONG)right);
534 else BN_add_word(val.openssl, (BN_ULONG)right);
535 if (BN_num_bits(val.openssl) <= (int)sizeof(long long) * 8 - 1) {
536 // TODO BN_ULONG != long long.
537 BN_ULONG tmp = BN_get_word(val.openssl);
538 if (BN_is_negative(val.openssl)) tmp *= -1;
539 BN_free(val.openssl);
540 val.native = tmp;
541 native_flag = true;
542 }
543 }
544 return *this;
545 }
546
547 } // Common
This page took 0.114089 seconds and 5 git commands to generate.