Jlm
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 
18 namespace jlm::rvsdg
19 {
20 
31 {
32 public:
33  BitValueRepresentation(size_t nbits, int64_t value)
34  {
35  if (nbits == 0)
36  throw util::Error("Number of bits is zero.");
37 
38  if (nbits < 64 && (value >> nbits) != 0 && (value >> nbits != -1))
39  throw util::Error("Value cannot be represented with the given number of bits.");
40 
41  for (size_t n = 0; n < nbits; ++n)
42  {
43  data_.push_back('0' + (value & 1));
44  value = value >> 1;
45  }
46  }
47 
48  BitValueRepresentation(const char * s)
49  {
50  if (strlen(s) == 0)
51  throw util::Error("Number of bits is zero.");
52 
53  for (size_t n = 0; n < strlen(s); n++)
54  {
55  if (s[n] != '0' && s[n] != '1' && s[n] != 'X' && s[n] != 'D')
56  throw util::Error("Not a valid bit.");
57  data_.push_back(s[n]);
58  }
59  }
60 
62  : data_(other.data_)
63  {}
64 
66  : data_(std::move(other.data_))
67  {}
68 
70  repeat(size_t nbits, char bit)
71  {
72  return BitValueRepresentation(std::string(nbits, bit).c_str());
73  }
74 
75 private:
76  inline char
77  lor(char a, char b) const noexcept
78  {
79  switch (a)
80  {
81  case '0':
82  return b;
83  case '1':
84  return '1';
85  case 'X':
86  if (b == '1')
87  return '1';
88  return 'X';
89  case 'D':
90  if (b == '1')
91  return '1';
92  if (b == 'X')
93  return 'X';
94  return 'D';
95  default:
96  return 'X';
97  }
98  }
99 
100  inline char
101  lxor(char a, char b) const noexcept
102  {
103  switch (a)
104  {
105  case '0':
106  return b;
107  case '1':
108  if (b == '1')
109  return '0';
110  if (b == '0')
111  return '1';
112  return b;
113  case 'X':
114  return 'X';
115  case 'D':
116  if (b == 'X')
117  return 'X';
118  return a;
119  default:
120  return 'X';
121  }
122  }
123 
124  inline char
125  lnot(char a) const noexcept
126  {
127  return lxor('1', a);
128  }
129 
130  inline char
131  land(char a, char b) const noexcept
132  {
133  switch (a)
134  {
135  case '0':
136  return '0';
137  case '1':
138  return b;
139  case 'X':
140  if (b == '0')
141  return '0';
142  return 'X';
143  case 'D':
144  if (b == '0')
145  return '0';
146  if (b == 'X')
147  return 'X';
148  return 'D';
149  default:
150  return 'X';
151  }
152  }
153 
154  inline char
155  carry(char a, char b, char c) const noexcept
156  {
157  return lor(lor(land(a, b), land(a, c)), land(b, c));
158  }
159 
160  inline char
161  add(char a, char b, char c) const noexcept
162  {
163  return lxor(lxor(a, b), c);
164  }
165 
166  inline void
168  const BitValueRepresentation & divisor,
169  BitValueRepresentation & quotient,
170  BitValueRepresentation & remainder) const
171  {
172  JLM_ASSERT(quotient == 0);
173  JLM_ASSERT(remainder == 0);
174 
175  if (divisor.nbits() != nbits())
176  throw util::Error(
177  jlm::util::strfmt("Unequal number of bits in udiv, ", divisor.nbits(), " != ", nbits()));
178 
179  /*
180  FIXME: This should check whether divisor is zero, not whether nbits() is zero.
181  */
182  if (divisor.nbits() == 0)
183  throw util::Error("Division by zero.");
184 
185  for (size_t n = 0; n < nbits(); n++)
186  {
187  remainder = remainder.shl(1);
188  remainder[0] = data_[nbits() - n - 1];
189  if (remainder.uge(divisor) == '1')
190  {
191  remainder = remainder.sub(divisor);
192  quotient[nbits() - n - 1] = '1';
193  }
194  }
195  }
196 
197  inline void
198  mul(const BitValueRepresentation & factor1,
199  const BitValueRepresentation & factor2,
200  BitValueRepresentation & product) const
201  {
202  JLM_ASSERT(product.nbits() == factor1.nbits() + factor2.nbits());
203 
204  for (size_t i = 0; i < factor1.nbits(); i++)
205  {
206  char c = '0';
207  for (size_t j = 0; j < factor2.nbits(); j++)
208  {
209  char s = land(factor1[i], factor2[j]);
210  char nc = carry(s, product[i + j], c);
211  product[i + j] = add(s, product[i + j], c);
212  c = nc;
213  }
214  }
215  }
216 
217 public:
218  /*
219  FIXME: add <, <=, >, >= operator for uint64_t and int64_t
220  */
223  {
224  data_ = other.data_;
225  return *this;
226  }
227 
230  {
231  if (this == &other)
232  return *this;
233 
234  data_ = std::move(other.data_);
235  return *this;
236  }
237 
238  inline char &
239  operator[](size_t n)
240  {
241  JLM_ASSERT(n < nbits());
242  return data_[n];
243  }
244 
245  inline const char &
246  operator[](size_t n) const
247  {
248  JLM_ASSERT(n < nbits());
249  return data_[n];
250  }
251 
252  inline bool
253  operator==(const BitValueRepresentation & other) const noexcept
254  {
255  return data_ == other.data_;
256  }
257 
258  inline bool
259  operator!=(const BitValueRepresentation & other) const noexcept
260  {
261  return !(*this == other);
262  }
263 
264  inline bool
265  operator==(int64_t value) const
266  {
267  return *this == BitValueRepresentation(nbits(), value);
268  }
269 
270  inline bool
271  operator!=(int64_t value) const
272  {
273  return !(*this == BitValueRepresentation(nbits(), value));
274  }
275 
276  inline bool
277  operator==(const std::string & other) const noexcept
278  {
279  if (nbits() != other.size())
280  return false;
281 
282  for (size_t n = 0; n < other.size(); n++)
283  {
284  if (data_[n] != other[n])
285  return false;
286  }
287 
288  return true;
289  }
290 
291  inline bool
292  operator!=(const std::string & other) const noexcept
293  {
294  return !(*this == other);
295  }
296 
297  inline char
298  sign() const noexcept
299  {
300  return data_[nbits() - 1];
301  }
302 
303  inline bool
304  is_defined() const noexcept
305  {
306  for (auto bit : data_)
307  {
308  if (bit == 'X')
309  return false;
310  }
311 
312  return true;
313  }
314 
315  inline bool
316  is_known() const noexcept
317  {
318  for (auto bit : data_)
319  {
320  if (bit == 'X' || bit == 'D')
321  return false;
322  }
323 
324  return true;
325  }
326 
327  inline bool
328  is_negative() const noexcept
329  {
330  return sign() == '1';
331  }
332 
334  concat(const BitValueRepresentation & other) const
335  {
336  BitValueRepresentation result(*this);
337  result.data_.insert(result.data_.end(), other.data_.begin(), other.data_.end());
338  return result;
339  }
340 
342  slice(size_t low, size_t high) const
343  {
344  if (high <= low || high > nbits())
345  {
346  throw util::Error("Slice is out of bound.");
347  }
348 
349  return BitValueRepresentation(std::string(&data_[low], high - low).c_str());
350  }
351 
353  zext(size_t nbits) const
354  {
355  if (nbits == 0)
356  return *this;
357 
358  return concat(BitValueRepresentation(nbits, 0));
359  }
360 
362  sext(size_t nbits) const
363  {
364  if (nbits == 0)
365  return *this;
366 
368  }
369 
370  inline size_t
371  nbits() const noexcept
372  {
373  return data_.size();
374  }
375 
376  inline std::string
377  str() const
378  {
379  return std::string(data_.begin(), data_.end());
380  }
381 
382  uint64_t
383  to_uint() const;
384 
385  int64_t
386  to_int() const;
387 
388  inline char
389  ult(const BitValueRepresentation & other) const
390  {
391  if (nbits() != other.nbits())
392  throw util::Error(
393  jlm::util::strfmt("Unequal number of bits in ult, ", nbits(), " != ", other.nbits()));
394 
395  char v = land(lnot(data_[0]), other[0]);
396  for (size_t n = 1; n < nbits(); n++)
397  v = land(lor(lnot(data_[n]), other[n]), lor(land(lnot(data_[n]), other[n]), v));
398 
399  return v;
400  }
401 
402  inline char
403  slt(const BitValueRepresentation & other) const
404  {
405  BitValueRepresentation t1(*this), t2(other);
406  t1[t1.nbits() - 1] = lnot(t1.sign());
407  t2[t2.nbits() - 1] = lnot(t2.sign());
408  return t1.ult(t2);
409  }
410 
411  inline char
412  ule(const BitValueRepresentation & other) const
413  {
414  if (nbits() != other.nbits())
415  throw util::Error(
416  jlm::util::strfmt("Unequal number of bits in ule, ", nbits(), " != ", other.nbits()));
417 
418  char v = '1';
419  for (size_t n = 0; n < nbits(); n++)
420  v = land(land(lor(lnot(data_[n]), other[n]), lor(lnot(data_[n]), v)), lor(v, other[n]));
421 
422  return v;
423  }
424 
425  inline char
426  sle(const BitValueRepresentation & other) const
427  {
428  BitValueRepresentation t1(*this), t2(other);
429  t1[t1.nbits() - 1] = lnot(t1.sign());
430  t2[t2.nbits() - 1] = lnot(t2.sign());
431  return t1.ule(t2);
432  }
433 
434  inline char
435  ne(const BitValueRepresentation & other) const
436  {
437  if (nbits() != other.nbits())
438  throw util::Error(
439  jlm::util::strfmt("Unequal number of bits in ne, ", nbits(), " != ", other.nbits()));
440 
441  char v = '0';
442  for (size_t n = 0; n < nbits(); n++)
443  v = lor(v, lxor(data_[n], other[n]));
444  return v;
445  }
446 
447  inline char
448  eq(const BitValueRepresentation & other) const
449  {
450  return lnot(ne(other));
451  }
452 
453  inline char
454  sge(const BitValueRepresentation & other) const
455  {
456  return lnot(slt(other));
457  }
458 
459  inline char
460  uge(const BitValueRepresentation & other) const
461  {
462  return lnot(ult(other));
463  }
464 
465  inline char
466  sgt(const BitValueRepresentation & other) const
467  {
468  return lnot(sle(other));
469  }
470 
471  inline char
472  ugt(const BitValueRepresentation & other) const
473  {
474  return lnot(ule(other));
475  }
476 
478  add(const BitValueRepresentation & other) const
479  {
480  if (nbits() != other.nbits())
481  throw util::Error(
482  jlm::util::strfmt("Unequal number of bits in add, ", nbits(), " != ", other.nbits()));
483 
484  char c = '0';
485  BitValueRepresentation sum = repeat(nbits(), 'X');
486  for (size_t n = 0; n < nbits(); n++)
487  {
488  sum[n] = add(data_[n], other[n], c);
489  c = carry(data_[n], other[n], c);
490  }
491 
492  return sum;
493  }
494 
496  land(const BitValueRepresentation & other) const
497  {
498  if (nbits() != other.nbits())
499  throw util::Error(
500  jlm::util::strfmt("Unequal number of bits in land, ", nbits(), " != ", other.nbits()));
501 
502  BitValueRepresentation result = repeat(nbits(), 'X');
503  for (size_t n = 0; n < nbits(); n++)
504  result[n] = land(data_[n], other[n]);
505 
506  return result;
507  }
508 
510  lor(const BitValueRepresentation & other) const
511  {
512  if (nbits() != other.nbits())
513  throw util::Error(
514  jlm::util::strfmt("Unequal number of bits in lor, ", nbits(), " != ", other.nbits()));
515 
516  BitValueRepresentation result = repeat(nbits(), 'X');
517  for (size_t n = 0; n < nbits(); n++)
518  result[n] = lor(data_[n], other[n]);
519 
520  return result;
521  }
522 
524  lxor(const BitValueRepresentation & other) const
525  {
526  if (nbits() != other.nbits())
527  throw util::Error(
528  jlm::util::strfmt("Unequal number of bits in lxor, ", nbits(), " != ", other.nbits()));
529 
530  BitValueRepresentation result = repeat(nbits(), 'X');
531  for (size_t n = 0; n < nbits(); n++)
532  result[n] = lxor(data_[n], other[n]);
533 
534  return result;
535  }
536 
538  lnot() const
539  {
540  return lxor(repeat(nbits(), '1'));
541  }
542 
544  neg() const
545  {
546  char c = '1';
547  BitValueRepresentation result = repeat(nbits(), 'X');
548  for (size_t n = 0; n < nbits(); n++)
549  {
550  char tmp = lxor(data_[n], '1');
551  result[n] = add(tmp, '0', c);
552  c = carry(tmp, '0', c);
553  }
554 
555  return result;
556  }
557 
559  sub(const BitValueRepresentation & other) const
560  {
561  return add(other.neg());
562  }
563 
565  shr(size_t shift) const
566  {
567  if (shift >= nbits())
568  return repeat(nbits(), '0');
569 
570  BitValueRepresentation result(std::string(&data_[shift], nbits() - shift).c_str());
571  return result.zext(shift);
572  }
573 
575  ashr(size_t shift) const
576  {
577  if (shift >= nbits())
578  return repeat(nbits(), sign());
579 
580  BitValueRepresentation result(std::string(&data_[shift], nbits() - shift).c_str());
581  return result.sext(shift);
582  }
583 
585  shl(size_t shift) const
586  {
587  if (shift >= nbits())
588  return repeat(nbits(), '0');
589 
590  return repeat(shift, '0').concat(slice(0, nbits() - shift));
591  }
592 
594  udiv(const BitValueRepresentation & other) const
595  {
596  BitValueRepresentation quotient(nbits(), 0);
597  BitValueRepresentation remainder(nbits(), 0);
598  udiv(other, quotient, remainder);
599  return quotient;
600  }
601 
603  umod(const BitValueRepresentation & other) const
604  {
605  BitValueRepresentation quotient(nbits(), 0);
606  BitValueRepresentation remainder(nbits(), 0);
607  udiv(other, quotient, remainder);
608  return remainder;
609  }
610 
612  sdiv(const BitValueRepresentation & other) const
613  {
614  BitValueRepresentation dividend(*this), divisor(other);
615 
616  if (dividend.is_negative())
617  dividend = dividend.neg();
618 
619  if (divisor.is_negative())
620  divisor = divisor.neg();
621 
622  BitValueRepresentation quotient(nbits(), 0), remainder(nbits(), 0);
623  dividend.udiv(divisor, quotient, remainder);
624 
625  if (is_negative())
626  remainder = remainder.neg();
627 
628  if (is_negative() ^ other.is_negative())
629  quotient = quotient.neg();
630 
631  return quotient;
632  }
633 
635  smod(const BitValueRepresentation & other) const
636  {
637  BitValueRepresentation dividend(*this), divisor(other);
638 
639  if (dividend.is_negative())
640  dividend = dividend.neg();
641 
642  if (divisor.is_negative())
643  divisor = divisor.neg();
644 
645  BitValueRepresentation quotient(nbits(), 0), remainder(nbits(), 0);
646  dividend.udiv(divisor, quotient, remainder);
647 
648  if (is_negative())
649  remainder = remainder.neg();
650 
651  if (is_negative() ^ other.is_negative())
652  quotient = quotient.neg();
653 
654  return remainder;
655  }
656 
658  mul(const BitValueRepresentation & other) const
659  {
660  if (nbits() != other.nbits())
661  throw util::Error(
662  jlm::util::strfmt("Unequal number of bits in mul, ", nbits(), " != ", other.nbits()));
663 
664  BitValueRepresentation product(2 * nbits(), 0);
665  mul(*this, other, product);
666  return product.slice(0, nbits());
667  }
668 
670  umulh(const BitValueRepresentation & other) const
671  {
672  if (nbits() != other.nbits())
673  throw util::Error(
674  jlm::util::strfmt("Unequal number of bits in umulh, ", nbits(), " != ", other.nbits()));
675 
676  BitValueRepresentation product(4 * nbits(), 0);
677  BitValueRepresentation factor1 = this->zext(nbits());
678  BitValueRepresentation factor2 = other.zext(nbits());
679  mul(factor1, factor2, product);
680  return product.slice(nbits(), 2 * nbits());
681  }
682 
684  smulh(const BitValueRepresentation & other) const
685  {
686  if (nbits() != other.nbits())
687  throw util::Error(
688  jlm::util::strfmt("Unequal number of bits in smulh, ", nbits(), " != ", other.nbits()));
689 
690  BitValueRepresentation product(4 * nbits(), 0);
691  BitValueRepresentation factor1 = this->sext(nbits());
692  BitValueRepresentation factor2 = other.sext(nbits());
693  mul(factor1, factor2, product);
694  return product.slice(nbits(), 2 * nbits());
695  }
696 
697  void
699  {
700  data_.insert(data_.end(), other.data_.begin(), other.data_.end());
701  }
702 
703 private:
704  /* [lsb ... msb] */
705  std::vector<char> data_;
706 };
707 
708 }
709 
710 #endif
BitValueRepresentation shl(size_t shift) const
void udiv(const BitValueRepresentation &divisor, BitValueRepresentation &quotient, BitValueRepresentation &remainder) const
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
char sgt(const BitValueRepresentation &other) const
BitValueRepresentation & operator=(const BitValueRepresentation &other)
char sge(const BitValueRepresentation &other) const
BitValueRepresentation mul(const BitValueRepresentation &other) const
BitValueRepresentation sdiv(const BitValueRepresentation &other) const
char ne(const BitValueRepresentation &other) const
BitValueRepresentation & operator=(BitValueRepresentation &&other)
char ule(const BitValueRepresentation &other) const
bool operator==(const std::string &other) const noexcept
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
const char & operator[](size_t n) 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
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
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35