Commit c9fc8bd802

Andrew Kelley <superjoe30@gmail.com>
2017-06-19 20:36:33
workaround for llvm bug
See #393 for details
1 parent 799c699
src/codegen.cpp
@@ -438,6 +438,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
     }
 
     addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");
+    addLLVMFnAttr(fn_table_entry->llvm_value, "nobuiltin");
     if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
         ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
         ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
std/math/acos.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn acos(x: var) -> @typeOf(x) {
+pub const acos = acos_workaround;
+
+// TODO issue #393
+pub fn acos_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(acos32, x),
@@ -137,12 +140,12 @@ fn acos64(x: f64) -> f64 {
     2 * (df + w)
 }
 
-test "acos" {
-    assert(acos(f32(0.0)) == acos32(0.0));
-    assert(acos(f64(0.0)) == acos64(0.0));
+test "math.acos" {
+    assert(acos_workaround(f32(0.0)) == acos32(0.0));
+    assert(acos_workaround(f64(0.0)) == acos64(0.0));
 }
 
-test "acos32" {
+test "math.acos32" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, acos32(0.0), 1.570796, epsilon));
@@ -153,7 +156,7 @@ test "acos32" {
     assert(math.approxEq(f32, acos32(-0.2), 1.772154, epsilon));
 }
 
-test "acos64" {
+test "math.acos64" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f64, acos64(0.0), 1.570796, epsilon));
std/math/acosh.zig
@@ -1,17 +1,20 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn acosh(x: var) -> @typeOf(x) {
+pub const acosh = acosh_workaround;
+
+// TODO issue #393
+pub fn acosh_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(acoshf, x),
-        f64 => @inlineCall(acoshd, x),
+        f32 => @inlineCall(acosh32, x),
+        f64 => @inlineCall(acosh64, x),
         else => @compileError("acosh not implemented for " ++ @typeName(T)),
     }
 }
 
 // acosh(x) = log(x + sqrt(x * x - 1))
-fn acoshf(x: f32) -> f32 {
+fn acosh32(x: f32) -> f32 {
     const u = @bitCast(u32, x);
     const i = u & 0x7FFFFFFF;
 
@@ -29,7 +32,7 @@ fn acoshf(x: f32) -> f32 {
     }
 }
 
-fn acoshd(x: f64) -> f64 {
+fn acosh64(x: f64) -> f64 {
     const u = @bitCast(u64, x);
     const e = (u >> 52) & 0x7FF;
 
@@ -47,25 +50,25 @@ fn acoshd(x: f64) -> f64 {
     }
 }
 
-test "acosh" {
-    assert(acosh(f32(1.5)) == acoshf(1.5));
-    assert(acosh(f64(1.5)) == acoshd(1.5));
+test "math.acosh" {
+    assert(acosh_workaround(f32(1.5)) == acosh32(1.5));
+    assert(acosh_workaround(f64(1.5)) == acosh64(1.5));
 }
 
-test "acoshf" {
+test "math.acosh32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, acoshf(1.5), 0.962424, epsilon));
-    assert(math.approxEq(f32, acoshf(37.45), 4.315976, epsilon));
-    assert(math.approxEq(f32, acoshf(89.123), 5.183133, epsilon));
-    assert(math.approxEq(f32, acoshf(123123.234375), 12.414088, epsilon));
+    assert(math.approxEq(f32, acosh32(1.5), 0.962424, epsilon));
+    assert(math.approxEq(f32, acosh32(37.45), 4.315976, epsilon));
+    assert(math.approxEq(f32, acosh32(89.123), 5.183133, epsilon));
+    assert(math.approxEq(f32, acosh32(123123.234375), 12.414088, epsilon));
 }
 
-test "acoshd" {
+test "math.acosh64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, acoshd(1.5), 0.962424, epsilon));
-    assert(math.approxEq(f64, acoshd(37.45), 4.315976, epsilon));
-    assert(math.approxEq(f64, acoshd(89.123), 5.183133, epsilon));
-    assert(math.approxEq(f64, acoshd(123123.234375), 12.414088, epsilon));
+    assert(math.approxEq(f64, acosh64(1.5), 0.962424, epsilon));
+    assert(math.approxEq(f64, acosh64(37.45), 4.315976, epsilon));
+    assert(math.approxEq(f64, acosh64(89.123), 5.183133, epsilon));
+    assert(math.approxEq(f64, acosh64(123123.234375), 12.414088, epsilon));
 }
std/math/asin.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn asin(x: var) -> @typeOf(x) {
+pub const asin = asin_workaround;
+
+// TODO issue #393
+pub fn asin_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(asin32, x),
@@ -129,12 +132,12 @@ fn asin64(x: f64) -> f64 {
     }
 }
 
-test "asin" {
-    assert(asin(f32(0.0)) == asin32(0.0));
-    assert(asin(f64(0.0)) == asin64(0.0));
+test "math.asin" {
+    assert(asin_workaround(f32(0.0)) == asin32(0.0));
+    assert(asin_workaround(f64(0.0)) == asin64(0.0));
 }
 
-test "asin32" {
+test "math.asin32" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, asin32(0.0), 0.0, epsilon));
@@ -145,7 +148,7 @@ test "asin32" {
     assert(math.approxEq(f32, asin32(0.8923), 1.102415, epsilon));
 }
 
-test "asin64" {
+test "math.asin64" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f64, asin64(0.0), 0.0, epsilon));
std/math/asinh.zig
@@ -1,17 +1,20 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn asinh(x: var) -> @typeOf(x) {
+pub const asinh = asinh_workaround;
+
+// TODO issue #393
+pub fn asinh_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(asinhf, x),
-        f64 => @inlineCall(asinhd, x),
+        f32 => @inlineCall(asinh32, x),
+        f64 => @inlineCall(asinh64, x),
         else => @compileError("asinh not implemented for " ++ @typeName(T)),
     }
 }
 
 // asinh(x) = sign(x) * log(|x| + sqrt(x * x + 1)) ~= x - x^3/6 + o(x^5)
-fn asinhf(x: f32) -> f32 {
+fn asinh32(x: f32) -> f32 {
     const u = @bitCast(u32, x);
     const i = u & 0x7FFFFFFF;
     const s = i >> 31;
@@ -38,7 +41,7 @@ fn asinhf(x: f32) -> f32 {
     if (s != 0) -rx else rx
 }
 
-fn asinhd(x: f64) -> f64 {
+fn asinh64(x: f64) -> f64 {
     const u = @bitCast(u64, x);
     const e = (u >> 52) & 0x7FF;
     const s = u >> 63;
@@ -65,31 +68,31 @@ fn asinhd(x: f64) -> f64 {
     if (s != 0) -rx else rx
 }
 
-test "asinh" {
-    assert(asinh(f32(0.0)) == asinhf(0.0));
-    assert(asinh(f64(0.0)) == asinhd(0.0));
+test "math.asinh" {
+    assert(asinh_workaround(f32(0.0)) == asinh32(0.0));
+    assert(asinh_workaround(f64(0.0)) == asinh64(0.0));
 }
 
-test "asinhf" {
+test "math.asinh32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, asinhf(0.0), 0.0, epsilon));
-    assert(math.approxEq(f32, asinhf(0.2), 0.198690, epsilon));
-    assert(math.approxEq(f32, asinhf(0.8923), 0.803133, epsilon));
-    assert(math.approxEq(f32, asinhf(1.5), 1.194763, epsilon));
-    assert(math.approxEq(f32, asinhf(37.45), 4.316332, epsilon));
-    assert(math.approxEq(f32, asinhf(89.123), 5.183196, epsilon));
-    assert(math.approxEq(f32, asinhf(123123.234375), 12.414088, epsilon));
+    assert(math.approxEq(f32, asinh32(0.0), 0.0, epsilon));
+    assert(math.approxEq(f32, asinh32(0.2), 0.198690, epsilon));
+    assert(math.approxEq(f32, asinh32(0.8923), 0.803133, epsilon));
+    assert(math.approxEq(f32, asinh32(1.5), 1.194763, epsilon));
+    assert(math.approxEq(f32, asinh32(37.45), 4.316332, epsilon));
+    assert(math.approxEq(f32, asinh32(89.123), 5.183196, epsilon));
+    assert(math.approxEq(f32, asinh32(123123.234375), 12.414088, epsilon));
 }
 
-test "asinhd" {
+test "math.asinh64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, asinhd(0.0), 0.0, epsilon));
-    assert(math.approxEq(f64, asinhd(0.2), 0.198690, epsilon));
-    assert(math.approxEq(f64, asinhd(0.8923), 0.803133, epsilon));
-    assert(math.approxEq(f64, asinhd(1.5), 1.194763, epsilon));
-    assert(math.approxEq(f64, asinhd(37.45), 4.316332, epsilon));
-    assert(math.approxEq(f64, asinhd(89.123), 5.183196, epsilon));
-    assert(math.approxEq(f64, asinhd(123123.234375), 12.414088, epsilon));
+    assert(math.approxEq(f64, asinh64(0.0), 0.0, epsilon));
+    assert(math.approxEq(f64, asinh64(0.2), 0.198690, epsilon));
+    assert(math.approxEq(f64, asinh64(0.8923), 0.803133, epsilon));
+    assert(math.approxEq(f64, asinh64(1.5), 1.194763, epsilon));
+    assert(math.approxEq(f64, asinh64(37.45), 4.316332, epsilon));
+    assert(math.approxEq(f64, asinh64(89.123), 5.183196, epsilon));
+    assert(math.approxEq(f64, asinh64(123123.234375), 12.414088, epsilon));
 }
std/math/atan.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn atan(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const atan = atan_workaround;
+
+pub fn atan_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(atan32, x),
@@ -201,12 +204,12 @@ fn atan64(x_: f64) -> f64 {
     }
 }
 
-test "atan" {
-    assert(atan(f32(0.2)) == atan32(0.2));
-    assert(atan(f64(0.2)) == atan64(0.2));
+test "math.atan" {
+    assert(atan_workaround(f32(0.2)) == atan32(0.2));
+    assert(atan_workaround(f64(0.2)) == atan64(0.2));
 }
 
-test "atan32" {
+test "math.atan32" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, atan32(0.2), 0.197396, epsilon));
@@ -216,7 +219,7 @@ test "atan32" {
     assert(math.approxEq(f32, atan32(1.5), 0.982794, epsilon));
 }
 
-test "atan64" {
+test "math.atan64" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f64, atan64(0.2), 0.197396, epsilon));
std/math/atan2.zig
@@ -1,15 +1,18 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn atan2(comptime T: type, x: T, y: T) -> T {
+pub const atan2 = atan2_workaround;
+
+// TODO issue #393
+pub fn atan2_workaround(comptime T: type, x: T, y: T) -> T {
     switch (T) {
-        f32 => @inlineCall(atan2f, x, y),
-        f64 => @inlineCall(atan2d, x, y),
+        f32 => @inlineCall(atan2_32, x, y),
+        f64 => @inlineCall(atan2_64, x, y),
         else => @compileError("atan2 not implemented for " ++ @typeName(T)),
     }
 }
 
-fn atan2f(y: f32, x: f32) -> f32 {
+fn atan2_32(y: f32, x: f32) -> f32 {
     const pi: f32    =  3.1415927410e+00;
     const pi_lo: f32 = -8.7422776573e-08;
 
@@ -94,7 +97,7 @@ fn atan2f(y: f32, x: f32) -> f32 {
     }
 }
 
-fn atan2d(y: f64, x: f64) -> f64 {
+fn atan2_64(y: f64, x: f64) -> f64 {
     const pi: f64    = 3.1415926535897931160E+00;
     const pi_lo: f64 = 1.2246467991473531772E-16;
 
@@ -184,31 +187,31 @@ fn atan2d(y: f64, x: f64) -> f64 {
     }
 }
 
-test "atan2" {
-    assert(atan2(f32, 0.2, 0.21) == atan2f(0.2, 0.21));
-    assert(atan2(f64, 0.2, 0.21) == atan2d(0.2, 0.21));
+test "math.atan2" {
+    assert(atan2_workaround(f32, 0.2, 0.21) == atan2_32(0.2, 0.21));
+    assert(atan2_workaround(f64, 0.2, 0.21) == atan2_64(0.2, 0.21));
 }
 
-test "atan2f" {
+test "math.atan2_32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, atan2f(0.0, 0.0), 0.0, epsilon));
-    assert(math.approxEq(f32, atan2f(0.2, 0.2), 0.785398, epsilon));
-    assert(math.approxEq(f32, atan2f(-0.2, 0.2), -0.785398, epsilon));
-    assert(math.approxEq(f32, atan2f(0.2, -0.2), 2.356194, epsilon));
-    assert(math.approxEq(f32, atan2f(-0.2, -0.2), -2.356194, epsilon));
-    assert(math.approxEq(f32, atan2f(0.34, -0.4), 2.437099, epsilon));
-    assert(math.approxEq(f32, atan2f(0.34, 1.243), 0.267001, epsilon));
+    assert(math.approxEq(f32, atan2_32(0.0, 0.0), 0.0, epsilon));
+    assert(math.approxEq(f32, atan2_32(0.2, 0.2), 0.785398, epsilon));
+    assert(math.approxEq(f32, atan2_32(-0.2, 0.2), -0.785398, epsilon));
+    assert(math.approxEq(f32, atan2_32(0.2, -0.2), 2.356194, epsilon));
+    assert(math.approxEq(f32, atan2_32(-0.2, -0.2), -2.356194, epsilon));
+    assert(math.approxEq(f32, atan2_32(0.34, -0.4), 2.437099, epsilon));
+    assert(math.approxEq(f32, atan2_32(0.34, 1.243), 0.267001, epsilon));
 }
 
-test "atan2d" {
+test "math.atan2_64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, atan2d(0.0, 0.0), 0.0, epsilon));
-    assert(math.approxEq(f64, atan2d(0.2, 0.2), 0.785398, epsilon));
-    assert(math.approxEq(f64, atan2d(-0.2, 0.2), -0.785398, epsilon));
-    assert(math.approxEq(f64, atan2d(0.2, -0.2), 2.356194, epsilon));
-    assert(math.approxEq(f64, atan2d(-0.2, -0.2), -2.356194, epsilon));
-    assert(math.approxEq(f64, atan2d(0.34, -0.4), 2.437099, epsilon));
-    assert(math.approxEq(f64, atan2d(0.34, 1.243), 0.267001, epsilon));
+    assert(math.approxEq(f64, atan2_64(0.0, 0.0), 0.0, epsilon));
+    assert(math.approxEq(f64, atan2_64(0.2, 0.2), 0.785398, epsilon));
+    assert(math.approxEq(f64, atan2_64(-0.2, 0.2), -0.785398, epsilon));
+    assert(math.approxEq(f64, atan2_64(0.2, -0.2), 2.356194, epsilon));
+    assert(math.approxEq(f64, atan2_64(-0.2, -0.2), -2.356194, epsilon));
+    assert(math.approxEq(f64, atan2_64(0.34, -0.4), 2.437099, epsilon));
+    assert(math.approxEq(f64, atan2_64(0.34, 1.243), 0.267001, epsilon));
 }
std/math/atanh.zig
@@ -1,17 +1,20 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn atanh(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const atanh = atanh_workaround;
+
+pub fn atanh_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(atanhf, x),
-        f64 => @inlineCall(atanhd, x),
+        f32 => @inlineCall(atanh_32, x),
+        f64 => @inlineCall(atanh_64, x),
         else => @compileError("atanh not implemented for " ++ @typeName(T)),
     }
 }
 
 // atanh(x) = log((1 + x) / (1 - x)) / 2 = log1p(2x / (1 - x)) / 2 ~= x + x^3 / 3 + o(x^5)
-fn atanhf(x: f32) -> f32 {
+fn atanh_32(x: f32) -> f32 {
     const u = @bitCast(u32, x);
     const i = u & 0x7FFFFFFF;
     const s = u >> 31;
@@ -37,7 +40,7 @@ fn atanhf(x: f32) -> f32 {
     if (s != 0) -y else y
 }
 
-fn atanhd(x: f64) -> f64 {
+fn atanh_64(x: f64) -> f64 {
     const u = @bitCast(u64, x);
     const e = (u >> 52) & 0x7FF;
     const s = u >> 63;
@@ -63,23 +66,23 @@ fn atanhd(x: f64) -> f64 {
     if (s != 0) -y else y
 }
 
-test "atanh" {
-    assert(atanh(f32(0.0)) == atanhf(0.0));
-    assert(atanh(f64(0.0)) == atanhd(0.0));
+test "math.atanh" {
+    assert(atanh(f32(0.0)) == atanh_32(0.0));
+    assert(atanh(f64(0.0)) == atanh_64(0.0));
 }
 
-test "atanhf" {
+test "math.atanh_32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, atanhf(0.0), 0.0, epsilon));
-    assert(math.approxEq(f32, atanhf(0.2), 0.202733, epsilon));
-    assert(math.approxEq(f32, atanhf(0.8923), 1.433099, epsilon));
+    assert(math.approxEq(f32, atanh_32(0.0), 0.0, epsilon));
+    assert(math.approxEq(f32, atanh_32(0.2), 0.202733, epsilon));
+    assert(math.approxEq(f32, atanh_32(0.8923), 1.433099, epsilon));
 }
 
-test "atanhd" {
+test "math.atanh_64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, atanhd(0.0), 0.0, epsilon));
-    assert(math.approxEq(f64, atanhd(0.2), 0.202733, epsilon));
-    assert(math.approxEq(f64, atanhd(0.8923), 1.433099, epsilon));
+    assert(math.approxEq(f64, atanh_64(0.0), 0.0, epsilon));
+    assert(math.approxEq(f64, atanh_64(0.2), 0.202733, epsilon));
+    assert(math.approxEq(f64, atanh_64(0.8923), 1.433099, epsilon));
 }
std/math/cbrt.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn cbrt(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const cbrt = cbrt_workaround;
+
+pub fn cbrt_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(cbrt32, x),
@@ -106,12 +109,12 @@ fn cbrt64(x: f64) -> f64 {
     t + t * q
 }
 
-test "cbrt" {
+test "math.cbrt" {
     assert(cbrt(f32(0.0)) == cbrt32(0.0));
     assert(cbrt(f64(0.0)) == cbrt64(0.0));
 }
 
-test "cbrt32" {
+test "math.cbrt32" {
     const epsilon = 0.000001;
 
     assert(cbrt32(0.0) == 0.0);
@@ -122,7 +125,7 @@ test "cbrt32" {
     assert(math.approxEq(f32, cbrt32(123123.234375), 49.748501, epsilon));
 }
 
-test "cbrt64" {
+test "math.cbrt64" {
     const epsilon = 0.000001;
 
     assert(cbrt64(0.0) == 0.0);
std/math/ceil.zig
@@ -2,7 +2,10 @@ const builtin = @import("builtin");
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn ceil(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const ceil = ceil_workaround;
+
+pub fn ceil_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(ceil32, x),
@@ -71,18 +74,18 @@ fn ceil64(x: f64) -> f64 {
     }
 }
 
-test "ceil" {
+test "math.ceil" {
     assert(ceil(f32(0.0)) == ceil32(0.0));
     assert(ceil(f64(0.0)) == ceil64(0.0));
 }
 
-test "ceil32" {
+test "math.ceil32" {
     assert(ceil32(1.3) == 2.0);
     assert(ceil32(-1.3) == -1.0);
     assert(ceil32(0.2) == 1.0);
 }
 
-test "ceil64" {
+test "math.ceil64" {
     assert(ceil64(1.3) == 2.0);
     assert(ceil64(-1.3) == -1.0);
     assert(ceil64(0.2) == 1.0);
std/math/copysign.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn copysign(comptime T: type, x: T, y: T) -> T {
+// TODO issue #393
+pub const copysign = copysign_workaround;
+
+pub fn copysign_workaround(comptime T: type, x: T, y: T) -> T {
     switch (T) {
         f32 => @inlineCall(copysign32, x, y),
         f64 => @inlineCall(copysign64, x, y),
@@ -27,19 +30,19 @@ fn copysign64(x: f64, y: f64) -> f64 {
     @bitCast(f64, h1 | h2)
 }
 
-test "copysign" {
+test "math.copysign" {
     assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));
     assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));
 }
 
-test "copysign32" {
+test "math.copysign32" {
     assert(copysign32(5.0, 1.0) == 5.0);
     assert(copysign32(5.0, -1.0) == -5.0);
     assert(copysign32(-5.0, -1.0) == -5.0);
     assert(copysign32(-5.0, 1.0) == 5.0);
 }
 
-test "copysign64" {
+test "math.copysign64" {
     assert(copysign64(5.0, 1.0) == 5.0);
     assert(copysign64(5.0, -1.0) == -5.0);
     assert(copysign64(-5.0, -1.0) == -5.0);
std/math/cos.zig
@@ -1,7 +1,11 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn cos(x: var) -> @typeOf(x) {
+
+// TODO issue #393
+pub const cos = cos_workaround;
+
+pub fn cos_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(cos32, x),
@@ -133,12 +137,12 @@ fn cos64(x_: f64) -> f64 {
     }
 }
 
-test "cos" {
+test "math.cos" {
     assert(cos(f32(0.0)) == cos32(0.0));
     assert(cos(f64(0.0)) == cos64(0.0));
 }
 
-test "cos32" {
+test "math.cos32" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));
@@ -149,7 +153,7 @@ test "cos32" {
     assert(math.approxEq(f32, cos32(89.123), 0.400798, epsilon));
 }
 
-test "cos64" {
+test "math.cos64" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f64, cos64(0.0), 1.0, epsilon));
std/math/cosh.zig
@@ -2,11 +2,14 @@ const math = @import("index.zig");
 const expo2 = @import("_expo2.zig").expo2;
 const assert = @import("../debug.zig").assert;
 
-pub fn cosh(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const cosh = cosh_workaround;
+
+pub fn cosh_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(coshf, x),
-        f64 => @inlineCall(coshd, x),
+        f32 => @inlineCall(cosh32, x),
+        f64 => @inlineCall(cosh64, x),
         else => @compileError("cosh not implemented for " ++ @typeName(T)),
     }
 }
@@ -14,7 +17,7 @@ pub fn cosh(x: var) -> @typeOf(x) {
 // cosh(x) = (exp(x) + 1 / exp(x)) / 2
 //         = 1 + 0.5 * (exp(x) - 1) * (exp(x) - 1) / exp(x)
 //         = 1 + (x * x) / 2 + o(x^4)
-fn coshf(x: f32) -> f32 {
+fn cosh32(x: f32) -> f32 {
     const u = @bitCast(u32, x);
     const ux = u & 0x7FFFFFFF;
     const ax = @bitCast(f32, ux);
@@ -39,7 +42,7 @@ fn coshf(x: f32) -> f32 {
     expo2(ax)
 }
 
-fn coshd(x: f64) -> f64 {
+fn cosh64(x: f64) -> f64 {
     const u = @bitCast(u64, x);
     const w = u32(u >> 32);
     const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
@@ -67,25 +70,25 @@ fn coshd(x: f64) -> f64 {
     expo2(ax)
 }
 
-test "cosh" {
-    assert(cosh(f32(1.5)) == coshf(1.5));
-    assert(cosh(f64(1.5)) == coshd(1.5));
+test "math.cosh" {
+    assert(cosh(f32(1.5)) == cosh32(1.5));
+    assert(cosh(f64(1.5)) == cosh64(1.5));
 }
 
-test "coshf" {
+test "math.cosh32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, coshf(0.0), 1.0, epsilon));
-    assert(math.approxEq(f32, coshf(0.2), 1.020067, epsilon));
-    assert(math.approxEq(f32, coshf(0.8923), 1.425225, epsilon));
-    assert(math.approxEq(f32, coshf(1.5), 2.352410, epsilon));
+    assert(math.approxEq(f32, cosh32(0.0), 1.0, epsilon));
+    assert(math.approxEq(f32, cosh32(0.2), 1.020067, epsilon));
+    assert(math.approxEq(f32, cosh32(0.8923), 1.425225, epsilon));
+    assert(math.approxEq(f32, cosh32(1.5), 2.352410, epsilon));
 }
 
-test "coshd" {
+test "math.cosh64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, coshd(0.0), 1.0, epsilon));
-    assert(math.approxEq(f64, coshd(0.2), 1.020067, epsilon));
-    assert(math.approxEq(f64, coshd(0.8923), 1.425225, epsilon));
-    assert(math.approxEq(f64, coshd(1.5), 2.352410, epsilon));
+    assert(math.approxEq(f64, cosh64(0.0), 1.0, epsilon));
+    assert(math.approxEq(f64, cosh64(0.2), 1.020067, epsilon));
+    assert(math.approxEq(f64, cosh64(0.8923), 1.425225, epsilon));
+    assert(math.approxEq(f64, cosh64(1.5), 2.352410, epsilon));
 }
std/math/exp.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn exp(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const exp = exp_workaround;
+
+pub fn exp_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(exp32, x),
@@ -165,12 +168,12 @@ fn exp64(x_: f64) -> f64 {
     }
 }
 
-test "exp" {
+test "math.exp" {
     assert(exp(f32(0.0)) == exp32(0.0));
     assert(exp(f64(0.0)) == exp64(0.0));
 }
 
-test "exp32" {
+test "math.exp32" {
     const epsilon = 0.000001;
 
     assert(exp32(0.0) == 1.0);
@@ -180,7 +183,7 @@ test "exp32" {
     assert(math.approxEq(f32, exp32(1.5), 4.481689, epsilon));
 }
 
-test "exp64" {
+test "math.exp64" {
     const epsilon = 0.000001;
 
     assert(exp64(0.0) == 1.0);
std/math/exp2.zig
@@ -1,11 +1,14 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn exp2(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const exp2 = exp2_workaround;
+
+pub fn exp2_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(exp2f, x),
-        f64 => @inlineCall(exp2d, x),
+        f32 => @inlineCall(exp2_32, x),
+        f64 => @inlineCall(exp2_64, x),
         else => @compileError("exp2 not implemented for " ++ @typeName(T)),
     }
 }
@@ -29,7 +32,7 @@ const exp2ft = []const f64 {
     0x1.5ab07dd485429p+0,
 };
 
-fn exp2f(x: f32) -> f32 {
+fn exp2_32(x: f32) -> f32 {
     @setFloatMode(this, @import("builtin").FloatMode.Strict);
 
     const tblsiz = u32(exp2ft.len);
@@ -346,7 +349,7 @@ const exp2dt = []f64 {
     0x1.690f4b19e9471p+0, -0x1.9780p-45,
 };
 
-fn exp2d(x: f64) -> f64 {
+fn exp2_64(x: f64) -> f64 {
     @setFloatMode(this, @import("builtin").FloatMode.Strict);
 
     const tblsiz     = u32(exp2dt.len / 2);
@@ -407,27 +410,27 @@ fn exp2d(x: f64) -> f64 {
     math.scalbn(r, ik)
 }
 
-test "exp2" {
-    assert(exp2(f32(0.8923)) == exp2f(0.8923));
-    assert(exp2(f64(0.8923)) == exp2d(0.8923));
+test "math.exp2" {
+    assert(exp2(f32(0.8923)) == exp2_32(0.8923));
+    assert(exp2(f64(0.8923)) == exp2_64(0.8923));
 }
 
-test "exp2f" {
+test "math.exp2_32" {
     const epsilon = 0.000001;
 
-    assert(exp2f(0.0) == 1.0);
-    assert(math.approxEq(f32, exp2f(0.2), 1.148698, epsilon));
-    assert(math.approxEq(f32, exp2f(0.8923), 1.856133, epsilon));
-    assert(math.approxEq(f32, exp2f(1.5), 2.828427, epsilon));
-    assert(math.approxEq(f32, exp2f(37.45), 187747237888, epsilon));
+    assert(exp2_32(0.0) == 1.0);
+    assert(math.approxEq(f32, exp2_32(0.2), 1.148698, epsilon));
+    assert(math.approxEq(f32, exp2_32(0.8923), 1.856133, epsilon));
+    assert(math.approxEq(f32, exp2_32(1.5), 2.828427, epsilon));
+    assert(math.approxEq(f32, exp2_32(37.45), 187747237888, epsilon));
 }
 
-test "exp2d" {
+test "math.exp2_64" {
     const epsilon = 0.000001;
 
-    assert(exp2d(0.0) == 1.0);
-    assert(math.approxEq(f64, exp2d(0.2), 1.148698, epsilon));
-    assert(math.approxEq(f64, exp2d(0.8923), 1.856133, epsilon));
-    assert(math.approxEq(f64, exp2d(1.5), 2.828427, epsilon));
-    // assert(math.approxEq(f64, exp2d(37.45), 18379273786760560.000000, epsilon));
+    assert(exp2_64(0.0) == 1.0);
+    assert(math.approxEq(f64, exp2_64(0.2), 1.148698, epsilon));
+    assert(math.approxEq(f64, exp2_64(0.8923), 1.856133, epsilon));
+    assert(math.approxEq(f64, exp2_64(1.5), 2.828427, epsilon));
+    // assert(math.approxEq(f64, exp2_64(37.45), 18379273786760560.000000, epsilon));
 }
std/math/expm1.zig
@@ -1,16 +1,19 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn expm1(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const expm1 = expm1_workaround;
+
+pub fn expm1_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(expm1f, x),
-        f64 => @inlineCall(expm1d, x),
+        f32 => @inlineCall(expm1_32, x),
+        f64 => @inlineCall(expm1_64, x),
         else => @compileError("exp1m not implemented for " ++ @typeName(T)),
     }
 }
 
-fn expm1f(x_: f32) -> f32 {
+fn expm1_32(x_: f32) -> f32 {
     const o_threshold: f32 = 8.8721679688e+01;
     const ln2_hi: f32      = 6.9313812256e-01;
     const ln2_lo: f32      = 9.0580006145e-06;
@@ -131,7 +134,7 @@ fn expm1f(x_: f32) -> f32 {
     }
 }
 
-fn expm1d(x_: f64) -> f64 {
+fn expm1_64(x_: f64) -> f64 {
     const o_threshold: f64 = 7.09782712893383973096e+02;
     const ln2_hi: f64      = 6.93147180369123816490e-01;
     const ln2_lo: f64      = 1.90821492927058770002e-10;
@@ -256,27 +259,27 @@ fn expm1d(x_: f64) -> f64 {
     }
 }
 
-test "exp1m" {
-    assert(expm1(f32(0.0)) == expm1f(0.0));
-    assert(expm1(f64(0.0)) == expm1d(0.0));
+test "math.exp1m" {
+    assert(expm1(f32(0.0)) == expm1_32(0.0));
+    assert(expm1(f64(0.0)) == expm1_64(0.0));
 }
 
-test "expm1f" {
+test "math.expm1_32" {
     const epsilon = 0.000001;
 
-    assert(expm1f(0.0) == 0.0);
-    assert(math.approxEq(f32, expm1f(0.0), 0.0, epsilon));
-    assert(math.approxEq(f32, expm1f(0.2), 0.221403, epsilon));
-    assert(math.approxEq(f32, expm1f(0.8923), 1.440737, epsilon));
-    assert(math.approxEq(f32, expm1f(1.5), 3.481689, epsilon));
+    assert(expm1_32(0.0) == 0.0);
+    assert(math.approxEq(f32, expm1_32(0.0), 0.0, epsilon));
+    assert(math.approxEq(f32, expm1_32(0.2), 0.221403, epsilon));
+    assert(math.approxEq(f32, expm1_32(0.8923), 1.440737, epsilon));
+    assert(math.approxEq(f32, expm1_32(1.5), 3.481689, epsilon));
 }
 
-test "expm1d" {
+test "math.expm1_64" {
     const epsilon = 0.000001;
 
-    assert(expm1d(0.0) == 0.0);
-    assert(math.approxEq(f64, expm1d(0.0), 0.0, epsilon));
-    assert(math.approxEq(f64, expm1d(0.2), 0.221403, epsilon));
-    assert(math.approxEq(f64, expm1d(0.8923), 1.440737, epsilon));
-    assert(math.approxEq(f64, expm1d(1.5), 3.481689, epsilon));
+    assert(expm1_64(0.0) == 0.0);
+    assert(math.approxEq(f64, expm1_64(0.0), 0.0, epsilon));
+    assert(math.approxEq(f64, expm1_64(0.2), 0.221403, epsilon));
+    assert(math.approxEq(f64, expm1_64(0.8923), 1.440737, epsilon));
+    assert(math.approxEq(f64, expm1_64(1.5), 3.481689, epsilon));
 }
std/math/fabs.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn fabs(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const fabs = fabs_workaround;
+
+pub fn fabs_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(fabs32, x),
@@ -22,17 +25,17 @@ fn fabs64(x: f64) -> f64 {
     @bitCast(f64, u)
 }
 
-test "fabs" {
+test "math.fabs" {
     assert(fabs(f32(1.0)) == fabs32(1.0));
     assert(fabs(f64(1.0)) == fabs64(1.0));
 }
 
-test "fabs32" {
+test "math.fabs32" {
     assert(fabs64(1.0) == 1.0);
     assert(fabs64(-1.0) == 1.0);
 }
 
-test "fabs64" {
+test "math.fabs64" {
     assert(fabs64(1.0) == 1.0);
     assert(fabs64(-1.0) == 1.0);
 }
std/math/floor.zig
@@ -2,7 +2,10 @@ const builtin = @import("builtin");
 const assert = @import("../debug.zig").assert;
 const math = @import("index.zig");
 
-pub fn floor(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const floor = floor_workaround;
+
+pub fn floor_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(floor32, x),
@@ -71,18 +74,18 @@ fn floor64(x: f64) -> f64 {
     }
 }
 
-test "floor" {
+test "math.floor" {
     assert(floor(f32(1.3)) == floor32(1.3));
     assert(floor(f64(1.3)) == floor64(1.3));
 }
 
-test "floor32" {
+test "math.floor32" {
     assert(floor32(1.3) == 1.0);
     assert(floor32(-1.3) == -2.0);
     assert(floor32(0.2) == 0.0);
 }
 
-test "floor64" {
+test "math.floor64" {
     assert(floor64(1.3) == 1.0);
     assert(floor64(-1.3) == -2.0);
     assert(floor64(0.2) == 0.0);
std/math/fma.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
+// TODO issue #393
+pub const fma = fma_workaround;
+
+pub fn fma_workaround(comptime T: type, x: T, y: T, z: T) -> T {
     switch (T) {
         f32 => @inlineCall(fma32, x, y, z),
         f64 => @inlineCall(fma64, x, y ,z),
@@ -130,12 +133,12 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 {
     math.scalbn(sum.hi, scale)
 }
 
-test "fma" {
+test "math.fma" {
     assert(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0));
     assert(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0));
 }
 
-test "fma32" {
+test "math.fma32" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon));
@@ -147,7 +150,7 @@ test "fma32" {
     assert(math.approxEq(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon));
 }
 
-test "fma64" {
+test "math.fma64" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon));
std/math/fmod.zig
@@ -1,190 +0,0 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
-
-pub fn fmod(comptime T: type, x: T, y: T) -> T {
-    switch (T) {
-        f32 => @inlineCall(fmod32, x, y),
-        f64 => @inlineCall(fmod64, x, y),
-        else => @compileError("fmod not implemented for " ++ @typeName(T)),
-    }
-}
-
-fn fmod32(x: f32, y: f32) -> f32 {
-    var ux = @bitCast(u32, x);
-    var uy = @bitCast(u32, y);
-    var ex = i32(ux >> 23) & 0xFF;
-    var ey = i32(ux >> 23) & 0xFF;
-    const sx = ux & 0x80000000;
-
-    if (uy << 1 == 0 or math.isNan(y) or ex == 0xFF) {
-        return (x * y) / (x * y);
-    }
-    if (ux << 1 <= uy << 1) {
-        if (ux << 1 == uy << 1) {
-            return 0 * x;
-        } else {
-            return x;
-        }
-    }
-
-    // normalize x and y
-    if (ex == 0) {
-        var i = ux << 9;
-        while (i >> 31 == 0) : (i <<= 1) {
-            ex -= 1;
-        }
-        ux <<= u32(-ex + 1);
-    } else {
-        ux &= @maxValue(u32) >> 9;
-        ux |= 1 << 23;
-    }
-
-    if (ey == 0) {
-        var i = uy << 9;
-        while (i >> 31 == 0) : (i <<= 1) {
-            ey -= 1;
-        }
-        uy <<= u32(-ey + 1);
-    } else {
-        uy &= @maxValue(u32) >> 9;
-        uy |= 1 << 23;
-    }
-
-    // x mod y
-    while (ex > ey) : (ex -= 1) {
-        const i = ux - uy;
-        if (i >> 31 == 0) {
-            if (i == 0) {
-                return 0 * x;
-            }
-            ux = i;
-        }
-        ux <<= 1;
-    }
-    {
-        const i = ux - uy;
-        if (i >> 31 == 0) {
-            if (i == 0) {
-                return 0 * x;
-            }
-            ux = i;
-        }
-    }
-
-    while (ux >> 23 == 0) : (ux <<= 1) {
-        ex -= 1;
-    }
-
-    // scale result up
-    if (ex > 0) {
-        ux -= 1 << 23;
-        ux |= u32(ex) << 23;
-    } else {
-        ux >>= u32(-ex + 1);
-    }
-
-    ux |= sx;
-    @bitCast(f32, ux)
-}
-
-fn fmod64(x: f64, y: f64) -> f64 {
-    var ux = @bitCast(u64, x);
-    var uy = @bitCast(u64, y);
-    var ex = i32(ux >> 52) & 0x7FF;
-    var ey = i32(ux >> 52) & 0x7FF;
-    const sx = ux >> 63;
-
-    if (uy << 1 == 0 or math.isNan(y) or ex == 0x7FF) {
-        return (x * y) / (x * y);
-    }
-    if (ux << 1 <= uy << 1) {
-        if (ux << 1 == uy << 1) {
-            return 0 * x;
-        } else {
-            return x;
-        }
-    }
-
-    // normalize x and y
-    if (ex == 0) {
-        var i = ux << 12;
-        while (i >> 63 == 0) : (i <<= 1) {
-            ex -= 1;
-        }
-        ux <<= u64(-ex + 1);
-    } else {
-        ux &= @maxValue(u64) >> 12;
-        ux |= 1 << 52;
-    }
-
-    if (ey == 0) {
-        var i = uy << 12;
-        while (i >> 63 == 0) : (i <<= 1) {
-            ey -= 1;
-        }
-        uy <<= u64(-ey + 1);
-    } else {
-        uy &= @maxValue(u64) >> 12;
-        uy |= 1 << 52;
-    }
-
-    // x mod y
-    while (ex > ey) : (ex -= 1) {
-        const i = ux - uy;
-        if (i >> 63 == 0) {
-            if (i == 0) {
-                return 0 * x;
-            }
-            ux = i;
-        }
-        ux <<= 1;
-    }
-    {
-        const i = ux - uy;
-        if (i >> 63 == 0) {
-            if (i == 0) {
-                return 0 * x;
-            }
-            ux = i;
-        }
-    }
-
-    while (ux >> 52 == 0) : (ux <<= 1) {
-        ex -= 1;
-    }
-
-    // scale result up
-    if (ex > 0) {
-        ux -= 1 << 52;
-        ux |= u64(ex) << 52;
-    } else {
-        ux >>= u64(-ex + 1);
-    }
-
-    ux |= sx << 63;
-    @bitCast(f64, ux)
-}
-
-// duplicate symbol clash with `fmod` test name
-test "fmod_" {
-    assert(fmod(f32, 1.3, 2.5) == fmod32(1.3, 2.5));
-    assert(fmod(f64, 1.3, 2.5) == fmod64(1.3, 2.5));
-}
-
-test "fmod32" {
-    const epsilon = 0.000001;
-
-    assert(math.approxEq(f32, fmod32(5.2, 2.0), 1.2, epsilon));
-    assert(math.approxEq(f32, fmod32(18.5, 4.2), 1.7, epsilon));
-    assert(math.approxEq(f32, fmod32(23, 48.34), 23.0, epsilon));
-    assert(math.approxEq(f32, fmod32(123.340890, 2398.2314), 123.340889, epsilon));
-}
-
-test "fmod64" {
-    const epsilon = 0.000001;
-
-    assert(math.approxEq(f64, fmod64(5.2, 2.0), 1.2, epsilon));
-    assert(math.approxEq(f64, fmod64(18.5, 4.2), 1.7, epsilon));
-    assert(math.approxEq(f64, fmod64(23, 48.34), 23.0, epsilon));
-    assert(math.approxEq(f64, fmod64(123.340890, 2398.2314), 123.340889, epsilon));
-}
std/math/frexp.zig
@@ -1,6 +1,9 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
+// TODO issue #393
+pub const frexp = frexp_workaround;
+
 fn frexp_result(comptime T: type) -> type {
     struct {
         significand: T,
@@ -10,7 +13,7 @@ fn frexp_result(comptime T: type) -> type {
 pub const frexp32_result = frexp_result(f32);
 pub const frexp64_result = frexp_result(f64);
 
-pub fn frexp(x: var) -> frexp_result(@typeOf(x)) {
+pub fn frexp_workaround(x: var) -> frexp_result(@typeOf(x)) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(frexp32, x),
@@ -80,7 +83,7 @@ fn frexp64(x: f64) -> frexp64_result {
     result
 }
 
-test "frexp" {
+test "math.frexp" {
     const a = frexp(f32(1.3));
     const b = frexp32(1.3);
     assert(a.significand == b.significand and a.exponent == b.exponent);
@@ -90,7 +93,7 @@ test "frexp" {
     assert(c.significand == d.significand and c.exponent == d.exponent);
 }
 
-test "frexp32" {
+test "math.frexp32" {
     const epsilon = 0.000001;
     var r: frexp32_result = undefined;
 
@@ -101,7 +104,7 @@ test "frexp32" {
     assert(math.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7);
 }
 
-test "frexp64" {
+test "math.frexp64" {
     const epsilon = 0.000001;
     var r: frexp64_result = undefined;
 
std/math/hypot.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn hypot(comptime T: type, x: T, y: T) -> T {
+// TODO issue #393
+pub const hypot = hypot_workaround;
+
+pub fn hypot_workaround(comptime T: type, x: T, y: T) -> T {
     switch (T) {
         f32 => @inlineCall(hypot32, x, y),
         f64 => @inlineCall(hypot64, x, y),
@@ -105,12 +108,12 @@ fn hypot64(x: f64, y: f64) -> f64 {
     z * math.sqrt(ly + lx + hy + hx)
 }
 
-test "hypot" {
+test "math.hypot" {
     assert(hypot(f32, 0.0, -1.2) == hypot32(0.0, -1.2));
     assert(hypot(f64, 0.0, -1.2) == hypot64(0.0, -1.2));
 }
 
-test "hypot32" {
+test "math.hypot32" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, hypot32(0.0, -1.2), 1.2, epsilon));
@@ -122,7 +125,7 @@ test "hypot32" {
     assert(math.approxEq(f32, hypot32(123123.234375, 529428.707813), 543556.875, epsilon));
 }
 
-test "hypot64" {
+test "math.hypot64" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f64, hypot64(0.0, -1.2), 1.2, epsilon));
std/math/ilogb.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn ilogb(x: var) -> i32 {
+// TODO issue #393
+pub const ilogb = ilogb_workaround;
+
+pub fn ilogb_workaround(x: var) -> i32 {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(ilogb32, x),
@@ -76,12 +79,12 @@ fn ilogb64(x: f64) -> i32 {
     e - 0x3FF
 }
 
-test "ilogb" {
+test "math.ilogb" {
     assert(ilogb(f32(0.2)) == ilogb32(0.2));
     assert(ilogb(f64(0.2)) == ilogb64(0.2));
 }
 
-test "ilogb32" {
+test "math.ilogb32" {
     assert(ilogb32(0.0) == fp_ilogb0);
     assert(ilogb32(0.5) == -1);
     assert(ilogb32(0.8923) == -1);
@@ -90,7 +93,7 @@ test "ilogb32" {
     assert(ilogb32(2398.23) == 11);
 }
 
-test "ilogb64" {
+test "math.ilogb64" {
     assert(ilogb64(0.0) == fp_ilogb0);
     assert(ilogb64(0.5) == -1);
     assert(ilogb64(0.8923) == -1);
std/math/index.zig
@@ -98,7 +98,6 @@ pub const round = @import("round.zig").round;
 pub const frexp = @import("frexp.zig").frexp;
 pub const frexp32_result = @import("frexp.zig").frexp32_result;
 pub const frexp64_result = @import("frexp.zig").frexp64_result;
-pub const fmod = @import("fmod.zig").fmod;
 pub const modf = @import("modf.zig").modf;
 pub const modf32_result = @import("modf.zig").modf32_result;
 pub const modf64_result = @import("modf.zig").modf64_result;
@@ -147,7 +146,6 @@ test "math" {
     _ = @import("trunc.zig");
     _ = @import("round.zig");
     _ = @import("frexp.zig");
-    _ = @import("fmod.zig");
     _ = @import("modf.zig");
     _ = @import("copysign.zig");
     _ = @import("isfinite.zig");
std/math/isfinite.zig
@@ -18,7 +18,7 @@ pub fn isFinite(x: var) -> bool {
     }
 }
 
-test "isFinite" {
+test "math.isFinite" {
     assert(isFinite(f32(0.0)));
     assert(isFinite(f32(-0.0)));
     assert(isFinite(f64(0.0)));
std/math/isinf.zig
@@ -48,7 +48,7 @@ pub fn isNegativeInf(x: var) -> bool {
     }
 }
 
-test "isInf" {
+test "math.isInf" {
     assert(!isInf(f32(0.0)));
     assert(!isInf(f32(-0.0)));
     assert(!isInf(f64(0.0)));
@@ -59,7 +59,7 @@ test "isInf" {
     assert(isInf(-math.inf(f64)));
 }
 
-test "isPositiveInf" {
+test "math.isPositiveInf" {
     assert(!isPositiveInf(f32(0.0)));
     assert(!isPositiveInf(f32(-0.0)));
     assert(!isPositiveInf(f64(0.0)));
@@ -70,7 +70,7 @@ test "isPositiveInf" {
     assert(!isPositiveInf(-math.inf(f64)));
 }
 
-test "isNegativeInf" {
+test "math.isNegativeInf" {
     assert(!isNegativeInf(f32(0.0)));
     assert(!isNegativeInf(f32(-0.0)));
     assert(!isNegativeInf(f64(0.0)));
std/math/isnan.zig
@@ -18,7 +18,7 @@ pub fn isNan(x: var) -> bool {
     }
 }
 
-test "isNan" {
+test "math.isNan" {
     assert(isNan(math.nan(f32)));
     assert(isNan(math.nan(f64)));
     assert(!isNan(f32(1.0)));
std/math/isnormal.zig
@@ -18,7 +18,7 @@ pub fn isNormal(x: var) -> bool {
     }
 }
 
-test "isNormal" {
+test "math.isNormal" {
     assert(!isNormal(math.nan(f32)));
     assert(!isNormal(math.nan(f64)));
     assert(isNormal(f32(1.0)));
std/math/ln.zig
@@ -1,7 +1,9 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn ln(x: var) -> @typeOf(x) {
+pub const ln = ln_workaround;
+
+pub fn ln_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(lnf, x),
std/math/log.zig
@@ -2,7 +2,10 @@ const math = @import("index.zig");
 const builtin = @import("builtin");
 const assert = @import("../debug.zig").assert;
 
-pub fn log(comptime base: usize, x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const log = log_workaround;
+
+pub fn log_workaround(comptime base: usize, x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (@typeId(T)) {
         builtin.TypeId.Int => {
@@ -13,41 +16,30 @@ pub fn log(comptime base: usize, x: var) -> @typeOf(x) {
             }
         },
 
-        builtin.TypeId.Float => {
-            return logf(base, x);
-        },
-
-        else => {
-            @compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'");
-        },
-    }
-}
-
-fn logf(comptime base: usize, x: var) -> @typeOf(x) {
-    const T = @typeOf(x);
-    switch (T) {
-        f32 => {
-            switch (base) {
+        builtin.TypeId.Float => switch (T) {
+            f32 => switch (base) {
                 2 => return math.log2(x),
                 10 => return math.log10(x),
                 else => return f32(math.ln(f64(x)) / math.ln(f64(base))),
-            }
-        },
+            },
 
-        f64 => {
-            switch (base) {
+            f64 => switch (base) {
                 2 => return math.log2(x),
                 10 => return math.log10(x),
                 // NOTE: This likely is computed with reduced accuracy.
                 else => return math.ln(x) / math.ln(f64(base)),
-            }
+            },
+
+            else => @compileError("log not implemented for " ++ @typeName(T)),
         },
 
-        else => @compileError("log not implemented for " ++ @typeName(T)),
+        else => {
+            @compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'");
+        },
     }
 }
 
-test "log_integer" {
+test "math.log integer" {
     assert(log(2, u8(0x1)) == 0);
     assert(log(2, u8(0x2)) == 1);
     assert(log(2, i16(0x72)) == 6);
@@ -55,7 +47,7 @@ test "log_integer" {
     assert(log(2, u64(0x7FF0123456789ABC)) == 62);
 }
 
-test "log_float" {
+test "math.log float" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, log(6, f32(0.23947)), -0.797723, epsilon));
@@ -63,7 +55,7 @@ test "log_float" {
     assert(math.approxEq(f64, log(123897, f64(12389216414)), 1.981724596, epsilon));
 }
 
-test "log_float_special" {
+test "math.log float_special" {
     assert(log(2, f32(0.2301974)) == math.log2(f32(0.2301974)));
     assert(log(10, f32(0.2301974)) == math.log10(f32(0.2301974)));
 
std/math/log10.zig
@@ -1,16 +1,19 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn log10(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const log10 = log10_workaround;
+
+pub fn log10_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(log10f, x),
-        f64 => @inlineCall(log10d, x),
+        f32 => @inlineCall(log10_32, x),
+        f64 => @inlineCall(log10_64, x),
         else => @compileError("log10 not implemented for " ++ @typeName(T)),
     }
 }
 
-fn log10f(x_: f32) -> f32 {
+fn log10_32(x_: f32) -> f32 {
     const ivln10hi: f32  =  4.3432617188e-01;
     const ivln10lo: f32  = -3.1689971365e-05;
     const log10_2hi: f32 =  3.0102920532e-01;
@@ -70,7 +73,7 @@ fn log10f(x_: f32) -> f32 {
     dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi
 }
 
-fn log10d(x_: f64) -> f64 {
+fn log10_64(x_: f64) -> f64 {
     const ivln10hi: f64  = 4.34294481878168880939e-01;
     const ivln10lo: f64  = 2.50829467116452752298e-11;
     const log10_2hi: f64 = 3.01029995663611771306e-01;
@@ -147,29 +150,29 @@ fn log10d(x_: f64) -> f64 {
     val_lo + val_hi
 }
 
-test "log10" {
-    assert(log10(f32(0.2)) == log10f(0.2));
-    assert(log10(f64(0.2)) == log10d(0.2));
+test "math.log10" {
+    assert(log10(f32(0.2)) == log10_32(0.2));
+    assert(log10(f64(0.2)) == log10_64(0.2));
 }
 
-test "log10f" {
+test "math.log10_32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, log10f(0.2), -0.698970, epsilon));
-    assert(math.approxEq(f32, log10f(0.8923), -0.049489, epsilon));
-    assert(math.approxEq(f32, log10f(1.5), 0.176091, epsilon));
-    assert(math.approxEq(f32, log10f(37.45), 1.573452, epsilon));
-    assert(math.approxEq(f32, log10f(89.123), 1.94999, epsilon));
-    assert(math.approxEq(f32, log10f(123123.234375), 5.09034, epsilon));
+    assert(math.approxEq(f32, log10_32(0.2), -0.698970, epsilon));
+    assert(math.approxEq(f32, log10_32(0.8923), -0.049489, epsilon));
+    assert(math.approxEq(f32, log10_32(1.5), 0.176091, epsilon));
+    assert(math.approxEq(f32, log10_32(37.45), 1.573452, epsilon));
+    assert(math.approxEq(f32, log10_32(89.123), 1.94999, epsilon));
+    assert(math.approxEq(f32, log10_32(123123.234375), 5.09034, epsilon));
 }
 
-test "log10d" {
+test "math.log10_64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, log10d(0.2), -0.698970, epsilon));
-    assert(math.approxEq(f64, log10d(0.8923), -0.049489, epsilon));
-    assert(math.approxEq(f64, log10d(1.5), 0.176091, epsilon));
-    assert(math.approxEq(f64, log10d(37.45), 1.573452, epsilon));
-    assert(math.approxEq(f64, log10d(89.123), 1.94999, epsilon));
-    assert(math.approxEq(f64, log10d(123123.234375), 5.09034, epsilon));
+    assert(math.approxEq(f64, log10_64(0.2), -0.698970, epsilon));
+    assert(math.approxEq(f64, log10_64(0.8923), -0.049489, epsilon));
+    assert(math.approxEq(f64, log10_64(1.5), 0.176091, epsilon));
+    assert(math.approxEq(f64, log10_64(37.45), 1.573452, epsilon));
+    assert(math.approxEq(f64, log10_64(89.123), 1.94999, epsilon));
+    assert(math.approxEq(f64, log10_64(123123.234375), 5.09034, epsilon));
 }
std/math/log1p.zig
@@ -1,16 +1,19 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn log1p(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const log1p = log1p_workaround;
+
+pub fn log1p_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(log1pf, x),
-        f64 => @inlineCall(log1pd, x),
+        f32 => @inlineCall(log1p_32, x),
+        f64 => @inlineCall(log1p_64, x),
         else => @compileError("log1p not implemented for " ++ @typeName(T)),
     }
 }
 
-fn log1pf(x: f32) -> f32 {
+fn log1p_32(x: f32) -> f32 {
     const ln2_hi = 6.9313812256e-01;
     const ln2_lo = 9.0580006145e-06;
     const Lg1: f32 = 0xaaaaaa.0p-24;
@@ -86,7 +89,7 @@ fn log1pf(x: f32) -> f32 {
     s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
 }
 
-fn log1pd(x: f64) -> f64 {
+fn log1p_64(x: f64) -> f64 {
     const ln2_hi: f64 = 6.93147180369123816490e-01;
     const ln2_lo: f64 = 1.90821492927058770002e-10;
     const Lg1: f64 = 6.666666666666735130e-01;
@@ -167,31 +170,31 @@ fn log1pd(x: f64) -> f64 {
     s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
 }
 
-test "log1p" {
-    assert(log1p(f32(0.0)) == log1pf(0.0));
-    assert(log1p(f64(0.0)) == log1pd(0.0));
+test "math.log1p" {
+    assert(log1p(f32(0.0)) == log1p_32(0.0));
+    assert(log1p(f64(0.0)) == log1p_64(0.0));
 }
 
-test "log1pf" {
+test "math.log1p_32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, log1pf(0.0), 0.0, epsilon));
-    assert(math.approxEq(f32, log1pf(0.2), 0.182322, epsilon));
-    assert(math.approxEq(f32, log1pf(0.8923), 0.637793, epsilon));
-    assert(math.approxEq(f32, log1pf(1.5), 0.916291, epsilon));
-    assert(math.approxEq(f32, log1pf(37.45), 3.649359, epsilon));
-    assert(math.approxEq(f32, log1pf(89.123), 4.501175, epsilon));
-    assert(math.approxEq(f32, log1pf(123123.234375), 11.720949, epsilon));
+    assert(math.approxEq(f32, log1p_32(0.0), 0.0, epsilon));
+    assert(math.approxEq(f32, log1p_32(0.2), 0.182322, epsilon));
+    assert(math.approxEq(f32, log1p_32(0.8923), 0.637793, epsilon));
+    assert(math.approxEq(f32, log1p_32(1.5), 0.916291, epsilon));
+    assert(math.approxEq(f32, log1p_32(37.45), 3.649359, epsilon));
+    assert(math.approxEq(f32, log1p_32(89.123), 4.501175, epsilon));
+    assert(math.approxEq(f32, log1p_32(123123.234375), 11.720949, epsilon));
 }
 
-test "log1pd" {
+test "math.log1p_64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, log1pd(0.0), 0.0, epsilon));
-    assert(math.approxEq(f64, log1pd(0.2), 0.182322, epsilon));
-    assert(math.approxEq(f64, log1pd(0.8923), 0.637793, epsilon));
-    assert(math.approxEq(f64, log1pd(1.5), 0.916291, epsilon));
-    assert(math.approxEq(f64, log1pd(37.45), 3.649359, epsilon));
-    assert(math.approxEq(f64, log1pd(89.123), 4.501175, epsilon));
-    assert(math.approxEq(f64, log1pd(123123.234375), 11.720949, epsilon));
+    assert(math.approxEq(f64, log1p_64(0.0), 0.0, epsilon));
+    assert(math.approxEq(f64, log1p_64(0.2), 0.182322, epsilon));
+    assert(math.approxEq(f64, log1p_64(0.8923), 0.637793, epsilon));
+    assert(math.approxEq(f64, log1p_64(1.5), 0.916291, epsilon));
+    assert(math.approxEq(f64, log1p_64(37.45), 3.649359, epsilon));
+    assert(math.approxEq(f64, log1p_64(89.123), 4.501175, epsilon));
+    assert(math.approxEq(f64, log1p_64(123123.234375), 11.720949, epsilon));
 }
std/math/log2.zig
@@ -1,16 +1,19 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn log2(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const log2 = log2_workaround;
+
+pub fn log2_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(log2f, x),
-        f64 => @inlineCall(log2d, x),
+        f32 => @inlineCall(log2_32, x),
+        f64 => @inlineCall(log2_64, x),
         else => @compileError("log2 not implemented for " ++ @typeName(T)),
     }
 }
 
-fn log2f(x_: f32) -> f32 {
+fn log2_32(x_: f32) -> f32 {
     const ivln2hi: f32 =  1.4428710938e+00;
     const ivln2lo: f32 = -1.7605285393e-04;
     const Lg1: f32 = 0xaaaaaa.0p-24;
@@ -66,7 +69,7 @@ fn log2f(x_: f32) -> f32 {
     (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k)
 }
 
-fn log2d(x_: f64) -> f64 {
+fn log2_64(x_: f64) -> f64 {
     const ivln2hi: f64 = 1.44269504072144627571e+00;
     const ivln2lo: f64 = 1.67517131648865118353e-10;
     const Lg1: f64 = 6.666666666666735130e-01;
@@ -139,27 +142,27 @@ fn log2d(x_: f64) -> f64 {
     val_lo + val_hi
 }
 
-test "log2" {
-    assert(log2(f32(0.2)) == log2f(0.2));
-    assert(log2(f64(0.2)) == log2d(0.2));
+test "math.log2" {
+    assert(log2(f32(0.2)) == log2_32(0.2));
+    assert(log2(f64(0.2)) == log2_64(0.2));
 }
 
-test "log2f" {
+test "math.log2_32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, log2f(0.2), -2.321928, epsilon));
-    assert(math.approxEq(f32, log2f(0.8923), -0.164399, epsilon));
-    assert(math.approxEq(f32, log2f(1.5), 0.584962, epsilon));
-    assert(math.approxEq(f32, log2f(37.45), 5.226894, epsilon));
-    assert(math.approxEq(f32, log2f(123123.234375), 16.909744, epsilon));
+    assert(math.approxEq(f32, log2_32(0.2), -2.321928, epsilon));
+    assert(math.approxEq(f32, log2_32(0.8923), -0.164399, epsilon));
+    assert(math.approxEq(f32, log2_32(1.5), 0.584962, epsilon));
+    assert(math.approxEq(f32, log2_32(37.45), 5.226894, epsilon));
+    assert(math.approxEq(f32, log2_32(123123.234375), 16.909744, epsilon));
 }
 
-test "log2d" {
+test "math.log2_64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, log2d(0.2), -2.321928, epsilon));
-    assert(math.approxEq(f64, log2d(0.8923), -0.164399, epsilon));
-    assert(math.approxEq(f64, log2d(1.5), 0.584962, epsilon));
-    assert(math.approxEq(f64, log2d(37.45), 5.226894, epsilon));
-    assert(math.approxEq(f64, log2d(123123.234375), 16.909744, epsilon));
+    assert(math.approxEq(f64, log2_64(0.2), -2.321928, epsilon));
+    assert(math.approxEq(f64, log2_64(0.8923), -0.164399, epsilon));
+    assert(math.approxEq(f64, log2_64(1.5), 0.584962, epsilon));
+    assert(math.approxEq(f64, log2_64(37.45), 5.226894, epsilon));
+    assert(math.approxEq(f64, log2_64(123123.234375), 16.909744, epsilon));
 }
std/math/modf.zig
@@ -1,6 +1,9 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
+// TODO issue #393
+pub const modf = modf_workaround;
+
 fn modf_result(comptime T: type) -> type {
     struct {
         fpart: T,
@@ -10,7 +13,7 @@ fn modf_result(comptime T: type) -> type {
 pub const modf32_result = modf_result(f32);
 pub const modf64_result = modf_result(f64);
 
-pub fn modf(x: var) -> modf_result(@typeOf(x)) {
+pub fn modf_workaround(x: var) -> modf_result(@typeOf(x)) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(modf32, x),
@@ -95,7 +98,7 @@ fn modf64(x: f64) -> modf64_result {
     result
 }
 
-test "modf" {
+test "math.modf" {
     const a = modf(f32(1.0));
     const b = modf32(1.0);
     // NOTE: No struct comparison on generic return type function? non-named, makes sense, but still.
@@ -106,7 +109,7 @@ test "modf" {
     assert(a.ipart == b.ipart and a.fpart == b.fpart);
 }
 
-test "modf32" {
+test "math.modf32" {
     const epsilon = 0.000001;
     var r: modf32_result = undefined;
 
@@ -131,7 +134,7 @@ test "modf32" {
     assert(math.approxEq(f32, r.fpart, 0.340820, epsilon));
 }
 
-test "modf64" {
+test "math.modf64" {
     const epsilon = 0.000001;
     var r: modf64_result = undefined;
 
std/math/nan.zig
@@ -1,6 +1,8 @@
 const math = @import("index.zig");
 
-pub fn nan(comptime T: type) -> T {
+pub const nan = nan_workaround;
+
+pub fn nan_workaround(comptime T: type) -> T {
     switch (T) {
         f32 => @bitCast(f32, math.nan_u32),
         f64 => @bitCast(f64, math.nan_u64),
std/math/oindex.zig
@@ -1,274 +0,0 @@
-const assert = @import("../debug.zig").assert;
-const builtin = @import("builtin");
-
-pub const frexp = @import("frexp.zig").frexp;
-
-pub const Cmp = enum {
-    Less,
-    Equal,
-    Greater,
-};
-
-pub fn min(x: var, y: var) -> @typeOf(x + y) {
-    if (x < y) x else y
-}
-
-test "math.min" {
-    assert(min(i32(-1), i32(2)) == -1);
-}
-
-pub fn max(x: var, y: var) -> @typeOf(x + y) {
-    if (x > y) x else y
-}
-
-test "math.max" {
-    assert(max(i32(-1), i32(2)) == 2);
-}
-
-error Overflow;
-pub fn mul(comptime T: type, a: T, b: T) -> %T {
-    var answer: T = undefined;
-    if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer
-}
-
-error Overflow;
-pub fn add(comptime T: type, a: T, b: T) -> %T {
-    var answer: T = undefined;
-    if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer
-}
-
-error Overflow;
-pub fn sub(comptime T: type, a: T, b: T) -> %T {
-    var answer: T = undefined;
-    if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer
-}
-
-pub fn negate(x: var) -> %@typeOf(x) {
-    return sub(@typeOf(x), 0, x);
-}
-
-error Overflow;
-pub fn shl(comptime T: type, a: T, b: T) -> %T {
-    var answer: T = undefined;
-    if (@shlWithOverflow(T, a, b, &answer)) error.Overflow else answer
-}
-
-test "math overflow functions" {
-    testOverflow();
-    comptime testOverflow();
-}
-
-fn testOverflow() {
-    assert(%%mul(i32, 3, 4) == 12);
-    assert(%%add(i32, 3, 4) == 7);
-    assert(%%sub(i32, 3, 4) == -1);
-    assert(%%shl(i32, 0b11, 4) == 0b110000);
-}
-
-
-error Overflow;
-pub fn absInt(x: var) -> %@typeOf(x) {
-    const T = @typeOf(x);
-    comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
-    comptime assert(T.is_signed); // must pass a signed integer to absInt
-    if (x == @minValue(@typeOf(x)))
-        return error.Overflow;
-    {
-        @setDebugSafety(this, false);
-        return if (x < 0) -x else x;
-    }
-}
-
-test "math.absInt" {
-    testAbsInt();
-    comptime testAbsInt();
-}
-fn testAbsInt() {
-    assert(%%absInt(i32(-10)) == 10);
-    assert(%%absInt(i32(10)) == 10);
-}
-
-pub const absFloat = @import("fabs.zig").fabs;
-
-error DivisionByZero;
-error Overflow;
-pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {
-    @setDebugSafety(this, false);
-    if (denominator == 0)
-        return error.DivisionByZero;
-    if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
-        return error.Overflow;
-    return @divTrunc(numerator, denominator);
-}
-
-test "math.divTrunc" {
-    testDivTrunc();
-    comptime testDivTrunc();
-}
-fn testDivTrunc() {
-    assert(%%divTrunc(i32, 5, 3) == 1);
-    assert(%%divTrunc(i32, -5, 3) == -1);
-    if (divTrunc(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
-    if (divTrunc(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow);
-
-    assert(%%divTrunc(f32, 5.0, 3.0) == 1.0);
-    assert(%%divTrunc(f32, -5.0, 3.0) == -1.0);
-}
-
-error DivisionByZero;
-error Overflow;
-pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {
-    @setDebugSafety(this, false);
-    if (denominator == 0)
-        return error.DivisionByZero;
-    if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
-        return error.Overflow;
-    return @divFloor(numerator, denominator);
-}
-
-test "math.divFloor" {
-    testDivFloor();
-    comptime testDivFloor();
-}
-fn testDivFloor() {
-    assert(%%divFloor(i32, 5, 3) == 1);
-    assert(%%divFloor(i32, -5, 3) == -2);
-    if (divFloor(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
-    if (divFloor(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow);
-
-    assert(%%divFloor(f32, 5.0, 3.0) == 1.0);
-    assert(%%divFloor(f32, -5.0, 3.0) == -2.0);
-}
-
-error DivisionByZero;
-error Overflow;
-error UnexpectedRemainder;
-pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {
-    @setDebugSafety(this, false);
-    if (denominator == 0)
-        return error.DivisionByZero;
-    if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == @minValue(T) and denominator == -1)
-        return error.Overflow;
-    const result = @divTrunc(numerator, denominator);
-    if (result * denominator != numerator)
-        return error.UnexpectedRemainder;
-    return result;
-}
-
-test "math.divExact" {
-    testDivExact();
-    comptime testDivExact();
-}
-fn testDivExact() {
-    assert(%%divExact(i32, 10, 5) == 2);
-    assert(%%divExact(i32, -10, 5) == -2);
-    if (divExact(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
-    if (divExact(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow);
-    if (divExact(i32, 5, 2)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder);
-
-    assert(%%divExact(f32, 10.0, 5.0) == 2.0);
-    assert(%%divExact(f32, -10.0, 5.0) == -2.0);
-    if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder);
-}
-
-error DivisionByZero;
-error NegativeDenominator;
-pub fn mod(comptime T: type, numerator: T, denominator: T) -> %T {
-    @setDebugSafety(this, false);
-    if (denominator == 0)
-        return error.DivisionByZero;
-    if (denominator < 0)
-        return error.NegativeDenominator;
-    return @mod(numerator, denominator);
-}
-
-test "math.mod" {
-    testMod();
-    comptime testMod();
-}
-fn testMod() {
-    assert(%%mod(i32, -5, 3) == 1);
-    assert(%%mod(i32, 5, 3) == 2);
-    if (mod(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator);
-    if (mod(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
-
-    assert(%%mod(f32, -5, 3) == 1);
-    assert(%%mod(f32, 5, 3) == 2);
-    if (mod(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator);
-    if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
-}
-
-error DivisionByZero;
-error NegativeDenominator;
-pub fn rem(comptime T: type, numerator: T, denominator: T) -> %T {
-    @setDebugSafety(this, false);
-    if (denominator == 0)
-        return error.DivisionByZero;
-    if (denominator < 0)
-        return error.NegativeDenominator;
-    return @rem(numerator, denominator);
-}
-
-test "math.rem" {
-    testRem();
-    comptime testRem();
-}
-fn testRem() {
-    assert(%%rem(i32, -5, 3) == -2);
-    assert(%%rem(i32, 5, 3) == 2);
-    if (rem(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator);
-    if (rem(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
-
-    assert(%%rem(f32, -5, 3) == -2);
-    assert(%%rem(f32, 5, 3) == 2);
-    if (rem(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator);
-    if (rem(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero);
-}
-
-/// Returns the absolute value of the integer parameter.
-/// Result is an unsigned integer.
-pub fn absCast(x: var) -> @IntType(false, @typeOf(x).bit_count) {
-    const uint = @IntType(false, @typeOf(x).bit_count);
-    if (x >= 0)
-        return uint(x);
-
-    return uint(-(x + 1)) + 1;
-}
-
-test "math.absCast" {
-    assert(absCast(i32(-999)) == 999);
-    assert(@typeOf(absCast(i32(-999))) == u32);
-
-    assert(absCast(i32(999)) == 999);
-    assert(@typeOf(absCast(i32(999))) == u32);
-
-    assert(absCast(i32(@minValue(i32))) == -@minValue(i32));
-    assert(@typeOf(absCast(i32(@minValue(i32)))) == u32);
-}
-
-/// Returns the negation of the integer parameter.
-/// Result is a signed integer.
-error Overflow;
-pub fn negateCast(x: var) -> %@IntType(true, @typeOf(x).bit_count) {
-    if (@typeOf(x).is_signed)
-        return negate(x);
-
-    const int = @IntType(true, @typeOf(x).bit_count);
-    if (x > -@minValue(int))
-        return error.Overflow;
-
-    if (x == -@minValue(int))
-        return @minValue(int);
-
-    return -int(x);
-}
-
-test "math.negateCast" {
-    assert(%%negateCast(u32(999)) == -999);
-    assert(@typeOf(%%negateCast(u32(999))) == i32);
-
-    assert(%%negateCast(u32(-@minValue(i32))) == @minValue(i32));
-    assert(@typeOf(%%negateCast(u32(-@minValue(i32)))) == i32);
-
-    if (negateCast(u32(@maxValue(i32) + 10))) |_| unreachable else |err| assert(err == error.Overflow);
-}
std/math/pow.zig
@@ -1,8 +1,11 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
+// TODO issue #393
+pub const pow = pow_workaround;
+
 // This implementation is taken from the go stlib, musl is a bit more complex.
-pub fn pow(comptime T: type, x: T, y: T) -> T {
+pub fn pow_workaround(comptime T: type, x: T, y: T) -> T {
 
     @setFloatMode(this, @import("builtin").FloatMode.Strict);
 
@@ -158,9 +161,7 @@ test "math.pow" {
     assert(math.approxEq(f32, pow(f32, 0.2, 3.3), 0.004936, epsilon));
     assert(math.approxEq(f32, pow(f32, 1.5, 3.3), 3.811546, epsilon));
     assert(math.approxEq(f32, pow(f32, 37.45, 3.3), 155736.703125, epsilon));
-
-    // TODO: Determine why aborting on release mode.
-    // assert(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon));
+    assert(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon));
 
     // assert(math.approxEq(f32, pow(f64, 0.0, 3.3), 0.0, epsilon)); // TODO: Handle div zero
     assert(math.approxEq(f64, pow(f64, 0.8923, 3.3), 0.686572, epsilon));
std/math/round.zig
@@ -2,7 +2,10 @@ const builtin = @import("builtin");
 const assert = @import("../debug.zig").assert;
 const math = @import("index.zig");
 
-pub fn round(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const round = round_workaround;
+
+pub fn round_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(round32, x),
@@ -85,19 +88,19 @@ fn round64(x_: f64) -> f64 {
     }
 }
 
-test "round" {
+test "math.round" {
     assert(round(f32(1.3)) == round32(1.3));
     assert(round(f64(1.3)) == round64(1.3));
 }
 
-test "round32" {
+test "math.round32" {
     assert(round32(1.3) == 1.0);
     assert(round32(-1.3) == -1.0);
     assert(round32(0.2) == 0.0);
     assert(round32(1.8) == 2.0);
 }
 
-test "round64" {
+test "math.round64" {
     assert(round64(1.3) == 1.0);
     assert(round64(-1.3) == -1.0);
     assert(round64(0.2) == 0.0);
std/math/scalbn.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
+// TODO issue #393
+pub const scalbn = scalbn_workaround;
+
+pub fn scalbn_workaround(x: var, n: i32) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(scalbn32, x, n),
@@ -71,15 +74,15 @@ fn scalbn64(x: f64, n_: i32) -> f64 {
     y * @bitCast(f64, u)
 }
 
-test "scalbn" {
+test "math.scalbn" {
     assert(scalbn(f32(1.5), 4) == scalbn32(1.5, 4));
     assert(scalbn(f64(1.5), 4) == scalbn64(1.5, 4));
 }
 
-test "scalbn32" {
+test "math.scalbn32" {
     assert(scalbn32(1.5, 4) == 24.0);
 }
 
-test "scalbn64" {
+test "math.scalbn64" {
     assert(scalbn64(1.5, 4) == 24.0);
 }
std/math/signbit.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn signbit(x: var) -> bool {
+// TODO issue #393
+pub const signbit = signbit_workaround;
+
+pub fn signbit_workaround(x: var) -> bool {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(signbit32, x),
@@ -20,17 +23,17 @@ fn signbit64(x: f64) -> bool {
     bits >> 63 != 0
 }
 
-test "signbit" {
+test "math.signbit" {
     assert(signbit(f32(4.0)) == signbit32(4.0));
     assert(signbit(f64(4.0)) == signbit64(4.0));
 }
 
-test "signbit32" {
+test "math.signbit32" {
     assert(!signbit32(4.0));
     assert(signbit32(-3.0));
 }
 
-test "signbit64" {
+test "math.signbit64" {
     assert(!signbit64(4.0));
     assert(signbit64(-3.0));
 }
std/math/sin.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn sin(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const sin = sin_workaround;
+
+pub fn sin_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(sin32, x),
@@ -135,12 +138,12 @@ fn sin64(x_: f64) -> f64 {
     }
 }
 
-test "sin" {
+test "math.sin" {
     assert(sin(f32(0.0)) == sin32(0.0));
     assert(sin(f64(0.0)) == sin64(0.0));
 }
 
-test "sin32" {
+test "math.sin32" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon));
@@ -151,7 +154,7 @@ test "sin32" {
     assert(math.approxEq(f32, sin32(89.123), 0.916166, epsilon));
 }
 
-test "sin64" {
+test "math.sin64" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f64, sin64(0.0), 0.0, epsilon));
std/math/sinh.zig
@@ -2,11 +2,14 @@ const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 const expo2 = @import("_expo2.zig").expo2;
 
-pub fn sinh(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const sinh = sinh_workaround;
+
+pub fn sinh_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(sinhf, x),
-        f64 => @inlineCall(sinhd, x),
+        f32 => @inlineCall(sinh32, x),
+        f64 => @inlineCall(sinh64, x),
         else => @compileError("sinh not implemented for " ++ @typeName(T)),
     }
 }
@@ -14,7 +17,7 @@ pub fn sinh(x: var) -> @typeOf(x) {
 // sinh(x) = (exp(x) - 1 / exp(x)) / 2
 //         = (exp(x) - 1 + (exp(x) - 1) / exp(x)) / 2
 //         = x + x^3 / 6 + o(x^5)
-fn sinhf(x: f32) -> f32 {
+fn sinh32(x: f32) -> f32 {
     const u = @bitCast(u32, x);
     const ux = u & 0x7FFFFFFF;
     const ax = @bitCast(f32, ux);
@@ -41,7 +44,7 @@ fn sinhf(x: f32) -> f32 {
     2 * h * expo2(ax)
 }
 
-fn sinhd(x: f64) -> f64 {
+fn sinh64(x: f64) -> f64 {
     const u = @bitCast(u64, x);
     const w = u32(u >> 32);
     const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
@@ -69,25 +72,25 @@ fn sinhd(x: f64) -> f64 {
     2 * h * expo2(ax)
 }
 
-test "sinh" {
-    assert(sinh(f32(1.5)) == sinhf(1.5));
-    assert(sinh(f64(1.5)) == sinhd(1.5));
+test "math.sinh" {
+    assert(sinh(f32(1.5)) == sinh32(1.5));
+    assert(sinh(f64(1.5)) == sinh64(1.5));
 }
 
-test "sinhf" {
+test "math.sinh32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, sinhf(0.0), 0.0, epsilon));
-    assert(math.approxEq(f32, sinhf(0.2), 0.201336, epsilon));
-    assert(math.approxEq(f32, sinhf(0.8923), 1.015512, epsilon));
-    assert(math.approxEq(f32, sinhf(1.5), 2.129279, epsilon));
+    assert(math.approxEq(f32, sinh32(0.0), 0.0, epsilon));
+    assert(math.approxEq(f32, sinh32(0.2), 0.201336, epsilon));
+    assert(math.approxEq(f32, sinh32(0.8923), 1.015512, epsilon));
+    assert(math.approxEq(f32, sinh32(1.5), 2.129279, epsilon));
 }
 
-test "sinhd" {
+test "math.sinh64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, sinhd(0.0), 0.0, epsilon));
-    assert(math.approxEq(f64, sinhd(0.2), 0.201336, epsilon));
-    assert(math.approxEq(f64, sinhd(0.8923), 1.015512, epsilon));
-    assert(math.approxEq(f64, sinhd(1.5), 2.129279, epsilon));
+    assert(math.approxEq(f64, sinh64(0.0), 0.0, epsilon));
+    assert(math.approxEq(f64, sinh64(0.2), 0.201336, epsilon));
+    assert(math.approxEq(f64, sinh64(0.8923), 1.015512, epsilon));
+    assert(math.approxEq(f64, sinh64(1.5), 2.129279, epsilon));
 }
std/math/sqrt.zig
@@ -1,7 +1,10 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn sqrt(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const sqrt = sqrt_workaround;
+
+pub fn sqrt_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(sqrt32, x),
@@ -219,12 +222,12 @@ fn sqrt64(x: f64) -> f64 {
     @bitCast(f64, uz)
 }
 
-test "sqrt" {
+test "math.sqrt" {
     assert(sqrt(f32(0.0)) == sqrt32(0.0));
     assert(sqrt(f64(0.0)) == sqrt64(0.0));
 }
 
-test "sqrt32" {
+test "math.sqrt32" {
     const epsilon = 0.000001;
 
     assert(sqrt32(0.0) == 0.0);
@@ -238,7 +241,7 @@ test "sqrt32" {
     assert(math.approxEq(f32, sqrt32(8942.230469), 94.563370, epsilon));
 }
 
-test "sqrt64" {
+test "math.sqrt64" {
     const epsilon = 0.000001;
 
     assert(sqrt64(0.0) == 0.0);
std/math/tan.zig
@@ -1,7 +1,9 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn tan(x: var) -> @typeOf(x) {
+pub const tan = tan_workaround;
+
+pub fn tan_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(tan32, x),
@@ -122,12 +124,12 @@ fn tan64(x_: f64) -> f64 {
     r
 }
 
-test "tan" {
+test "math.tan" {
     assert(tan(f32(0.0)) == tan32(0.0));
     assert(tan(f64(0.0)) == tan64(0.0));
 }
 
-test "tan32" {
+test "math.tan32" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon));
@@ -138,7 +140,7 @@ test "tan32" {
     assert(math.approxEq(f32, tan32(89.123), 2.285852, epsilon));
 }
 
-test "tan64" {
+test "math.tan64" {
     const epsilon = 0.000001;
 
     assert(math.approxEq(f64, tan64(0.0), 0.0, epsilon));
std/math/tanh.zig
@@ -2,11 +2,14 @@ const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 const expo2 = @import("_expo2.zig").expo2;
 
-pub fn tanh(x: var) -> @typeOf(x) {
+// TODO issue #393
+pub const tanh = tanh_workaround;
+
+pub fn tanh_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
-        f32 => @inlineCall(tanhf, x),
-        f64 => @inlineCall(tanhd, x),
+        f32 => @inlineCall(tanh32, x),
+        f64 => @inlineCall(tanh64, x),
         else => @compileError("tanh not implemented for " ++ @typeName(T)),
     }
 }
@@ -14,7 +17,7 @@ pub fn tanh(x: var) -> @typeOf(x) {
 // tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
 //         = (exp(2x) - 1) / (exp(2x) - 1 + 2)
 //         = (1 - exp(-2x)) / (exp(-2x) - 1 + 2)
-fn tanhf(x: f32) -> f32 {
+fn tanh32(x: f32) -> f32 {
     const u = @bitCast(u32, x);
     const ux = u & 0x7FFFFFFF;
     const ax = @bitCast(f32, ux);
@@ -54,7 +57,7 @@ fn tanhf(x: f32) -> f32 {
     }
 }
 
-fn tanhd(x: f64) -> f64 {
+fn tanh64(x: f64) -> f64 {
     const u = @bitCast(u64, x);
     const w = u32(u >> 32);
     const ax = @bitCast(f64, u & (@maxValue(u64) >> 1));
@@ -94,27 +97,27 @@ fn tanhd(x: f64) -> f64 {
     }
 }
 
-test "tanh" {
-    assert(tanh(f32(1.5)) == tanhf(1.5));
-    assert(tanh(f64(1.5)) == tanhd(1.5));
+test "math.tanh" {
+    assert(tanh(f32(1.5)) == tanh32(1.5));
+    assert(tanh(f64(1.5)) == tanh64(1.5));
 }
 
-test "tanhf" {
+test "math.tanh32" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f32, tanhf(0.0), 0.0, epsilon));
-    assert(math.approxEq(f32, tanhf(0.2), 0.197375, epsilon));
-    assert(math.approxEq(f32, tanhf(0.8923), 0.712528, epsilon));
-    assert(math.approxEq(f32, tanhf(1.5), 0.905148, epsilon));
-    assert(math.approxEq(f32, tanhf(37.45), 1.0, epsilon));
+    assert(math.approxEq(f32, tanh32(0.0), 0.0, epsilon));
+    assert(math.approxEq(f32, tanh32(0.2), 0.197375, epsilon));
+    assert(math.approxEq(f32, tanh32(0.8923), 0.712528, epsilon));
+    assert(math.approxEq(f32, tanh32(1.5), 0.905148, epsilon));
+    assert(math.approxEq(f32, tanh32(37.45), 1.0, epsilon));
 }
 
-test "tanhd" {
+test "math.tanh64" {
     const epsilon = 0.000001;
 
-    assert(math.approxEq(f64, tanhd(0.0), 0.0, epsilon));
-    assert(math.approxEq(f64, tanhd(0.2), 0.197375, epsilon));
-    assert(math.approxEq(f64, tanhd(0.8923), 0.712528, epsilon));
-    assert(math.approxEq(f64, tanhd(1.5), 0.905148, epsilon));
-    assert(math.approxEq(f64, tanhd(37.45), 1.0, epsilon));
+    assert(math.approxEq(f64, tanh64(0.0), 0.0, epsilon));
+    assert(math.approxEq(f64, tanh64(0.2), 0.197375, epsilon));
+    assert(math.approxEq(f64, tanh64(0.8923), 0.712528, epsilon));
+    assert(math.approxEq(f64, tanh64(1.5), 0.905148, epsilon));
+    assert(math.approxEq(f64, tanh64(37.45), 1.0, epsilon));
 }
std/math/trunc.zig
@@ -1,7 +1,9 @@
 const math = @import("index.zig");
 const assert = @import("../debug.zig").assert;
 
-pub fn trunc(x: var) -> @typeOf(x) {
+pub const trunc = trunc_workaround;
+
+pub fn trunc_workaround(x: var) -> @typeOf(x) {
     const T = @typeOf(x);
     switch (T) {
         f32 => @inlineCall(trunc32, x),
@@ -52,18 +54,18 @@ fn trunc64(x: f64) -> f64 {
     }
 }
 
-test "trunc" {
+test "math.trunc" {
     assert(trunc(f32(1.3)) == trunc32(1.3));
     assert(trunc(f64(1.3)) == trunc64(1.3));
 }
 
-test "trunc32" {
+test "math.trunc32" {
     assert(trunc32(1.3) == 1.0);
     assert(trunc32(-1.3) == -1.0);
     assert(trunc32(0.2) == 0.0);
 }
 
-test "trunc64" {
+test "math.trunc64" {
     assert(trunc64(1.3) == 1.0);
     assert(trunc64(-1.3) == -1.0);
     assert(trunc64(0.2) == 0.0);