Jlm
Loading...
Searching...
No Matches
value-representation.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 Helge Bahmann <hcb@chaoticmind.net>
3 * Copyright 2015 Nico Reißmann <nico.reissmann@gmail.com>
4 * See COPYING for terms of redistribution.
5 */
6
7#ifndef JLM_RVSDG_BITSTRING_VALUE_REPRESENTATION_HPP
8#define JLM_RVSDG_BITSTRING_VALUE_REPRESENTATION_HPP
9
10#include <jlm/util/common.hpp>
11#include <jlm/util/strfmt.hpp>
12
13#include <cstdint>
14#include <cstring>
15#include <string>
16#include <vector>
17
18namespace jlm::rvsdg
19{
20
31{
33
34public:
36 {
37 if (nbits == 0)
38 throw util::Error("Number of bits is zero.");
39
40 if (nbits < 64 && (value >> nbits) != 0 && (value >> nbits != -1))
41 throw util::Error("Value cannot be represented with the given number of bits.");
42
43 for (size_t n = 0; n < nbits; ++n)
44 {
45 data_.push_back('0' + (value & 1));
46 value = value >> 1;
47 }
48 }
49
51 {
52 if (strlen(s) == 0)
53 throw util::Error("Number of bits is zero.");
54
55 for (size_t n = 0; n < strlen(s); n++)
56 {
57 if (s[n] != '0' && s[n] != '1' && s[n] != 'X' && s[n] != 'D')
58 throw util::Error("Not a valid bit.");
59 data_.push_back(s[n]);
60 }
61 }
62
63 explicit BitValueRepresentation(const char c)
64 {
65 if (c != '0' && c != '1' && c != 'X' && c != 'D')
66 throw util::Error("Not a valid bit.");
67
68 data_.push_back(c);
69 }
70
74
78
80 repeat(size_t nbits, char bit)
81 {
82 return BitValueRepresentation(std::string(nbits, bit).c_str());
83 }
84
96 create(const std::vector<BitValueRepresentation> & bitValues)
97 {
98 JLM_ASSERT(!bitValues.empty());
99
100 if (bitValues.size() == 1)
101 return bitValues[0];
102
104 for (auto bitValue : bitValues)
105 {
106 for (auto bit : bitValue.data_)
107 result.data_.push_back(bit);
108 }
109
110 return result;
111 }
112
113private:
114 inline char
115 lor(char a, char b) const noexcept
116 {
117 switch (a)
118 {
119 case '0':
120 return b;
121 case '1':
122 return '1';
123 case 'X':
124 if (b == '1')
125 return '1';
126 return 'X';
127 case 'D':
128 if (b == '1')
129 return '1';
130 if (b == 'X')
131 return 'X';
132 return 'D';
133 default:
134 return 'X';
135 }
136 }
137
138 inline char
139 lxor(char a, char b) const noexcept
140 {
141 switch (a)
142 {
143 case '0':
144 return b;
145 case '1':
146 if (b == '1')
147 return '0';
148 if (b == '0')
149 return '1';
150 return b;
151 case 'X':
152 return 'X';
153 case 'D':
154 if (b == 'X')
155 return 'X';
156 return a;
157 default:
158 return 'X';
159 }
160 }
161
162 inline char
163 lnot(char a) const noexcept
164 {
165 return lxor('1', a);
166 }
167
168 inline char
169 land(char a, char b) const noexcept
170 {
171 switch (a)
172 {
173 case '0':
174 return '0';
175 case '1':
176 return b;
177 case 'X':
178 if (b == '0')
179 return '0';
180 return 'X';
181 case 'D':
182 if (b == '0')
183 return '0';
184 if (b == 'X')
185 return 'X';
186 return 'D';
187 default:
188 return 'X';
189 }
190 }
191
192 inline char
193 carry(char a, char b, char c) const noexcept
194 {
195 return lor(lor(land(a, b), land(a, c)), land(b, c));
196 }
197
198 inline char
199 add(char a, char b, char c) const noexcept
200 {
201 return lxor(lxor(a, b), c);
202 }
203
204 inline void
208 BitValueRepresentation & remainder) const
209 {
210 JLM_ASSERT(quotient == 0);
211 JLM_ASSERT(remainder == 0);
212
213 if (divisor.nbits() != nbits())
214 throw util::Error(
215 jlm::util::strfmt("Unequal number of bits in udiv, ", divisor.nbits(), " != ", nbits()));
216
217 /*
218 FIXME: This should check whether divisor is zero, not whether nbits() is zero.
219 */
220 if (divisor.nbits() == 0)
221 throw util::Error("Division by zero.");
222
223 for (size_t n = 0; n < nbits(); n++)
224 {
225 remainder = remainder.shl(1);
226 remainder[0] = data_[nbits() - n - 1];
227 if (remainder.uge(divisor) == '1')
228 {
229 remainder = remainder.sub(divisor);
230 quotient[nbits() - n - 1] = '1';
231 }
232 }
233 }
234
235 inline void
239 {
240 JLM_ASSERT(product.nbits() == factor1.nbits() + factor2.nbits());
241
242 for (size_t i = 0; i < factor1.nbits(); i++)
243 {
244 char c = '0';
245 for (size_t j = 0; j < factor2.nbits(); j++)
246 {
247 char s = land(factor1[i], factor2[j]);
248 char nc = carry(s, product[i + j], c);
249 product[i + j] = add(s, product[i + j], c);
250 c = nc;
251 }
252 }
253 }
254
255public:
256 /*
257 FIXME: add <, <=, >, >= operator for uint64_t and int64_t
258 */
261 {
262 data_ = other.data_;
263 return *this;
264 }
265
268 {
269 if (this == &other)
270 return *this;
271
272 data_ = std::move(other.data_);
273 return *this;
274 }
275
276 inline char &
277 operator[](size_t n)
278 {
279 JLM_ASSERT(n < nbits());
280 return data_[n];
281 }
282
283 inline const char &
284 operator[](size_t n) const
285 {
286 JLM_ASSERT(n < nbits());
287 return data_[n];
288 }
289
290 inline bool
292 {
293 return data_ == other.data_;
294 }
295
296 inline bool
298 {
299 return !(*this == other);
300 }
301
302 inline bool
303 operator==(int64_t value) const
304 {
305 return *this == BitValueRepresentation(nbits(), value);
306 }
307
308 inline bool
309 operator!=(int64_t value) const
310 {
311 return !(*this == BitValueRepresentation(nbits(), value));
312 }
313
314 inline bool
315 operator==(const std::string & other) const noexcept
316 {
317 if (nbits() != other.size())
318 return false;
319
320 for (size_t n = 0; n < other.size(); n++)
321 {
322 if (data_[n] != other[n])
323 return false;
324 }
325
326 return true;
327 }
328
329 inline bool
330 operator!=(const std::string & other) const noexcept
331 {
332 return !(*this == other);
333 }
334
335 inline char
337 {
338 return data_[nbits() - 1];
339 }
340
341 inline bool
343 {
344 for (auto bit : data_)
345 {
346 if (bit == 'X')
347 return false;
348 }
349
350 return true;
351 }
352
353 inline bool
355 {
356 for (auto bit : data_)
357 {
358 if (bit == 'X' || bit == 'D')
359 return false;
360 }
361
362 return true;
363 }
364
365 bool
367 {
368 for (const auto bit : data_)
369 {
370 if (bit != '0')
371 return false;
372 }
373
374 return true;
375 }
376
377 inline bool
379 {
380 return sign() == '1';
381 }
382
385 {
386 BitValueRepresentation result(*this);
387 result.data_.insert(result.data_.end(), other.data_.begin(), other.data_.end());
388 return result;
389 }
390
392 slice(size_t low, size_t high) const
393 {
395 {
396 throw util::Error("Slice is out of bound.");
397 }
398
399 return BitValueRepresentation(std::string(&data_[low], high - low).c_str());
400 }
401
403 zext(size_t nbits) const
404 {
405 if (nbits == 0)
406 return *this;
407
409 }
410
412 sext(size_t nbits) const
413 {
414 if (nbits == 0)
415 return *this;
416
418 }
419
421 trunc(const size_t numBits) const
422 {
423 return slice(0, numBits);
424 }
425
426 inline size_t
428 {
429 return data_.size();
430 }
431
432 inline std::string
433 str() const
434 {
435 return std::string(data_.begin(), data_.end());
436 }
437
439 to_uint() const;
440
441 int64_t
442 to_int() const;
443
444 inline char
446 {
447 if (nbits() != other.nbits())
448 throw util::Error(
449 jlm::util::strfmt("Unequal number of bits in ult, ", nbits(), " != ", other.nbits()));
450
451 char v = land(lnot(data_[0]), other[0]);
452 for (size_t n = 1; n < nbits(); n++)
453 v = land(lor(lnot(data_[n]), other[n]), lor(land(lnot(data_[n]), other[n]), v));
454
455 return v;
456 }
457
458 inline char
460 {
462 t1[t1.nbits() - 1] = lnot(t1.sign());
463 t2[t2.nbits() - 1] = lnot(t2.sign());
464 return t1.ult(t2);
465 }
466
467 inline char
469 {
470 if (nbits() != other.nbits())
471 throw util::Error(
472 jlm::util::strfmt("Unequal number of bits in ule, ", nbits(), " != ", other.nbits()));
473
474 char v = '1';
475 for (size_t n = 0; n < nbits(); n++)
476 v = land(land(lor(lnot(data_[n]), other[n]), lor(lnot(data_[n]), v)), lor(v, other[n]));
477
478 return v;
479 }
480
481 inline char
483 {
485 t1[t1.nbits() - 1] = lnot(t1.sign());
486 t2[t2.nbits() - 1] = lnot(t2.sign());
487 return t1.ule(t2);
488 }
489
490 inline char
492 {
493 if (nbits() != other.nbits())
494 throw util::Error(
495 jlm::util::strfmt("Unequal number of bits in ne, ", nbits(), " != ", other.nbits()));
496
497 char v = '0';
498 for (size_t n = 0; n < nbits(); n++)
499 v = lor(v, lxor(data_[n], other[n]));
500 return v;
501 }
502
503 inline char
505 {
506 return lnot(ne(other));
507 }
508
509 inline char
511 {
512 return lnot(slt(other));
513 }
514
515 inline char
517 {
518 return lnot(ult(other));
519 }
520
521 inline char
523 {
524 return lnot(sle(other));
525 }
526
527 inline char
529 {
530 return lnot(ule(other));
531 }
532
535 {
536 if (nbits() != other.nbits())
537 throw util::Error(
538 jlm::util::strfmt("Unequal number of bits in add, ", nbits(), " != ", other.nbits()));
539
540 char c = '0';
542 for (size_t n = 0; n < nbits(); n++)
543 {
544 sum[n] = add(data_[n], other[n], c);
545 c = carry(data_[n], other[n], c);
546 }
547
548 return sum;
549 }
550
553 {
554 if (nbits() != other.nbits())
555 throw util::Error(
556 jlm::util::strfmt("Unequal number of bits in land, ", nbits(), " != ", other.nbits()));
557
558 BitValueRepresentation result = repeat(nbits(), 'X');
559 for (size_t n = 0; n < nbits(); n++)
560 result[n] = land(data_[n], other[n]);
561
562 return result;
563 }
564
567 {
568 if (nbits() != other.nbits())
569 throw util::Error(
570 jlm::util::strfmt("Unequal number of bits in lor, ", nbits(), " != ", other.nbits()));
571
572 BitValueRepresentation result = repeat(nbits(), 'X');
573 for (size_t n = 0; n < nbits(); n++)
574 result[n] = lor(data_[n], other[n]);
575
576 return result;
577 }
578
581 {
582 if (nbits() != other.nbits())
583 throw util::Error(
584 jlm::util::strfmt("Unequal number of bits in lxor, ", nbits(), " != ", other.nbits()));
585
586 BitValueRepresentation result = repeat(nbits(), 'X');
587 for (size_t n = 0; n < nbits(); n++)
588 result[n] = lxor(data_[n], other[n]);
589
590 return result;
591 }
592
594 lnot() const
595 {
596 return lxor(repeat(nbits(), '1'));
597 }
598
600 neg() const
601 {
602 char c = '1';
603 BitValueRepresentation result = repeat(nbits(), 'X');
604 for (size_t n = 0; n < nbits(); n++)
605 {
606 char tmp = lxor(data_[n], '1');
607 result[n] = add(tmp, '0', c);
608 c = carry(tmp, '0', c);
609 }
610
611 return result;
612 }
613
616 {
617 return add(other.neg());
618 }
619
621 shr(size_t shift) const
622 {
623 if (shift >= nbits())
624 return repeat(nbits(), '0');
625
626 BitValueRepresentation result(std::string(&data_[shift], nbits() - shift).c_str());
627 return result.zext(shift);
628 }
629
631 ashr(size_t shift) const
632 {
633 if (shift >= nbits())
634 return repeat(nbits(), sign());
635
636 BitValueRepresentation result(std::string(&data_[shift], nbits() - shift).c_str());
637 return result.sext(shift);
638 }
639
641 shl(size_t shift) const
642 {
643 if (shift == 0)
644 return *this;
645
646 if (shift >= nbits())
647 return repeat(nbits(), '0');
648
649 return repeat(shift, '0').concat(slice(0, nbits() - shift));
650 }
651
654 {
656 BitValueRepresentation remainder(nbits(), 0);
657 udiv(other, quotient, remainder);
658 return quotient;
659 }
660
663 {
665 BitValueRepresentation remainder(nbits(), 0);
666 udiv(other, quotient, remainder);
667 return remainder;
668 }
669
672 {
674
675 if (dividend.is_negative())
676 dividend = dividend.neg();
677
678 if (divisor.is_negative())
679 divisor = divisor.neg();
680
681 BitValueRepresentation quotient(nbits(), 0), remainder(nbits(), 0);
682 dividend.udiv(divisor, quotient, remainder);
683
684 if (is_negative())
685 remainder = remainder.neg();
686
687 if (is_negative() ^ other.is_negative())
689
690 return quotient;
691 }
692
695 {
697
698 if (dividend.is_negative())
699 dividend = dividend.neg();
700
701 if (divisor.is_negative())
702 divisor = divisor.neg();
703
704 BitValueRepresentation quotient(nbits(), 0), remainder(nbits(), 0);
705 dividend.udiv(divisor, quotient, remainder);
706
707 if (is_negative())
708 remainder = remainder.neg();
709
710 if (is_negative() ^ other.is_negative())
712
713 return remainder;
714 }
715
718 {
719 if (nbits() != other.nbits())
720 throw util::Error(
721 jlm::util::strfmt("Unequal number of bits in mul, ", nbits(), " != ", other.nbits()));
722
724 mul(*this, other, product);
725 return product.slice(0, nbits());
726 }
727
730 {
731 if (nbits() != other.nbits())
732 throw util::Error(
733 jlm::util::strfmt("Unequal number of bits in umulh, ", nbits(), " != ", other.nbits()));
734
739 return product.slice(nbits(), 2 * nbits());
740 }
741
744 {
745 if (nbits() != other.nbits())
746 throw util::Error(
747 jlm::util::strfmt("Unequal number of bits in smulh, ", nbits(), " != ", other.nbits()));
748
753 return product.slice(nbits(), 2 * nbits());
754 }
755
756 void
758 {
759 data_.insert(data_.end(), other.data_.begin(), other.data_.end());
760 }
761
762private:
763 /* [lsb ... msb] */
764 std::vector<char> data_{};
765};
766
767}
768
769#endif
BitValueRepresentation shl(size_t shift) const
void udiv(const BitValueRepresentation &divisor, BitValueRepresentation &quotient, BitValueRepresentation &remainder) const
BitValueRepresentation & operator=(const BitValueRepresentation &other)
BitValueRepresentation land(const BitValueRepresentation &other) const
BitValueRepresentation smod(const BitValueRepresentation &other) const
BitValueRepresentation sext(size_t nbits) const
BitValueRepresentation(const BitValueRepresentation &other)
void mul(const BitValueRepresentation &factor1, const BitValueRepresentation &factor2, BitValueRepresentation &product) const
static BitValueRepresentation create(const std::vector< BitValueRepresentation > &bitValues)
char sgt(const BitValueRepresentation &other) const
char sge(const BitValueRepresentation &other) const
BitValueRepresentation mul(const BitValueRepresentation &other) const
BitValueRepresentation sdiv(const BitValueRepresentation &other) const
char ne(const BitValueRepresentation &other) const
char ule(const BitValueRepresentation &other) const
bool operator==(const std::string &other) const noexcept
BitValueRepresentation trunc(const size_t numBits) const
BitValueRepresentation & operator=(BitValueRepresentation &&other)
char ult(const BitValueRepresentation &other) const
BitValueRepresentation neg() const
BitValueRepresentation umulh(const BitValueRepresentation &other) const
char carry(char a, char b, char c) const noexcept
char lor(char a, char b) const noexcept
bool operator!=(const std::string &other) const noexcept
bool operator==(const BitValueRepresentation &other) const noexcept
char ugt(const BitValueRepresentation &other) const
BitValueRepresentation concat(const BitValueRepresentation &other) const
char eq(const BitValueRepresentation &other) const
BitValueRepresentation(size_t nbits, int64_t value)
bool operator!=(const BitValueRepresentation &other) const noexcept
char lxor(char a, char b) const noexcept
BitValueRepresentation lxor(const BitValueRepresentation &other) const
BitValueRepresentation sub(const BitValueRepresentation &other) const
void Append(const BitValueRepresentation &other)
BitValueRepresentation lor(const BitValueRepresentation &other) const
char slt(const BitValueRepresentation &other) const
BitValueRepresentation ashr(size_t shift) const
BitValueRepresentation(BitValueRepresentation &&other)
BitValueRepresentation zext(size_t nbits) const
BitValueRepresentation udiv(const BitValueRepresentation &other) const
static BitValueRepresentation repeat(size_t nbits, char bit)
BitValueRepresentation shr(size_t shift) const
BitValueRepresentation umod(const BitValueRepresentation &other) const
BitValueRepresentation slice(size_t low, size_t high) const
BitValueRepresentation smulh(const BitValueRepresentation &other) const
BitValueRepresentation lnot() const
char sle(const BitValueRepresentation &other) const
char land(char a, char b) const noexcept
const char & operator[](size_t n) const
BitValueRepresentation add(const BitValueRepresentation &other) const
char uge(const BitValueRepresentation &other) const
char add(char a, char b, char c) const noexcept
#define JLM_ASSERT(x)
Definition common.hpp:16
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
static std::string strfmt(Args... args)
Definition strfmt.hpp:35