]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/internal/math: add multiplication with overflow check
authorMartin Möhrmann <moehrmann@google.com>
Sat, 27 Jan 2018 10:55:34 +0000 (11:55 +0100)
committerMartin Möhrmann <moehrmann@google.com>
Mon, 15 Oct 2018 17:58:06 +0000 (17:58 +0000)
This CL adds a new internal math package for use by the runtime.
The new package exports a MulUintptr function with uintptr arguments
a and b and returns uintptr(a*b) and whether the full-width product
x*y does overflow the uintptr value range (uintptr(x*y) != x*y).

Uses of MulUinptr in the runtime and intrinsics for performance
will be added in followup CLs.

Updates #21588

Change-Id: Ia5a02eeabc955249118e4edf68c67d9fc0858058
Reviewed-on: https://go-review.googlesource.com/c/91755
Run-TryBot: Martin Möhrmann <moehrmann@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/inl_test.go
src/cmd/compile/internal/gc/racewalk.go
src/go/build/deps_test.go
src/runtime/internal/math/math.go [new file with mode: 0644]
src/runtime/internal/math/math_test.go [new file with mode: 0644]

index a452f2ad2946a5e17c77f8e4cab2d7a395577391..3fc0fbed1d639c5eb84152053bdfdb3037693977 100644 (file)
@@ -96,6 +96,9 @@ func TestIntendedInlining(t *testing.T) {
                        "(*puintptr).set",
                },
                "runtime/internal/sys": {},
+               "runtime/internal/math": {
+                       "MulUintptr",
+               },
                "bytes": {
                        "(*Buffer).Bytes",
                        "(*Buffer).Cap",
index e8c7fb5b149060b5597ac24fbbfa40657bb81f56..8a8b436a23ab2dad0403ecdacc00002f7fc92535 100644 (file)
@@ -32,7 +32,15 @@ import (
 
 // Do not instrument the following packages at all,
 // at best instrumentation would cause infinite recursion.
-var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan", "internal/cpu"}
+var omit_pkgs = []string{
+       "runtime/internal/atomic",
+       "runtime/internal/sys",
+       "runtime/internal/math",
+       "runtime",
+       "runtime/race",
+       "runtime/msan",
+       "internal/cpu",
+}
 
 // Only insert racefuncenterfp/racefuncexit into the following packages.
 // Memory accesses in the packages are either uninteresting or will cause false positives.
index 91617714f6cc46984860766055800367014a9413..904759fe3b7483e3e93efad5a594dbf3e4856899 100644 (file)
@@ -36,9 +36,10 @@ var pkgDeps = map[string][]string{
        // L0 is the lowest level, core, nearly unavoidable packages.
        "errors":                  {},
        "io":                      {"errors", "sync", "sync/atomic"},
-       "runtime":                 {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "internal/cpu", "internal/bytealg"},
+       "runtime":                 {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "runtime/internal/math", "internal/cpu", "internal/bytealg"},
        "runtime/internal/sys":    {},
        "runtime/internal/atomic": {"unsafe", "internal/cpu"},
+       "runtime/internal/math":   {"runtime/internal/sys"},
        "internal/race":           {"runtime", "unsafe"},
        "sync":                    {"internal/race", "runtime", "sync/atomic", "unsafe"},
        "sync/atomic":             {"unsafe"},
diff --git a/src/runtime/internal/math/math.go b/src/runtime/internal/math/math.go
new file mode 100644 (file)
index 0000000..5385f5d
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+import "runtime/internal/sys"
+
+const MaxUintptr = ^uintptr(0)
+
+// MulUintptr returns a * b and whether the multiplication overflowed.
+// On supported platforms this is an intrinsic lowered by the compiler.
+func MulUintptr(a, b uintptr) (uintptr, bool) {
+       if a|b < 1<<(4*sys.PtrSize) || a == 0 {
+               return a * b, false
+       }
+       overflow := b > MaxUintptr/a
+       return a * b, overflow
+}
diff --git a/src/runtime/internal/math/math_test.go b/src/runtime/internal/math/math_test.go
new file mode 100644 (file)
index 0000000..9447bd2
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math_test
+
+import (
+       . "runtime/internal/math"
+       "testing"
+)
+
+const (
+       UintptrSize = 32 << (^uintptr(0) >> 63)
+)
+
+type mulUintptrTest struct {
+       a        uintptr
+       b        uintptr
+       overflow bool
+}
+
+var mulUintptrTests = []mulUintptrTest{
+       {0, 0, false},
+       {1000, 1000, false},
+       {MaxUintptr, 0, false},
+       {MaxUintptr, 1, false},
+       {MaxUintptr / 2, 2, false},
+       {MaxUintptr / 2, 3, true},
+       {MaxUintptr, 10, true},
+       {MaxUintptr, 100, true},
+       {MaxUintptr / 100, 100, false},
+       {MaxUintptr / 1000, 1001, true},
+       {1<<(UintptrSize/2) - 1, 1<<(UintptrSize/2) - 1, false},
+       {1 << (UintptrSize / 2), 1 << (UintptrSize / 2), true},
+       {MaxUintptr >> 32, MaxUintptr >> 32, false},
+       {MaxUintptr, MaxUintptr, true},
+}
+
+func TestMulUintptr(t *testing.T) {
+       for _, test := range mulUintptrTests {
+               a, b := test.a, test.b
+               for i := 0; i < 2; i++ {
+                       mul, overflow := MulUintptr(a, b)
+                       if mul != a*b || overflow != test.overflow {
+                               t.Errorf("MulUintptr(%v, %v) = %v, %v want %v, %v",
+                                       a, b, mul, overflow, a*b, test.overflow)
+                       }
+                       a, b = b, a
+               }
+       }
+}