1 |
|
/* |
2 |
|
** Copyright (C) 2018 Martin Brain |
3 |
|
** |
4 |
|
** See the file LICENSE for licensing information. |
5 |
|
*/ |
6 |
|
|
7 |
|
/* |
8 |
|
** operations.h |
9 |
|
** |
10 |
|
** Martin Brain |
11 |
|
** martin.brain@cs.ox.ac.uk |
12 |
|
** 15/11/14 |
13 |
|
** |
14 |
|
** A number of compound operations on bit-vectors. These are default |
15 |
|
** implementations to reduce the amount of code that is needed for a |
16 |
|
** back-end (and the risk of making a mistake). Back-ends can provide |
17 |
|
** their own implementations of these if they can handle them in a |
18 |
|
** smarter way than the default. |
19 |
|
** |
20 |
|
*/ |
21 |
|
|
22 |
|
#include <cassert> |
23 |
|
#include <map> |
24 |
|
|
25 |
|
#include "../utils/common.h" |
26 |
|
|
27 |
|
|
28 |
|
#ifndef SYMFPU_OPERATIONS |
29 |
|
#define SYMFPU_OPERATIONS |
30 |
|
|
31 |
|
namespace symfpu { |
32 |
|
|
33 |
|
/*** Size matching ***/ |
34 |
|
template <class t, class bv> |
35 |
|
std::pair<bv, bv> sameWidth(const bv &op1, const bv &op2) { |
36 |
|
typename t::bwt w1(op1.getWidth()); |
37 |
|
typename t::bwt w2(op2.getWidth()); |
38 |
|
|
39 |
|
if (w1 == w2) { |
40 |
|
return std::make_pair(op1, op2); |
41 |
|
} else if (w1 < w2) { |
42 |
|
return std::make_pair(op1.matchWidth(op2), op2); |
43 |
|
} else { |
44 |
|
INVARIANT(w1 > w2); |
45 |
|
return std::make_pair(op1.matchWidth(op2), op2); |
46 |
|
} |
47 |
|
} |
48 |
|
|
49 |
|
|
50 |
|
|
51 |
|
/*** Expanding operations ***/ |
52 |
|
template <class t, class bv> |
53 |
4 |
bv expandingAdd (const bv &op1, const bv &op2) { |
54 |
4 |
PRECONDITION(op1.getWidth() == op2.getWidth()); |
55 |
|
|
56 |
8 |
bv x(op1.extend(1)); |
57 |
8 |
bv y(op2.extend(1)); |
58 |
|
|
59 |
8 |
return x + y; |
60 |
|
} |
61 |
|
|
62 |
|
template <class t, class bv, class prop> |
63 |
158 |
bv expandingAddWithCarryIn (const bv &op1, const bv &op2, const prop &cin) { |
64 |
158 |
PRECONDITION(op1.getWidth() == op2.getWidth()); |
65 |
|
|
66 |
316 |
bv x(op1.extend(1)); |
67 |
316 |
bv y(op2.extend(1)); |
68 |
|
|
69 |
316 |
bv sum(x + y); |
70 |
|
|
71 |
158 |
typename t::bwt w(sum.getWidth()); |
72 |
316 |
bv carry(ITE(cin, bv::one(w), bv::zero(w))); |
73 |
158 |
bv res(sum.modularAdd(carry)); // Modular is safe due to the extension |
74 |
|
// (2^n - 1) + (2^n - 1) + 1 == 2^(n+1) - 1 |
75 |
|
// -(2^n) + -(2^n) + 1 > 2^(n+1) |
76 |
316 |
return res; |
77 |
|
} |
78 |
|
|
79 |
|
template <class t, class bv> |
80 |
1940 |
bv expandingSubtract (const bv &op1, const bv &op2) { |
81 |
1940 |
PRECONDITION(op1.getWidth() == op2.getWidth()); |
82 |
|
|
83 |
3880 |
bv x(op1.extend(1)); |
84 |
3880 |
bv y(op2.extend(1)); |
85 |
|
|
86 |
3880 |
return x - y; |
87 |
|
} |
88 |
|
|
89 |
|
template <class t, class bv> |
90 |
530 |
bv expandingMultiply (const bv &op1, const bv &op2) { |
91 |
530 |
typename t::bwt width = op1.getWidth(); |
92 |
530 |
PRECONDITION(width == op2.getWidth()); |
93 |
|
|
94 |
1060 |
bv x(op1.extend(width)); |
95 |
1060 |
bv y(op2.extend(width)); |
96 |
|
|
97 |
1060 |
return x * y; |
98 |
|
} |
99 |
|
|
100 |
|
|
101 |
|
/*** Conditional Operations ***/ |
102 |
|
template <class t, class bv, class prop> |
103 |
1219 |
bv conditionalIncrement (const prop &p, const bv &b) { |
104 |
1219 |
PRECONDITION(IMPLIES(p, b < bv::maxValue(b.getWidth()))); |
105 |
|
|
106 |
1219 |
typename t::bwt w(b.getWidth()); |
107 |
2438 |
bv inc(ITE(p, bv::one(w), bv::zero(w))); |
108 |
|
|
109 |
2438 |
return b + inc; |
110 |
|
} |
111 |
|
|
112 |
|
template <class t, class bv, class prop> |
113 |
202 |
bv conditionalDecrement (const prop &p, const bv &b) { |
114 |
202 |
PRECONDITION(IMPLIES(p, bv::minValue(b.getWidth()) < b)); |
115 |
|
|
116 |
202 |
typename t::bwt w(b.getWidth()); |
117 |
404 |
bv inc(ITE(p, bv::one(w), bv::zero(w))); |
118 |
|
|
119 |
404 |
return b - inc; |
120 |
|
} |
121 |
|
|
122 |
|
template <class t, class bv, class prop> |
123 |
1019 |
bv conditionalLeftShiftOne (const prop &p, const bv &b) { |
124 |
1019 |
typename t::bwt w(b.getWidth()); |
125 |
1019 |
PRECONDITION(IMPLIES(p, (b.extract(w - 1, w - 1).isAllZeros()))); |
126 |
|
|
127 |
2038 |
bv shifted(b.modularLeftShift(bv::one(w))); |
128 |
2038 |
return bv(ITE(p, shifted, b)); |
129 |
|
} |
130 |
|
|
131 |
|
template <class t, class bv, class prop> |
132 |
628 |
bv conditionalRightShiftOne (const prop &p, const bv &b) { |
133 |
628 |
typename t::bwt w(b.getWidth()); |
134 |
|
// PRECONDITION(IMPLIES(p, (b.extract(0, 0).isAllZeros()))); // Adder uses and compensates for this case. |
135 |
|
|
136 |
1256 |
bv shifted(b.modularRightShift(bv::one(w))); |
137 |
1256 |
return bv(ITE(p, shifted, b)); |
138 |
|
} |
139 |
|
|
140 |
|
template <class t, class bv, class prop> |
141 |
640 |
bv conditionalNegate (const prop &p, const bv &b) { |
142 |
640 |
typename t::bwt w(b.getWidth()); |
143 |
640 |
PRECONDITION(w >= 2); |
144 |
640 |
PRECONDITION(IMPLIES(p, !(b.extract(w - 1, w - 1).isAllOnes() && |
145 |
|
b.extract(w - 2, 0).isAllZeros()))); |
146 |
|
|
147 |
640 |
return bv(ITE(p, -b, b)); |
148 |
|
} |
149 |
|
|
150 |
|
template <class t, class bv> |
151 |
8 |
bv abs(const bv &b) { |
152 |
8 |
return conditionalNegate<t, bv, typename t::prop>(b < bv::zero(b.getWidth()), b); |
153 |
|
} |
154 |
|
|
155 |
|
|
156 |
|
|
157 |
|
/*** Probability Annotations ***/ |
158 |
|
enum probability { |
159 |
|
VERYLIKELY = 100, |
160 |
|
LIKELY = 50, |
161 |
|
NEUTRAL = 0, |
162 |
|
UNLIKELY = -50, |
163 |
|
VERYUNLIKELY = -100 |
164 |
|
}; |
165 |
|
|
166 |
|
template <class t, class prop> |
167 |
33453 |
void probabilityAnnotation (const prop &, const probability &) { |
168 |
|
// Back-ends can make use of this information if they want |
169 |
33453 |
return; |
170 |
|
} |
171 |
|
|
172 |
|
|
173 |
|
/*** Max and min ***/ |
174 |
|
template <class t, class bv> |
175 |
29967 |
bv max (const bv &op1, const bv &op2) { |
176 |
29967 |
return ITE(op1 <= op2, op2, op1); |
177 |
|
} |
178 |
|
|
179 |
|
template <class t, class bv> |
180 |
|
bv min (const bv &op1, const bv &op2) { |
181 |
|
return ITE(op1 <= op2, op1, op2); |
182 |
|
} |
183 |
|
|
184 |
|
template <class t, class bv> |
185 |
1219 |
bv collar(const bv &op, const bv &lower, const bv &upper) { |
186 |
2280 |
return ITE(op < lower, |
187 |
|
lower, |
188 |
2280 |
ITE(upper < op, |
189 |
|
upper, |
190 |
4639 |
op)); |
191 |
|
} |
192 |
|
|
193 |
|
|
194 |
|
/*** Unary/Binary operations ***/ |
195 |
|
template <class t, class bv, class prop, class bwt> |
196 |
|
bv countLeadingZerosRec (const bv &op, const bwt position, const prop &allPreceedingZeros) { |
197 |
|
typename t::bwt w(op.getWidth()); |
198 |
|
|
199 |
|
PRECONDITION(0 <= position && position < w); |
200 |
|
|
201 |
|
bv bit(op.extract(position, position)); |
202 |
|
|
203 |
|
prop isLeadingOne(allPreceedingZeros && (bit.isAllOnes())); |
204 |
|
prop continuingZero(allPreceedingZeros && (bit.isAllZeros())); |
205 |
|
|
206 |
|
if (position == 0) { |
207 |
|
return ITE(isLeadingOne, bv(w, w - 1), bv(w, w)); |
208 |
|
} else { |
209 |
|
return ITE(isLeadingOne, |
210 |
|
bv(w, w - (position + 1)), |
211 |
|
countLeadingZerosRec<t>(op, position - 1, continuingZero)); |
212 |
|
} |
213 |
|
} |
214 |
|
|
215 |
|
template <class t, class bv> |
216 |
|
bv countLeadingZeros (const bv &op) { |
217 |
|
typedef typename t::bwt bwt; |
218 |
|
typedef typename t::prop prop; |
219 |
|
bwt w(op.getWidth()); |
220 |
|
|
221 |
|
return countLeadingZerosRec<t>(op, w - 1, prop(true)); |
222 |
|
} |
223 |
|
|
224 |
|
// This is sort of the opposite of count trailing 1's (a.k.a. clz(reverse(not(x))) ) |
225 |
|
template <class t, class bv> |
226 |
20154 |
bv orderEncode (const bv &op) { |
227 |
20154 |
typename t::bwt w(op.getWidth()); |
228 |
|
|
229 |
|
//PRECONDITION(bv::zero(w) <= op && op <= bv(w, w)); // Not needed as using modular shift |
230 |
|
|
231 |
20154 |
bv tmp((bv::one(w + 1).modularLeftShift(op.resize(w + 1))).modularDecrement().extract(w-1,0)); |
232 |
20154 |
return tmp; |
233 |
|
} |
234 |
|
|
235 |
|
|
236 |
|
// The comparison we need to do is |
237 |
|
// op.extract(relevantBits - 1, 0) == bv(relevantBits, position + 1) |
238 |
|
// bits can be shared between instances of this. |
239 |
|
// The following is a dynamic programming style solution. |
240 |
|
// HOWEVER : it may not actually give a net saving depending on your application |
241 |
|
template <class t, class bv> |
242 |
5015 |
struct fragmentMap { |
243 |
|
typedef typename t::bwt bwt; |
244 |
|
typedef typename t::prop prop; |
245 |
|
|
246 |
|
typedef std::pair<bwt, bwt> fragment; |
247 |
|
typedef std::map<fragment, prop> map; |
248 |
|
|
249 |
|
protected : |
250 |
|
const bv &op; |
251 |
|
map m; |
252 |
|
|
253 |
|
prop getComparitorRec(bwt length, bwt value) |
254 |
|
{ |
255 |
|
PRECONDITION(length > 0); |
256 |
|
PRECONDITION(bitsToRepresent(value) <= length); |
257 |
|
typename map::const_iterator it = m.find(std::make_pair(length, value)); |
258 |
|
|
259 |
|
if (it != m.end()) { |
260 |
|
return it->second; |
261 |
|
} else { |
262 |
|
bwt leadingBit = bwt(1) << (length - 1); |
263 |
|
prop leadingBitIsOne(op.extract(length - 1, length - 1).isAllOnes()); |
264 |
|
prop correctComparison((value & leadingBit) ? |
265 |
|
leadingBitIsOne : !leadingBitIsOne); |
266 |
|
prop *step = NULL; |
267 |
|
|
268 |
|
if (length == 1) { |
269 |
|
step = new prop(correctComparison); |
270 |
|
} else { |
271 |
|
prop rec(getComparitorRec(length - 1, value & (~leadingBit))); |
272 |
|
step = new prop(correctComparison && rec); |
273 |
|
} |
274 |
|
|
275 |
|
prop res(*step); |
276 |
|
delete step; |
277 |
|
|
278 |
|
m.insert(std::make_pair(std::make_pair(length, value), res)); |
279 |
|
return res; |
280 |
|
} |
281 |
|
} |
282 |
|
|
283 |
|
public : |
284 |
5015 |
fragmentMap(const bv &_op) : op(_op) {} |
285 |
|
|
286 |
|
prop getComparitor(bwt length, bwt value) |
287 |
|
{ |
288 |
|
PRECONDITION(length > 0); |
289 |
|
PRECONDITION(bitsToRepresent(value) <= length); |
290 |
|
|
291 |
|
prop res(getComparitorRec(length, value)); |
292 |
|
|
293 |
|
POSTCONDITION(bv(res) == (op.extract(length - 1, 0) == bv(length, value))); |
294 |
|
return res; |
295 |
|
} |
296 |
|
}; |
297 |
|
|
298 |
|
|
299 |
|
// A more compact, bitwise implementation of orderEncode for SAT encoding |
300 |
|
// Intended to be used in specialisation of orderEncode |
301 |
|
template <class t, class bv> |
302 |
5015 |
bv orderEncodeBitwise (const bv &op) { |
303 |
|
typedef typename t::bwt bwt; |
304 |
5015 |
bwt w(op.getWidth()); |
305 |
|
|
306 |
10030 |
fragmentMap<t,bv> m(op); |
307 |
|
|
308 |
|
// If op is too large, then set everything to 1 |
309 |
10030 |
bv outOfRange(op >= bv(w, w)); |
310 |
|
|
311 |
|
// SAND to fill in the remaining bits |
312 |
5015 |
bv * working = new bv(outOfRange); |
313 |
65687 |
for (bwt i = w; i > 0; --i) { |
314 |
60672 |
bwt position = i - 1; // Position in the output bitvectors |
315 |
60672 |
bwt relevantBits = bitsToRepresent(position + 1); |
316 |
60672 |
INVARIANT(relevantBits > 0); |
317 |
|
|
318 |
|
//bv activateBit(m.getComparitor(relevantBits, position + 1)); // No more compact and slower |
319 |
121344 |
bv activateBit(op.extract(relevantBits - 1, 0) == bv(relevantBits, position + 1)); |
320 |
121344 |
bv nextBit(working->extract(0,0) | activateBit); |
321 |
|
|
322 |
60672 |
bv * tmp = working; |
323 |
60672 |
working = new bv(working->append(nextBit)); |
324 |
60672 |
delete tmp; |
325 |
|
} |
326 |
|
|
327 |
5015 |
bv output(working->extract(w - 1,0)); |
328 |
5015 |
delete working; |
329 |
|
|
330 |
5015 |
POSTCONDITION(output == (bv::one(w + 1).modularLeftShift(op.resize(w + 1))).modularDecrement().extract(w-1,0)); |
331 |
|
|
332 |
10030 |
return output; |
333 |
|
} |
334 |
|
|
335 |
|
|
336 |
|
/*** Custom shifts ***/ |
337 |
|
// 1 if and only if the right shift moves at least one 1 out of the word |
338 |
|
template <class t, class bv> |
339 |
628 |
bv rightShiftStickyBit (const bv &op, const bv &shift) { |
340 |
1884 |
bv stickyBit(ITE((orderEncode<t>(shift) & op).isAllZeros(), |
341 |
1256 |
bv::zero(op.getWidth()), |
342 |
1256 |
bv::one(op.getWidth()))); |
343 |
|
|
344 |
628 |
return stickyBit; |
345 |
|
} |
346 |
|
|
347 |
|
|
348 |
|
// It is easier to compute along with the shift |
349 |
|
template <class t> |
350 |
628 |
struct stickyRightShiftResult { |
351 |
|
typedef typename t::ubv ubv; |
352 |
|
|
353 |
|
ubv signExtendedResult; |
354 |
|
ubv stickyBit; |
355 |
|
|
356 |
628 |
stickyRightShiftResult(const ubv &ser, const ubv &sb) : signExtendedResult(ser), stickyBit(sb) {} |
357 |
|
stickyRightShiftResult(const stickyRightShiftResult &old) : signExtendedResult(old.signExtendedResult), stickyBit(old.stickyBit) {} |
358 |
|
}; |
359 |
|
|
360 |
|
|
361 |
|
template <class t> |
362 |
593 |
stickyRightShiftResult<t> stickyRightShift (const typename t::ubv &input, const typename t::ubv &shiftAmount) { |
363 |
593 |
stickyRightShiftResult<t> res(input.signExtendRightShift(shiftAmount), rightShiftStickyBit<t>(input, shiftAmount)); |
364 |
|
|
365 |
593 |
return res; |
366 |
|
} |
367 |
|
|
368 |
|
|
369 |
|
template <class t> |
370 |
35 |
stickyRightShiftResult<t> stickyRightShiftBitwise (const typename t::ubv &input, const typename t::ubv &shiftAmount) { |
371 |
|
typedef typename t::bwt bwt; |
372 |
|
typedef typename t::prop prop; |
373 |
|
typedef typename t::ubv ubv; |
374 |
|
|
375 |
35 |
bwt width(input.getWidth()); |
376 |
35 |
bwt startingPosition(positionOfLeadingOne(width)); |
377 |
35 |
INVARIANT(0 < startingPosition && startingPosition < width); |
378 |
|
|
379 |
|
// Catch the out of bounds case |
380 |
35 |
PRECONDITION(shiftAmount.getWidth() == width); |
381 |
70 |
prop fullShift(shiftAmount >= ubv(width, width)); |
382 |
|
// Note the shiftAmount is treated as unsigned... |
383 |
|
|
384 |
35 |
ubv *working = new ubv(input); |
385 |
35 |
prop *stickyBit = new prop(ITE(fullShift, !input.isAllZeros(), prop(false))); |
386 |
|
|
387 |
208 |
for (bwt i = startingPosition + 1; i > 0; --i) |
388 |
|
{ |
389 |
173 |
bwt shiftAmountPosition = i - 1; |
390 |
|
|
391 |
346 |
prop shiftEnabled = fullShift || shiftAmount.extract(shiftAmountPosition, shiftAmountPosition).isAllOnes(); |
392 |
|
|
393 |
346 |
prop stickyAccumulate(shiftEnabled && !(working->extract((1ULL << shiftAmountPosition) - 1, 0).isAllZeros())); // Would this loose data? |
394 |
|
|
395 |
173 |
prop * tmp = stickyBit; |
396 |
173 |
stickyBit = new prop(*stickyBit || stickyAccumulate); |
397 |
173 |
delete tmp; |
398 |
|
|
399 |
|
|
400 |
|
// Note the slightly unexpected sign extension |
401 |
346 |
ubv shifted(working->signExtendRightShift(ubv::one(width) << ubv(width, shiftAmountPosition))); |
402 |
|
|
403 |
173 |
ubv * workingTmp = working; |
404 |
173 |
working = new ubv(ITE(shiftEnabled, shifted, *working)); |
405 |
173 |
delete workingTmp; |
406 |
|
} |
407 |
|
|
408 |
35 |
stickyRightShiftResult<t> res(*working, ubv(*stickyBit).extend(width - 1)); |
409 |
|
|
410 |
35 |
delete working; |
411 |
35 |
delete stickyBit; |
412 |
|
|
413 |
35 |
POSTCONDITION(res.signExtendedResult == input.signExtendRightShift(shiftAmount)); |
414 |
35 |
POSTCONDITION(res.stickyBit == rightShiftStickyBit<t>(input, shiftAmount)); |
415 |
|
|
416 |
70 |
return res; |
417 |
|
} |
418 |
|
|
419 |
|
|
420 |
|
|
421 |
|
template <class t> |
422 |
1168 |
struct normaliseShiftResult { |
423 |
|
typedef typename t::ubv ubv; |
424 |
|
typedef typename t::prop prop; |
425 |
|
|
426 |
|
ubv normalised; |
427 |
|
ubv shiftAmount; |
428 |
|
prop isZero; |
429 |
|
|
430 |
1168 |
normaliseShiftResult(const ubv &n, const ubv &s, const prop &z) : normalised(n), shiftAmount(s), isZero(z) {} |
431 |
|
normaliseShiftResult(const normaliseShiftResult<t> &old) : normalised(old.normalised), shiftAmount(old.shiftAmount), isZero(old.isZero) {} |
432 |
|
}; |
433 |
|
|
434 |
|
template <class t> |
435 |
1168 |
normaliseShiftResult<t> normaliseShift (const typename t::ubv input) { |
436 |
|
typedef typename t::bwt bwt; |
437 |
|
typedef typename t::prop prop; |
438 |
|
typedef typename t::ubv ubv; |
439 |
|
|
440 |
1168 |
bwt width(input.getWidth()); |
441 |
1168 |
bwt startingMask(previousPowerOfTwo(width)); |
442 |
1168 |
INVARIANT(startingMask < width); |
443 |
|
|
444 |
|
// Catch the zero case |
445 |
1239 |
prop zeroCase(input.isAllZeros()); |
446 |
|
|
447 |
1168 |
ubv *working = new ubv(input); |
448 |
1168 |
ubv *shiftAmount = NULL; |
449 |
1168 |
prop *deactivateShifts = new prop(zeroCase); |
450 |
|
|
451 |
5600 |
for (bwt i = startingMask; i > 0; i >>= 1) { |
452 |
4760 |
prop newDeactivateShifts = *deactivateShifts || working->extract(width-1,width-1).isAllOnes(); |
453 |
4432 |
delete deactivateShifts; |
454 |
4432 |
deactivateShifts = new prop(newDeactivateShifts); |
455 |
|
|
456 |
8864 |
ubv mask(ubv::allOnes(i).append(ubv::zero(width - i))); |
457 |
4760 |
prop shiftNeeded(!(*deactivateShifts) && (mask & *working).isAllZeros()); |
458 |
|
|
459 |
|
// Modular is safe because of the mask comparison |
460 |
8864 |
ubv shifted(ITE(shiftNeeded, working->modularLeftShift(ubv(width, i)), *working)); |
461 |
4432 |
delete working; |
462 |
4432 |
working = new ubv(shifted); |
463 |
|
|
464 |
4432 |
if (shiftAmount == NULL) { |
465 |
1168 |
shiftAmount = new ubv(shiftNeeded); |
466 |
|
} else { |
467 |
6528 |
ubv newShiftAmount = shiftAmount->append(ubv(shiftNeeded)); |
468 |
3264 |
delete shiftAmount; |
469 |
3264 |
shiftAmount = new ubv(newShiftAmount); |
470 |
|
} |
471 |
|
} |
472 |
|
|
473 |
1168 |
normaliseShiftResult<t> res(*working, *shiftAmount, zeroCase); |
474 |
|
|
475 |
1168 |
delete deactivateShifts; |
476 |
1168 |
delete working; |
477 |
1168 |
delete shiftAmount; |
478 |
|
|
479 |
1168 |
POSTCONDITION(res.normalised.extract(width-1,width-1).isAllZeros() == res.isZero); |
480 |
1168 |
POSTCONDITION(IMPLIES(res.isZero, res.shiftAmount.isAllZeros())); |
481 |
|
|
482 |
1168 |
bwt shiftAmountWidth(res.shiftAmount.getWidth()); |
483 |
1168 |
bwt widthBits(bitsToRepresent(width)); |
484 |
1168 |
POSTCONDITION(shiftAmountWidth == widthBits || |
485 |
|
shiftAmountWidth == widthBits - 1); // If width is an exact power of 2 |
486 |
2336 |
ubv widthBV(widthBits, width); |
487 |
1168 |
POSTCONDITION(res.shiftAmount.matchWidth(widthBV) < widthBV); |
488 |
|
|
489 |
2336 |
return res; |
490 |
|
} |
491 |
|
|
492 |
|
|
493 |
|
/*** Dividers ***/ |
494 |
|
template <class t> |
495 |
5349 |
struct resultWithRemainderBit { |
496 |
|
typedef typename t::ubv ubv; |
497 |
|
typedef typename t::prop prop; |
498 |
|
|
499 |
|
ubv result; |
500 |
|
prop remainderBit; |
501 |
|
|
502 |
5349 |
resultWithRemainderBit(const ubv &o, const prop &r) : result(o), remainderBit(r) {} |
503 |
|
resultWithRemainderBit(const resultWithRemainderBit<t> &old) : result(old.result), remainderBit(old.remainderBit) {} |
504 |
|
}; |
505 |
|
|
506 |
|
// x and y are fixed-point numbers in the range [1,2) |
507 |
|
// Compute o \in [0.5,2), r \in [0,\delta) such that: x = o*y + r |
508 |
|
// Return (o, r != 0) |
509 |
|
template <class t> |
510 |
202 |
resultWithRemainderBit<t> fixedPointDivide (const typename t::ubv &x, const typename t::ubv &y) { |
511 |
202 |
typename t::bwt w(x.getWidth()); |
512 |
|
|
513 |
|
// Same width and both have MSB ones |
514 |
202 |
PRECONDITION(y.getWidth() == w); |
515 |
202 |
PRECONDITION(x.extract(w - 1, w - 1).isAllOnes()); |
516 |
202 |
PRECONDITION(y.extract(w - 1, w - 1).isAllOnes()); |
517 |
|
|
518 |
|
typedef typename t::ubv ubv; |
519 |
|
|
520 |
|
// Not the best way of doing this but pretty universal |
521 |
404 |
ubv ex(x.append(ubv::zero(w - 1))); |
522 |
404 |
ubv ey(y.extend(w - 1)); |
523 |
|
|
524 |
404 |
ubv div(ex / ey); |
525 |
404 |
ubv rem(ex % ey); |
526 |
|
|
527 |
404 |
return resultWithRemainderBit<t>(div.extract(w - 1, 0), !(rem.isAllZeros())); |
528 |
|
} |
529 |
|
|
530 |
|
|
531 |
|
// x is a fixed-point number in the range [1,4) with 2/p bits |
532 |
|
// Compute o \in [1,sqrt(2)), r \in [0,o*2 + 1) such that x = o*o + r with 1/p bits |
533 |
|
// Return (o, r != 0) |
534 |
|
template <class t> |
535 |
31 |
resultWithRemainderBit<t> fixedPointSqrt (const typename t::ubv &x) { |
536 |
|
typedef typename t::bwt bwt; |
537 |
|
typedef typename t::ubv ubv; |
538 |
|
typedef typename t::prop prop; |
539 |
|
|
540 |
|
// The default algorithm given here isn't a great one |
541 |
|
// However it is simple and has a very simple termination criteria. |
542 |
|
// Plus most symbolic back ends will prefer |
543 |
|
// o = nondet(), r = nondet(), assert(r < o*2 + 1), assert(x = o*o + r) |
544 |
|
|
545 |
31 |
bwt inputWidth(x.getWidth()); |
546 |
31 |
bwt outputWidth(inputWidth - 1); |
547 |
|
|
548 |
|
// To compare against, we need to pad x to 2/2p |
549 |
62 |
ubv xcomp(x.append(ubv::zero(inputWidth - 2))); |
550 |
|
|
551 |
|
// Start at 1 |
552 |
62 |
ubv working(ubv::one(outputWidth) << ubv(outputWidth, outputWidth - 1)); |
553 |
|
|
554 |
|
bwt location; |
555 |
372 |
for (location = outputWidth - 1; location > 0; --location) { // Offset by 1 for easy termination |
556 |
682 |
ubv shift(ubv(outputWidth, location - 1)); |
557 |
|
|
558 |
682 |
ubv candidate(working | (ubv::one(outputWidth) << shift)); |
559 |
|
|
560 |
352 |
prop addBit(expandingMultiply<t, ubv>(candidate, candidate) <= xcomp); |
561 |
|
|
562 |
341 |
working = working | (ubv(addBit).extend(outputWidth - 1) << shift); |
563 |
|
} |
564 |
|
|
565 |
62 |
return resultWithRemainderBit<t>(working, !(expandingMultiply<t, ubv>(working, working) == xcomp)); |
566 |
|
} |
567 |
|
|
568 |
|
// One step of a divider |
569 |
|
// Here the "remainder bit" is actual the result bit and |
570 |
|
// The result is the remainder |
571 |
|
template <class t> |
572 |
5116 |
resultWithRemainderBit<t> divideStep (const typename t::ubv &x, const typename t::ubv &y) { |
573 |
|
typedef typename t::bwt bwt; |
574 |
|
typedef typename t::ubv ubv; |
575 |
|
typedef typename t::prop prop; |
576 |
|
|
577 |
5116 |
bwt xWidth(x.getWidth()); |
578 |
5116 |
bwt yWidth(y.getWidth()); |
579 |
|
|
580 |
5116 |
PRECONDITION(xWidth == yWidth); |
581 |
5116 |
PRECONDITION(yWidth >= 2); |
582 |
5116 |
PRECONDITION(y.extract(yWidth - 2, yWidth - 2).isAllOnes()); // Assume y is aligned |
583 |
|
|
584 |
5763 |
prop canSubtract(x >= y); |
585 |
10232 |
ubv sub(x.modularAdd(y.modularNegate())); // TODO : modular subtract or better |
586 |
10232 |
ubv step(ITE(canSubtract, sub, x)); |
587 |
|
|
588 |
10232 |
return resultWithRemainderBit<t>(step << ubv::one(xWidth), canSubtract); |
589 |
|
} |
590 |
|
} |
591 |
|
|
592 |
|
#endif |