2015-08-18 10:26:28 -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
|
|
|
|
|
|
2016-02-08 11:00:43 -08:00
|
|
|
// decompose converts phi ops on compound builtin types into phi
|
2015-08-18 10:26:28 -07:00
|
|
|
// ops on simple types.
|
|
|
|
|
// (The remaining compound ops are decomposed with rewrite rules.)
|
2016-02-08 11:00:43 -08:00
|
|
|
func decomposeBuiltIn(f *Func) {
|
2015-08-18 10:26:28 -07:00
|
|
|
for _, b := range f.Blocks {
|
|
|
|
|
for _, v := range b.Values {
|
|
|
|
|
if v.Op != OpPhi {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2016-02-08 11:00:43 -08:00
|
|
|
decomposeBuiltInPhi(v)
|
2015-08-18 10:26:28 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-11-02 08:10:26 -08:00
|
|
|
|
|
|
|
|
// Split up named values into their components.
|
|
|
|
|
// NOTE: the component values we are making are dead at this point.
|
|
|
|
|
// We must do the opt pass before any deadcode elimination or we will
|
|
|
|
|
// lose the name->value correspondence.
|
2016-03-31 21:24:10 -07:00
|
|
|
var newNames []LocalSlot
|
2015-11-02 08:10:26 -08:00
|
|
|
for _, name := range f.Names {
|
|
|
|
|
t := name.Type
|
|
|
|
|
switch {
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
case t.IsInteger() && t.Size() == 8 && f.Config.IntSize == 4:
|
|
|
|
|
var elemType Type
|
|
|
|
|
if t.IsSigned() {
|
2017-03-16 22:42:10 -07:00
|
|
|
elemType = f.fe.TypeInt32()
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
} else {
|
2017-03-16 22:42:10 -07:00
|
|
|
elemType = f.fe.TypeUInt32()
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
}
|
2017-03-16 22:42:10 -07:00
|
|
|
hiName, loName := f.fe.SplitInt64(name)
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
newNames = append(newNames, hiName, loName)
|
|
|
|
|
for _, v := range f.NamedValues[name] {
|
2016-12-07 18:14:35 -08:00
|
|
|
hi := v.Block.NewValue1(v.Pos, OpInt64Hi, elemType, v)
|
2017-03-16 22:42:10 -07:00
|
|
|
lo := v.Block.NewValue1(v.Pos, OpInt64Lo, f.fe.TypeUInt32(), v)
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
f.NamedValues[hiName] = append(f.NamedValues[hiName], hi)
|
|
|
|
|
f.NamedValues[loName] = append(f.NamedValues[loName], lo)
|
|
|
|
|
}
|
|
|
|
|
delete(f.NamedValues, name)
|
2015-11-02 08:10:26 -08:00
|
|
|
case t.IsComplex():
|
|
|
|
|
var elemType Type
|
|
|
|
|
if t.Size() == 16 {
|
2017-03-16 22:42:10 -07:00
|
|
|
elemType = f.fe.TypeFloat64()
|
2015-11-02 08:10:26 -08:00
|
|
|
} else {
|
2017-03-16 22:42:10 -07:00
|
|
|
elemType = f.fe.TypeFloat32()
|
2015-11-02 08:10:26 -08:00
|
|
|
}
|
2017-03-16 22:42:10 -07:00
|
|
|
rName, iName := f.fe.SplitComplex(name)
|
2016-03-31 21:24:10 -07:00
|
|
|
newNames = append(newNames, rName, iName)
|
2015-11-02 08:10:26 -08:00
|
|
|
for _, v := range f.NamedValues[name] {
|
2016-12-07 18:14:35 -08:00
|
|
|
r := v.Block.NewValue1(v.Pos, OpComplexReal, elemType, v)
|
|
|
|
|
i := v.Block.NewValue1(v.Pos, OpComplexImag, elemType, v)
|
2015-11-02 08:10:26 -08:00
|
|
|
f.NamedValues[rName] = append(f.NamedValues[rName], r)
|
|
|
|
|
f.NamedValues[iName] = append(f.NamedValues[iName], i)
|
|
|
|
|
}
|
2016-03-31 21:24:10 -07:00
|
|
|
delete(f.NamedValues, name)
|
2015-11-02 08:10:26 -08:00
|
|
|
case t.IsString():
|
2017-03-16 22:42:10 -07:00
|
|
|
ptrType := f.fe.TypeBytePtr()
|
|
|
|
|
lenType := f.fe.TypeInt()
|
|
|
|
|
ptrName, lenName := f.fe.SplitString(name)
|
2016-03-31 21:24:10 -07:00
|
|
|
newNames = append(newNames, ptrName, lenName)
|
2015-11-02 08:10:26 -08:00
|
|
|
for _, v := range f.NamedValues[name] {
|
2016-12-07 18:14:35 -08:00
|
|
|
ptr := v.Block.NewValue1(v.Pos, OpStringPtr, ptrType, v)
|
|
|
|
|
len := v.Block.NewValue1(v.Pos, OpStringLen, lenType, v)
|
2015-11-02 08:10:26 -08:00
|
|
|
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
|
|
|
|
|
f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
|
|
|
|
|
}
|
2016-03-31 21:24:10 -07:00
|
|
|
delete(f.NamedValues, name)
|
2015-11-02 08:10:26 -08:00
|
|
|
case t.IsSlice():
|
2017-03-16 22:42:10 -07:00
|
|
|
ptrType := f.fe.TypeBytePtr()
|
|
|
|
|
lenType := f.fe.TypeInt()
|
|
|
|
|
ptrName, lenName, capName := f.fe.SplitSlice(name)
|
2016-03-31 21:24:10 -07:00
|
|
|
newNames = append(newNames, ptrName, lenName, capName)
|
2015-11-02 08:10:26 -08:00
|
|
|
for _, v := range f.NamedValues[name] {
|
2016-12-07 18:14:35 -08:00
|
|
|
ptr := v.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, v)
|
|
|
|
|
len := v.Block.NewValue1(v.Pos, OpSliceLen, lenType, v)
|
|
|
|
|
cap := v.Block.NewValue1(v.Pos, OpSliceCap, lenType, v)
|
2015-11-02 08:10:26 -08:00
|
|
|
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
|
|
|
|
|
f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
|
|
|
|
|
f.NamedValues[capName] = append(f.NamedValues[capName], cap)
|
|
|
|
|
}
|
2016-03-31 21:24:10 -07:00
|
|
|
delete(f.NamedValues, name)
|
2015-11-02 08:10:26 -08:00
|
|
|
case t.IsInterface():
|
2017-03-16 22:42:10 -07:00
|
|
|
ptrType := f.fe.TypeBytePtr()
|
|
|
|
|
typeName, dataName := f.fe.SplitInterface(name)
|
2016-03-31 21:24:10 -07:00
|
|
|
newNames = append(newNames, typeName, dataName)
|
2015-11-02 08:10:26 -08:00
|
|
|
for _, v := range f.NamedValues[name] {
|
2016-12-07 18:14:35 -08:00
|
|
|
typ := v.Block.NewValue1(v.Pos, OpITab, ptrType, v)
|
|
|
|
|
data := v.Block.NewValue1(v.Pos, OpIData, ptrType, v)
|
2015-11-02 08:10:26 -08:00
|
|
|
f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
|
|
|
|
|
f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
|
|
|
|
|
}
|
2016-03-31 21:24:10 -07:00
|
|
|
delete(f.NamedValues, name)
|
2016-05-31 11:27:16 -04:00
|
|
|
case t.IsFloat():
|
|
|
|
|
// floats are never decomposed, even ones bigger than IntSize
|
2015-11-02 08:10:26 -08:00
|
|
|
case t.Size() > f.Config.IntSize:
|
2016-09-14 11:35:29 -07:00
|
|
|
f.Fatalf("undecomposed named type %v %v", name, t)
|
2016-03-31 21:24:10 -07:00
|
|
|
default:
|
|
|
|
|
newNames = append(newNames, name)
|
2015-11-02 08:10:26 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-03-31 21:24:10 -07:00
|
|
|
f.Names = newNames
|
2015-08-18 10:26:28 -07:00
|
|
|
}
|
|
|
|
|
|
2016-02-08 11:00:43 -08:00
|
|
|
func decomposeBuiltInPhi(v *Value) {
|
2016-01-11 21:05:33 -08:00
|
|
|
switch {
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
case v.Type.IsInteger() && v.Type.Size() == 8 && v.Block.Func.Config.IntSize == 4:
|
2016-08-08 11:26:25 -07:00
|
|
|
if v.Block.Func.Config.arch == "amd64p32" {
|
|
|
|
|
// Even though ints are 32 bits, we have 64-bit ops.
|
|
|
|
|
break
|
|
|
|
|
}
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
decomposeInt64Phi(v)
|
2016-01-11 21:05:33 -08:00
|
|
|
case v.Type.IsComplex():
|
|
|
|
|
decomposeComplexPhi(v)
|
|
|
|
|
case v.Type.IsString():
|
|
|
|
|
decomposeStringPhi(v)
|
|
|
|
|
case v.Type.IsSlice():
|
|
|
|
|
decomposeSlicePhi(v)
|
|
|
|
|
case v.Type.IsInterface():
|
|
|
|
|
decomposeInterfacePhi(v)
|
2016-05-31 11:27:16 -04:00
|
|
|
case v.Type.IsFloat():
|
|
|
|
|
// floats are never decomposed, even ones bigger than IntSize
|
2016-01-11 21:05:33 -08:00
|
|
|
case v.Type.Size() > v.Block.Func.Config.IntSize:
|
2016-09-14 10:01:05 -07:00
|
|
|
v.Fatalf("undecomposed type %s", v.Type)
|
2016-01-11 21:05:33 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-18 10:26:28 -07:00
|
|
|
func decomposeStringPhi(v *Value) {
|
2017-03-16 22:42:10 -07:00
|
|
|
fe := v.Block.Func.fe
|
2015-08-18 10:26:28 -07:00
|
|
|
ptrType := fe.TypeBytePtr()
|
2015-10-22 14:22:38 -07:00
|
|
|
lenType := fe.TypeInt()
|
2015-08-18 10:26:28 -07:00
|
|
|
|
2016-12-07 18:14:35 -08:00
|
|
|
ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
|
|
|
|
|
len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
|
2015-08-18 10:26:28 -07:00
|
|
|
for _, a := range v.Args {
|
2016-12-07 18:14:35 -08:00
|
|
|
ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a))
|
|
|
|
|
len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a))
|
2015-08-18 10:26:28 -07:00
|
|
|
}
|
2016-02-04 17:21:57 +01:00
|
|
|
v.reset(OpStringMake)
|
2015-08-18 10:26:28 -07:00
|
|
|
v.AddArg(ptr)
|
|
|
|
|
v.AddArg(len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decomposeSlicePhi(v *Value) {
|
2017-03-16 22:42:10 -07:00
|
|
|
fe := v.Block.Func.fe
|
2015-08-18 10:26:28 -07:00
|
|
|
ptrType := fe.TypeBytePtr()
|
2015-10-22 14:22:38 -07:00
|
|
|
lenType := fe.TypeInt()
|
2015-08-18 10:26:28 -07:00
|
|
|
|
2016-12-07 18:14:35 -08:00
|
|
|
ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
|
|
|
|
|
len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
|
|
|
|
|
cap := v.Block.NewValue0(v.Pos, OpPhi, lenType)
|
2015-08-18 10:26:28 -07:00
|
|
|
for _, a := range v.Args {
|
2016-12-07 18:14:35 -08:00
|
|
|
ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a))
|
|
|
|
|
len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a))
|
|
|
|
|
cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a))
|
2015-08-18 10:26:28 -07:00
|
|
|
}
|
2016-02-04 17:21:57 +01:00
|
|
|
v.reset(OpSliceMake)
|
2015-08-18 10:26:28 -07:00
|
|
|
v.AddArg(ptr)
|
|
|
|
|
v.AddArg(len)
|
|
|
|
|
v.AddArg(cap)
|
|
|
|
|
}
|
|
|
|
|
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
func decomposeInt64Phi(v *Value) {
|
2017-03-16 22:42:10 -07:00
|
|
|
fe := v.Block.Func.fe
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
var partType Type
|
|
|
|
|
if v.Type.IsSigned() {
|
|
|
|
|
partType = fe.TypeInt32()
|
|
|
|
|
} else {
|
|
|
|
|
partType = fe.TypeUInt32()
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-07 18:14:35 -08:00
|
|
|
hi := v.Block.NewValue0(v.Pos, OpPhi, partType)
|
|
|
|
|
lo := v.Block.NewValue0(v.Pos, OpPhi, fe.TypeUInt32())
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
for _, a := range v.Args {
|
2016-12-07 18:14:35 -08:00
|
|
|
hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a))
|
|
|
|
|
lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, fe.TypeUInt32(), a))
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
}
|
|
|
|
|
v.reset(OpInt64Make)
|
|
|
|
|
v.AddArg(hi)
|
|
|
|
|
v.AddArg(lo)
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 14:24:10 -04:00
|
|
|
func decomposeComplexPhi(v *Value) {
|
2017-03-16 22:42:10 -07:00
|
|
|
fe := v.Block.Func.fe
|
2015-08-28 14:24:10 -04:00
|
|
|
var partType Type
|
2015-08-28 14:24:10 -04:00
|
|
|
switch z := v.Type.Size(); z {
|
|
|
|
|
case 8:
|
2015-08-28 14:24:10 -04:00
|
|
|
partType = fe.TypeFloat32()
|
2015-08-28 14:24:10 -04:00
|
|
|
case 16:
|
2015-08-28 14:24:10 -04:00
|
|
|
partType = fe.TypeFloat64()
|
2015-08-28 14:24:10 -04:00
|
|
|
default:
|
|
|
|
|
v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
|
2015-08-28 14:24:10 -04:00
|
|
|
}
|
|
|
|
|
|
2016-12-07 18:14:35 -08:00
|
|
|
real := v.Block.NewValue0(v.Pos, OpPhi, partType)
|
|
|
|
|
imag := v.Block.NewValue0(v.Pos, OpPhi, partType)
|
2015-08-28 14:24:10 -04:00
|
|
|
for _, a := range v.Args {
|
2016-12-07 18:14:35 -08:00
|
|
|
real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a))
|
|
|
|
|
imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a))
|
2015-08-28 14:24:10 -04:00
|
|
|
}
|
2016-02-04 17:21:57 +01:00
|
|
|
v.reset(OpComplexMake)
|
2015-08-28 14:24:10 -04:00
|
|
|
v.AddArg(real)
|
|
|
|
|
v.AddArg(imag)
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-18 10:26:28 -07:00
|
|
|
func decomposeInterfacePhi(v *Value) {
|
2017-03-16 22:42:10 -07:00
|
|
|
ptrType := v.Block.Func.fe.TypeBytePtr()
|
2015-08-18 10:26:28 -07:00
|
|
|
|
2016-12-07 18:14:35 -08:00
|
|
|
itab := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
|
|
|
|
|
data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
|
2015-08-18 10:26:28 -07:00
|
|
|
for _, a := range v.Args {
|
2016-12-07 18:14:35 -08:00
|
|
|
itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, ptrType, a))
|
|
|
|
|
data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
|
2015-08-18 10:26:28 -07:00
|
|
|
}
|
2016-02-04 17:21:57 +01:00
|
|
|
v.reset(OpIMake)
|
2015-08-18 10:26:28 -07:00
|
|
|
v.AddArg(itab)
|
|
|
|
|
v.AddArg(data)
|
|
|
|
|
}
|
2016-02-08 11:00:43 -08:00
|
|
|
|
|
|
|
|
func decomposeUser(f *Func) {
|
|
|
|
|
for _, b := range f.Blocks {
|
|
|
|
|
for _, v := range b.Values {
|
|
|
|
|
if v.Op != OpPhi {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
decomposeUserPhi(v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Split up named values into their components.
|
|
|
|
|
// NOTE: the component values we are making are dead at this point.
|
|
|
|
|
// We must do the opt pass before any deadcode elimination or we will
|
|
|
|
|
// lose the name->value correspondence.
|
|
|
|
|
i := 0
|
2016-03-31 21:24:10 -07:00
|
|
|
var fnames []LocalSlot
|
|
|
|
|
var newNames []LocalSlot
|
2016-02-08 11:00:43 -08:00
|
|
|
for _, name := range f.Names {
|
|
|
|
|
t := name.Type
|
|
|
|
|
switch {
|
|
|
|
|
case t.IsStruct():
|
|
|
|
|
n := t.NumFields()
|
2016-03-31 21:24:10 -07:00
|
|
|
fnames = fnames[:0]
|
|
|
|
|
for i := 0; i < n; i++ {
|
2017-03-16 22:42:10 -07:00
|
|
|
fnames = append(fnames, f.fe.SplitStruct(name, i))
|
2016-03-31 21:24:10 -07:00
|
|
|
}
|
2016-02-08 11:00:43 -08:00
|
|
|
for _, v := range f.NamedValues[name] {
|
2016-03-14 12:45:18 -07:00
|
|
|
for i := 0; i < n; i++ {
|
2016-12-07 18:14:35 -08:00
|
|
|
x := v.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), v)
|
2016-03-31 21:24:10 -07:00
|
|
|
f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x)
|
2016-02-08 11:00:43 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete(f.NamedValues, name)
|
2016-03-31 21:24:10 -07:00
|
|
|
newNames = append(newNames, fnames...)
|
2016-10-30 21:10:03 -07:00
|
|
|
case t.IsArray():
|
|
|
|
|
if t.NumElem() == 0 {
|
|
|
|
|
// TODO(khr): Not sure what to do here. Probably nothing.
|
|
|
|
|
// Names for empty arrays aren't important.
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if t.NumElem() != 1 {
|
|
|
|
|
f.Fatalf("array not of size 1")
|
|
|
|
|
}
|
2017-03-16 22:42:10 -07:00
|
|
|
elemName := f.fe.SplitArray(name)
|
2016-10-30 21:10:03 -07:00
|
|
|
for _, v := range f.NamedValues[name] {
|
2016-12-07 18:14:35 -08:00
|
|
|
e := v.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, v)
|
2016-10-30 21:10:03 -07:00
|
|
|
f.NamedValues[elemName] = append(f.NamedValues[elemName], e)
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-08 11:00:43 -08:00
|
|
|
default:
|
|
|
|
|
f.Names[i] = name
|
|
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
f.Names = f.Names[:i]
|
2016-03-31 21:24:10 -07:00
|
|
|
f.Names = append(f.Names, newNames...)
|
2016-02-08 11:00:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decomposeUserPhi(v *Value) {
|
|
|
|
|
switch {
|
|
|
|
|
case v.Type.IsStruct():
|
|
|
|
|
decomposeStructPhi(v)
|
2016-10-30 21:10:03 -07:00
|
|
|
case v.Type.IsArray():
|
|
|
|
|
decomposeArrayPhi(v)
|
2016-02-08 11:00:43 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-30 21:10:03 -07:00
|
|
|
// decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field),
|
|
|
|
|
// and then recursively decomposes the phis for each field.
|
2015-08-18 10:26:28 -07:00
|
|
|
func decomposeStructPhi(v *Value) {
|
2016-01-11 21:05:33 -08:00
|
|
|
t := v.Type
|
|
|
|
|
n := t.NumFields()
|
|
|
|
|
var fields [MaxStruct]*Value
|
2016-03-14 12:45:18 -07:00
|
|
|
for i := 0; i < n; i++ {
|
2016-12-07 18:14:35 -08:00
|
|
|
fields[i] = v.Block.NewValue0(v.Pos, OpPhi, t.FieldType(i))
|
2016-01-11 21:05:33 -08:00
|
|
|
}
|
|
|
|
|
for _, a := range v.Args {
|
2016-03-14 12:45:18 -07:00
|
|
|
for i := 0; i < n; i++ {
|
2016-12-07 18:14:35 -08:00
|
|
|
fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a))
|
2016-01-11 21:05:33 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-02-04 17:21:57 +01:00
|
|
|
v.reset(StructMakeOp(n))
|
2016-01-11 21:05:33 -08:00
|
|
|
v.AddArgs(fields[:n]...)
|
|
|
|
|
|
|
|
|
|
// Recursively decompose phis for each field.
|
|
|
|
|
for _, f := range fields[:n] {
|
2016-10-30 21:10:03 -07:00
|
|
|
decomposeUserPhi(f)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element),
|
|
|
|
|
// and then recursively decomposes the element phi.
|
|
|
|
|
func decomposeArrayPhi(v *Value) {
|
|
|
|
|
t := v.Type
|
|
|
|
|
if t.NumElem() == 0 {
|
|
|
|
|
v.reset(OpArrayMake0)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if t.NumElem() != 1 {
|
|
|
|
|
v.Fatalf("SSAable array must have no more than 1 element")
|
2016-01-11 21:05:33 -08:00
|
|
|
}
|
2016-12-07 18:14:35 -08:00
|
|
|
elem := v.Block.NewValue0(v.Pos, OpPhi, t.ElemType())
|
2016-10-30 21:10:03 -07:00
|
|
|
for _, a := range v.Args {
|
2016-12-07 18:14:35 -08:00
|
|
|
elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, a))
|
2016-10-30 21:10:03 -07:00
|
|
|
}
|
|
|
|
|
v.reset(OpArrayMake1)
|
|
|
|
|
v.AddArg(elem)
|
|
|
|
|
|
|
|
|
|
// Recursively decompose elem phi.
|
|
|
|
|
decomposeUserPhi(elem)
|
2016-01-11 21:05:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MaxStruct is the maximum number of fields a struct
|
|
|
|
|
// can have and still be SSAable.
|
|
|
|
|
const MaxStruct = 4
|
|
|
|
|
|
|
|
|
|
// StructMakeOp returns the opcode to construct a struct with the
|
|
|
|
|
// given number of fields.
|
2016-03-14 12:45:18 -07:00
|
|
|
func StructMakeOp(nf int) Op {
|
2016-01-11 21:05:33 -08:00
|
|
|
switch nf {
|
|
|
|
|
case 0:
|
|
|
|
|
return OpStructMake0
|
|
|
|
|
case 1:
|
|
|
|
|
return OpStructMake1
|
|
|
|
|
case 2:
|
|
|
|
|
return OpStructMake2
|
|
|
|
|
case 3:
|
|
|
|
|
return OpStructMake3
|
|
|
|
|
case 4:
|
|
|
|
|
return OpStructMake4
|
|
|
|
|
}
|
|
|
|
|
panic("too many fields in an SSAable struct")
|
2015-08-18 10:26:28 -07:00
|
|
|
}
|