+unsigned
+lp_mantissa(struct lp_type type)
+{
+ assert(type.floating);
+
+ if(type.floating) {
+ switch(type.width) {
+ case 32:
+ return 23;
+ case 64:
+ return 53;
+ default:
+ assert(0);
+ return 0;
+ }
+ }
+ else {
+ if(type.sign)
+ return type.width - 1;
+ else
+ return type.width;
+ }
+}
+
+
+/**
+ * Shift of the unity.
+ *
+ * Same as lp_const_scale(), but in terms of shifts.
+ */
+unsigned
+lp_const_shift(struct lp_type type)
+{
+ if(type.floating)
+ return 0;
+ else if(type.fixed)
+ return type.width/2;
+ else if(type.norm)
+ return type.sign ? type.width - 1 : type.width;
+ else
+ return 0;
+}
+
+
+unsigned
+lp_const_offset(struct lp_type type)
+{
+ if(type.floating || type.fixed)
+ return 0;
+ else if(type.norm)
+ return 1;
+ else
+ return 0;
+}
+
+
+/**
+ * Scaling factor between the LLVM native value and its interpretation.
+ *
+ * This is 1.0 for all floating types and unnormalized integers, and something
+ * else for the fixed points types and normalized integers.
+ */
+double
+lp_const_scale(struct lp_type type)
+{
+ unsigned long long llscale;
+ double dscale;
+
+ llscale = (unsigned long long)1 << lp_const_shift(type);
+ llscale -= lp_const_offset(type);
+ dscale = (double)llscale;
+ assert((unsigned long long)dscale == llscale);
+
+ return dscale;
+}
+
+
+/**
+ * Minimum value representable by the type.
+ */
+double
+lp_const_min(struct lp_type type)
+{
+ unsigned bits;
+
+ if(!type.sign)
+ return 0.0;
+
+ if(type.norm)
+ return -1.0;
+
+ if (type.floating) {
+ switch(type.width) {
+ case 32:
+ return -FLT_MAX;
+ case 64:
+ return -DBL_MAX;
+ default:
+ assert(0);
+ return 0.0;
+ }
+ }
+
+ if(type.fixed)
+ /* FIXME: consider the fractional bits? */
+ bits = type.width / 2 - 1;
+ else
+ bits = type.width - 1;
+
+ return (double)-((long long)1 << bits);
+}
+
+
+/**
+ * Maximum value representable by the type.
+ */
+double
+lp_const_max(struct lp_type type)
+{
+ unsigned bits;
+
+ if(type.norm)
+ return 1.0;
+
+ if (type.floating) {
+ switch(type.width) {
+ case 32:
+ return FLT_MAX;
+ case 64:
+ return DBL_MAX;
+ default:
+ assert(0);
+ return 0.0;
+ }
+ }
+
+ if(type.fixed)
+ bits = type.width / 2;
+ else
+ bits = type.width;
+
+ if(type.sign)
+ bits -= 1;
+
+ return (double)(((unsigned long long)1 << bits) - 1);
+}
+
+
+double
+lp_const_eps(struct lp_type type)
+{
+ if (type.floating) {
+ switch(type.width) {
+ case 32:
+ return FLT_EPSILON;
+ case 64:
+ return DBL_EPSILON;
+ default:
+ assert(0);
+ return 0.0;
+ }
+ }
+ else {
+ double scale = lp_const_scale(type);
+ return 1.0/scale;
+ }
+}
+
+