提交 9f848656 编写于 作者: 3 3dgen

Merge branch 'master' of https://gitee.com/wa-lang/wa

......@@ -10,6 +10,7 @@
![](docs/images/logo/logo-animate1.svg)
- 主页: [https://wa-lang.org](https://wa-lang.org)
- 参考手册: [https://wa-lang.org/man/](https://wa-lang.org/man/)
- 仓库(Gitee): [https://gitee.com/wa-lang/wa](https://gitee.com/wa-lang/wa)
- 仓库(Github): [https://github.com/wa-lang/wa](https://github.com/wa-lang/wa)
- Playground: [https://wa-lang.org/playground](https://wa-lang.org/playground)
......
......@@ -22,6 +22,7 @@ Instead of requiring complex toolchains to set up, you can simply go install it
![](docs/images/logo/logo-animate1.svg)
- Home: [https://wa-lang.org](https://wa-lang.org)
- Manual(Chinese): [https://wa-lang.org/man/](https://wa-lang.org/man/)
- Github: [https://github.com/wa-lang/wa](https://github.com/wa-lang/wa)
- Playground: [https://wa-lang.org/playground](https://wa-lang.org/playground)
......
......@@ -98,8 +98,49 @@ func runTest(cfg *config.Config, pkgpath string, appArgs ...string) {
// 执行测试函数
var firstError error
for _, t := range mainPkg.TestInfo.Tests {
_, stdout, stderr, err := m.RunFunc(mainPkg.Pkg.Path() + "." + t.Name)
for i := 0; i < len(mainPkg.TestInfo.Tests); i++ {
t := mainPkg.TestInfo.Tests[i]
tFuncName := mainPkg.Pkg.Path() + "." + t.Name
tFuncName = strings.ReplaceAll(tFuncName, "/", "$")
_, stdout, stderr, err := m.RunFunc(tFuncName)
if t.OutputPanic {
stdout = bytes.TrimSpace(stdout)
expect, got := t.Output, string(stdout)
if exitCode, _ := wazero.AsExitError(err); exitCode == 0 {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect panic, got = nil\n")
if firstError == nil {
firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, "nil")
}
continue
}
if !strings.HasPrefix(got, "panic: "+expect) { // panic: ${expect} (pos)
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect(panic) = %q, got = %q\n", expect, got)
if firstError == nil {
firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, got)
}
}
// 重新加载
{
m, err = wazero.BuildModule(cfg, wasmName, wasmBytes, wasmArgs...)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// 临时方案: defer 太多
defer m.Close()
}
continue
}
if err != nil {
if len(stdout) > 0 {
if s := sWithPrefix(string(stdout), " "); s != "" {
......@@ -110,7 +151,12 @@ func runTest(cfg *config.Config, pkgpath string, appArgs ...string) {
if s := sWithPrefix(string(stderr), " "); s != "" {
fmt.Println(s)
}
} else {
if s := sWithPrefix(err.Error(), " "); s != "" {
fmt.Println(s)
}
}
os.Exit(1)
}
......@@ -146,8 +192,50 @@ func runTest(cfg *config.Config, pkgpath string, appArgs ...string) {
}
}
}
for _, t := range mainPkg.TestInfo.Examples {
_, stdout, stderr, err := m.RunFunc(mainPkg.Pkg.Path() + "." + t.Name)
for i := 0; i < len(mainPkg.TestInfo.Examples); i++ {
t := mainPkg.TestInfo.Examples[i]
tFuncName := mainPkg.Pkg.Path() + "." + t.Name
tFuncName = strings.ReplaceAll(tFuncName, "/", "$")
_, stdout, stderr, err := m.RunFunc(tFuncName)
if t.OutputPanic {
stdout = bytes.TrimSpace(stdout)
expect, got := t.Output, string(stdout)
if exitCode, _ := wazero.AsExitError(err); exitCode == 0 {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect panic, got = nil\n")
if firstError == nil {
firstError = fmt.Errorf("expect panic, got = nil")
}
continue
}
if !strings.HasPrefix(got, "panic: "+expect) { // panic: ${expect} (pos)
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect(panic) = %q, got = %q\n", expect, got)
if firstError == nil {
firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, got)
}
}
// 重新加载
{
m, err = wazero.BuildModule(cfg, wasmName, wasmBytes, wasmArgs...)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// 临时方案: defer 太多
defer m.Close()
}
continue
}
if err != nil {
if len(stdout) > 0 {
if s := sWithPrefix(string(stdout), " "); s != "" {
......
......@@ -44,9 +44,10 @@ type TestInfo struct {
// 测试函数信息
type TestFuncInfo struct {
FuncPos token.Pos // 函数位置
Name string // 函数名, 不含包路径
Output string // 期望输出, 为空表示不验证
FuncPos token.Pos // 函数位置
Name string // 函数名, 不含包路径
Output string // 期望输出, 为空表示不验证
OutputPanic bool // 异常信息
}
// 汇编代码文件
......
......@@ -300,10 +300,12 @@ func (p *_Loader) parseTestInfo(pkg *Package, filenames []string) (*TestInfo, er
switch {
case strings.HasPrefix(name, "Test"):
output, isPanic := p.parseExampleOutputComment(file, fn)
tInfo.Tests = append(tInfo.Tests, TestFuncInfo{
FuncPos: obj.Pos(),
Name: name,
Output: p.parseExampleOutputComment(file, fn),
FuncPos: obj.Pos(),
Name: name,
Output: output,
OutputPanic: isPanic,
})
case strings.HasPrefix(name, "Bench"):
tInfo.Benchs = append(tInfo.Benchs, TestFuncInfo{
......@@ -311,10 +313,12 @@ func (p *_Loader) parseTestInfo(pkg *Package, filenames []string) (*TestInfo, er
Name: name,
})
case strings.HasPrefix(name, "Example"):
output, isPanic := p.parseExampleOutputComment(file, fn)
tInfo.Examples = append(tInfo.Examples, TestFuncInfo{
FuncPos: obj.Pos(),
Name: name,
Output: p.parseExampleOutputComment(file, fn),
FuncPos: obj.Pos(),
Name: name,
Output: output,
OutputPanic: isPanic,
})
}
}
......@@ -324,7 +328,7 @@ func (p *_Loader) parseTestInfo(pkg *Package, filenames []string) (*TestInfo, er
return tInfo, nil
}
func (p *_Loader) parseExampleOutputComment(f *ast.File, fn *ast.FuncDecl) string {
func (p *_Loader) parseExampleOutputComment(f *ast.File, fn *ast.FuncDecl) (output string, isPanic bool) {
for _, commentGroup := range f.Comments {
if commentGroup.Pos() <= fn.Body.Pos() {
continue
......@@ -334,23 +338,33 @@ func (p *_Loader) parseExampleOutputComment(f *ast.File, fn *ast.FuncDecl) strin
}
for j, comment := range commentGroup.List {
if comment.Text != "// Output:" {
continue
}
switch comment.Text {
case "// Output:":
var lineTexts []string
for _, x := range commentGroup.List[j+1:] {
if !strings.HasPrefix(x.Text, "//") {
break
}
lineTexts = append(lineTexts, strings.TrimSpace(x.Text[2:]))
}
var lineTexts []string
for _, x := range commentGroup.List[j+1:] {
if !strings.HasPrefix(x.Text, "//") {
break
return strings.Join(lineTexts, "\n"), false
case "// Output(panic):":
var lineTexts []string
for _, x := range commentGroup.List[j+1:] {
if !strings.HasPrefix(x.Text, "//") {
break
}
lineTexts = append(lineTexts, strings.TrimSpace(x.Text[2:]))
}
lineTexts = append(lineTexts, strings.TrimSpace(x.Text[2:]))
}
return strings.Join(lineTexts, "\n")
return strings.Join(lineTexts, "\n"), true
}
}
}
return ""
return "", false
}
func (p *_Loader) ParseDir_wsFiles(pkgpath string) (files []*WsFile, err error) {
......
......@@ -23,4 +23,11 @@ func ExampleApple {
// Output:
// apple-mvp
}
\ No newline at end of file
}
func ExamplePanic {
panic("fuck panic")
// Output(panic):
// fuck panic
}
......@@ -12,40 +12,32 @@ const (
// u8 is the set of all unsigned 8-bit integers.
// Range: 0 through 255.
type u8: u8
type uint8: u8
// u16 is the set of all unsigned 16-bit integers.
// Range: 0 through 65535.
type u16: u16
type uint16: u16
// u32 is the set of all unsigned 32-bit integers.
// Range: 0 through 4294967295.
type u32: u32
type uint32: u32
// u64 is the set of all unsigned 64-bit integers.
// Range: 0 through 18446744073709551615.
type u64: u64
type uint64: u64
// int32 is the set of all signed 32-bit integers.
// Range: -2147483648 through 2147483647.
type i32: i32
type int32: i32
// int64 is the set of all signed 64-bit integers.
// Range: -9223372036854775808 through 9223372036854775807.
type i64: i64
type int64: i64
// float32 is the set of all IEEE-754 32-bit floating-point numbers.
type f32: f32
type float32: f32
// float64 is the set of all IEEE-754 64-bit floating-point numbers.
type f64: f64
type float64: f64
// string is the set of all strings of 8-bit bytes, conventionally but not
// necessarily representing UTF-8-encoded text. A string may be empty, but
......@@ -60,10 +52,6 @@ type int: int
// distinct type, however, and not an alias for, say, u32.
type uint: uint
// uintptr is an integer type that is large enough to hold the bit pattern of
// any pointer.
type uintptr uintptr
// byte is an alias for u8 and is equivalent to u8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
......@@ -73,24 +61,14 @@ type byte = u8
// used, by convention, to distinguish character values from integer values.
type rune = i32
// iota is a predeclared identifier representing the untyped integer ordinal
// number of the current const specification in a (usually parenthesized)
// const declaration. It is zero-indexed.
const iota = 0 // Untyped int.
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
global nil: Type // Type must be a pointer, channel, func, interface, map, or slice type
// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// for any Wa type, but represents the same type for any given function
// invocation.
type Type: int
// Type1 is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
type Type1: int
// nil is a predeclared identifier representing the zero value for a
// pointer, func, interface, map, or slice type.
global nil: Type // Type must be a pointer, func, interface, map, or slice type
// IntegerType is here for the purposes of documentation only. It is a stand-in
// for any integer type: int, uint, int8 etc.
......@@ -123,10 +101,8 @@ func copy(dst, src: []Type) => int
// Pointer to array: the number of elements in *v (even if v is nil).
// Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
// String: the number of bytes in v.
// Channel: the number of elements queued (unread) in the channel buffer;
// if v is nil, len(v) is zero.
// For some arguments, such as a string literal or a simple array expression, the
// result can be a constant. See the Go language specification's "Length and
// result can be a constant. See the Wa language specification's "Length and
// capacity" section for details.
func len(v: Type) => int
......@@ -135,15 +111,13 @@ func len(v: Type) => int
// Pointer to array: the number of elements in *v (same as len(v)).
// Slice: the maximum length the slice can reach when resliced;
// if v is nil, cap(v) is zero.
// Channel: the channel buffer capacity, in units of elements;
// if v is nil, cap(v) is zero.
// For some arguments, such as a simple array expression, the result can be a
// constant. See the Go language specification's "Length and capacity" section for
// constant. See the Wa language specification's "Length and capacity" section for
// details.
func cap(v: Type) => int
// The make built-in function allocates and initializes an object of type
// slice, map, or chan (only). Like new, the first argument is a type, not a
// slice, or map. Like new, the first argument is a type, not a
// value. Unlike new, make's return type is the same as the type of its
// argument, not a pointer to it. The specification of the result depends on
// the type:
......@@ -156,9 +130,6 @@ func cap(v: Type) => int
// Map: An empty map is allocated with enough space to hold the
// specified number of elements. The size may be omitted, in which case
// a small starting size is allocated.
// Channel: The channel's buffer is initialized with the specified
// buffer capacity. If zero, or the size is omitted, the channel is
// unbuffered.
func make(t: Type, size: ...IntegerType) => Type
// The new built-in function allocates memory. The first argument is a type,
......@@ -167,15 +138,7 @@ func make(t: Type, size: ...IntegerType) => Type
func new(Type) => *Type
// The panic built-in function stops normal execution of the current
// goroutine. When a function F calls panic, normal execution of F stops
// immediately. Any functions whose execution was deferred by F are run in
// the usual way, and then F returns to its caller. To the caller G, the
// invocation of F then behaves like a call to panic, terminating G's
// execution and running any deferred functions. This continues until all
// functions in the executing goroutine have stopped, in reverse order. At
// that point, the program is terminated with a non-zero exit code. This
// termination sequence is called panicking and can be controlled by the
// built-in function recover.
// application.
func panic(msg: string)
// The print built-in function formats its arguments in an
......
......@@ -4,6 +4,11 @@
//go:generate go run make_tables.go
const (
overflowError = "integer overflow"
divideError = "integer divide by zero"
)
const uintSize = 32 << (^uint(0) >> 63) // 32 or 64
// UintSize is the size of a uint in bits.
......@@ -21,24 +26,24 @@ func LeadingZeros8(x: uint8) => int { return 8 - Len8(x) }
func LeadingZeros16(x: uint16) => int { return 16 - Len16(x) }
// LeadingZeros32 returns the number of leading zero bits in x; the result is 32 for x == 0.
func LeadingZeros32(x: uint32) => int { return 32 - Len32(x) }
func LeadingZeros32(x: u32) => int { return 32 - Len32(x) }
// LeadingZeros64 returns the number of leading zero bits in x; the result is 64 for x == 0.
func LeadingZeros64(x: uint64) => int { return 64 - Len64(x) }
func LeadingZeros64(x: u64) => int { return 64 - Len64(x) }
// --- TrailingZeros ---
// See http://supertech.csail.mit.edu/papers/debruijn.pdf
const deBruijn32 = 0x077CB531
var deBruijn32tab = [32]byte{
global deBruijn32tab = [32]byte{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
}
const deBruijn64 = 0x03f79d71b4ca8b09
var deBruijn64tab = [64]byte{
global deBruijn64tab = [64]byte{
0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
......@@ -48,9 +53,9 @@ var deBruijn64tab = [64]byte{
// TrailingZeros returns the number of trailing zero bits in x; the result is UintSize for x == 0.
func TrailingZeros(x: uint) => int {
if UintSize == 32 {
return TrailingZeros32(uint32(x))
return TrailingZeros32(u32(x))
}
return TrailingZeros64(uint64(x))
return TrailingZeros64(u64(x))
}
// TrailingZeros8 returns the number of trailing zero bits in x; the result is 8 for x == 0.
......@@ -64,11 +69,11 @@ func TrailingZeros16(x: uint16) => int {
return 16
}
// see comment in TrailingZeros64
return int(deBruijn32tab[uint32(x&-x)*deBruijn32>>(32-5)])
return int(deBruijn32tab[u32(x&-x)*deBruijn32>>(32-5)])
}
// TrailingZeros32 returns the number of trailing zero bits in x; the result is 32 for x == 0.
func TrailingZeros32(x: uint32) => int {
func TrailingZeros32(x: u32) => int {
if x == 0 {
return 32
}
......@@ -77,7 +82,7 @@ func TrailingZeros32(x: uint32) => int {
}
// TrailingZeros64 returns the number of trailing zero bits in x; the result is 64 for x == 0.
func TrailingZeros64(x: uint64) => int {
func TrailingZeros64(x: u64) => int {
if x == 0 {
return 64
}
......@@ -106,9 +111,9 @@ const m4 = 0x0000ffff0000ffff
// OnesCount returns the number of one bits ("population count") in x.
func OnesCount(x: uint) => int {
if UintSize == 32 {
return OnesCount32(uint32(x))
return OnesCount32(u32(x))
}
return OnesCount64(uint64(x))
return OnesCount64(u64(x))
}
// OnesCount8 returns the number of one bits ("population count") in x.
......@@ -122,12 +127,12 @@ func OnesCount16(x: uint16) => int {
}
// OnesCount32 returns the number of one bits ("population count") in x.
func OnesCount32(x: uint32) => int {
func OnesCount32(x: u32) => int {
return int(pop8tab[x>>24] + pop8tab[x>>16&0xff] + pop8tab[x>>8&0xff] + pop8tab[x&0xff])
}
// OnesCount64 returns the number of one bits ("population count") in x.
func OnesCount64(x: uint64) => int {
func OnesCount64(x: u64) => int {
// Implementation: Parallel summing of adjacent bits.
// See "Hacker's Delight", Chap. 5: Counting Bits.
// The following pattern shows the general approach:
......@@ -165,9 +170,9 @@ func OnesCount64(x: uint64) => int {
// This function's execution time does not depend on the inputs.
func RotateLeft(x: uint, k: int) => uint {
if UintSize == 32 {
return uint(RotateLeft32(uint32(x), k))
return uint(RotateLeft32(u32(x), k))
}
return uint(RotateLeft64(uint64(x), k))
return uint(RotateLeft64(u64(x), k))
}
// RotateLeft8 returns the value of x rotated left by (k mod 8) bits.
......@@ -194,7 +199,7 @@ func RotateLeft16(x: uint16, k: int) => uint16 {
// To rotate x right by k bits, call RotateLeft32(x, -k).
//
// This function's execution time does not depend on the inputs.
func RotateLeft32(x: uint32, k: int) => uint32 {
func RotateLeft32(x: u32, k: int) => u32 {
const n = 32
s := uint(k) & (n - 1)
return x<<s | x>>(n-s)
......@@ -204,7 +209,7 @@ func RotateLeft32(x: uint32, k: int) => uint32 {
// To rotate x right by k bits, call RotateLeft64(x, -k).
//
// This function's execution time does not depend on the inputs.
func RotateLeft64(x: uint64, k: int) => uint64 {
func RotateLeft64(x: u64, k: int) => u64 {
const n = 64
s := uint(k) & (n - 1)
return x<<s | x>>(n-s)
......@@ -215,9 +220,9 @@ func RotateLeft64(x: uint64, k: int) => uint64 {
// Reverse returns the value of x with its bits in reversed order.
func Reverse(x: uint) => uint {
if UintSize == 32 {
return uint(Reverse32(uint32(x)))
return uint(Reverse32(u32(x)))
}
return uint(Reverse64(uint64(x)))
return uint(Reverse64(u64(x)))
}
// Reverse8 returns the value of x with its bits in reversed order.
......@@ -231,7 +236,7 @@ func Reverse16(x: uint16) => uint16 {
}
// Reverse32 returns the value of x with its bits in reversed order.
func Reverse32(x: uint32) => uint32 {
func Reverse32(x: u32) => u32 {
const m = 1<<32 - 1
x = x>>1&(m0&m) | x&(m0&m)<<1
x = x>>2&(m1&m) | x&(m1&m)<<2
......@@ -240,7 +245,7 @@ func Reverse32(x: uint32) => uint32 {
}
// Reverse64 returns the value of x with its bits in reversed order.
func Reverse64(x: uint64) => uint64 {
func Reverse64(x: u64) => u64 {
const m = 1<<64 - 1
x = x>>1&(m0&m) | x&(m0&m)<<1
x = x>>2&(m1&m) | x&(m1&m)<<2
......@@ -255,9 +260,9 @@ func Reverse64(x: uint64) => uint64 {
// This function's execution time does not depend on the inputs.
func ReverseBytes(x: uint) => uint {
if UintSize == 32 {
return uint(ReverseBytes32(uint32(x)))
return uint(ReverseBytes32(u32(x)))
}
return uint(ReverseBytes64(uint64(x)))
return uint(ReverseBytes64(u64(x)))
}
// ReverseBytes16 returns the value of x with its bytes in reversed order.
......@@ -270,7 +275,7 @@ func ReverseBytes16(x: uint16) => uint16 {
// ReverseBytes32 returns the value of x with its bytes in reversed order.
//
// This function's execution time does not depend on the inputs.
func ReverseBytes32(x: uint32) => uint32 {
func ReverseBytes32(x: u32) => u32 {
const m = 1<<32 - 1
x = x>>8&(m3&m) | x&(m3&m)<<8
return x>>16 | x<<16
......@@ -279,7 +284,7 @@ func ReverseBytes32(x: uint32) => uint32 {
// ReverseBytes64 returns the value of x with its bytes in reversed order.
//
// This function's execution time does not depend on the inputs.
func ReverseBytes64(x: uint64) => uint64 {
func ReverseBytes64(x: u64) => u64 {
const m = 1<<64 - 1
x = x>>8&(m3&m) | x&(m3&m)<<8
x = x>>16&(m4&m) | x&(m4&m)<<16
......@@ -291,9 +296,9 @@ func ReverseBytes64(x: uint64) => uint64 {
// Len returns the minimum number of bits required to represent x; the result is 0 for x == 0.
func Len(x: uint) => int {
if UintSize == 32 {
return Len32(uint32(x))
return Len32(u32(x))
}
return Len64(uint64(x))
return Len64(u64(x))
}
// Len8 returns the minimum number of bits required to represent x; the result is 0 for x == 0.
......@@ -311,7 +316,7 @@ func Len16(x: uint16) => (n: int) {
}
// Len32 returns the minimum number of bits required to represent x; the result is 0 for x == 0.
func Len32(x: uint32) => (n: int) {
func Len32(x: u32) => (n: int) {
if x >= 1<<16 {
x >>= 16
n = 16
......@@ -324,7 +329,7 @@ func Len32(x: uint32) => (n: int) {
}
// Len64 returns the minimum number of bits required to represent x; the result is 0 for x == 0.
func Len64(x: uint64) => (n: int) {
func Len64(x: u64) => (n: int) {
if x >= 1<<32 {
x >>= 32
n = 32
......@@ -349,10 +354,10 @@ func Len64(x: uint64) => (n: int) {
// This function's execution time does not depend on the inputs.
func Add(x, y, carry: uint) => (sum, carryOut: uint) {
if UintSize == 32 {
s32, c32 := Add32(uint32(x), uint32(y), uint32(carry))
s32, c32 := Add32(u32(x), u32(y), u32(carry))
return uint(s32), uint(c32)
}
s64, c64 := Add64(uint64(x), uint64(y), uint64(carry))
s64, c64 := Add64(u64(x), u64(y), u64(carry))
return uint(s64), uint(c64)
}
......@@ -361,10 +366,10 @@ func Add(x, y, carry: uint) => (sum, carryOut: uint) {
// The carryOut output is guaranteed to be 0 or 1.
//
// This function's execution time does not depend on the inputs.
func Add32(x, y, carry: uint32) => (sum, carryOut: uint32) {
sum64 := uint64(x) + uint64(y) + uint64(carry)
sum = uint32(sum64)
carryOut = uint32(sum64 >> 32)
func Add32(x, y, carry: u32) => (sum, carryOut: u32) {
sum64 := u64(x) + u64(y) + u64(carry)
sum = u32(sum64)
carryOut = u32(sum64 >> 32)
return
}
......@@ -373,7 +378,7 @@ func Add32(x, y, carry: uint32) => (sum, carryOut: uint32) {
// The carryOut output is guaranteed to be 0 or 1.
//
// This function's execution time does not depend on the inputs.
func Add64(x, y, carry: uint64) => (sum, carryOut: uint64) {
func Add64(x, y, carry: u64) => (sum, carryOut: u64) {
sum = x + y + carry
// The sum will overflow if both top bits are set (x & y) or if one of them
// is (x | y), and a carry from the lower place happened. If such a carry
......@@ -391,10 +396,10 @@ func Add64(x, y, carry: uint64) => (sum, carryOut: uint64) {
// This function's execution time does not depend on the inputs.
func Sub(x, y, borrow: uint) => (diff, borrowOut: uint) {
if UintSize == 32 {
d32, b32 := Sub32(uint32(x), uint32(y), uint32(borrow))
d32, b32 := Sub32(u32(x), u32(y), u32(borrow))
return uint(d32), uint(b32)
}
d64, b64 := Sub64(uint64(x), uint64(y), uint64(borrow))
d64, b64 := Sub64(u64(x), u64(y), u64(borrow))
return uint(d64), uint(b64)
}
......@@ -403,7 +408,7 @@ func Sub(x, y, borrow: uint) => (diff, borrowOut: uint) {
// The borrowOut output is guaranteed to be 0 or 1.
//
// This function's execution time does not depend on the inputs.
func Sub32(x, y, borrow: uint32) => (diff, borrowOut: uint32) {
func Sub32(x, y, borrow: u32) => (diff, borrowOut: u32) {
diff = x - y - borrow
// The difference will underflow if the top bit of x is not set and the top
// bit of y is set (^x & y) or if they are the same (^(x ^ y)) and a borrow
......@@ -418,7 +423,7 @@ func Sub32(x, y, borrow: uint32) => (diff, borrowOut: uint32) {
// The borrowOut output is guaranteed to be 0 or 1.
//
// This function's execution time does not depend on the inputs.
func Sub64(x, y, borrow: uint64) => (diff, borrowOut: uint64) {
func Sub64(x, y, borrow: u64) => (diff, borrowOut: u64) {
diff = x - y - borrow
// See Sub32 for the bit logic.
borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63
......@@ -434,10 +439,10 @@ func Sub64(x, y, borrow: uint64) => (diff, borrowOut: uint64) {
// This function's execution time does not depend on the inputs.
func Mul(x, y: uint) => (hi, lo: uint) {
if UintSize == 32 {
h, l := Mul32(uint32(x), uint32(y))
h, l := Mul32(u32(x), u32(y))
return uint(h), uint(l)
}
h, l := Mul64(uint64(x), uint64(y))
h, l := Mul64(u64(x), u64(y))
return uint(h), uint(l)
}
......@@ -446,9 +451,9 @@ func Mul(x, y: uint) => (hi, lo: uint) {
// half returned in lo.
//
// This function's execution time does not depend on the inputs.
func Mul32(x, y: uint32) => (hi, lo: uint32) {
tmp := uint64(x) * uint64(y)
hi, lo = uint32(tmp>>32), uint32(tmp)
func Mul32(x, y: u32) => (hi, lo: u32) {
tmp := u64(x) * u64(y)
hi, lo = u32(tmp>>32), u32(tmp)
return
}
......@@ -457,7 +462,7 @@ func Mul32(x, y: uint32) => (hi, lo: uint32) {
// half returned in lo.
//
// This function's execution time does not depend on the inputs.
func Mul64(x, y: uint64) => (hi, lo: uint64) {
func Mul64(x, y: u64) => (hi, lo: u64) {
const mask32 = 1<<32 - 1
x0 := x & mask32
x1 := x >> 32
......@@ -481,10 +486,10 @@ func Mul64(x, y: uint64) => (hi, lo: uint64) {
// Div panics for y == 0 (division by zero) or y <= hi (quotient overflow).
func Div(hi, lo, y: uint) => (quo, rem: uint) {
if UintSize == 32 {
q, r := Div32(uint32(hi), uint32(lo), uint32(y))
q, r := Div32(u32(hi), u32(lo), u32(y))
return uint(q), uint(r)
}
q, r := Div64(uint64(hi), uint64(lo), uint64(y))
q, r := Div64(u64(hi), u64(lo), u64(y))
return uint(q), uint(r)
}
......@@ -492,12 +497,15 @@ func Div(hi, lo, y: uint) => (quo, rem: uint) {
// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper
// half in parameter hi and the lower half in parameter lo.
// Div32 panics for y == 0 (division by zero) or y <= hi (quotient overflow).
func Div32(hi, lo, y: uint32) => (quo, rem: uint32) {
func Div32(hi, lo, y: u32) => (quo, rem: u32) {
if y != 0 && y <= hi {
// panic(overflowError)
panic(overflowError)
}
if y == 0 {
panic(divideError)
}
z := uint64(hi)<<32 | uint64(lo)
quo, rem = uint32(z/uint64(y)), uint32(z%uint64(y))
z := u64(hi)<<32 | u64(lo)
quo, rem = u32(z/u64(y)), u32(z%u64(y))
return
}
......@@ -505,16 +513,16 @@ func Div32(hi, lo, y: uint32) => (quo, rem: uint32) {
// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper
// half in parameter hi and the lower half in parameter lo.
// Div64 panics for y == 0 (division by zero) or y <= hi (quotient overflow).
func Div64(hi, lo, y: uint64) => (quo, rem: uint64) {
func Div64(hi, lo, y: u64) => (quo, rem: u64) {
const (
two32 = 1 << 32
mask32 = two32 - 1
)
if y == 0 {
// panic(divideError)
panic(divideError)
}
if y <= hi {
// panic(overflowError)
panic(overflowError)
}
s := uint(LeadingZeros64(y))
......@@ -557,22 +565,22 @@ func Div64(hi, lo, y: uint64) => (quo, rem: uint64) {
// quotient overflow.
func Rem(hi, lo, y: uint) => uint {
if UintSize == 32 {
return uint(Rem32(uint32(hi), uint32(lo), uint32(y)))
return uint(Rem32(u32(hi), u32(lo), u32(y)))
}
return uint(Rem64(uint64(hi), uint64(lo), uint64(y)))
return uint(Rem64(u64(hi), u64(lo), u64(y)))
}
// Rem32 returns the remainder of (hi, lo) divided by y. Rem32 panics
// for y == 0 (division by zero) but, unlike Div32, it doesn't panic
// on a quotient overflow.
func Rem32(hi, lo, y: uint32) => uint32 {
return uint32((uint64(hi)<<32 | uint64(lo)) % uint64(y))
func Rem32(hi, lo, y: u32) => u32 {
return u32((u64(hi)<<32 | u64(lo)) % u64(y))
}
// Rem64 returns the remainder of (hi, lo) divided by y. Rem64 panics
// for y == 0 (division by zero) but, unlike Div64, it doesn't panic
// on a quotient overflow.
func Rem64(hi, lo, y: uint64) => uint64 {
func Rem64(hi, lo, y: u64) => u64 {
// We scale down hi so that hi < y, then use Div64 to compute the
// rem with the guarantee that it won't panic on quotient overflow.
// Given that
......
// Copyright 2019 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.
//go:build compiler_bootstrap
// +build compiler_bootstrap
// This version used only for bootstrap (on this path we want
// to avoid use of go:linkname as applied to variables).
type errorString struct {
msg string
}
func (e: errorString) RuntimeError {}
func (e: errorString) Error => string {
return "runtime error: " + string(e.msg)
}
var overflowError = error(&errorString{"integer overflow"})
var divideError = error(&errorString{"integer divide by zero"})
// 版权 @2023 凹语言 作者。保留所有权利。
const (
divZeroError = "runtime error: integer divide by zero"
)
func TestDivPanicOverflow {
// Output(panic):
// integer overflow
assert(overflowError == "integer overflow")
q, r := Div(1, 0, 1)
_, _= q, r
assert(false, "should panic")
}
func TestDiv32PanicOverflow {
// Output(panic):
// integer overflow
assert(overflowError == "integer overflow")
q, r := Div32(1, 0, 1)
_, _= q, r
assert(false, "should panic")
}
func TestDiv64PanicOverflow {
// Output(panic):
// integer overflow
assert(overflowError == "integer overflow")
q, r := Div64(1, 0, 1)
_, _= q, r
assert(false, "should panic")
}
func TestDivPanicZero {
// Output(panic):
// integer divide by zero
assert(divideError == "integer divide by zero")
q, r := Div(1, 1, 0)
_, _= q, r
assert(false, "should panic")
}
func TestDiv32PanicZero {
// Output(panic):
// integer divide by zero
assert(divideError == "integer divide by zero")
q, r := Div32(1, 1, 0)
_, _= q, r
assert(false, "should panic")
}
func TestDiv64PanicZero {
// Output(panic):
// integer divide by zero
assert(divideError == "integer divide by zero")
q, r := Div64(1, 1, 0)
_, _= q, r
assert(false, "should panic")
}
// 版权 @2023 凹语言 作者。保留所有权利。
// ----------------------------------------------------------------------------
// Testing support
const DeBruijn64 = deBruijn64
type entry = struct {
nlz, ntz, pop: int
}
// tab contains results for all uint8 values
global tab: [256]entry
func init() {
tab[0] = entry{8, 8, 0}
for i := 1; i < len(tab); i++ {
// nlz
x := i // x != 0
n := 0
for x&0x80 == 0 {
n++
x <<= 1
}
tab[i].nlz = n
// ntz
x = i // x != 0
n = 0
for x&1 == 0 {
n++
x >>= 1
}
tab[i].ntz = n
// pop
x = i // x != 0
n = 0
for x != 0 {
n += int(x & 1)
x >>= 1
}
tab[i].pop = n
}
}
// ----------------------------------------------------------------------------
func TestUintSize {
assert(UintSize == 32)
}
func TestLeadingZeros {
for i := 0; i < 256; i++ {
nlz := tab[i].nlz
for k := 0; k < 64-8; k++ {
x := u64(i) << uint(k)
if x <= 1<<8-1 {
got := LeadingZeros8(uint8(x))
want := nlz - k + (8 - 8)
if x == 0 {
want = 8
}
assert(got == want, "LeadingZeros8 got != want")
}
if x <= 1<<16-1 {
got := LeadingZeros16(uint16(x))
want := nlz - k + (16 - 8)
if x == 0 {
want = 16
}
assert(got == want, "LeadingZeros16 got != want")
}
if x <= 1<<32-1 {
got := LeadingZeros32(uint32(x))
want := nlz - k + (32 - 8)
if x == 0 {
want = 32
}
assert(got == want, "LeadingZeros32 got != want")
if UintSize == 32 {
got = LeadingZeros(uint(x))
if got != want {
assert(got == want, "LeadingZeros got != want")
}
}
}
if x <= 1<<64-1 {
got := LeadingZeros64(u64(x))
want := nlz - k + (64 - 8)
if x == 0 {
want = 64
}
assert(got == want, "LeadingZeros64 got != want")
if UintSize == 64 {
got = LeadingZeros(uint(x))
if got != want {
assert(got == want, "LeadingZeros got != want")
}
}
}
}
}
}
func TestTrailingZeros {
for i := 0; i < 256; i++ {
ntz := tab[i].ntz
for k := 0; k < 64-8; k++ {
x := u64(i) << uint(k)
want := ntz + k
if x <= 1<<8-1 {
got := TrailingZeros8(u8(x))
if x == 0 {
want = 8
}
if got != want {
assert(got == want, "TrailingZeros8 got != want")
}
}
if x <= 1<<16-1 {
got := TrailingZeros16(u16(x))
if x == 0 {
want = 16
}
if got != want {
assert(got == want, "TrailingZeros16 got != want")
}
}
if x <= 1<<32-1 {
got := TrailingZeros32(u32(x))
if x == 0 {
want = 32
}
if got != want {
assert(got == want, "TrailingZeros32 got != want")
}
if UintSize == 32 {
got = TrailingZeros(uint(x))
if got != want {
assert(got == want, "TrailingZeros got != want")
}
}
}
if x <= 1<<64-1 {
got := TrailingZeros64(u64(x))
if x == 0 {
want = 64
}
if got != want {
assert(got == want, "TrailingZeros64 got != want")
}
if UintSize == 64 {
got = TrailingZeros(uint(x))
if got != want {
assert(got == want, "TrailingZeros got != want")
}
}
}
}
}
}
func TestOnesCount {
x: u64
for i := 0; i <= 64; i++ {
testOnesCount(x, i)
x = x<<1 | 1
}
for i := 64; i >= 0; i-- {
testOnesCount(x, i)
x = x << 1
}
for i := 0; i < 256; i++ {
for k := 0; k < 64-8; k++ {
testOnesCount(u64(i)<<uint(k), tab[i].pop)
}
}
}
func testOnesCount(x: u64, want: int) {
if x <= 1<<8-1 {
got := OnesCount8(u8(x))
if got != want {
assert(got == want, "OnesCount8 got != want")
}
}
if x <= 1<<16-1 {
got := OnesCount16(u16(x))
if got != want {
assert(got == want, "OnesCount16 got != want")
}
}
if x <= 1<<32-1 {
got := OnesCount32(u32(x))
if got != want {
assert(got == want, "OnesCount32 got != want")
}
if UintSize == 32 {
got = OnesCount(uint(x))
if got != want {
assert(got == want, "OnesCount got != want")
}
}
}
if x <= 1<<64-1 {
got := OnesCount64(u64(x))
if got != want {
assert(got == want, "OnesCount64 got != want")
}
if UintSize == 64 {
got = OnesCount(uint(x))
if got != want {
assert(got == want, "OnesCount got != want")
}
}
}
}
func TestRotateLeft {
m: u64 = DeBruijn64
for k := uint(0); k < 128; k++ {
x8 := u8(m)
got8 := RotateLeft8(x8, int(k))
want8 := x8<<(k&0x7) | x8>>(8-k&0x7)
if got8 != want8 {
assert(got8 == want8, "RotateLeft8 got != want")
}
got8 = RotateLeft8(want8, -int(k))
if got8 != x8 {
assert(got8 == x8, "RotateLeft8 got != want")
}
x16 := u16(m)
got16 := RotateLeft16(x16, int(k))
want16 := x16<<(k&0xf) | x16>>(16-k&0xf)
if got16 != want16 {
assert(got16 == want16, "RotateLeft16 got != want")
}
got16 = RotateLeft16(want16, -int(k))
if got16 != x16 {
assert(got16 == x16, "RotateLeft16 got != want")
}
x32 := uint32(m)
got32 := RotateLeft32(x32, int(k))
want32 := x32<<(k&0x1f) | x32>>(32-k&0x1f)
if got32 != want32 {
assert(got32 == want32, "RotateLeft32 got != want")
}
got32 = RotateLeft32(want32, -int(k))
if got32 != x32 {
assert(got32 == x32, "RotateLeft32 got != want")
}
if UintSize == 32 {
x := uint(m)
got := RotateLeft(x, int(k))
want := x<<(k&0x1f) | x>>(32-k&0x1f)
if got != want {
assert(got == want, "RotateLeft got != want")
}
got = RotateLeft(want, -int(k))
if got != x {
assert(got == x, "RotateLeft got != want")
}
}
x64 := u64(m)
got64 := RotateLeft64(x64, int(k))
want64 := x64<<(k&0x3f) | x64>>(64-k&0x3f)
if got64 != want64 {
assert(got64 == want64, "RotateLeft64 got != want")
}
got64 = RotateLeft64(want64, -int(k))
if got64 != x64 {
assert(got64 == x64, "RotateLeft64 got != want")
}
if UintSize == 64 {
x := uint(m)
got := RotateLeft(x, int(k))
want := x<<(k&0x3f) | x>>(64-k&0x3f)
if got != want {
assert(got == want, "RotateLeft got != want")
}
got = RotateLeft(want, -int(k))
if got != x {
assert(got == x, "RotateLeft got != want")
}
}
}
}
func TestReverse {
// test each bit
for i := uint(0); i < 64; i++ {
testReverse(u64(1)<<i, u64(1)<<(63-i))
}
// test a few patterns
for _, test := range []struct {
x, r: u64
}{
{0, 0},
{0x1, 0x8 << 60},
{0x2, 0x4 << 60},
{0x3, 0xc << 60},
{0x4, 0x2 << 60},
{0x5, 0xa << 60},
{0x6, 0x6 << 60},
{0x7, 0xe << 60},
{0x8, 0x1 << 60},
{0x9, 0x9 << 60},
{0xa, 0x5 << 60},
{0xb, 0xd << 60},
{0xc, 0x3 << 60},
{0xd, 0xb << 60},
{0xe, 0x7 << 60},
{0xf, 0xf << 60},
{0x5686487, 0xe12616a000000000},
{0x0123456789abcdef, 0xf7b3d591e6a2c480},
} {
testReverse(test.x, test.r)
testReverse(test.r, test.x)
}
}
func testReverse(x64, want64: u64) {
x8 := u8(x64)
got8 := Reverse8(x8)
want8 := u8(want64 >> (64 - 8))
if got8 != want8 {
assert(got8 == want8, "Reverse8 got != want")
}
x16 := u16(x64)
got16 := Reverse16(x16)
want16 := u16(want64 >> (64 - 16))
if got16 != want16 {
assert(got16 == want16, "Reverse16 got != want")
}
x32 := u32(x64)
got32 := Reverse32(x32)
want32 := u32(want64 >> (64 - 32))
if got32 != want32 {
assert(got32 == want32, "Reverse32 got != want")
}
if UintSize == 32 {
x := uint(x32)
got := Reverse(x)
want := uint(want32)
if got != want {
assert(got == want, "Reverse got != want")
}
}
got64 := Reverse64(x64)
if got64 != want64 {
assert(got64 == want64, "Reverse64 got != want")
}
if UintSize == 64 {
x := uint(x64)
got := Reverse(x)
want := uint(want64)
if got != want {
assert(got == want, "Reverse got != want")
}
}
}
func TestReverseBytes {
for _, test := range []struct {
x, r uint64
}{
{0, 0},
{0x01, 0x01 << 56},
{0x0123, 0x2301 << 48},
{0x012345, 0x452301 << 40},
{0x01234567, 0x67452301 << 32},
{0x0123456789, 0x8967452301 << 24},
{0x0123456789ab, 0xab8967452301 << 16},
{0x0123456789abcd, 0xcdab8967452301 << 8},
{0x0123456789abcdef, 0xefcdab8967452301 << 0},
} {
testReverseBytes(test.x, test.r)
testReverseBytes(test.r, test.x)
}
}
func testReverseBytes(x64, want64: u64) {
x16 := u16(x64)
got16 := ReverseBytes16(x16)
want16 := u16(want64 >> (64 - 16))
if got16 != want16 {
assert(got16 == want16, "ReverseBytes16 got != want")
}
x32 := u32(x64)
got32 := ReverseBytes32(x32)
want32 := u32(want64 >> (64 - 32))
if got32 != want32 {
assert(got32 == want32, "ReverseBytes32 got != want")
}
if UintSize == 32 {
x := uint(x32)
got := ReverseBytes(x)
want := uint(want32)
if got != want {
assert(got == want, "ReverseBytes got != want")
}
}
got64 := ReverseBytes64(x64)
if got64 != want64 {
assert(got64 == want64, "ReverseBytes64 got != want")
}
if UintSize == 64 {
x := uint(x64)
got := ReverseBytes(x)
want := uint(want64)
if got != want {
assert(got == want, "ReverseBytes got != want")
}
}
}
func TestLen {
for i := 0; i < 256; i++ {
len := 8 - tab[i].nlz
for k := 0; k < 64-8; k++ {
x := u64(i) << uint(k)
want := 0
if x != 0 {
want = len + k
}
if x <= 1<<8-1 {
got := Len8(u8(x))
if got != want {
assert(got == want, "Len8 got != want")
}
}
if x <= 1<<16-1 {
got := Len16(u16(x))
if got != want {
assert(got == want, "Len16 got != want")
}
}
if x <= 1<<32-1 {
got := Len32(u32(x))
if got != want {
assert(got == want, "Len32 got != want")
}
if UintSize == 32 {
got := Len(uint(x))
if got != want {
assert(got == want, "Len got != want")
}
}
}
if x <= 1<<64-1 {
got := Len64(u64(x))
if got != want {
assert(got == want, "Len64 got != want")
}
if UintSize == 64 {
got := Len(uint(x))
if got != want {
assert(got == want, "Len got != want")
}
}
}
}
}
}
func TestRem32 {
// Sanity check: for non-oveflowing dividends, the result is the
// same as the rem returned by Div32
hi, lo, y := u32(510510), u32(9699690), u32(510510+1) // ensure hi < y
for i := 0; i < 1000; i++ {
r := Rem32(hi, lo, y)
_, r2 := Div32(hi, lo, y)
if r != r2 {
assert(false, "Rem32 failed")
}
y += 13
}
}
func TestRem32Overflow {
// To trigger a quotient overflow, we need y <= hi
hi, lo, y := u32(510510), u32(9699690), u32(7)
for i := 0; i < 1000; i++ {
r := Rem32(hi, lo, y)
_, r2 := Div64(0, u64(hi)<<32|u64(lo), u64(y))
if r != u32(r2) {
assert(false, "Rem32 failed")
}
y += 13
}
}
func TestRem64 {
// Sanity check: for non-oveflowing dividends, the result is the
// same as the rem returned by Div64
hi, lo, y := u64(510510), u64(9699690), u64(510510+1) // ensure hi < y
for i := 0; i < 1000; i++ {
r := Rem64(hi, lo, y)
_, r2 := Div64(hi, lo, y)
if r != r2 {
assert(false, "Rem64 failed")
}
y += 13
}
}
func TestRem64Overflow {
Rem64Tests := []struct {
hi, lo, y: u64
rem: u64
}{
// Testcases computed using Python 3, as:
// >>> hi = 42; lo = 1119; y = 42
// >>> ((hi<<64)+lo) % y
{42, 1119, 42, 27},
{42, 1119, 38, 9},
{42, 1119, 26, 23},
{469, 0, 467, 271},
{469, 0, 113, 58},
{111111, 111111, 1171, 803},
{3968194946088682615, 3192705705065114702, 1000037, 56067},
}
for _, rt := range Rem64Tests {
if rt.hi < rt.y {
assert(false, "Rem64 is not a test with quo overflow")
}
rem := Rem64(rt.hi, rt.lo, rt.y)
if rem != rt.rem {
assert(false, "Rem64 failed")
}
}
}
// 版权 @2023 凹语言 作者。保留所有权利。
func TestLeadingZeros8 {
assert(0b00000001 == 1)
assert(7 == LeadingZeros8(1))
}
func TestLeadingZeros16 {
assert(0b0000000000000001 == 1)
assert(15 == LeadingZeros16(1))
}
func TestLeadingZeros32 {
assert(0b00000000000000000000000000000001 == 1)
assert(31 == LeadingZeros32(1))
}
func TestLeadingZeros64 {
assert(0b0000000000000000000000000000000000000000000000000000000000000001 == 1)
assert(63 == LeadingZeros64(1))
}
func TestTrailingZeros8 {
assert(0b00001110 == 14)
assert(1 == TrailingZeros8(14))
}
func TestTrailingZeros16 {
assert(0b0000000000001110 == 14)
assert(1 == TrailingZeros16(14))
}
func TestTrailingZeros32 {
assert(0b00000000000000000000000000001110 == 14)
assert(1 == TrailingZeros32(14))
}
func TestTrailingZeros64 {
assert(0b0000000000000000000000000000000000000000000000000000000000001110 == 14)
assert(1 == TrailingZeros64(14))
}
func TestOnesCount8 {
assert(0b00001110 == 14)
assert(3 == OnesCount8(14))
}
func TestOnesCount16 {
assert(0b0000000000001110 == 14)
assert(3 == OnesCount16(14))
}
func TestOnesCount32 {
assert(0b00000000000000000000000000001110 == 14)
assert(3 == OnesCount32(14))
}
func TestOnesCount64 {
assert(0b0000000000000000000000000000000000000000000000000000000000001110 == 14)
assert(3 == OnesCount64(14))
}
func TestRotateLeft8 {
assert(0b00001111 == 15)
assert(0b00111100 == RotateLeft8(15, 2))
assert(0b11000011 == RotateLeft8(15, -2))
}
func TestRotateLeft16 {
assert(0b0000000000001111 == 15)
assert(0b0000000000111100 == RotateLeft16(15, 2))
assert(0b1100000000000011 == RotateLeft16(15, -2))
}
func TestRotateLeft32 {
assert(0b00000000000000000000000000001111 == 15)
assert(0b00000000000000000000000000111100 == RotateLeft32(15, 2))
assert(0b11000000000000000000000000000011 == RotateLeft32(15, -2))
}
func TestRotateLeft64 {
assert(0b0000000000000000000000000000000000000000000000000000000000001111 == 15)
assert(0b0000000000000000000000000000000000000000000000000000000000111100 == RotateLeft64(15, 2))
assert(0b1100000000000000000000000000000000000000000000000000000000000011 == RotateLeft64(15, -2))
}
func TestReverse8 {
assert(0b00010011 == 19)
assert(0b11001000 == Reverse8(19))
}
func TestReverse16 {
assert(0b0000000000010011 == 19)
assert(0b1100100000000000 == Reverse16(19))
}
func TestReverse32 {
assert(0b00000000000000000000000000010011 == 19)
assert(0b11001000000000000000000000000000 == Reverse32(19))
}
func TestReverse64 {
assert(0b0000000000000000000000000000000000000000000000000000000000010011 == 19)
assert(0b1100100000000000000000000000000000000000000000000000000000000000 == Reverse64(19))
}
func TestReverseBytes16 {
assert(0b0000000000001111 == 15)
assert(0b0000111100000000 == ReverseBytes16(15))
}
func TestReverseBytes32 {
assert(0b00000000000000000000000000001111 == 15)
assert(0b00001111000000000000000000000000 == ReverseBytes32(15))
}
func TestReverseBytes64 {
assert(0b0000000000000000000000000000000000000000000000000000000000001111 == 15)
assert(0b0000111100000000000000000000000000000000000000000000000000000000 == ReverseBytes64(15))
}
func TestLen8 {
assert(0b00001000 == 8)
assert(4 == Len8(8))
}
func TestLen16 {
assert(0b0000000000001000 == 8)
assert(4 == Len16(8))
}
func TestLen32 {
assert(0b00000000000000000000000000001000 == 8)
assert(4 == Len32(8))
}
func TestLen64 {
assert(0b0000000000000000000000000000000000000000000000000000000000001000 == 8)
assert(4 == Len64(8))
}
// Copyright 2017 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.
//go:build ignore
// +build ignore
// This program generates example_test.go.
package main
import (
"bytes"
"fmt"
"log"
"math/bits"
"os"
)
const header = `// Copyright 2017 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.
// Code generated by go run make_examples.go. DO NOT EDIT.
package bits_test
import (
"fmt"
"math/bits"
)
`
func main() {
w := bytes.NewBuffer([]byte(header))
for _, e := range []struct {
name string
in int
out [4]interface{}
out2 [4]interface{}
}{
{
name: "LeadingZeros",
in: 1,
out: [4]interface{}{bits.LeadingZeros8(1), bits.LeadingZeros16(1), bits.LeadingZeros32(1), bits.LeadingZeros64(1)},
},
{
name: "TrailingZeros",
in: 14,
out: [4]interface{}{bits.TrailingZeros8(14), bits.TrailingZeros16(14), bits.TrailingZeros32(14), bits.TrailingZeros64(14)},
},
{
name: "OnesCount",
in: 14,
out: [4]interface{}{bits.OnesCount8(14), bits.OnesCount16(14), bits.OnesCount32(14), bits.OnesCount64(14)},
},
{
name: "RotateLeft",
in: 15,
out: [4]interface{}{bits.RotateLeft8(15, 2), bits.RotateLeft16(15, 2), bits.RotateLeft32(15, 2), bits.RotateLeft64(15, 2)},
out2: [4]interface{}{bits.RotateLeft8(15, -2), bits.RotateLeft16(15, -2), bits.RotateLeft32(15, -2), bits.RotateLeft64(15, -2)},
},
{
name: "Reverse",
in: 19,
out: [4]interface{}{bits.Reverse8(19), bits.Reverse16(19), bits.Reverse32(19), bits.Reverse64(19)},
},
{
name: "ReverseBytes",
in: 15,
out: [4]interface{}{nil, bits.ReverseBytes16(15), bits.ReverseBytes32(15), bits.ReverseBytes64(15)},
},
{
name: "Len",
in: 8,
out: [4]interface{}{bits.Len8(8), bits.Len16(8), bits.Len32(8), bits.Len64(8)},
},
} {
for i, size := range []int{8, 16, 32, 64} {
if e.out[i] == nil {
continue // function doesn't exist
}
f := fmt.Sprintf("%s%d", e.name, size)
fmt.Fprintf(w, "\nfunc Example%s() {\n", f)
switch e.name {
case "RotateLeft", "Reverse", "ReverseBytes":
fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", %d)\n", size, e.in)
if e.name == "RotateLeft" {
fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d, 2))\n", size, f, e.in)
fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d, -2))\n", size, f, e.in)
} else {
fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d))\n", size, f, e.in)
}
fmt.Fprintf(w, "\t// Output:\n")
fmt.Fprintf(w, "\t// %0*b\n", size, e.in)
fmt.Fprintf(w, "\t// %0*b\n", size, e.out[i])
if e.name == "RotateLeft" && e.out2[i] != nil {
fmt.Fprintf(w, "\t// %0*b\n", size, e.out2[i])
}
default:
fmt.Fprintf(w, "\tfmt.Printf(\"%s(%%0%db) = %%d\\n\", %d, bits.%s(%d))\n", f, size, e.in, f, e.in)
fmt.Fprintf(w, "\t// Output:\n")
fmt.Fprintf(w, "\t// %s(%0*b) = %d\n", f, size, e.in, e.out[i])
}
fmt.Fprintf(w, "}\n")
}
}
if err := os.WriteFile("example_test.go", w.Bytes(), 0666); err != nil {
log.Fatal(err)
}
}
......@@ -2,7 +2,7 @@
import "syscall/arduino"
var WAOS = "arduino"
const WAOS = "arduino"
#wa:linkname $runtime.argsSizesGet
func argsSizesGet(result_argc: i32, result_argv_len: i32) => (errno: i32) {
......@@ -70,8 +70,8 @@ func waPrintI64(i: i32) {
}
#wa:linkname $runtime.waPrintU64
func waPrintU64(i: i32) {
printU64(u64(i))
func waPrintU64(i: u64) {
printU64(i)
}
#wa:linkname $runtime.waPrintF32
......
......@@ -2,7 +2,7 @@
import "syscall/chrome"
var WAOS = "chrome"
const WAOS = "chrome"
#wa:linkname $runtime.argsSizesGet
func argsSizesGet(result_argc: i32, result_argv_len: i32) => (errno: i32) {
......@@ -70,8 +70,8 @@ func waPrintI64(i: i32) {
}
#wa:linkname $runtime.waPrintU64
func waPrintU64(i: i32) {
printU64(u64(i))
func waPrintU64(i: u64) {
printU64(i)
}
#wa:linkname $runtime.waPrintF32
......
......@@ -2,7 +2,7 @@
import "syscall/mvp"
var WAOS = "mvp"
const WAOS = "mvp"
#wa:linkname $runtime.argsSizesGet
func argsSizesGet(result_argc: i32, result_argv_len: i32) => (errno: i32) {
......
......@@ -2,7 +2,7 @@
import "syscall/wasi"
var WAOS = "wasi"
const WAOS = "wasi"
#wa:linkname $runtime.argsSizesGet
func argsSizesGet(result_argc: i32, result_argv_len: i32) => (errno: i32) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册