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 inline bool
367 {
368 return sign() == '1';
369 }
370
373 {
374 BitValueRepresentation result(*this);
375 result.data_.insert(result.data_.end(), other.data_.begin(), other.data_.end());
376 return result;
377 }
378
380 slice(size_t low, size_t high) const
381 {
383 {
384 throw util::Error("Slice is out of bound.");
385 }
386
387 return BitValueRepresentation(std::string(&data_[low], high - low).c_str());
388 }
389
391 zext(size_t nbits) const
392 {
393 if (nbits == 0)
394 return *this;
395
397 }
398
400 sext(size_t nbits) const
401 {
402 if (nbits == 0)
403 return *this;
404
406 }
407
409 trunc(const size_t numBits) const
410 {
411 return slice(0, numBits);
412 }
413
414 inline size_t
416 {
417 return data_.size();
418 }
419
420 inline std::string
421 str() const
422 {
423 return std::string(data_.begin(), data_.end());
424 }
425
427 to_uint() const;
428
429 int64_t
430 to_int() const;
431
432 inline char
434 {
435 if (nbits() != other.nbits())
436 throw util::Error(
437 jlm::util::strfmt("Unequal number of bits in ult, ", nbits(), " != ", other.nbits()));
438
439 char v = land(lnot(data_[0]), other[0]);
440 for (size_t n = 1; n < nbits(); n++)
441 v = land(lor(lnot(data_[n]), other[n]), lor(land(lnot(data_[n]), other[n]), v));
442
443 return v;
444 }
445
446 inline char
448 {
450 t1[t1.nbits() - 1] = lnot(t1.sign());
451 t2[t2.nbits() - 1] = lnot(t2.sign());
452 return t1.ult(t2);
453 }
454
455 inline char
457 {
458 if (nbits() != other.nbits())
459 throw util::Error(
460 jlm::util::strfmt("Unequal number of bits in ule, ", nbits(), " != ", other.nbits()));
461
462 char v = '1';
463 for (size_t n = 0; n < nbits(); n++)
464 v = land(land(lor(lnot(data_[n]), other[n]), lor(lnot(data_[n]), v)), lor(v, other[n]));
465
466 return v;
467 }
468
469 inline char
471 {
473 t1[t1.nbits() - 1] = lnot(t1.sign());
474 t2[t2.nbits() - 1] = lnot(t2.sign());
475 return t1.ule(t2);
476 }
477
478 inline char
480 {
481 if (nbits() != other.nbits())
482 throw util::Error(
483 jlm::util::strfmt("Unequal number of bits in ne, ", nbits(), " != ", other.nbits()));
484
485 char v = '0';
486 for (size_t n = 0; n < nbits(); n++)
487 v = lor(v, lxor(data_[n], other[n]));
488 return v;
489 }
490
491 inline char
493 {
494 return lnot(ne(other));
495 }
496
497 inline char
499 {
500 return lnot(slt(other));
501 }
502
503 inline char
505 {
506 return lnot(ult(other));
507 }
508
509 inline char
511 {
512 return lnot(sle(other));
513 }
514
515 inline char
517 {
518 return lnot(ule(other));
519 }
520
523 {
524 if (nbits() != other.nbits())
525 throw util::Error(
526 jlm::util::strfmt("Unequal number of bits in add, ", nbits(), " != ", other.nbits()));
527
528 char c = '0';
530 for (size_t n = 0; n < nbits(); n++)
531 {
532 sum[n] = add(data_[n], other[n], c);
533 c = carry(data_[n], other[n], c);
534 }
535
536 return sum;
537 }
538
541 {
542 if (nbits() != other.nbits())
543 throw util::Error(
544 jlm::util::strfmt("Unequal number of bits in land, ", nbits(), " != ", other.nbits()));
545
546 BitValueRepresentation result = repeat(nbits(), 'X');
547 for (size_t n = 0; n < nbits(); n++)
548 result[n] = land(data_[n], other[n]);
549
550 return result;
551 }
552
555 {
556 if (nbits() != other.nbits())
557 throw util::Error(
558 jlm::util::strfmt("Unequal number of bits in lor, ", nbits(), " != ", other.nbits()));
559
560 BitValueRepresentation result = repeat(nbits(), 'X');
561 for (size_t n = 0; n < nbits(); n++)
562 result[n] = lor(data_[n], other[n]);
563
564 return result;
565 }
566
569 {
570 if (nbits() != other.nbits())
571 throw util::Error(
572 jlm::util::strfmt("Unequal number of bits in lxor, ", nbits(), " != ", other.nbits()));
573
574 BitValueRepresentation result = repeat(nbits(), 'X');
575 for (size_t n = 0; n < nbits(); n++)
576 result[n] = lxor(data_[n], other[n]);
577
578 return result;
579 }
580
582 lnot() const
583 {
584 return lxor(repeat(nbits(), '1'));
585 }
586
588 neg() const
589 {
590 char c = '1';
591 BitValueRepresentation result = repeat(nbits(), 'X');
592 for (size_t n = 0; n < nbits(); n++)
593 {
594 char tmp = lxor(data_[n], '1');
595 result[n] = add(tmp, '0', c);
596 c = carry(tmp, '0', c);
597 }
598
599 return result;
600 }
601
604 {
605 return add(other.neg());
606 }
607
609 shr(size_t shift) const
610 {
611 if (shift >= nbits())
612 return repeat(nbits(), '0');
613
614 BitValueRepresentation result(std::string(&data_[shift], nbits() - shift).c_str());
615 return result.zext(shift);
616 }
617
619 ashr(size_t shift) const
620 {
621 if (shift >= nbits())
622 return repeat(nbits(), sign());
623
624 BitValueRepresentation result(std::string(&data_[shift], nbits() - shift).c_str());
625 return result.sext(shift);
626 }
627
629 shl(size_t shift) const
630 {
631 if (shift == 0)
632 return *this;
633
634 if (shift >= nbits())
635 return repeat(nbits(), '0');
636
637 return repeat(shift, '0').concat(slice(0, nbits() - shift));
638 }
639
642 {
644 BitValueRepresentation remainder(nbits(), 0);
645 udiv(other, quotient, remainder);
646 return quotient;
647 }
648
651 {
653 BitValueRepresentation remainder(nbits(), 0);
654 udiv(other, quotient, remainder);
655 return remainder;
656 }
657
660 {
662
663 if (dividend.is_negative())
664 dividend = dividend.neg();
665
666 if (divisor.is_negative())
667 divisor = divisor.neg();
668
669 BitValueRepresentation quotient(nbits(), 0), remainder(nbits(), 0);
670 dividend.udiv(divisor, quotient, remainder);
671
672 if (is_negative())
673 remainder = remainder.neg();
674
675 if (is_negative() ^ other.is_negative())
677
678 return quotient;
679 }
680
683 {
685
686 if (dividend.is_negative())
687 dividend = dividend.neg();
688
689 if (divisor.is_negative())
690 divisor = divisor.neg();
691
692 BitValueRepresentation quotient(nbits(), 0), remainder(nbits(), 0);
693 dividend.udiv(divisor, quotient, remainder);
694
695 if (is_negative())
696 remainder = remainder.neg();
697
698 if (is_negative() ^ other.is_negative())
700
701 return remainder;
702 }
703
706 {
707 if (nbits() != other.nbits())
708 throw util::Error(
709 jlm::util::strfmt("Unequal number of bits in mul, ", nbits(), " != ", other.nbits()));
710
712 mul(*this, other, product);
713 return product.slice(0, nbits());
714 }
715
718 {
719 if (nbits() != other.nbits())
720 throw util::Error(
721 jlm::util::strfmt("Unequal number of bits in umulh, ", nbits(), " != ", other.nbits()));
722
727 return product.slice(nbits(), 2 * nbits());
728 }
729
732 {
733 if (nbits() != other.nbits())
734 throw util::Error(
735 jlm::util::strfmt("Unequal number of bits in smulh, ", nbits(), " != ", other.nbits()));
736
741 return product.slice(nbits(), 2 * nbits());
742 }
743
744 void
746 {
747 data_.insert(data_.end(), other.data_.begin(), other.data_.end());
748 }
749
750private:
751 /* [lsb ... msb] */
752 std::vector<char> data_{};
753};
754
755}
756
757#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