1 module d.semantic.vrp;
2 
3 import d.ir.expression;
4 import d.ir.symbol;
5 import d.ir.type;
6 
7 import d.semantic.semantic;
8 
9 import std.traits;
10 
11 // Conflict with Interface in object.di
12 alias Interface = d.ir.symbol.Interface;
13 
14 /**
15  * ValueRangePropagator to figure out if it is safe to truncate
16  * a value to make it fit in a smaller type.
17  *
18  * It does so by computing the range of possible values the
19  * expression can take and checking if that range fit in a given type.
20  *
21  * It is only specialized for uint and ulong, as smaller integral type
22  * are promoted before any computation to 32bits values and above.
23  * As a result, smaller types do not really matter as long as we promote
24  * them properly. As a result, ranges computed from improperly promoted
25  * expression may be extremely pessimistics.
26  */
27 struct ValueRangePropagator(T) if (is(T == uint) || is(T == ulong)) {
28 	private SemanticPass pass;
29 	alias pass this;
30 
31 	alias VR = ValueRange!T;
32 
33 	this(SemanticPass pass) {
34 		this.pass = pass;
35 	}
36 
37 	bool canFit(Expression e, Type t) in {
38 		assert(isValidExpr(e), "VRP expect integral types.");
39 	} do {
40 		return canFit(e, getBuiltin(t));
41 	}
42 
43 	bool canFit(Expression e, BuiltinType t) in {
44 		assert(isValidExpr(e), "VRP expect integral types.");
45 		assert(canConvertToIntegral(t), "VRP only supports integral types.");
46 	} do {
47 		static canFitDMDMonkeyDance(R)(R r, BuiltinType t) {
48 			auto mask = cast(R.U) ((1UL << t.getBits()) - 1);
49 
50 			// Try to fit into the unsigned range.
51 			auto urange = r.unsigned.normalized;
52 			if (urange.max <= mask) {
53 				return true;
54 			}
55 
56 			// Try to fit into the signed range.
57 			auto smask = mask >> 1;
58 			auto nmask = ~smask;
59 
60 			auto srange = r.signed.normalized;
61 			if (srange.min >= nmask && srange.max <= smask) {
62 				return true;
63 			}
64 
65 			// Ho noes, it doesn't fit /o\
66 			return false;
67 		}
68 
69 		return processExpr!canFitDMDMonkeyDance(e, t);
70 	}
71 
72 private:
73 	static asHandlerDMDMonkeyDance(R)(R r) {
74 		return r.as!T;
75 	}
76 
77 	auto processExpr(alias handler = asHandlerDMDMonkeyDance,
78 	                 A...)(Expression e, A args) {
79 		import std.algorithm;
80 		auto s = max(getBuiltin(e.type).getSize(), uint.sizeof);
81 		if (s == T.sizeof) {
82 			return handler(visit(e), args);
83 		}
84 
85 		switch (s) {
86 			case uint.sizeof:
87 				return handler(ValueRangePropagator!uint(pass).visit(e), args);
88 
89 			case ulong.sizeof:
90 				return handler(ValueRangePropagator!ulong(pass).visit(e), args);
91 
92 			default:
93 				assert(0, "Size not supported by VRP");
94 		}
95 	}
96 
97 	BuiltinType getBuiltin(Type t) out(result) {
98 		assert(canConvertToIntegral(result),
99 		       "VRP only supports integral types.");
100 	} do {
101 		t = t.getCanonicalAndPeelEnum();
102 		if (t.hasPointerABI()) {
103 			return getBuiltin(pass.object.getSizeT().type);
104 		}
105 
106 		assert(t.kind == TypeKind.Builtin, "Invalid type for VRP");
107 		return t.builtin;
108 	}
109 
110 	VR getRange(Type t) {
111 		return getRange(getBuiltin(t));
112 	}
113 
114 	VR getRange(BuiltinType t) in {
115 		assert(t.getSize() <= T.sizeof);
116 	} do {
117 		if (t == BuiltinType.Bool) {
118 			return VR(0, 1);
119 		}
120 
121 		if (isChar(t)) {
122 			t = integralOfChar(t);
123 		}
124 
125 		return ValueRange!ulong(getMin(t), getMax(t)).as!T;
126 	}
127 
128 public:
129 	VR visit(Expression e) in {
130 		assert(isValidExpr(e), "VRP expect integral types.");
131 	} do {
132 		return this.dispatch!(e => getRange(e.type))(e);
133 	}
134 
135 	VR visit(BooleanLiteral e) {
136 		return VR(e.value);
137 	}
138 
139 	VR visit(IntegerLiteral e) {
140 		return ValueRange!ulong(e.value).as!T;
141 	}
142 
143 	VR visit(BinaryExpression e) {
144 		switch (e.op) with (BinaryOp) {
145 			case Comma, Assign:
146 				return visit(e.rhs);
147 
148 			case Add:
149 				return visit(e.lhs) + visit(e.rhs);
150 
151 			case Sub:
152 				return visit(e.lhs) - visit(e.rhs);
153 
154 			case Mul:
155 				return visit(e.lhs) * visit(e.rhs);
156 
157 			case UDiv:
158 				return visit(e.lhs) / visit(e.rhs);
159 
160 			case SDiv:
161 				return (visit(e.lhs).signed / visit(e.rhs).signed).unsigned;
162 
163 			case URem:
164 				return visit(e.lhs) % visit(e.rhs);
165 
166 			case SRem:
167 				return (visit(e.lhs).signed % visit(e.rhs).signed).unsigned;
168 
169 			case Or:
170 				return visit(e.lhs) | visit(e.rhs);
171 
172 			case And:
173 				return visit(e.lhs) & visit(e.rhs);
174 
175 			case Xor:
176 				return visit(e.lhs) ^ visit(e.rhs);
177 
178 			case LeftShift:
179 				return visit(e.lhs) << visit(e.rhs);
180 
181 			case UnsignedRightShift:
182 				return visit(e.lhs) >>> visit(e.rhs);
183 
184 			case SignedRightShift:
185 				return (visit(e.lhs).signed >> visit(e.rhs).signed).unsigned;
186 
187 			default:
188 				assert(0, "Not implemented.");
189 		}
190 	}
191 
192 	VR visit(UnaryExpression e) {
193 		switch (e.op) with (UnaryOp) {
194 			case Plus:
195 				return visit(e.expr);
196 
197 			case Minus:
198 				return -visit(e.expr);
199 
200 			default:
201 				assert(0, "Not implemented.");
202 		}
203 	}
204 
205 	VR visit(VariableExpression e) {
206 		auto v = e.var;
207 		scheduler.require(v, Step.Processed);
208 		return visit(v);
209 	}
210 
211 	VR visit(Variable v) in {
212 		assert(v.step >= Step.Processed);
213 	} do {
214 		return (v.storage == Storage.Enum
215 				|| v.type.getCanonical().qualifier == TypeQualifier.Immutable)
216 			? visit(v.value)
217 			: getRange(v.type);
218 	}
219 
220 	VR visit(CastExpression e) {
221 		final switch (e.kind) with (CastKind) {
222 			case Invalid:
223 				assert(0, "Invalid cast");
224 
225 			case IntToPtr, Down:
226 				assert(0, "Do not make any sense on integrals");
227 
228 			case PtrToInt:
229 				assert(0, "Not implemented");
230 
231 				// return ValueRange.get(e.type.builtin);
232 
233 			case IntToBool:
234 				static doTheDMDMonkeyDance(R)(R r) {
235 					if (r == typeof(r)(0)) {
236 						return VR(0);
237 					}
238 
239 					if (!r.containsZero) {
240 						return VR(1);
241 					}
242 
243 					return VR(0, 1);
244 				}
245 
246 				return processExpr!doTheDMDMonkeyDance(e.expr);
247 
248 			case Trunc:
249 				static doTheDMDMonkeyDance(R)(R r, BuiltinType t) {
250 					auto signed = isIntegral(t) && isSigned(t);
251 					auto mask = cast(R.U) ((1UL << t.getBits()) - 1);
252 
253 					return
254 						signed ? r.signed.trunc(mask).as!T : r.trunc(mask).as!T;
255 				}
256 
257 				return
258 					processExpr!doTheDMDMonkeyDance(e.expr, getBuiltin(e.type));
259 
260 			case UPad:
261 				auto t = getBuiltin(e.expr.type);
262 				auto r = processExpr(e.expr);
263 
264 				auto mask = cast(T) ((1UL << t.getBits()) - 1);
265 				return r.pad(mask);
266 
267 			case SPad:
268 				auto t = getBuiltin(e.expr.type);
269 				auto r = processExpr(e.expr);
270 
271 				auto mask = cast(T) ((1UL << t.getBits()) - 1);
272 				return r.signed.pad(mask).unsigned;
273 
274 			case Bit, Qual, Exact:
275 				return visit(e.expr);
276 		}
277 	}
278 }
279 
280 unittest {
281 	import std.meta;
282 	foreach (T; AliasSeq!(uint, ulong)) {
283 		auto vrp = ValueRangePropagator!T();
284 
285 		alias VR = ValueRange!T;
286 		VR v;
287 
288 		enum LS = T.sizeof == long.sizeof;
289 
290 		/**
291 		 * Test internal facilities
292 		 */
293 		assert(vrp.getRange(BuiltinType.Bool) == VR(0, 1));
294 
295 		assert(vrp.getRange(BuiltinType.Byte) == VR(byte.min, byte.max));
296 		assert(vrp.getRange(BuiltinType.Ubyte) == VR(ubyte.min, ubyte.max));
297 		assert(vrp.getRange(BuiltinType.Short) == VR(short.min, short.max));
298 		assert(vrp.getRange(BuiltinType.Ushort) == VR(ushort.min, ushort.max));
299 		assert(vrp.getRange(BuiltinType.Int) == VR(int.min, int.max));
300 		assert(vrp.getRange(BuiltinType.Uint) == VR(uint.min, uint.max));
301 
302 		static if (LS) {
303 			assert(vrp.getRange(BuiltinType.Long) == VR(long.min, long.max));
304 			assert(vrp.getRange(BuiltinType.Ulong) == VR(ulong.min, ulong.max));
305 		}
306 
307 		assert(vrp.getRange(BuiltinType.Char) == VR(ubyte.min, ubyte.max));
308 		assert(vrp.getRange(BuiltinType.Wchar) == VR(ushort.min, ushort.max));
309 		assert(vrp.getRange(BuiltinType.Dchar) == VR(uint.min, uint.max));
310 
311 		/**
312 		 * Literals
313 		 */
314 		import source.location;
315 		v = vrp.visit(new BooleanLiteral(Location.init, false));
316 		assert(v == VR(0));
317 
318 		v = vrp.visit(new BooleanLiteral(Location.init, true));
319 		assert(v == VR(1));
320 
321 		v = vrp.visit(new IntegerLiteral(Location.init, -9, BuiltinType.Byte));
322 		assert(v == VR(-9));
323 
324 		v = vrp.visit(new IntegerLiteral(Location.init, 42, BuiltinType.Uint));
325 		assert(v == VR(42));
326 
327 		// Let's define some values we can reuse.
328 		auto zero = new IntegerLiteral(Location.init, 0, BuiltinType.Int);
329 		auto i1 = new IntegerLiteral(Location.init, -7, BuiltinType.Int);
330 		auto i2 = new IntegerLiteral(Location.init, 42, BuiltinType.Int);
331 		auto i3 = new IntegerLiteral(Location.init, 2, BuiltinType.Uint);
332 
333 		auto bmax = new IntegerLiteral(Location.init, 255, BuiltinType.Byte);
334 
335 		auto tbool = Type.get(BuiltinType.Bool);
336 		auto tint = Type.get(BuiltinType.Int);
337 		auto tuint = Type.get(BuiltinType.Uint);
338 		auto tubyte = Type.get(BuiltinType.Ubyte);
339 		auto tlong = Type.get(BuiltinType.Long);
340 
341 		/**
342 		 * Binary ops
343 		 */
344 		v = vrp.visit(
345 			new BinaryExpression(Location.init, tint, BinaryOp.Comma, i1, i2));
346 		assert(v == VR(42));
347 
348 		// Technically, this is illegal, but it is out of scope of VRP to detect this, so will do.
349 		v = vrp.visit(
350 			new BinaryExpression(Location.init, tint, BinaryOp.Assign, i1, i2));
351 		assert(v == VR(42));
352 
353 		v = vrp.visit(
354 			new BinaryExpression(Location.init, tint, BinaryOp.Add, i1, i2));
355 		assert(v == VR(35));
356 
357 		v = vrp.visit(
358 			new BinaryExpression(Location.init, tint, BinaryOp.Sub, i1, i2));
359 		assert(v == VR(-49));
360 
361 		v = vrp.visit(
362 			new BinaryExpression(Location.init, tint, BinaryOp.Mul, i1, i2));
363 		assert(v == VR(-294));
364 
365 		v = vrp.visit(
366 			new BinaryExpression(Location.init, tuint, BinaryOp.UDiv, i1, i2));
367 		assert(v == VR((T.max - 6) / 42));
368 
369 		v = vrp.visit(
370 			new BinaryExpression(Location.init, tint, BinaryOp.SDiv, i2, i1));
371 		assert(v == VR(-6));
372 
373 		v = vrp.visit(
374 			new BinaryExpression(Location.init, tuint, BinaryOp.URem, i1, i2));
375 		assert(v == VR(LS ? 9 : 39));
376 
377 		v = vrp.visit(
378 			new BinaryExpression(Location.init, tint, BinaryOp.SRem, i1, i3));
379 		assert(v == VR(-1));
380 
381 		v = vrp.visit(
382 			new BinaryExpression(Location.init, tint, BinaryOp.Or, i1, i2));
383 		assert(v == VR(-5));
384 
385 		v = vrp.visit(
386 			new BinaryExpression(Location.init, tint, BinaryOp.And, i1, i2));
387 		assert(v == VR(40));
388 
389 		v = vrp.visit(
390 			new BinaryExpression(Location.init, tint, BinaryOp.Xor, i1, i2));
391 		assert(v == VR(-45));
392 
393 		v = vrp.visit(new BinaryExpression(Location.init, tint,
394 		                                   BinaryOp.LeftShift, i1, i3));
395 		assert(v == VR(-28));
396 
397 		v = vrp.visit(new BinaryExpression(
398 			Location.init, tuint, BinaryOp.UnsignedRightShift, i1, i3));
399 		assert(v == VR((T.max >> 2) - 1));
400 
401 		v = vrp.visit(new BinaryExpression(Location.init, tint,
402 		                                   BinaryOp.SignedRightShift, i1, i3));
403 		assert(v == VR(-2));
404 
405 		/**
406 		 * Unary ops
407 		 */
408 		v = vrp
409 			.visit(new UnaryExpression(Location.init, tuint, UnaryOp.Plus, i1));
410 		assert(v == VR(-7));
411 
412 		v = vrp.visit(
413 			new UnaryExpression(Location.init, tuint, UnaryOp.Minus, i1));
414 		assert(v == VR(7));
415 
416 		/**
417 		 * Variables
418 		 */
419 		import source.name;
420 		auto var = new Variable(Location.init,
421 		                        tuint.getParamType(ParamKind.Regular),
422 		                        BuiltinName!"", i1);
423 		var.step = Step.Processed;
424 
425 		v = vrp.visit(var);
426 		assert(v == VR(uint.min, uint.max));
427 
428 		var.type = tbool;
429 		v = vrp.visit(var);
430 		assert(v == VR(0, 1));
431 
432 		var.type = Type.get(BuiltinType.Short);
433 		v = vrp.visit(var);
434 		assert(v == VR(short.min, short.max));
435 
436 		var.storage = Storage.Enum;
437 		v = vrp.visit(var);
438 		assert(v == VR(-7));
439 
440 		var.storage = Storage.Static;
441 		v = vrp.visit(var);
442 		assert(v == VR(short.min, short.max));
443 
444 		var.type = var.type.qualify(TypeQualifier.Immutable);
445 		v = vrp.visit(var);
446 		assert(v == VR(-7));
447 
448 		/**
449 		 * Casts
450 		 */
451 		v = vrp.visit(
452 			new CastExpression(Location.init, CastKind.IntToBool, tbool, zero));
453 		assert(v == VR(0));
454 
455 		v = vrp.visit(
456 			new CastExpression(Location.init, CastKind.IntToBool, tbool, i1));
457 		assert(v == VR(1));
458 
459 		// FIXME: test the 0, 1 int to bool case ?
460 
461 		v = vrp.visit(
462 			new CastExpression(Location.init, CastKind.Trunc, tubyte, i1));
463 		assert(v == VR(249));
464 
465 		v = vrp.visit(
466 			new CastExpression(Location.init, CastKind.UPad, tint, bmax));
467 		assert(v == VR(255));
468 
469 		v = vrp.visit(
470 			new CastExpression(Location.init, CastKind.SPad, tint, bmax));
471 		assert(v == VR(-1));
472 
473 		v = vrp
474 			.visit(new CastExpression(Location.init, CastKind.Bit, tint, i1));
475 		assert(v == VR(-7));
476 
477 		v = vrp
478 			.visit(new CastExpression(Location.init, CastKind.Qual, tint, i1));
479 		assert(v == VR(-7));
480 
481 		v = vrp
482 			.visit(new CastExpression(Location.init, CastKind.Exact, tint, i1));
483 		assert(v == VR(-7));
484 	}
485 }
486 
487 private:
488 
489 auto isValidExpr(Expression e) {
490 	auto t = e.type.getCanonicalAndPeelEnum();
491 	return t.kind == TypeKind.Builtin && canConvertToIntegral(t.builtin);
492 }
493 
494 bool isMask(T)(T mask) if (isIntegral!T) {
495 	auto p = mask + 1;
496 	return (p & -p) == p;
497 }
498 
499 unittest {
500 	assert(isMask(0));
501 	assert(isMask(1));
502 	assert(!isMask(2));
503 	assert(isMask(3));
504 	assert(!isMask(10));
505 	assert(isMask(255));
506 }
507 
508 struct ValueRange(T) if (is(uint : T) && isIntegral!T) {
509 	T min = T.min;
510 	T max = T.max;
511 
512 	this(T min, T max) {
513 		this.min = min;
514 		this.max = max;
515 	}
516 
517 	this(T val) {
518 		this(val, val);
519 	}
520 
521 	alias U = Unsigned!T;
522 	alias S = Signed!T;
523 
524 	alias URange = ValueRange!U;
525 	alias SRange = ValueRange!S;
526 
527 	enum Bits = T.sizeof * 8;
528 
529 	@property
530 	U range() const {
531 		return max - min;
532 	}
533 
534 	@property
535 	bool full() const {
536 		return range == typeof(range).max;
537 	}
538 
539 	@property
540 	auto unsigned() const {
541 		return URange(min, max);
542 	}
543 
544 	@property
545 	auto signed() const {
546 		return SRange(min, max);
547 	}
548 
549 	@property
550 	auto normalized() const out(result) {
551 		assert(result.range >= range);
552 		assert(result.min <= result.max);
553 	} do {
554 		// This is lossy, only use when stritcly necessary.
555 		if (min > max) {
556 			return ValueRange();
557 		}
558 
559 		return this;
560 	}
561 
562 	@property
563 	bool containsZero() const {
564 		return unsigned.normalized.min == 0;
565 	}
566 
567 	@property
568 	bool isReduced() const {
569 		// A reduced range if of the form XXXX0000 => XXXX1111.
570 		auto x = (min ^ max) + 1;
571 		return (x & -x) == x;
572 	}
573 
574 	auto unionWith(ValueRange other) const {
575 		auto twraparound = this.max < this.min;
576 		auto owraparound = other.max < other.min;
577 
578 		if (twraparound == owraparound) {
579 			import std.algorithm : min, max;
580 			auto rmin = min(this.min, other.min);
581 			auto rmax = max(this.max, other.max);
582 
583 			auto r = ValueRange(rmin, rmax);
584 
585 			if (twraparound) {
586 				// Checks if we don't do more than a full range
587 				if (rmin <= rmax) {
588 					return ValueRange();
589 				}
590 			} else {
591 				// Maybe a wraparound range would be tighter.
592 				auto wmin = max(this.min, other.min);
593 				auto wmax = min(this.max, other.max);
594 
595 				auto w = ValueRange(wmin, wmax);
596 
597 				// If so, wraparound !
598 				if (wmin > wmax && (w.range < r.range)) {
599 					return w;
600 				}
601 			}
602 
603 			return r;
604 		}
605 
606 		ValueRange wr = this;
607 		if (owraparound) {
608 			import std.algorithm : swap;
609 			swap(wr, other);
610 		}
611 
612 		// Try to merge up and down, and chose the tighter.
613 		import std.algorithm : min, max;
614 		auto d = ValueRange(wr.min, max(wr.max, other.max));
615 		if (d.min <= d.max) {
616 			d = ValueRange();
617 		}
618 
619 		auto u = ValueRange(min(wr.min, other.min), wr.max);
620 		if (u.min <= u.max) {
621 			u = ValueRange();
622 		}
623 
624 		return u.range < d.range ? u : d;
625 	}
626 
627 	@property
628 	ValueRange!A as(A)() const if (is(uint : A) && isIntegral!A) out(result) {
629 		assert(result.range <= Unsigned!A.max);
630 	} do {
631 		static if (T.sizeof <= A.sizeof) {
632 			// Type are the same size, it is a noop.
633 			return ValueRange!A(min, max);
634 		} else {
635 			enum MaxRange = Unsigned!A.max;
636 
637 			// If the current range is larger than the destination: full range.
638 			if (range >= MaxRange) {
639 				return ValueRange!A();
640 			}
641 
642 			// Now the range fits. It's now a matter
643 			// of wrapping things around the right way.
644 
645 			// If we have a proper unsigned range, go for it.
646 			auto urange = this.unsigned;
647 			if (urange.min <= urange.max) {
648 				alias UA = Unsigned!A;
649 				auto umin = cast(UA) urange.min;
650 				auto umax = cast(UA) urange.max;
651 
652 				// No overflow check because the high bits are lost anyway.
653 				return ValueRange!UA(umin, umax).as!A;
654 			}
655 
656 			// If we have a proper signed range, go for it.
657 			auto srange = this.signed;
658 			if (srange.min <= srange.max) {
659 				alias SA = Unsigned!A;
660 				auto smin = cast(SA) srange.min;
661 				auto smax = cast(SA) srange.max;
662 
663 				// No overflow check because the high bits are lost anyway.
664 				return ValueRange!SA(smin, smax).as!A;
665 			}
666 
667 			// OK, we have some sort of screwed up range :)
668 			return ValueRange!A();
669 		}
670 	}
671 
672 	/**
673 	 * Fit a range into a smaller type with less bits.
674 	 *
675 	 * Try to produce a wrappign around range when possible.
676 	 * This will create ranges needlessly large when normalizing,
677 	 * but it doesn't matter as well formed expression should
678 	 * UPad or SPad before normalizing due to integer promotion.
679 	 */
680 	ValueRange trunc(U mask) const out(result) {
681 		assert(isMask(mask));
682 		assert(result.range <= mask);
683 	} do {
684 		auto smask = mask >> 1;
685 
686 		// Worse case scenario, we can return this.
687 		auto fail =
688 			isSigned!T ? ValueRange(~smask, smask) : ValueRange(0, mask);
689 
690 		// We do something similar to as!T, except that we sign extend
691 		// manually in the signed range case.
692 		if (range > mask) {
693 			return fail;
694 		}
695 
696 		auto urange = this.unsigned;
697 		if (urange.min <= urange.max) {
698 			auto umin = urange.min & mask;
699 			auto umax = urange.max & mask;
700 
701 			// Maybe umax wrapped around, in which case we wrap around.
702 			if (umax < umin) {
703 				umin = umin | ~mask;
704 			}
705 
706 			return ValueRange(umin, umax);
707 		}
708 
709 		auto srange = this.signed;
710 		if (srange.min <= srange.max) {
711 			// Other cases are already handled as unsigned.
712 			assert(srange.min < 0);
713 			assert(srange.max >= 0);
714 
715 			auto smin = srange.min | ~mask;
716 			auto smax = srange.max & mask;
717 			return ValueRange(smin, smax);
718 		}
719 
720 		// I don't think this can actually happen unless mask is all ones.
721 		// In which case, why we are truncating is a mystery to begin with.
722 		assert(mask + 1 == 0);
723 		return fail;
724 	}
725 
726 	/**
727 	 * Because it is a signed operation, paddign is actually the one
728 	 * finishing the truncate work. It works because properly formed
729 	 * expression are promoted before being used, and this promotion
730 	 * translates into a pad operation here.
731 	 */
732 	ValueRange pad()(U mask) const if (isUnsigned!T) out(result) {
733 		assert(result.range <= mask);
734 		assert(isMask(mask));
735 	} do {
736 		auto bits = min ^ max;
737 		return ((min > max) || (bits & ~mask))
738 			? ValueRange(0, mask)
739 			: ValueRange(min & mask, max & mask);
740 	}
741 
742 	ValueRange pad()(U mask) const if (isSigned!T) out(result) {
743 		assert(result.range <= mask);
744 		assert(isMask(mask));
745 	} do {
746 		auto offset = URange(~(mask >> 1));
747 		return ((unsigned - offset).pad(mask) + offset).signed;
748 	}
749 
750 	bool opEquals(ValueRange rhs) const {
751 		return (full && rhs.full) || (min == rhs.min && max == rhs.max);
752 	}
753 
754 	auto opUnary(string op : "-")() const {
755 		return ValueRange(-max, -min);
756 	}
757 
758 	auto opUnary(string op : "~")() const {
759 		return ValueRange(~max, ~min);
760 	}
761 
762 	auto opBinary(string op : "+")(ValueRange rhs) const {
763 		ulong lrange = this.range;
764 		ulong rrange = rhs.range;
765 		auto range = lrange + rrange;
766 
767 		// If the type is small enough, do the easy dance.
768 		auto overflow =
769 			Bits < 64 ? range > U.max : range < lrange && range < rrange;
770 
771 		return
772 			overflow ? ValueRange() : ValueRange(min + rhs.min, max + rhs.max);
773 	}
774 
775 	auto opBinary(string op : "-")(ValueRange rhs) const {
776 		return this + -rhs;
777 	}
778 
779 	auto smul()(ValueRange rhs) const if (isUnsigned!T) in {
780 		assert(min > max && max != 0);
781 	} do {
782 		auto v0 = ValueRange(0, max) * rhs;
783 		auto v1 = ValueRange(0, -min) * -rhs;
784 
785 		if (rhs.min <= rhs.max) {
786 			// If rhs don't wrap around, 0 should one of v0 bound.
787 			assert(v0.min == 0 || v0.max == 0);
788 			auto rmin = v0.min ? v0.min : v1.min;
789 			auto rmax = v0.min ? v1.max : v0.max;
790 			if (rmin > rmax) {
791 				return ValueRange(rmin, rmax);
792 			}
793 		} else {
794 			// If rhs wrap around, v1 and v0 will wrap around or be 0.
795 			import std.algorithm : min, max;
796 			auto rmin = min(v0.min, v1.min);
797 			auto rmax = max(v0.max, v1.max);
798 			if (rmin > rmax) {
799 				return ValueRange(rmin, rmax);
800 			}
801 		}
802 
803 		// We have an overflow.
804 		return ValueRange();
805 	}
806 
807 	auto umul()(ValueRange rhs) const if (isUnsigned!T) in {
808 		assert(min <= max);
809 		assert(rhs.min <= rhs.max);
810 	} do {
811 		// So we can swap modify.
812 		ValueRange lhs = this;
813 
814 		// If the whole range is in the negative, a * b = -(a * b).
815 		auto lneg = lhs.min > S.max;
816 		if (lneg) {
817 			lhs = -lhs;
818 		}
819 
820 		auto rneg = rhs.min > S.max;
821 		if (rneg) {
822 			rhs = -rhs;
823 		}
824 
825 		// Zero is a special case as it always produce a
826 		// range containign only itself. By splitting it,
827 		// we can make sure we minimally extend the range
828 		// to include 0 at the end.
829 		bool hasZero;
830 
831 		if (lhs.min == 0) {
832 			hasZero = true;
833 			lhs.min = 1;
834 		}
835 
836 		if (rhs.min == 0) {
837 			hasZero = true;
838 			rhs.min = 1;
839 		}
840 
841 		// Alright, now we are in a canonical form, we can proceed.
842 		static T mulhi(ulong a, ulong b) {
843 			static if (Bits < 64) {
844 				// XXX: VRP can't figure that one out aparently.
845 				return cast(T) ((a * b) >> Bits);
846 			} else {
847 				// (a0 << 32 + a1)(b0 << 32 + b1) = a0b0 << 64 + (a0b1 + a1b0) << 32 + a1b1
848 				auto a0 = a >> 32;
849 				auto a1 = a & uint.max;
850 
851 				auto b0 = b >> 32;
852 				auto b1 = b & uint.max;
853 
854 				auto a0b0 = a0 * b0;
855 				auto a0b1 = a0 * b1;
856 				auto a1b0 = a1 * b0;
857 				auto a1b1 = a1 * b1;
858 
859 				auto carry = (a1b1 >> 32 + ((a0b1 + a1b0) & uint.max)) >> 32;
860 				return a0b0 + (a0b1 >> 32) + (a1b0 >> 32) + carry;
861 			}
862 		}
863 
864 		// If this overflows, then return a full range.
865 		if (mulhi(lhs.min, rhs.min) != mulhi(lhs.max, rhs.max)) {
866 			return ValueRange();
867 		}
868 
869 		auto res = ValueRange(lhs.min * rhs.min, lhs.max * rhs.max);
870 		if (lneg != rneg) {
871 			res = -res;
872 		}
873 
874 		// We try to zero extend the range to be the most restrictive.
875 		if (!hasZero) {
876 			return res;
877 		}
878 
879 		if (res.min <= -res.max) {
880 			return ValueRange(0, res.max);
881 		} else {
882 			return ValueRange(res.min, 0);
883 		}
884 	}
885 
886 	auto opBinary(string op : "*")(ValueRange rhs) const if (isSigned!T) {
887 		// Multiplication doesn't care about sign.
888 		return (this.unsigned * rhs.unsigned).signed;
889 	}
890 
891 	ValueRange opBinary(string op : "*")(ValueRange rhs) const
892 			if (isUnsigned!T) {
893 		// Multiplication by 0 is always 0.
894 		auto zero = ValueRange(0);
895 		if (this == zero || rhs == zero) {
896 			// Zero is pain in the ass as it reduce ranges
897 			// to one element, making it hard to figure out
898 			// if an overflow occured.
899 			return zero;
900 		}
901 
902 		// Try to avoid slicing when not necessary.
903 		if (max == 0) {
904 			// [-a, 0] * rhs = -(rhs * [0 .. a])
905 			return -(rhs * -this);
906 		}
907 
908 		if (rhs.max == 0) {
909 			return -(this * -rhs);
910 		}
911 
912 		// If the range is of the kind [min .. T.max][0 .. max]
913 		// we split it in half and union the result.
914 		if (min > max) {
915 			return smul(rhs);
916 		}
917 
918 		if (rhs.min > rhs.max) {
919 			return rhs.smul(this);
920 		}
921 
922 		return umul(rhs);
923 	}
924 
925 	auto opBinary(string op : "/")(ValueRange rhs) const {
926 		rhs = rhs.normalized;
927 		if (rhs == ValueRange(0)) {
928 			// We have a division by 0, bail out.
929 			return ValueRange();
930 		}
931 
932 		// Remove 0 from rhs.
933 		rhs.min = rhs.min ? rhs.min : 1;
934 		rhs.max = rhs.max ? rhs.max : U.max;
935 
936 		// Make sure we normalize full ranges.
937 		ValueRange lhs = this.normalized;
938 		if (isUnsigned!T) {
939 			return ValueRange(lhs.min / rhs.max, lhs.max / rhs.min);
940 		} else {
941 			if (rhs.containsZero) {
942 				import std.algorithm : min, max;
943 				return
944 					ValueRange(min(lhs.min, -lhs.max), max(lhs.max, -lhs.min));
945 			}
946 
947 			// Alright, this is a signed division.
948 			bool neg = rhs.max < 0;
949 			if (neg) {
950 				// a / -b = -(a / b)
951 				rhs = -rhs;
952 			}
953 
954 			auto min = lhs.min / (lhs.min < 0 ? rhs.min : rhs.max);
955 			auto max = lhs.max / (lhs.max < 0 ? rhs.max : rhs.min);
956 			return neg ? ValueRange(-max, -min) : ValueRange(min, max);
957 		}
958 	}
959 
960 	auto srem()(ValueRange rhs) const if (isSigned!T) in {
961 		assert(this != ValueRange(0));
962 		assert(rhs is rhs.normalized);
963 	} do {
964 		if (rhs.max < 0) {
965 			// a % -b = a % b
966 			rhs = -rhs;
967 		}
968 
969 		if (rhs.containsZero) {
970 			import std.algorithm : max;
971 			rhs = ValueRange(1, max(-rhs.min, rhs.max));
972 		}
973 
974 		auto lhs = this.normalized;
975 
976 		// lhs is positive
977 		if (lhs.min >= 0) {
978 			return lhs.unsigned.urem(rhs.unsigned).signed;
979 		}
980 
981 		// lhs is negative
982 		if (lhs.max <= 0) {
983 			lhs = -lhs;
984 			return -lhs.unsigned.urem(rhs.unsigned).signed;
985 		}
986 
987 		// Ok lhs can be both positive and negative.
988 		// Compute both range and aggregate.
989 		auto pos = URange(0, lhs.max).urem(rhs.unsigned);
990 		auto neg = URange(0, -lhs.min).urem(rhs.unsigned);
991 
992 		return ValueRange(-neg.max, pos.max);
993 	}
994 
995 	auto urem()(ValueRange rhs) const if (isUnsigned!T) in {
996 		assert(this != ValueRange(0));
997 		assert(rhs is rhs.normalized);
998 		assert(rhs.min > 0);
999 	} do {
1000 		auto lhs = this.normalized;
1001 
1002 		// If lhs is within the bound of rhs.
1003 		if (lhs.max < rhs.max) {
1004 			// If rhs.min <= rhs.max we need to 0 extend.
1005 			return ValueRange((lhs.max > rhs.min) ? 0 : lhs.min, lhs.max);
1006 		}
1007 
1008 		// We count how many time we can remove rhs.max from lhs.
1009 		auto lminrmaxloop = lhs.min / rhs.max;
1010 		auto lmaxrmaxloop = lhs.max / rhs.max;
1011 
1012 		// If these counts aren't the same, we have the full modulo range.
1013 		if (lminrmaxloop != lmaxrmaxloop) {
1014 			return ValueRange(0, rhs.max - 1);
1015 		}
1016 
1017 		// Same process for rhs.min.
1018 		auto lminrminloop = lhs.min / rhs.min;
1019 		auto lmaxrminloop = lhs.max / rhs.min;
1020 
1021 		// FIXME: Idealy, we would look for the biggest
1022 		// value in rhs that have the correct count.
1023 		if (lminrminloop != lmaxrminloop || lminrminloop != lminrmaxloop) {
1024 			return ValueRange(0, rhs.max - 1);
1025 		}
1026 
1027 		// At this point, we know that as rhs grow, the result will reduce.
1028 		// and as lhs grow, the result will increase.
1029 		return ValueRange(lhs.min % rhs.max, lhs.max % rhs.min);
1030 	}
1031 
1032 	auto opBinary(string op : "%")(ValueRange rhs) const {
1033 		rhs = rhs.normalized;
1034 		if (rhs == ValueRange(0)) {
1035 			// We have a division by 0, bail out.
1036 			return this;
1037 		}
1038 
1039 		static if (isSigned!T) {
1040 			return srem(rhs);
1041 		} else {
1042 			rhs.min = rhs.min ? rhs.min : 1;
1043 			return urem(rhs);
1044 		}
1045 	}
1046 
1047 	auto sshl()(ValueRange rhs) const if (isUnsigned!T) in {
1048 		assert(rhs is rhs.normalized);
1049 		assert(rhs.max < Bits);
1050 	} do {
1051 		auto v0 = ValueRange(0, max).ushl(rhs);
1052 		auto v1 = -ValueRange(0, -min).ushl(rhs);
1053 
1054 		if (v0.max >= v1.min) {
1055 			return ValueRange();
1056 		}
1057 
1058 		return ValueRange(v1.min, v0.max);
1059 	}
1060 
1061 	auto ushl()(ValueRange rhs) const if (isUnsigned!T) in {
1062 		assert(rhs is rhs.normalized);
1063 		assert(rhs.max < Bits);
1064 		assert(this.min <= Signed!T.max);
1065 	} do {
1066 		auto minhi = rhs.min ? (min >> (Bits - rhs.min)) : 0;
1067 		auto maxhi = rhs.max ? (max >> (Bits - rhs.max)) : 0;
1068 		if (minhi != maxhi) {
1069 			return ValueRange();
1070 		}
1071 
1072 		return ValueRange(min << rhs.min, max << rhs.max);
1073 	}
1074 
1075 	auto opBinary(string op : "<<")(ValueRange rhs) const if (isSigned!T) {
1076 		return (this.unsigned << rhs.unsigned).signed;
1077 	}
1078 
1079 	auto opBinary(string op : "<<")(ValueRange rhs) const if (isUnsigned!T) {
1080 		rhs = rhs.normalized;
1081 
1082 		// We are in undefined territory, pessimize.
1083 		if (rhs.max >= Bits) {
1084 			// We assume that shifting 0 is alright.
1085 			return this == ValueRange(0) ? ValueRange(0) : ValueRange();
1086 		}
1087 
1088 		if (min > max) {
1089 			return sshl(rhs);
1090 		}
1091 
1092 		ValueRange lhs = this;
1093 
1094 		auto lneg = min > S.max;
1095 		if (lneg) {
1096 			lhs = -lhs;
1097 		}
1098 
1099 		auto res = lhs.ushl(rhs);
1100 		return lneg ? -res : res;
1101 	}
1102 
1103 	auto sshr(URange rhs) const in {
1104 		assert(rhs is rhs.normalized);
1105 		assert(rhs.min < Bits);
1106 	} do {
1107 		auto v0 = ValueRange(0, max).ushr(rhs);
1108 		auto v1 = ValueRange(min, U.max).ushr(rhs);
1109 
1110 		auto res = ValueRange();
1111 
1112 		U rmax = v0.max;
1113 		U rmin = v1.min;
1114 		if (rmin > rmax) {
1115 			res = ValueRange(rmin, rmax);
1116 		}
1117 
1118 		if (isUnsigned!T) {
1119 			rmax = U.max >> rhs.min;
1120 			if (res.range > rmax) {
1121 				// If 0 .. umax >> rhs.min is smaller than
1122 				// what we have now, use that instead.
1123 				res = ValueRange(0, rmax);
1124 			}
1125 		}
1126 
1127 		return res;
1128 	}
1129 
1130 	auto ushr(URange rhs) const in {
1131 		assert(rhs is rhs.normalized);
1132 		assert(rhs.min < Bits);
1133 	} do {
1134 		T rmin = min >> (min < 0 ? rhs.min : rhs.max);
1135 		if (min >= 0 && rhs.max >= Bits) {
1136 			rmin = 0;
1137 		}
1138 
1139 		T rmax = max >> (max < 0 ? rhs.max : rhs.min);
1140 		if (max < 0 && rhs.max >= Bits) {
1141 			rmax = Unsigned!T.max;
1142 		}
1143 
1144 		return ValueRange(rmin, rmax);
1145 	}
1146 
1147 	auto opBinary(string op : ">>")(ValueRange other) const {
1148 		auto rhs = other.unsigned.normalized;
1149 
1150 		// We are in undefined territory, pessimize.
1151 		if (rhs.min >= Bits) {
1152 			// We assume that shifting 0 is alright.
1153 			// XXX: This is undefined, so I'm not sure what to do.
1154 			// Probably anything is fine as it is undefined :)
1155 			return ValueRange(0);
1156 		}
1157 
1158 		auto lhs = this.unsigned;
1159 		return lhs.min > lhs.max ? sshr(rhs) : ushr(rhs);
1160 	}
1161 
1162 	auto opBinary(string op : ">>>")(ValueRange rhs) const if (isSigned!T) {
1163 		return (this.unsigned >>> rhs.unsigned).signed;
1164 	}
1165 
1166 	auto opBinary(string op : ">>>")(ValueRange rhs) const if (isUnsigned!T) {
1167 		return this >> rhs;
1168 	}
1169 
1170 	/**
1171 	 * This whole dance is O(n^2) but n is small, so it doesn't matter.
1172 	 * This split lhs into reduced ranges and combine the results.
1173 	 */
1174 	ValueRange reduceOrdered(alias doOp, bool hasFlipped = false)(
1175 		ValueRange rhs,
1176 	) const if (isUnsigned!T) in {
1177 		assert(min <= max && rhs.min <= rhs.max);
1178 	} do {
1179 		static nextRange(T t) out(result) {
1180 			assert((t & result) == 0);
1181 		} do {
1182 			return (t & -t) - 1;
1183 		}
1184 
1185 		ValueRange lhs = this;
1186 
1187 		// Just pick one value we know is in the range.
1188 		auto result = doOp(ValueRange(lhs.min), ValueRange(rhs.min));
1189 
1190 		while (true) {
1191 			T split;
1192 			ValueRange reduced;
1193 
1194 			auto lminrange = nextRange(lhs.min);
1195 			auto lmaxrange = nextRange(lhs.max + 1);
1196 
1197 			auto reduceFromMin = lminrange <= lmaxrange;
1198 			if (reduceFromMin) {
1199 				split = lhs.min | lminrange;
1200 				reduced = ValueRange(lhs.min, split);
1201 			} else {
1202 				split = lhs.max - lmaxrange;
1203 				reduced = ValueRange(split, lhs.max);
1204 			}
1205 
1206 			static if (hasFlipped) {
1207 				assert(reduced.isReduced && rhs.isReduced);
1208 				result = result.unionWith(doOp(reduced, rhs));
1209 			} else {
1210 				assert(reduced.isReduced);
1211 				result =
1212 					result.unionWith(rhs.reduceOrdered!(doOp, true)(reduced));
1213 			}
1214 
1215 			// We just fully reduced this range, return.
1216 			if (reduced == lhs) {
1217 				return result;
1218 			}
1219 
1220 			lhs = reduceFromMin
1221 				? ValueRange(split + 1, lhs.max)
1222 				: ValueRange(lhs.min, split - 1);
1223 		}
1224 	}
1225 
1226 	ValueRange reduce(alias doOp, bool hasFlipped = false)(
1227 		ValueRange rhs,
1228 	) const if (isUnsigned!T) {
1229 		if (min <= max) {
1230 			return hasFlipped
1231 				? reduceOrdered!doOp(rhs)
1232 				: rhs.reduce!(doOp, true)(this);
1233 		}
1234 
1235 		return rhs.reduce!(doOp, true)(ValueRange(0, max))
1236 			.unionWith(rhs.reduce!(doOp, true)(ValueRange(min, T.max)));
1237 	}
1238 
1239 	auto opBinary(string op : "&")(ValueRange rhs) const if (isSigned!T) {
1240 		return (this.unsigned & rhs.unsigned).signed;
1241 	}
1242 
1243 	ValueRange opBinary(string op : "&")(ValueRange rhs) const
1244 			if (isUnsigned!T) {
1245 		static doAnd(ValueRange lhs, ValueRange rhs) {
1246 			return ValueRange(lhs.min & rhs.min, lhs.max & rhs.max);
1247 		}
1248 
1249 		return reduce!doAnd(rhs);
1250 	}
1251 
1252 	auto opBinary(string op : "|")(ValueRange rhs) const {
1253 		// Just bitflip, and use the and logic.
1254 		return ~(~this & ~rhs);
1255 	}
1256 
1257 	auto opBinary(string op : "^")(ValueRange rhs) const if (isSigned!T) {
1258 		return (this.unsigned ^ rhs.unsigned).signed;
1259 	}
1260 
1261 	auto opBinary(string op : "^")(ValueRange rhs) const if (isUnsigned!T) {
1262 		static doXor(ValueRange lhs, ValueRange rhs) {
1263 			auto mask = (lhs.min ^ lhs.max) | (rhs.min ^ rhs.max);
1264 			auto base = lhs.min ^ rhs.min;
1265 			return ValueRange(base & ~mask, base | mask);
1266 		}
1267 
1268 		return reduce!doXor(rhs);
1269 	}
1270 }
1271 
1272 unittest {
1273 	template coerceRange(T) {
1274 		auto coerceRange(A...)(A args) {
1275 			alias U = CommonType!(A, T);
1276 			return ValueRange!U(args).as!T;
1277 		}
1278 	}
1279 
1280 	void testComplement(T)(ValueRange!T a, ValueRange!T b) {
1281 		assert(~a == b, "~a = b");
1282 		assert(a == ~b, "a = ~b");
1283 
1284 		auto one = ValueRange!T(1);
1285 		assert(-a == b + one, "-a = b + 1");
1286 		assert(a == -b - one, "a = -b - 1");
1287 	}
1288 
1289 	void testUnion(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1290 		assert(a.unionWith(b) == c, "a U b = c");
1291 		assert(b.unionWith(a) == c, "b U a = c");
1292 
1293 		assert((-a).unionWith(-b) == -c, "-a U -b = -c");
1294 		assert((-b).unionWith(-a) == -c, "-b U -a = -c");
1295 	}
1296 
1297 	void testAddSub(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c,
1298 	                   ValueRange!T d) {
1299 		// Add
1300 		assert(a + b == c, "a + b = c");
1301 		assert(b + a == c, "b + a = c");
1302 		assert(-a - b == -c, "-a - b = -c");
1303 		assert(-(a + b) == -c, "-(a + b) = -c");
1304 		assert(-a + -b == -c, "-a + -b = -c");
1305 
1306 		// Sub
1307 		assert(a - b == d, "a - b = d");
1308 		assert(b - a == -d, "b - a = -d");
1309 		assert(a + -b == d, "a + -b = d");
1310 		assert(-a - -b == -d, "-a - -b = -d");
1311 	}
1312 
1313 	void testMul(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1314 		assert(a * b == c, "a * b = c");
1315 		assert(b * a == c, "b * a = c");
1316 
1317 		bool asym = a == -a;
1318 		bool bsym = b == -b;
1319 
1320 		assert(-a * b == (asym ? c : -c), "-a * b = -c");
1321 		assert(b * -a == (asym ? c : -c), "b * -a = -c");
1322 		assert(a * -b == (bsym ? c : -c), "a * -b = -c");
1323 		assert(-b * a == (bsym ? c : -c), "-b * a = -c");
1324 		assert(-a * -b == ((asym == bsym) ? c : -c), "-a * -b = c");
1325 		assert(-b * -a == ((asym == bsym) ? c : -c), "-b * -a = c");
1326 	}
1327 
1328 	void testDiv(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1329 		assert(a / b == c, "a / b = c");
1330 
1331 		static if (isSigned!T) {
1332 			assert(-a / b == -c, "-a / b = -c");
1333 			assert(a / -b == -c, "a / -b = -c");
1334 			assert(-a / -b == c, "-a / -b = c");
1335 		}
1336 	}
1337 
1338 	void testRem(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1339 		assert(a % b == c, "a % b = c");
1340 
1341 		static if (isSigned!T) {
1342 			assert(-a % b == -c, "-a % b = -c");
1343 			assert(a % -b == c, "a % -b = c");
1344 			assert(-a % -b == -c, "-a % -b = -c");
1345 		}
1346 	}
1347 
1348 	void testLShift(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1349 		assert(a << b == c, "a << b = c");
1350 	}
1351 
1352 	void testSRShift(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1353 		assert(a >> b == c, "a >> b = c");
1354 	}
1355 
1356 	void testURShift(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1357 		assert(a >>> b == c, "a >>> b = c");
1358 	}
1359 
1360 	void testAnd(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1361 		assert((a & b) == c, "a & b = c");
1362 		assert((b & a) == c, "b & a = c");
1363 	}
1364 
1365 	void testOr(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1366 		assert((a | b) == c, "a | b = c");
1367 		assert((b | a) == c, "b | a = c");
1368 	}
1369 
1370 	void testXor(T)(ValueRange!T a, ValueRange!T b, ValueRange!T c) {
1371 		assert((a ^ b) == c, "a ^ b = c");
1372 		assert((b ^ a) == c, "b ^ a = c");
1373 	}
1374 
1375 	import std.meta;
1376 	foreach (T; AliasSeq!(int, uint, long, ulong)) {
1377 		alias VR = coerceRange!T;
1378 		enum LS = T.sizeof == long.sizeof;
1379 
1380 		// Some useful values
1381 		auto umax = Unsigned!T.max;
1382 		auto umin = Unsigned!T.min;
1383 		auto smax = umax >>> 1;
1384 		auto smin = smax + 1;
1385 
1386 		/**
1387 		 * Test coercion
1388 		 */
1389 		assert(VR() == ValueRange!T());
1390 		assert(VR(0) == ValueRange!T(0));
1391 		assert(VR(1, 25) == ValueRange!T(1, 25));
1392 		assert(VR(-3, 12) == ValueRange!T(-3, 12));
1393 		assert(VR(-44, -26) == ValueRange!T(-44, -26));
1394 
1395 		// Check coercion with wrap around
1396 		assert(ValueRange!int(25, 1).as!T == VR(25, 1));
1397 		assert(ValueRange!long(25, 1).as!T == (LS ? VR(25, 1) : VR()));
1398 		assert(ValueRange!int(-25, -37).as!T == VR(-25, -37));
1399 		assert(ValueRange!long(-25, -37).as!T == (LS ? VR(-25, -37) : VR()));
1400 
1401 		/**
1402 		 * Test normalization
1403 		 */
1404 		assert(VR().normalized == VR());
1405 		assert(VR(15).normalized == VR(15));
1406 		assert(VR(3, 15).normalized == VR(3, 15));
1407 		assert(VR(-38, -15).normalized == VR(-38, -15));
1408 
1409 		// Wraparound
1410 		assert(VR(-31, 11).normalized == (isSigned!T ? VR(-31, 11) : VR()));
1411 		assert(VR(31, smax + 31).normalized
1412 			== (isSigned!T ? VR() : VR(31, smax + 31)));
1413 
1414 		// Degenerate ranges
1415 		assert(VR(138, 15).normalized == VR());
1416 		assert(VR(-38, -153).normalized == VR());
1417 
1418 		/**
1419 		 * Test truncation
1420 		 */
1421 		assert(VR(0).trunc(0xFF) == VR(0));
1422 		assert(VR(15).trunc(0xFF) == VR(15));
1423 		assert(VR(-8, 15).trunc(0xFF) == VR(-8, 15));
1424 		assert(VR(-80, -8).trunc(0xFF) == VR(176, 248));
1425 
1426 		// Do not fit
1427 		assert(VR(5, 300).trunc(0xFF)
1428 			== (isSigned!T ? VR(-0x80, 0x7F) : VR(0, 0xFF)));
1429 		assert(
1430 			VR().trunc(0xFF) == (isSigned!T ? VR(-0x80, 0x7F) : VR(0, 0xFF)));
1431 
1432 		// Fit via wraparound
1433 		assert(VR(250, 260).trunc(0xFF) == VR(-6, 4));
1434 
1435 		/**
1436 		 * Test padding
1437 		 */
1438 		assert(VR(0).pad(0xFF) == VR(0));
1439 		assert(VR(15).pad(0xFF) == VR(15));
1440 		assert(VR(255).pad(0xFF) == (isSigned!T ? VR(-1) : VR(255)));
1441 		assert(VR(176, 248).pad(0xFF)
1442 			== (isSigned!T ? VR(-80, -8) : VR(176, 248)));
1443 		assert(
1444 			VR(-80, -8).pad(0xFF) == (isSigned!T ? VR(-80, -8) : VR(176, 248)));
1445 
1446 		// Immaterializable ranges
1447 		assert(
1448 			VR(1, 158).pad(0xFF) == (isSigned!T ? VR(-128, 127) : VR(1, 158)));
1449 		assert(VR(-8, 15).pad(0xFF) == (isSigned!T ? VR(-8, 15) : VR(0, 255)));
1450 		assert(VR(5, 300).pad(0xFF)
1451 			== (isSigned!T ? VR(-0x80, 0x7F) : VR(0, 0xFF)));
1452 
1453 		/**
1454 		 * Test complement
1455 		 */
1456 		testComplement(VR(0), VR(-1));
1457 		testComplement(VR(1), VR(-2));
1458 		testComplement(VR(42), VR(-43));
1459 
1460 		// T.min and T.max are a special cases
1461 		testComplement(VR(T.min), VR(T.max));
1462 
1463 		// Full range
1464 		testComplement(VR(), VR());
1465 
1466 		// Various ranges
1467 		testComplement(VR(0, 42), VR(-43, -1));
1468 		testComplement(VR(42, 0), VR(-1, -43));
1469 		testComplement(VR(23, 38), VR(-39, -24));
1470 		testComplement(VR(-23, 38), VR(-39, 22));
1471 
1472 		/**
1473 		 * Test union
1474 		 */
1475 		testUnion(VR(), VR(), VR());
1476 		testUnion(VR(0), VR(0), VR(0));
1477 		testUnion(VR(42), VR(42), VR(42));
1478 		testUnion(VR(1), VR(7), VR(1, 7));
1479 
1480 		// Positive ranges
1481 		testUnion(VR(1, 7), VR(17, 23), VR(1, 23)); // disjoint
1482 		testUnion(VR(3, 23), VR(17, 27), VR(3, 27)); // overlaping
1483 		testUnion(VR(3, 27), VR(17, 23), VR(3, 27)); // contained
1484 
1485 		// Negative ranges
1486 		testUnion(VR(-7, -1), VR(-23, -17), VR(-23, -1)); // disjoint
1487 		testUnion(VR(-17, -3), VR(-23, -13), VR(-23, -3)); // overlaping
1488 		testUnion(VR(-27, -3), VR(-23, -17), VR(-27, -3)); // contained
1489 
1490 		// Signed ranges
1491 		testUnion(VR(-7, 1), VR(3, 12), VR(-7, 12)); // disjoint
1492 		testUnion(VR(-7, 7), VR(3, 12), VR(-7, 12)); // overlaping
1493 		testUnion(VR(-7, 12), VR(3, 5), VR(-7, 12)); // contained
1494 
1495 		testUnion(VR(-7, -1), VR(3, 12), VR(-7, 12)); // disjoint
1496 		testUnion(VR(-7, 7), VR(-3, 12), VR(-7, 12)); // overlaping
1497 		testUnion(VR(-7, 12), VR(-3, 5), VR(-7, 12)); // contained
1498 
1499 		// Degenerate ranges
1500 		testUnion(VR(23, 1), VR(3, 12), VR(23, 12)); // disjoint
1501 		testUnion(VR(23, 7), VR(3, 12), VR(23, 12)); // overlaping
1502 		testUnion(VR(23, 12), VR(3, 5), VR(23, 12)); // contained
1503 
1504 		/**
1505 		 * Test add/sub
1506 		 */
1507 		testAddSub(VR(1), VR(-1), VR(0), VR(2));
1508 		testAddSub(VR(-5, 0), VR(-1, 5), VR(-6, 5), VR(-10, 1));
1509 		testAddSub(VR(5, 6), VR(-3, 5), VR(2, 11), VR(0, 9));
1510 		testAddSub(VR(-12, 85), VR(5, 53), VR(-7, 138), VR(-65, 80));
1511 
1512 		// Flirting with the limit
1513 		testAddSub(VR(1, smax), VR(smin, -1), VR(smin + 1, smax - 1),
1514 		           VR(2, -1));
1515 
1516 		// overflow
1517 		testAddSub(VR(0, -42), VR(42, -1), VR(), VR());
1518 		testAddSub(VR(1, long.max + 2), VR(long.min, -1), VR(), VR());
1519 
1520 		/**
1521 		 * Test mul
1522 		 */
1523 		// Zero time all kind of things is always 0.
1524 		testMul(VR(0), VR(), VR(0));
1525 		testMul(VR(0), VR(0), VR(0));
1526 		testMul(VR(0), VR(2, 3), VR(0));
1527 		testMul(VR(0), VR(-7, 3), VR(0));
1528 		testMul(VR(0), VR(3, -23), VR(0));
1529 		testMul(VR(0), VR(-39, -23), VR(0));
1530 
1531 		// One time all of things is all kind of things.
1532 		testMul(VR(1), VR(), VR());
1533 		testMul(VR(1), VR(2, 3), VR(2, 3));
1534 		testMul(VR(1), VR(-7, 3), VR(-7, 3));
1535 		testMul(VR(1), VR(3, -23), VR(3, -23));
1536 		testMul(VR(1), VR(-39, -23), VR(-39, -23));
1537 
1538 		// Full ranges
1539 		testMul(VR(), VR(), VR());
1540 
1541 		// [0 .. 1] do zero extend.
1542 		testMul(VR(0, 1), VR(2, 3), VR(0, 3));
1543 		testMul(VR(0, 1), VR(-7, 3), VR(-7, 3));
1544 		testMul(VR(0, 1), VR(3, -23), VR(0, -23));
1545 		testMul(VR(0, 1), VR(-39, -23), VR(-39, 0));
1546 
1547 		// Symetric ranges are tools of the devil.
1548 		testMul(VR(0, 1), VR(3, -3), VR(0, -3));
1549 		testMul(VR(-1, 1), VR(3, 5), VR(-5, 5));
1550 
1551 		// min < max
1552 		testMul(VR(2, 3), VR(7, 23), VR(14, 69));
1553 		testMul(VR(1), VR(125, -32), VR(125, -32));
1554 		testMul(VR(-7, -4), VR(-5, -3), VR(12, 35));
1555 		testMul(VR(3, 3037000500), VR(7, 3037000500),
1556 		        VR(21, 9223372037000250000UL));
1557 
1558 		// min > max on one side
1559 		testMul(VR(-5, 42), VR(1), VR(-5, 42));
1560 		testMul(VR(-5, 42), VR(2, 5), VR(-25, 210));
1561 		testMul(VR(-5, 12), VR(0, 7), VR(-35, 84));
1562 		testMul(VR(-5, 42), VR(0), VR(0));
1563 		testMul(VR(5, 3037000500), VR(-12, 3037000500),
1564 		        VR(-36444006000, 9223372037000250000UL));
1565 
1566 		// min > max on both side
1567 		testMul(VR(-1, 5), VR(-7, 22), VR(-35, 110));
1568 		testMul(VR(-11, 3037000500), VR(-8, 3037000500),
1569 		        VR(-33407005500, 9223372037000250000UL));
1570 
1571 		// overflow
1572 		testMul(VR(123), VR(long.min, ulong.max), VR());
1573 		testMul(VR(0, 4294967296), VR(0, 4294967297), VR());
1574 		testMul(VR(-23, 4294967296), VR(10, 4294967297), VR());
1575 		testMul(VR(-3037000500, 3037000500), VR(-3037000500, 3037000500), VR());
1576 
1577 		/**
1578 		 * Test div
1579 		 */
1580 		// unsigned numerator.
1581 		testDiv(VR(23), VR(5), VR(4));
1582 		testDiv(VR(23, 125), VR(5, 7), VR(3, 25));
1583 		testDiv(VR(0, 201), VR(12, 17), VR(0, 16));
1584 
1585 		// signed numerator
1586 		testDiv(VR(-23), VR(5), isSigned!T ? VR(-4) : VR((T.min - 23) / 5));
1587 		testDiv(VR(-27, 31), VR(5, 9),
1588 		        isSigned!T ? VR(-5, 6) : VR(0, T.max / 5));
1589 		testDiv(VR(-23, 125), VR(89351496, 458963274),
1590 		        isSigned!T ? VR(0) : VR(0, (T.min - 23) / 89351496));
1591 
1592 		// signed denumerator
1593 		testDiv(VR(23), VR(-5), isSigned!T ? VR(-4) : VR(0));
1594 		testDiv(VR(23, 125), VR(-7, -5), isSigned!T ? VR(-25, -3) : VR(0));
1595 
1596 		// division by 0.
1597 		testDiv(VR(42), VR(0), VR());
1598 		testDiv(VR(42), VR(0, 25), VR(1, 42));
1599 		testDiv(VR(42), VR(-8, 0), isSigned!T ? VR(-42, -5) : VR(0, 42));
1600 		testDiv(VR(42), VR(-5, 7), isSigned!T ? VR(-42, 42) : VR(0, 42));
1601 		testDiv(VR(-47, 42), VR(-5, 7), isSigned!T ? VR(-47, 47) : VR());
1602 
1603 		// degenerate numerator.
1604 		testDiv(VR(2, 1), VR(89351496, 458963274),
1605 		        VR(T.min / 89351496, T.max / 89351496));
1606 		testDiv(VR(125, -23), VR(89351496, 458963274),
1607 		        VR(T.min / 89351496, T.max / 89351496));
1608 		testDiv(VR(-12, -23), VR(89351496, 458963274),
1609 		        VR(T.min / 89351496, T.max / 89351496));
1610 
1611 		/**
1612 		 * Test rem
1613 		 */
1614 		// non overflowing
1615 		testRem(VR(14, 52), VR(101, 109), VR(14, 52));
1616 		testRem(VR(18, 47), VR(9, 109), VR(0, 47));
1617 		testRem(VR(-21, 16), VR(123, 456),
1618 		        isSigned!T ? VR(-21, 16) : VR(0, 455));
1619 
1620 		// within the same loop
1621 		testRem(VR(23), VR(5), VR(3));
1622 		testRem(VR(127), VR(121, 123), VR(4, 6));
1623 		testRem(VR(127, 132), VR(121, 125), VR(2, 11));
1624 		testRem(VR(144, 156), VR(136, 144), VR(0, 20));
1625 
1626 		// not in the same loop
1627 		testRem(VR(12, 61), VR(49), VR(0, 48));
1628 		testRem(VR(23, 152), VR(50), VR(0, 49));
1629 		testRem(VR(12, 61), VR(49, 124), VR(0, 61));
1630 		testRem(VR(118, 152), VR(50, 57), VR(0, 56));
1631 
1632 		// degenerate numerator
1633 		testRem(VR(125, -23), VR(210, 214),
1634 		        isSigned!T ? VR(-213, 213) : VR(0, 213));
1635 
1636 		// modulo 0 elimination.
1637 		testRem(VR(23), VR(0, 3), VR(0, 2));
1638 		testRem(VR(121, 161), VR(-57, 52), isSigned!T ? VR(0, 56) : VR(0, 161));
1639 		testRem(VR(-21, 34), VR(-17, 24),
1640 		        isSigned!T ? VR(-21, 23) : VR(0, T.max - 1));
1641 		testRem(VR(34, 53), VR(-41, 36), isSigned!T ? VR(0, 40) : VR(0, 53));
1642 		testRem(VR(-25, 42), VR(-13, 75),
1643 		        isSigned!T ? VR(-25, 42) : VR(0, T.max - 1));
1644 
1645 		/**
1646 		 * Test left shift
1647 		 */
1648 		testLShift(VR(42), VR(0), VR(42));
1649 		testLShift(VR(23), VR(2), VR(92));
1650 		testLShift(VR(13), VR(0, 2), VR(13, 52));
1651 		testLShift(VR(3, 13), VR(1, 7), VR(6, 1664));
1652 		testLShift(VR(-30, -18), VR(1, 7), VR(-3840, -36));
1653 		testLShift(VR(-5, 18), VR(1, 7), VR(-640, 2304));
1654 
1655 		// full ranges and zeros
1656 		testLShift(VR(0), VR(0), VR(0));
1657 		testLShift(VR(0), VR(), VR(0));
1658 		testLShift(VR(), VR(0), VR());
1659 		testLShift(VR(), VR(), VR());
1660 
1661 		// overflowing rhs
1662 		testLShift(VR(5), VR(32), VR(LS ? 5UL << 32 : 0, 5UL << 32));
1663 		testLShift(VR(5), VR(64), VR());
1664 		testLShift(VR(5), VR(78), VR());
1665 		testLShift(VR(5), VR(-1), VR());
1666 		testLShift(VR(5), VR(-1, 7), VR());
1667 
1668 		// oveflow lhs
1669 		testLShift(VR(-1084, 1084), VR(21), VR(-1084UL << 21, 1084UL << 21));
1670 
1671 		// degenerate ranges
1672 		testLShift(VR(23, 6), VR(0), VR(23, 6));
1673 		testLShift(VR(23, 6), VR(1), VR());
1674 		testLShift(VR(23, -6), VR(0, 2), VR());
1675 		testLShift(VR(-23, -62), VR(0, 2), VR());
1676 
1677 		/**
1678 		 * Test signed right shift
1679 		 */
1680 		testSRShift(VR(42), VR(0), VR(42));
1681 		testSRShift(VR(42), VR(2), VR(10));
1682 		testSRShift(VR(4321), VR(2, 7), VR(33, 1080));
1683 		testSRShift(VR(12, 65), VR(1, 3), VR(1, 32));
1684 
1685 		// Signed shift
1686 		testSRShift(
1687 			VR(-35, -22), VR(1, 3),
1688 			isSigned!T ? VR(-18, -3) : VR((umin - 35) >> 3, (umin - 22) >> 1));
1689 		testSRShift(VR(-35, 22), VR(0, 3),
1690 		            isSigned!T ? VR(-35, 22) : VR((umin - 35) >> 3, 22));
1691 		testSRShift(VR(-35, 22), VR(1, 3),
1692 		            isSigned!T ? VR(-18, 11) : VR(0, umax >> 1));
1693 
1694 		// full ranges and zeros
1695 		testSRShift(VR(0), VR(0), VR(0));
1696 		testSRShift(VR(0), VR(), VR(0));
1697 		testSRShift(VR(), VR(0), VR());
1698 		testSRShift(VR(), VR(), VR());
1699 
1700 		// degenerate ranges
1701 		testSRShift(VR(23, 6), VR(0), VR(23, 6));
1702 		testSRShift(VR(23, 6), VR(1),
1703 		            isSigned!T ? VR(11, 3) : VR(0, umax >> 1));
1704 		testSRShift(VR(23, -6), VR(0, 2), isSigned!T ? VR(5, -2) : VR(5, -6));
1705 		testSRShift(VR(23, -6), VR(1, 2),
1706 		            isSigned!T ? VR(5, -2) : VR(5, (umin - 6) >> 1));
1707 		testSRShift(VR(-23, -62), VR(0, 2), VR());
1708 
1709 		/**
1710 		 * Test unsigned right shift
1711 		 */
1712 		testURShift(VR(42), VR(0), VR(42));
1713 		testURShift(VR(42), VR(2), VR(10));
1714 		testURShift(VR(4321), VR(2, 7), VR(33, 1080));
1715 		testURShift(VR(12, 65), VR(1, 3), VR(1, 32));
1716 
1717 		// Signed shift
1718 		testURShift(VR(-35, -22), VR(1, 3),
1719 		            VR((umin - 35) >> 3, (umin - 22) >> 1));
1720 		testURShift(VR(-35, 22), VR(0, 3), VR((umin - 35) >> 3, 22));
1721 		testURShift(VR(-35, 22), VR(1, 3), VR(0, umax >> 1));
1722 
1723 		// full ranges and zeros
1724 		testURShift(VR(0), VR(0), VR(0));
1725 		testURShift(VR(0), VR(), VR(0));
1726 		testURShift(VR(), VR(0), VR());
1727 		testURShift(VR(), VR(), VR());
1728 
1729 		// degenerate ranges
1730 		testURShift(VR(23, 6), VR(0), VR(23, 6));
1731 		testURShift(VR(23, 6), VR(1), VR(0, umax >> 1));
1732 		testURShift(VR(23, -6), VR(0, 2), VR(5, -6));
1733 		testURShift(VR(23, -6), VR(2, 4), VR(1, (umin - 6) >> 2));
1734 		testURShift(VR(-23, -62), VR(0, 2), VR());
1735 		testURShift(VR(-23, -62), VR(1, 2), VR(0, umax >> 1));
1736 
1737 		/**
1738 		 * Test and
1739 		 */
1740 		testAnd(VR(123), VR(1), VR(1));
1741 		testAnd(VR(11, 15), VR(1), VR(0, 1));
1742 		testAnd(VR(11, 15), VR(2), VR(0, 2));
1743 		testAnd(VR(10, 11), VR(2), VR(2, 2));
1744 		testAnd(VR(10, 11), VR(3), VR(2, 3));
1745 		testAnd(VR(9, 11), VR(3), VR(1, 3));
1746 		testAnd(VR(10, 12), VR(3), VR(0, 3));
1747 		testAnd(VR(21, 138), VR(0, 6), VR(0, 6));
1748 
1749 		// Zero always gives 0
1750 		testAnd(VR(0), VR(0), VR(0));
1751 		testAnd(VR(123), VR(0), VR(0));
1752 		testAnd(VR(123, 456), VR(0), VR(0));
1753 		testAnd(VR(-5, 12), VR(0), VR(0));
1754 		testAnd(VR(5, -12), VR(0), VR(0));
1755 
1756 		// -1 Does nothing
1757 		testAnd(VR(), VR(-1), VR());
1758 		testAnd(VR(123), VR(-1), VR(123));
1759 		testAnd(VR(123, 456), VR(-1), VR(123, 456));
1760 		testAnd(VR(-123, 456), VR(-1), VR(-123, 456));
1761 		// testAnd(VR(123, -456), VR(-1), VR(123, -456));
1762 
1763 		// Full range extend to 0
1764 		testAnd(VR(), VR(), VR());
1765 		testAnd(VR(123), VR(), VR(0, 123));
1766 		testAnd(VR(123, 456), VR(), VR(0, 456));
1767 		testAnd(VR(-123, 456), VR(), VR());
1768 
1769 		// Signed range
1770 		testAnd(VR(-123, 456), VR(-1, 0), VR(-123, 456));
1771 		testAnd(VR(-123, 456), VR(-1, 3), VR(-123, 456));
1772 		testAnd(VR(-123, 456), VR(-2, 0), VR(-124, 456));
1773 
1774 		/**
1775 		 * Test or
1776 		 */
1777 		testOr(VR(), VR(), VR());
1778 		testOr(VR(0), VR(0), VR(0));
1779 		testOr(VR(1), VR(2), VR(3));
1780 		testOr(VR(10, 12), VR(2), VR(10, 14));
1781 		testOr(VR(10, 12), VR(3), VR(11, 15));
1782 
1783 		// Zero does nothing
1784 		testOr(VR(0), VR(0), VR(0));
1785 		testOr(VR(123), VR(0), VR(123));
1786 		testOr(VR(-5, 12), VR(0), VR(-5, 12));
1787 		// testOr(VR(5, -12), VR(0), VR(5, -12));
1788 
1789 		// -1 always gives -1
1790 		testOr(VR(), VR(-1), VR(-1));
1791 		testOr(VR(123), VR(-1), VR(-1));
1792 		testOr(VR(123, 456), VR(-1), VR(-1));
1793 		testOr(VR(-123, 456), VR(-1), VR(-1));
1794 		testOr(VR(123, -456), VR(-1), VR(-1));
1795 
1796 		// Full range extends to -1
1797 		testOr(VR(), VR(), VR());
1798 		testOr(VR(123), VR(), VR(123, -1));
1799 		testOr(VR(123, 456), VR(), VR(123, -1));
1800 		testOr(VR(-123, 456), VR(), VR());
1801 
1802 		// Signed range
1803 		testOr(VR(-123, 456), VR(-1, 0), VR(-123, 456));
1804 		testOr(VR(-123, 456), VR(-1, 3), VR(-123, 459));
1805 		testOr(VR(-123, 456), VR(1, 2), VR(-123, 458));
1806 
1807 		/**
1808 		 * Test xor
1809 		 */
1810 		// To be 100% honest, I'm not sure what are good test cases for xor.
1811 		testXor(VR(), VR(), VR());
1812 		testXor(VR(0), VR(0), VR(0));
1813 		testXor(VR(1), VR(2), VR(3));
1814 		testXor(VR(1), VR(3), VR(2));
1815 		testXor(VR(123), VR(123), VR(0));
1816 		testXor(VR(123), VR(123, 124), VR(0, 7));
1817 		testXor(VR(3), VR(2, 3), VR(0, 1));
1818 	}
1819 }