2015-04-15 15:51:25 -07:00
|
|
|
// 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 ssa
|
|
|
|
|
|
|
|
|
|
type Config struct {
|
2015-07-30 11:03:05 -07:00
|
|
|
arch string // "amd64", etc.
|
|
|
|
|
IntSize int64 // 4 or 8
|
|
|
|
|
PtrSize int64 // 4 or 8
|
2015-05-27 14:52:22 -07:00
|
|
|
lowerBlock func(*Block) bool // lowering function
|
|
|
|
|
lowerValue func(*Value, *Config) bool // lowering function
|
|
|
|
|
fe Frontend // callbacks into compiler frontend
|
2015-04-15 15:51:25 -07:00
|
|
|
|
|
|
|
|
// TODO: more stuff. Compiler flags of interest, ...
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 11:03:05 -07:00
|
|
|
type TypeSource interface {
|
|
|
|
|
TypeBool() Type
|
|
|
|
|
TypeInt8() Type
|
|
|
|
|
TypeInt16() Type
|
|
|
|
|
TypeInt32() Type
|
|
|
|
|
TypeInt64() Type
|
|
|
|
|
TypeUInt8() Type
|
|
|
|
|
TypeUInt16() Type
|
|
|
|
|
TypeUInt32() Type
|
|
|
|
|
TypeUInt64() Type
|
|
|
|
|
TypeInt() Type
|
|
|
|
|
TypeUintptr() Type
|
|
|
|
|
TypeString() Type
|
|
|
|
|
TypeBytePtr() Type // TODO: use unsafe.Pointer instead?
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-27 14:52:22 -07:00
|
|
|
type Frontend interface {
|
2015-07-30 11:03:05 -07:00
|
|
|
TypeSource
|
|
|
|
|
|
2015-07-24 11:28:12 -07:00
|
|
|
// StringData returns a symbol pointing to the given string's contents.
|
|
|
|
|
StringData(string) interface{} // returns *gc.Sym
|
2015-06-12 11:01:13 -07:00
|
|
|
|
|
|
|
|
// Log logs a message from the compiler.
|
2015-06-24 14:03:39 -07:00
|
|
|
Logf(string, ...interface{})
|
2015-06-12 11:01:13 -07:00
|
|
|
|
|
|
|
|
// Fatal reports a compiler error and exits.
|
2015-06-24 14:03:39 -07:00
|
|
|
Fatalf(string, ...interface{})
|
2015-06-12 11:01:13 -07:00
|
|
|
|
|
|
|
|
// Unimplemented reports that the function cannot be compiled.
|
|
|
|
|
// It will be removed once SSA work is complete.
|
2015-06-24 14:03:39 -07:00
|
|
|
Unimplementedf(msg string, args ...interface{})
|
2015-05-27 14:52:22 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-15 15:51:25 -07:00
|
|
|
// NewConfig returns a new configuration object for the given architecture.
|
2015-05-27 14:52:22 -07:00
|
|
|
func NewConfig(arch string, fe Frontend) *Config {
|
|
|
|
|
c := &Config{arch: arch, fe: fe}
|
2015-04-15 15:51:25 -07:00
|
|
|
switch arch {
|
|
|
|
|
case "amd64":
|
[dev.ssa] cmd/compile/internal/ssa: redo how sign extension is handled
For integer types less than a machine register, we have to decide
what the invariants are for the high bits of the register. We used
to set the high bits to the correct extension (sign or zero, as
determined by the type) of the low bits.
This CL makes the compiler ignore the high bits of the register
altogether (they are junk).
On this plus side, this means ops that generate subword results don't
have to worry about correctly extending them. On the minus side,
ops that consume subword arguments have to deal with the input
registers not being correctly extended.
For x86, this tradeoff is probably worth it. Almost all opcodes
have versions that use only the correct subword piece of their
inputs. (The one big exception is array indexing.) Not many opcodes
can correctly sign extend on output.
For other architectures, the tradeoff is probably not so clear, as
they don't have many subword-safe opcodes (e.g. 16-bit compare,
ignoring the high 16/48 bits). Fortunately we can decide whether
we do this per-architecture.
For the machine-independent opcodes, we pretend that the "register"
size is equal to the type width, so sign extension is immaterial.
Opcodes that care about the signedness of the input (e.g. compare,
right shift) have two different variants.
Change-Id: I465484c5734545ee697afe83bc8bf4b53bd9df8d
Reviewed-on: https://go-review.googlesource.com/12600
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2015-07-23 14:35:02 -07:00
|
|
|
c.IntSize = 8
|
2015-07-19 15:48:20 -07:00
|
|
|
c.PtrSize = 8
|
2015-06-06 16:03:33 -07:00
|
|
|
c.lowerBlock = rewriteBlockAMD64
|
|
|
|
|
c.lowerValue = rewriteValueAMD64
|
2015-04-15 15:51:25 -07:00
|
|
|
case "386":
|
[dev.ssa] cmd/compile/internal/ssa: redo how sign extension is handled
For integer types less than a machine register, we have to decide
what the invariants are for the high bits of the register. We used
to set the high bits to the correct extension (sign or zero, as
determined by the type) of the low bits.
This CL makes the compiler ignore the high bits of the register
altogether (they are junk).
On this plus side, this means ops that generate subword results don't
have to worry about correctly extending them. On the minus side,
ops that consume subword arguments have to deal with the input
registers not being correctly extended.
For x86, this tradeoff is probably worth it. Almost all opcodes
have versions that use only the correct subword piece of their
inputs. (The one big exception is array indexing.) Not many opcodes
can correctly sign extend on output.
For other architectures, the tradeoff is probably not so clear, as
they don't have many subword-safe opcodes (e.g. 16-bit compare,
ignoring the high 16/48 bits). Fortunately we can decide whether
we do this per-architecture.
For the machine-independent opcodes, we pretend that the "register"
size is equal to the type width, so sign extension is immaterial.
Opcodes that care about the signedness of the input (e.g. compare,
right shift) have two different variants.
Change-Id: I465484c5734545ee697afe83bc8bf4b53bd9df8d
Reviewed-on: https://go-review.googlesource.com/12600
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2015-07-23 14:35:02 -07:00
|
|
|
c.IntSize = 4
|
2015-07-19 15:48:20 -07:00
|
|
|
c.PtrSize = 4
|
2015-06-06 16:03:33 -07:00
|
|
|
c.lowerBlock = rewriteBlockAMD64
|
|
|
|
|
c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
|
2015-04-15 15:51:25 -07:00
|
|
|
default:
|
2015-06-24 14:03:39 -07:00
|
|
|
fe.Unimplementedf("arch %s not implemented", arch)
|
2015-04-15 15:51:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return c
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-22 13:13:53 -07:00
|
|
|
func (c *Config) Frontend() Frontend { return c.fe }
|
|
|
|
|
|
2015-04-15 15:51:25 -07:00
|
|
|
// NewFunc returns a new, empty function object
|
|
|
|
|
func (c *Config) NewFunc() *Func {
|
|
|
|
|
// TODO(khr): should this function take name, type, etc. as arguments?
|
|
|
|
|
return &Func{Config: c}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-24 14:03:39 -07:00
|
|
|
func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
|
|
|
|
|
func (c *Config) Fatalf(msg string, args ...interface{}) { c.fe.Fatalf(msg, args...) }
|
|
|
|
|
func (c *Config) Unimplementedf(msg string, args ...interface{}) { c.fe.Unimplementedf(msg, args...) }
|
2015-06-12 11:01:13 -07:00
|
|
|
|
2015-04-15 15:51:25 -07:00
|
|
|
// TODO(khr): do we really need a separate Config, or can we just
|
|
|
|
|
// store all its fields inside a Func?
|