1
0
mirror of https://github.com/golang/go synced 2024-11-24 04:00:13 -07:00

[dev.cc] cmd/asm: delete overflow checking, make labels function-scoped

The overflow checking was causing more problems than it was avoiding,
so get rid of it. But because arithmetic is done with uint64s, to simplify
dealing with large constants, complain about right shift and divide with
huge numbers to avoid ambiguity about signed shifts.

Change-Id: I5b5ea55d8e8c02846605f4a3f8fd7a176b1e962b
Reviewed-on: https://go-review.googlesource.com/3531
Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
Rob Pike 2015-01-29 12:07:50 -08:00
parent 36e5f4d53f
commit b528063099
3 changed files with 16 additions and 142 deletions

View File

@ -153,6 +153,11 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) {
p.errorf("expect two or three operands for TEXT") p.errorf("expect two or three operands for TEXT")
} }
// Labels are function scoped. Patch existing labels and
// create a new label space for this TEXT.
p.patch()
p.labels = make(map[string]*obj.Prog)
// Operand 0 is the symbol name in the form foo(SB). // Operand 0 is the symbol name in the form foo(SB).
// That means symbol plus indirect on SB and no offset. // That means symbol plus indirect on SB and no offset.
nameAddr := p.address(operands[0]) nameAddr := p.address(operands[0])
@ -219,6 +224,7 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) {
Index: uint8(p.arch.D_NONE), Index: uint8(p.arch.D_NONE),
}, },
} }
// Encoding of frameSize and argSize depends on architecture. // Encoding of frameSize and argSize depends on architecture.
switch p.arch.Thechar { switch p.arch.Thechar {
case '6': case '6':
@ -231,6 +237,7 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) {
default: default:
p.errorf("internal error: can't encode TEXT $arg-frame") p.errorf("internal error: can't encode TEXT $arg-frame")
} }
p.append(prog, true) p.append(prog, true)
} }
@ -493,6 +500,7 @@ func (p *Parser) patch() {
p.branch(patch.prog, targetProg) p.branch(patch.prog, targetProg)
} }
} }
p.toPatch = p.toPatch[:0]
} }
func (p *Parser) branch(jmp, target *obj.Prog) { func (p *Parser) branch(jmp, target *obj.Prog) {

View File

@ -1,129 +0,0 @@
// Copyright 2015 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 asm
/*
Tested with uint8s like this:
for a := 0; a <= 255; a++ {
for b := 0; b <= 127; b++ {
ovfl := a+b != int(uint8(a)+uint8(b))
if addOverflows(uint8(a), uint8(b)) != ovfl {
fmt.Printf("%d+%d fails\n", a, b)
break
}
}
}
for a := 0; a <= 255; a++ {
for b := 0; b <= 127; b++ {
ovfl := a-b != int(uint8(a)-uint8(b))
if subOverflows(uint8(a), uint8(b)) != ovfl {
fmt.Printf("%d-%d fails\n", a, b)
break
}
}
}
for a := 0; a <= 255; a++ {
for b := 0; b <= 255; b++ {
ovfl := a*b != int(uint8(a)*uint8(b))
if mulOverflows(uint8(a), uint8(b)) != ovfl {
fmt.Printf("%d*%d fails\n", a, b)
}
}
}
overflow := func(a, b int) bool {
for ; b > 0; b-- {
a <<= 1
if a >= 256 {
return true
}
}
return false
}
for a := 0; a <= 255; a++ {
for b := 0; b <= 255; b++ {
ovfl := overflow(a, b)
if shiftOverflows(uint8(a), uint8(b)) != ovfl {
fmt.Printf("%d<<%d fails\n", a, b)
}
}
}
*/
func addOverflows(a, b uint64) bool {
return a+b < a
}
func subOverflows(a, b uint64) bool {
return a-b > a
}
func mulOverflows(a, b uint64) bool {
if a <= 1 || b <= 1 {
return false
}
c := a * b
return c/b != a
}
func shiftOverflows(a, b uint64) bool {
c := a << b
return c>>b != a
}
/*
For the record, signed overflow:
const mostNegative = -(mostPositive + 1)
const mostPositive = 1<<63 - 1
func signedAddOverflows(a, b int64) bool {
if (a >= 0) != (b >= 0) {
// Different signs cannot overflow.
return false
}
if a >= 0 {
// Both are positive.
return a+b < 0
}
return a+b >= 0
}
func signedSubOverflows(a, b int64) bool {
if (a >= 0) == (b >= 0) {
// Same signs cannot overflow.
return false
}
if a >= 0 {
// a positive, b negative.
return a-b < 0
}
return a-b >= 0
}
func signedMulOverflows(a, b int64) bool {
if a == 0 || b == 0 || a == 1 || b == 1 {
return false
}
if a == mostNegative || b == mostNegative {
return true
}
c := a * b
return c/b != a
}
func signedShiftOverflows(a, b int64) bool {
// Avoid right shift of a negative number.
if a >= 0 {
c := a << b
return c>>b != a
}
// Otherwise it's negative, so we complement, which
// puts zeros at the top.
a = ^a
c := a << b
return c>>b != a
}
*/

View File

@ -360,11 +360,7 @@ func (p *Parser) expr() uint64 {
switch p.peek() { switch p.peek() {
case '+': case '+':
p.next() p.next()
x := p.term() value += p.term()
if addOverflows(x, value) {
p.errorf("overflow in %d+%d", value, x)
}
value += x
case '-': case '-':
p.next() p.next()
value -= p.term() value -= p.term()
@ -408,13 +404,12 @@ func (p *Parser) term() uint64 {
switch p.peek() { switch p.peek() {
case '*': case '*':
p.next() p.next()
x := p.factor() value *= p.factor()
if mulOverflows(value, x) {
p.errorf("%d * %d overflows", value, x)
}
value *= x
case '/': case '/':
p.next() p.next()
if value&(1<<63) != 0 {
p.errorf("divide with high bit set")
}
value /= p.factor() value /= p.factor()
case '%': case '%':
p.next() p.next()
@ -425,9 +420,6 @@ func (p *Parser) term() uint64 {
if int64(shift) < 0 { if int64(shift) < 0 {
p.errorf("negative left shift %d", shift) p.errorf("negative left shift %d", shift)
} }
if shiftOverflows(value, shift) {
p.errorf("%d << %d overflows", value, shift)
}
return value << shift return value << shift
case lex.RSH: case lex.RSH:
p.next() p.next()
@ -435,6 +427,9 @@ func (p *Parser) term() uint64 {
if shift < 0 { if shift < 0 {
p.errorf("negative right shift %d", shift) p.errorf("negative right shift %d", shift)
} }
if shift > 0 && value&(1<<63) != 0 {
p.errorf("right shift with high bit set")
}
value >>= uint(shift) value >>= uint(shift)
case '&': case '&':
p.next() p.next()