2016-03-21 22:57:26 -07:00
|
|
|
// Copyright 2016 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 arm
|
|
|
|
|
|
|
|
|
|
import (
|
2016-06-17 10:34:06 -04:00
|
|
|
"fmt"
|
2016-05-31 11:27:16 -04:00
|
|
|
"math"
|
|
|
|
|
|
2016-03-21 22:57:26 -07:00
|
|
|
"cmd/compile/internal/gc"
|
|
|
|
|
"cmd/compile/internal/ssa"
|
|
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"cmd/internal/obj/arm"
|
|
|
|
|
)
|
|
|
|
|
|
2016-05-15 00:12:56 -04:00
|
|
|
// loadByType returns the load instruction of the given type.
|
|
|
|
|
func loadByType(t ssa.Type) obj.As {
|
|
|
|
|
if t.IsFloat() {
|
2016-05-31 11:27:16 -04:00
|
|
|
switch t.Size() {
|
|
|
|
|
case 4:
|
|
|
|
|
return arm.AMOVF
|
|
|
|
|
case 8:
|
|
|
|
|
return arm.AMOVD
|
|
|
|
|
}
|
2016-05-15 00:12:56 -04:00
|
|
|
} else {
|
|
|
|
|
switch t.Size() {
|
|
|
|
|
case 1:
|
|
|
|
|
if t.IsSigned() {
|
|
|
|
|
return arm.AMOVB
|
|
|
|
|
} else {
|
|
|
|
|
return arm.AMOVBU
|
|
|
|
|
}
|
|
|
|
|
case 2:
|
|
|
|
|
if t.IsSigned() {
|
|
|
|
|
return arm.AMOVH
|
|
|
|
|
} else {
|
|
|
|
|
return arm.AMOVHU
|
|
|
|
|
}
|
|
|
|
|
case 4:
|
|
|
|
|
return arm.AMOVW
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
panic("bad load type")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// storeByType returns the store instruction of the given type.
|
|
|
|
|
func storeByType(t ssa.Type) obj.As {
|
|
|
|
|
if t.IsFloat() {
|
2016-05-31 11:27:16 -04:00
|
|
|
switch t.Size() {
|
|
|
|
|
case 4:
|
|
|
|
|
return arm.AMOVF
|
|
|
|
|
case 8:
|
|
|
|
|
return arm.AMOVD
|
|
|
|
|
}
|
2016-05-15 00:12:56 -04:00
|
|
|
} else {
|
|
|
|
|
switch t.Size() {
|
|
|
|
|
case 1:
|
|
|
|
|
return arm.AMOVB
|
|
|
|
|
case 2:
|
|
|
|
|
return arm.AMOVH
|
|
|
|
|
case 4:
|
|
|
|
|
return arm.AMOVW
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
panic("bad store type")
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-17 10:34:06 -04:00
|
|
|
// shift type is used as Offset in obj.TYPE_SHIFT operands to encode shifted register operands
|
|
|
|
|
type shift int64
|
|
|
|
|
|
|
|
|
|
// copied from ../../../internal/obj/util.go:/TYPE_SHIFT
|
|
|
|
|
func (v shift) String() string {
|
|
|
|
|
op := "<<>>->@>"[((v>>5)&3)<<1:]
|
|
|
|
|
if v&(1<<4) != 0 {
|
|
|
|
|
// register shift
|
|
|
|
|
return fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
|
|
|
|
|
} else {
|
|
|
|
|
// constant shift
|
|
|
|
|
return fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// makeshift encodes a register shifted by a constant
|
|
|
|
|
func makeshift(reg int16, typ int64, s int64) shift {
|
|
|
|
|
return shift(int64(reg&0xf) | typ | (s&31)<<7)
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-20 08:01:28 -07:00
|
|
|
// genshift generates a Prog for r = r0 op (r1 shifted by n)
|
|
|
|
|
func genshift(s *gc.SSAGenState, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
|
|
|
|
|
p := s.Prog(as)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.From.Type = obj.TYPE_SHIFT
|
2017-03-20 08:01:28 -07:00
|
|
|
p.From.Offset = int64(makeshift(r1, typ, n))
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Reg = r0
|
|
|
|
|
if r != 0 {
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
}
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// makeregshift encodes a register shifted by a register
|
|
|
|
|
func makeregshift(r1 int16, typ int64, r2 int16) shift {
|
|
|
|
|
return shift(int64(r1&0xf) | typ | int64(r2&0xf)<<8 | 1<<4)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// genregshift generates a Prog for r = r0 op (r1 shifted by r2)
|
2017-03-20 08:01:28 -07:00
|
|
|
func genregshift(s *gc.SSAGenState, as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog {
|
|
|
|
|
p := s.Prog(as)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.From.Type = obj.TYPE_SHIFT
|
|
|
|
|
p.From.Offset = int64(makeregshift(r1, typ, r2))
|
|
|
|
|
p.Reg = r0
|
|
|
|
|
if r != 0 {
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
}
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 22:57:26 -07:00
|
|
|
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
|
|
|
|
switch v.Op {
|
2016-06-13 16:49:09 -04:00
|
|
|
case ssa.OpCopy, ssa.OpARMMOVWconvert, ssa.OpARMMOVWreg:
|
2016-05-13 15:31:14 -04:00
|
|
|
if v.Type.IsMemory() {
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-09-16 09:36:00 -07:00
|
|
|
x := v.Args[0].Reg()
|
|
|
|
|
y := v.Reg()
|
2016-05-13 15:31:14 -04:00
|
|
|
if x == y {
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-05-31 11:27:16 -04:00
|
|
|
as := arm.AMOVW
|
|
|
|
|
if v.Type.IsFloat() {
|
|
|
|
|
switch v.Type.Size() {
|
|
|
|
|
case 4:
|
|
|
|
|
as = arm.AMOVF
|
|
|
|
|
case 8:
|
|
|
|
|
as = arm.AMOVD
|
|
|
|
|
default:
|
|
|
|
|
panic("bad float size")
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(as)
|
2016-05-13 15:31:14 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = x
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = y
|
2016-07-15 14:07:15 -04:00
|
|
|
case ssa.OpARMMOVWnop:
|
2016-09-16 09:36:00 -07:00
|
|
|
if v.Reg() != v.Args[0].Reg() {
|
2016-07-15 14:07:15 -04:00
|
|
|
v.Fatalf("input[0] and output not in same register %s", v.LongString())
|
|
|
|
|
}
|
|
|
|
|
// nothing to do
|
2016-03-21 22:57:26 -07:00
|
|
|
case ssa.OpLoadReg:
|
2016-05-15 00:12:56 -04:00
|
|
|
if v.Type.IsFlags() {
|
2016-09-14 10:01:05 -07:00
|
|
|
v.Fatalf("load flags not implemented: %v", v.LongString())
|
2016-05-15 00:12:56 -04:00
|
|
|
return
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(loadByType(v.Type))
|
2016-10-03 12:26:25 -07:00
|
|
|
gc.AddrAuto(&p.From, v.Args[0])
|
2016-03-21 22:57:26 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-03-21 22:57:26 -07:00
|
|
|
case ssa.OpStoreReg:
|
2016-05-15 00:12:56 -04:00
|
|
|
if v.Type.IsFlags() {
|
2016-09-14 10:01:05 -07:00
|
|
|
v.Fatalf("store flags not implemented: %v", v.LongString())
|
2016-05-15 00:12:56 -04:00
|
|
|
return
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(storeByType(v.Type))
|
2016-03-21 22:57:26 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-10-03 12:26:25 -07:00
|
|
|
gc.AddrAuto(&p.To, v)
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.OpARMADD,
|
[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
|
|
|
ssa.OpARMADC,
|
2016-05-06 10:13:31 -07:00
|
|
|
ssa.OpARMSUB,
|
[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
|
|
|
ssa.OpARMSBC,
|
2016-05-06 10:13:31 -07:00
|
|
|
ssa.OpARMRSB,
|
|
|
|
|
ssa.OpARMAND,
|
|
|
|
|
ssa.OpARMOR,
|
|
|
|
|
ssa.OpARMXOR,
|
2016-05-13 15:22:56 -04:00
|
|
|
ssa.OpARMBIC,
|
2016-05-31 11:27:16 -04:00
|
|
|
ssa.OpARMMUL,
|
|
|
|
|
ssa.OpARMADDF,
|
|
|
|
|
ssa.OpARMADDD,
|
|
|
|
|
ssa.OpARMSUBF,
|
|
|
|
|
ssa.OpARMSUBD,
|
|
|
|
|
ssa.OpARMMULF,
|
|
|
|
|
ssa.OpARMMULD,
|
|
|
|
|
ssa.OpARMDIVF,
|
|
|
|
|
ssa.OpARMDIVD:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg()
|
|
|
|
|
r1 := v.Args[0].Reg()
|
|
|
|
|
r2 := v.Args[1].Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-03-21 22:57:26 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-05-06 10:13:31 -07:00
|
|
|
p.From.Reg = r2
|
|
|
|
|
p.Reg = r1
|
2016-03-21 22:57:26 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
[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 ssa.OpARMADDS,
|
|
|
|
|
ssa.OpARMSUBS:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg0()
|
|
|
|
|
r1 := v.Args[0].Reg()
|
|
|
|
|
r2 := v.Args[1].Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
[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
|
|
|
p.Scond = arm.C_SBIT
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = r2
|
|
|
|
|
p.Reg = r1
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
2016-05-13 15:22:56 -04:00
|
|
|
case ssa.OpARMSLL,
|
2016-06-17 10:34:06 -04:00
|
|
|
ssa.OpARMSRL,
|
|
|
|
|
ssa.OpARMSRA:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg()
|
|
|
|
|
r1 := v.Args[0].Reg()
|
|
|
|
|
r2 := v.Args[1].Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-05-13 15:22:56 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = r2
|
|
|
|
|
p.Reg = r1
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMSRAcond:
|
2016-05-13 15:22:56 -04:00
|
|
|
// ARM shift instructions uses only the low-order byte of the shift amount
|
|
|
|
|
// generate conditional instructions to deal with large shifts
|
2016-06-17 10:34:06 -04:00
|
|
|
// flag is already set
|
2016-05-13 15:22:56 -04:00
|
|
|
// SRA.HS $31, Rarg0, Rdst // shift 31 bits to get the sign bit
|
|
|
|
|
// SRA.LO Rarg1, Rarg0, Rdst
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg()
|
|
|
|
|
r1 := v.Args[0].Reg()
|
|
|
|
|
r2 := v.Args[1].Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(arm.ASRA)
|
2016-05-13 15:22:56 -04:00
|
|
|
p.Scond = arm.C_SCOND_HS
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = 31
|
|
|
|
|
p.Reg = r1
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
2017-03-20 08:01:28 -07:00
|
|
|
p = s.Prog(arm.ASRA)
|
2016-05-13 15:22:56 -04:00
|
|
|
p.Scond = arm.C_SCOND_LO
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = r2
|
|
|
|
|
p.Reg = r1
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
2016-06-06 22:36:45 -04:00
|
|
|
case ssa.OpARMADDconst,
|
2016-06-13 16:49:09 -04:00
|
|
|
ssa.OpARMADCconst,
|
2016-06-06 22:36:45 -04:00
|
|
|
ssa.OpARMSUBconst,
|
2016-06-13 16:49:09 -04:00
|
|
|
ssa.OpARMSBCconst,
|
2016-05-06 10:13:31 -07:00
|
|
|
ssa.OpARMRSBconst,
|
2016-06-13 16:49:09 -04:00
|
|
|
ssa.OpARMRSCconst,
|
2016-05-06 10:13:31 -07:00
|
|
|
ssa.OpARMANDconst,
|
|
|
|
|
ssa.OpARMORconst,
|
|
|
|
|
ssa.OpARMXORconst,
|
2016-05-13 15:22:56 -04:00
|
|
|
ssa.OpARMBICconst,
|
|
|
|
|
ssa.OpARMSLLconst,
|
|
|
|
|
ssa.OpARMSRLconst,
|
|
|
|
|
ssa.OpARMSRAconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-03-21 22:57:26 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
2016-09-16 09:36:00 -07:00
|
|
|
p.Reg = v.Args[0].Reg()
|
2016-03-21 22:57:26 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-06-13 16:49:09 -04:00
|
|
|
case ssa.OpARMADDSconst,
|
|
|
|
|
ssa.OpARMSUBSconst,
|
|
|
|
|
ssa.OpARMRSBSconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-06-13 16:49:09 -04:00
|
|
|
p.Scond = arm.C_SBIT
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
2016-09-16 09:36:00 -07:00
|
|
|
p.Reg = v.Args[0].Reg()
|
2016-06-13 16:49:09 -04:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg0()
|
2016-05-25 23:17:42 -04:00
|
|
|
case ssa.OpARMSRRconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, arm.AMOVW, 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMADDshiftLL,
|
|
|
|
|
ssa.OpARMADCshiftLL,
|
|
|
|
|
ssa.OpARMSUBshiftLL,
|
|
|
|
|
ssa.OpARMSBCshiftLL,
|
|
|
|
|
ssa.OpARMRSBshiftLL,
|
|
|
|
|
ssa.OpARMRSCshiftLL,
|
|
|
|
|
ssa.OpARMANDshiftLL,
|
|
|
|
|
ssa.OpARMORshiftLL,
|
|
|
|
|
ssa.OpARMXORshiftLL,
|
|
|
|
|
ssa.OpARMBICshiftLL:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMADDSshiftLL,
|
|
|
|
|
ssa.OpARMSUBSshiftLL,
|
|
|
|
|
ssa.OpARMRSBSshiftLL:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LL, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Scond = arm.C_SBIT
|
|
|
|
|
case ssa.OpARMADDshiftRL,
|
|
|
|
|
ssa.OpARMADCshiftRL,
|
|
|
|
|
ssa.OpARMSUBshiftRL,
|
|
|
|
|
ssa.OpARMSBCshiftRL,
|
|
|
|
|
ssa.OpARMRSBshiftRL,
|
|
|
|
|
ssa.OpARMRSCshiftRL,
|
|
|
|
|
ssa.OpARMANDshiftRL,
|
|
|
|
|
ssa.OpARMORshiftRL,
|
|
|
|
|
ssa.OpARMXORshiftRL,
|
|
|
|
|
ssa.OpARMBICshiftRL:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMADDSshiftRL,
|
|
|
|
|
ssa.OpARMSUBSshiftRL,
|
|
|
|
|
ssa.OpARMRSBSshiftRL:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Scond = arm.C_SBIT
|
|
|
|
|
case ssa.OpARMADDshiftRA,
|
|
|
|
|
ssa.OpARMADCshiftRA,
|
|
|
|
|
ssa.OpARMSUBshiftRA,
|
|
|
|
|
ssa.OpARMSBCshiftRA,
|
|
|
|
|
ssa.OpARMRSBshiftRA,
|
|
|
|
|
ssa.OpARMRSCshiftRA,
|
|
|
|
|
ssa.OpARMANDshiftRA,
|
|
|
|
|
ssa.OpARMORshiftRA,
|
|
|
|
|
ssa.OpARMXORshiftRA,
|
|
|
|
|
ssa.OpARMBICshiftRA:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMADDSshiftRA,
|
|
|
|
|
ssa.OpARMSUBSshiftRA,
|
|
|
|
|
ssa.OpARMRSBSshiftRA:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_AR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Scond = arm.C_SBIT
|
2016-08-30 09:12:22 -04:00
|
|
|
case ssa.OpARMXORshiftRR:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMVNshiftLL:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMVNshiftRL:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMVNshiftRA:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMVNshiftLLreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMVNshiftRLreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMVNshiftRAreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMADDshiftLLreg,
|
|
|
|
|
ssa.OpARMADCshiftLLreg,
|
|
|
|
|
ssa.OpARMSUBshiftLLreg,
|
|
|
|
|
ssa.OpARMSBCshiftLLreg,
|
|
|
|
|
ssa.OpARMRSBshiftLLreg,
|
|
|
|
|
ssa.OpARMRSCshiftLLreg,
|
|
|
|
|
ssa.OpARMANDshiftLLreg,
|
|
|
|
|
ssa.OpARMORshiftLLreg,
|
|
|
|
|
ssa.OpARMXORshiftLLreg,
|
|
|
|
|
ssa.OpARMBICshiftLLreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LL)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMADDSshiftLLreg,
|
|
|
|
|
ssa.OpARMSUBSshiftLLreg,
|
|
|
|
|
ssa.OpARMRSBSshiftLLreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LL)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Scond = arm.C_SBIT
|
|
|
|
|
case ssa.OpARMADDshiftRLreg,
|
|
|
|
|
ssa.OpARMADCshiftRLreg,
|
|
|
|
|
ssa.OpARMSUBshiftRLreg,
|
|
|
|
|
ssa.OpARMSBCshiftRLreg,
|
|
|
|
|
ssa.OpARMRSBshiftRLreg,
|
|
|
|
|
ssa.OpARMRSCshiftRLreg,
|
|
|
|
|
ssa.OpARMANDshiftRLreg,
|
|
|
|
|
ssa.OpARMORshiftRLreg,
|
|
|
|
|
ssa.OpARMXORshiftRLreg,
|
|
|
|
|
ssa.OpARMBICshiftRLreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LR)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMADDSshiftRLreg,
|
|
|
|
|
ssa.OpARMSUBSshiftRLreg,
|
|
|
|
|
ssa.OpARMRSBSshiftRLreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LR)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Scond = arm.C_SBIT
|
|
|
|
|
case ssa.OpARMADDshiftRAreg,
|
|
|
|
|
ssa.OpARMADCshiftRAreg,
|
|
|
|
|
ssa.OpARMSUBshiftRAreg,
|
|
|
|
|
ssa.OpARMSBCshiftRAreg,
|
|
|
|
|
ssa.OpARMRSBshiftRAreg,
|
|
|
|
|
ssa.OpARMRSCshiftRAreg,
|
|
|
|
|
ssa.OpARMANDshiftRAreg,
|
|
|
|
|
ssa.OpARMORshiftRAreg,
|
|
|
|
|
ssa.OpARMXORshiftRAreg,
|
|
|
|
|
ssa.OpARMBICshiftRAreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_AR)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMADDSshiftRAreg,
|
|
|
|
|
ssa.OpARMSUBSshiftRAreg,
|
|
|
|
|
ssa.OpARMRSBSshiftRAreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_AR)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Scond = arm.C_SBIT
|
2016-05-13 15:22:56 -04:00
|
|
|
case ssa.OpARMHMUL,
|
|
|
|
|
ssa.OpARMHMULU:
|
|
|
|
|
// 32-bit high multiplication
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-05-13 15:22:56 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
|
|
|
|
p.Reg = v.Args[1].Reg()
|
2016-05-13 15:22:56 -04:00
|
|
|
p.To.Type = obj.TYPE_REGREG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-05-13 15:22:56 -04:00
|
|
|
p.To.Offset = arm.REGTMP // throw away low 32-bit into tmp register
|
[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 ssa.OpARMMULLU:
|
2016-07-13 16:15:54 -07:00
|
|
|
// 32-bit multiplication, results 64-bit, high 32-bit in out0, low 32-bit in out1
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
[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
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
|
|
|
|
p.Reg = v.Args[1].Reg()
|
[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
|
|
|
p.To.Type = obj.TYPE_REGREG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg0() // high 32-bit
|
|
|
|
|
p.To.Offset = int64(v.Reg1()) // low 32-bit
|
[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 ssa.OpARMMULA:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
[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
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
|
|
|
|
p.Reg = v.Args[1].Reg()
|
[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
|
|
|
p.To.Type = obj.TYPE_REGREG2
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg() // result
|
|
|
|
|
p.To.Offset = int64(v.Args[2].Reg()) // addend
|
2016-03-21 22:57:26 -07:00
|
|
|
case ssa.OpARMMOVWconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-03-21 22:57:26 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
2016-03-29 16:39:53 -07:00
|
|
|
p.From.Offset = v.AuxInt
|
2016-03-21 22:57:26 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-05-31 11:27:16 -04:00
|
|
|
case ssa.OpARMMOVFconst,
|
|
|
|
|
ssa.OpARMMOVDconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-05-31 11:27:16 -04:00
|
|
|
p.From.Type = obj.TYPE_FCONST
|
|
|
|
|
p.From.Val = math.Float64frombits(uint64(v.AuxInt))
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.OpARMCMP,
|
|
|
|
|
ssa.OpARMCMN,
|
|
|
|
|
ssa.OpARMTST,
|
2016-05-31 11:27:16 -04:00
|
|
|
ssa.OpARMTEQ,
|
|
|
|
|
ssa.OpARMCMPF,
|
|
|
|
|
ssa.OpARMCMPD:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-03-21 22:57:26 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-04-18 12:21:51 -04:00
|
|
|
// Special layout in ARM assembly
|
|
|
|
|
// Comparing to x86, the operands of ARM's CMP are reversed.
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[1].Reg()
|
|
|
|
|
p.Reg = v.Args[0].Reg()
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.OpARMCMPconst,
|
|
|
|
|
ssa.OpARMCMNconst,
|
|
|
|
|
ssa.OpARMTSTconst,
|
|
|
|
|
ssa.OpARMTEQconst:
|
|
|
|
|
// Special layout in ARM assembly
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-05-06 10:13:31 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
2016-09-16 09:36:00 -07:00
|
|
|
p.Reg = v.Args[0].Reg()
|
2016-07-06 10:04:45 -04:00
|
|
|
case ssa.OpARMCMPF0,
|
|
|
|
|
ssa.OpARMCMPD0:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-06 10:04:45 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMCMPshiftLL:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LL, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMCMPshiftRL:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMCMPshiftRA:
|
2017-03-20 08:01:28 -07:00
|
|
|
genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_AR, v.AuxInt)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMCMPshiftLLreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LL)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMCMPshiftRLreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LR)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMCMPshiftRAreg:
|
2017-03-20 08:01:28 -07:00
|
|
|
genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_AR)
|
2016-06-06 22:36:45 -04:00
|
|
|
case ssa.OpARMMOVWaddr:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(arm.AMOVW)
|
2016-06-15 15:56:52 -07:00
|
|
|
p.From.Type = obj.TYPE_ADDR
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-06-15 15:56:52 -07:00
|
|
|
|
|
|
|
|
var wantreg string
|
2016-06-06 22:36:45 -04:00
|
|
|
// MOVW $sym+off(base), R
|
|
|
|
|
// the assembler expands it as the following:
|
|
|
|
|
// - base is SP: add constant offset to SP (R13)
|
|
|
|
|
// when constant is large, tmp register (R11) may be used
|
|
|
|
|
// - base is SB: load external address from constant pool (use relocation)
|
|
|
|
|
switch v.Aux.(type) {
|
|
|
|
|
default:
|
|
|
|
|
v.Fatalf("aux is of unknown type %T", v.Aux)
|
|
|
|
|
case *ssa.ExternSymbol:
|
2016-06-15 15:56:52 -07:00
|
|
|
wantreg = "SB"
|
|
|
|
|
gc.AddAux(&p.From, v)
|
2016-06-15 15:17:45 -07:00
|
|
|
case *ssa.ArgSymbol, *ssa.AutoSymbol:
|
2016-06-15 15:56:52 -07:00
|
|
|
wantreg = "SP"
|
|
|
|
|
gc.AddAux(&p.From, v)
|
|
|
|
|
case nil:
|
|
|
|
|
// No sym, just MOVW $off(SP), R
|
|
|
|
|
wantreg = "SP"
|
|
|
|
|
p.From.Reg = arm.REGSP
|
|
|
|
|
p.From.Offset = v.AuxInt
|
2016-06-06 22:36:45 -04:00
|
|
|
}
|
2016-09-16 09:36:00 -07:00
|
|
|
if reg := v.Args[0].RegName(); reg != wantreg {
|
|
|
|
|
v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
|
2016-06-15 15:56:52 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.OpARMMOVBload,
|
|
|
|
|
ssa.OpARMMOVBUload,
|
|
|
|
|
ssa.OpARMMOVHload,
|
|
|
|
|
ssa.OpARMMOVHUload,
|
2016-05-31 11:27:16 -04:00
|
|
|
ssa.OpARMMOVWload,
|
|
|
|
|
ssa.OpARMMOVFload,
|
|
|
|
|
ssa.OpARMMOVDload:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-03-21 22:57:26 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-03-21 22:57:26 -07:00
|
|
|
gc.AddAux(&p.From, v)
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.OpARMMOVBstore,
|
|
|
|
|
ssa.OpARMMOVHstore,
|
2016-05-31 11:27:16 -04:00
|
|
|
ssa.OpARMMOVWstore,
|
|
|
|
|
ssa.OpARMMOVFstore,
|
|
|
|
|
ssa.OpARMMOVDstore:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-03-21 22:57:26 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[1].Reg()
|
2016-03-21 22:57:26 -07:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Args[0].Reg()
|
2016-03-21 22:57:26 -07:00
|
|
|
gc.AddAux(&p.To, v)
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMOVWloadidx:
|
|
|
|
|
// this is just shift 0 bits
|
|
|
|
|
fallthrough
|
|
|
|
|
case ssa.OpARMMOVWloadshiftLL:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMOVWloadshiftRL:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMOVWloadshiftRA:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMOVWstoreidx:
|
|
|
|
|
// this is just shift 0 bits
|
|
|
|
|
fallthrough
|
|
|
|
|
case ssa.OpARMMOVWstoreshiftLL:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-06-17 10:34:06 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[2].Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
p.To.Type = obj.TYPE_SHIFT
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Args[0].Reg()
|
|
|
|
|
p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LL, v.AuxInt))
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMOVWstoreshiftRL:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-06-17 10:34:06 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[2].Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
p.To.Type = obj.TYPE_SHIFT
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Args[0].Reg()
|
|
|
|
|
p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LR, v.AuxInt))
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMMOVWstoreshiftRA:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-06-17 10:34:06 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[2].Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
p.To.Type = obj.TYPE_SHIFT
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Args[0].Reg()
|
|
|
|
|
p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_AR, v.AuxInt))
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.OpARMMOVBreg,
|
|
|
|
|
ssa.OpARMMOVBUreg,
|
|
|
|
|
ssa.OpARMMOVHreg,
|
2016-06-17 10:34:06 -04:00
|
|
|
ssa.OpARMMOVHUreg:
|
|
|
|
|
a := v.Args[0]
|
2016-07-15 14:07:15 -04:00
|
|
|
for a.Op == ssa.OpCopy || a.Op == ssa.OpARMMOVWreg || a.Op == ssa.OpARMMOVWnop {
|
2016-06-17 10:34:06 -04:00
|
|
|
a = a.Args[0]
|
|
|
|
|
}
|
|
|
|
|
if a.Op == ssa.OpLoadReg {
|
|
|
|
|
t := a.Type
|
|
|
|
|
switch {
|
|
|
|
|
case v.Op == ssa.OpARMMOVBreg && t.Size() == 1 && t.IsSigned(),
|
|
|
|
|
v.Op == ssa.OpARMMOVBUreg && t.Size() == 1 && !t.IsSigned(),
|
|
|
|
|
v.Op == ssa.OpARMMOVHreg && t.Size() == 2 && t.IsSigned(),
|
|
|
|
|
v.Op == ssa.OpARMMOVHUreg && t.Size() == 2 && !t.IsSigned():
|
|
|
|
|
// arg is a proper-typed load, already zero/sign-extended, don't extend again
|
2016-09-16 09:36:00 -07:00
|
|
|
if v.Reg() == v.Args[0].Reg() {
|
2016-06-17 10:34:06 -04:00
|
|
|
return
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(arm.AMOVW)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
return
|
|
|
|
|
default:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
case ssa.OpARMMVN,
|
2016-08-30 09:12:22 -04:00
|
|
|
ssa.OpARMCLZ,
|
2017-01-24 09:48:58 +00:00
|
|
|
ssa.OpARMREV,
|
|
|
|
|
ssa.OpARMRBIT,
|
2016-05-31 11:27:16 -04:00
|
|
|
ssa.OpARMSQRTD,
|
2016-06-29 15:20:48 -04:00
|
|
|
ssa.OpARMNEGF,
|
|
|
|
|
ssa.OpARMNEGD,
|
2016-05-31 11:27:16 -04:00
|
|
|
ssa.OpARMMOVWF,
|
|
|
|
|
ssa.OpARMMOVWD,
|
|
|
|
|
ssa.OpARMMOVFW,
|
|
|
|
|
ssa.OpARMMOVDW,
|
|
|
|
|
ssa.OpARMMOVFD,
|
|
|
|
|
ssa.OpARMMOVDF:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-05-31 11:27:16 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-05-31 11:27:16 -04:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-05-31 11:27:16 -04:00
|
|
|
case ssa.OpARMMOVWUF,
|
|
|
|
|
ssa.OpARMMOVWUD,
|
|
|
|
|
ssa.OpARMMOVFWU,
|
|
|
|
|
ssa.OpARMMOVDWU:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-05-31 11:27:16 -04:00
|
|
|
p.Scond = arm.C_UBIT
|
2016-05-06 10:13:31 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-05-06 10:13:31 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMCMOVWHSconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(arm.AMOVW)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Scond = arm.C_SCOND_HS
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-06-17 10:34:06 -04:00
|
|
|
case ssa.OpARMCMOVWLSconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(arm.AMOVW)
|
2016-06-17 10:34:06 -04:00
|
|
|
p.Scond = arm.C_SCOND_LS
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2017-04-20 07:50:17 -07:00
|
|
|
case ssa.OpARMCALLstatic, ssa.OpARMCALLclosure, ssa.OpARMCALLinter:
|
|
|
|
|
s.Call(v)
|
|
|
|
|
case ssa.OpARMCALLudiv:
|
|
|
|
|
v.Aux = gc.Udiv
|
2017-03-10 18:34:41 -08:00
|
|
|
s.Call(v)
|
2016-05-13 15:31:14 -04:00
|
|
|
case ssa.OpARMDUFFZERO:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.ADUFFZERO)
|
2016-05-13 15:31:14 -04:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
2017-02-06 14:46:48 -08:00
|
|
|
p.To.Sym = gc.Duffzero
|
2016-05-13 15:31:14 -04:00
|
|
|
p.To.Offset = v.AuxInt
|
|
|
|
|
case ssa.OpARMDUFFCOPY:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.ADUFFCOPY)
|
2016-05-13 15:31:14 -04:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
2017-02-06 14:46:48 -08:00
|
|
|
p.To.Sym = gc.Duffcopy
|
2016-05-13 15:31:14 -04:00
|
|
|
p.To.Offset = v.AuxInt
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.OpARMLoweredNilCheck:
|
|
|
|
|
// Issue a load which will fault if arg is nil.
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(arm.AMOVB)
|
2016-05-06 10:13:31 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-05-06 10:13:31 -07:00
|
|
|
gc.AddAux(&p.From, v)
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = arm.REGTMP
|
2016-12-07 18:14:35 -08:00
|
|
|
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
|
|
|
|
|
gc.Warnl(v.Pos, "generated nil check")
|
2016-05-06 10:13:31 -07:00
|
|
|
}
|
2016-07-27 12:33:08 -04:00
|
|
|
case ssa.OpARMLoweredZero:
|
2016-05-13 15:31:14 -04:00
|
|
|
// MOVW.P Rarg2, 4(R1)
|
|
|
|
|
// CMP Rarg1, R1
|
2016-07-27 12:33:08 -04:00
|
|
|
// BLE -2(PC)
|
|
|
|
|
// arg1 is the address of the last element to zero
|
2016-05-13 15:31:14 -04:00
|
|
|
// arg2 is known to be zero
|
2016-07-27 12:33:08 -04:00
|
|
|
// auxint is alignment
|
|
|
|
|
var sz int64
|
|
|
|
|
var mov obj.As
|
|
|
|
|
switch {
|
|
|
|
|
case v.AuxInt%4 == 0:
|
|
|
|
|
sz = 4
|
|
|
|
|
mov = arm.AMOVW
|
|
|
|
|
case v.AuxInt%2 == 0:
|
|
|
|
|
sz = 2
|
|
|
|
|
mov = arm.AMOVH
|
|
|
|
|
default:
|
2016-06-27 16:54:57 -04:00
|
|
|
sz = 1
|
|
|
|
|
mov = arm.AMOVB
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(mov)
|
2016-05-13 15:31:14 -04:00
|
|
|
p.Scond = arm.C_PBIT
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[2].Reg()
|
2016-05-13 15:31:14 -04:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Reg = arm.REG_R1
|
2016-06-27 16:54:57 -04:00
|
|
|
p.To.Offset = sz
|
2017-03-20 08:01:28 -07:00
|
|
|
p2 := s.Prog(arm.ACMP)
|
2016-05-13 15:31:14 -04:00
|
|
|
p2.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p2.From.Reg = v.Args[1].Reg()
|
2016-05-13 15:31:14 -04:00
|
|
|
p2.Reg = arm.REG_R1
|
2017-03-20 08:01:28 -07:00
|
|
|
p3 := s.Prog(arm.ABLE)
|
2016-05-13 15:31:14 -04:00
|
|
|
p3.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
gc.Patch(p3, p)
|
2016-07-27 12:33:08 -04:00
|
|
|
case ssa.OpARMLoweredMove:
|
2016-05-13 15:31:14 -04:00
|
|
|
// MOVW.P 4(R1), Rtmp
|
|
|
|
|
// MOVW.P Rtmp, 4(R2)
|
|
|
|
|
// CMP Rarg2, R1
|
2016-07-27 12:33:08 -04:00
|
|
|
// BLE -3(PC)
|
|
|
|
|
// arg2 is the address of the last element of src
|
|
|
|
|
// auxint is alignment
|
|
|
|
|
var sz int64
|
|
|
|
|
var mov obj.As
|
|
|
|
|
switch {
|
|
|
|
|
case v.AuxInt%4 == 0:
|
|
|
|
|
sz = 4
|
|
|
|
|
mov = arm.AMOVW
|
|
|
|
|
case v.AuxInt%2 == 0:
|
|
|
|
|
sz = 2
|
|
|
|
|
mov = arm.AMOVH
|
|
|
|
|
default:
|
2016-06-27 16:54:57 -04:00
|
|
|
sz = 1
|
|
|
|
|
mov = arm.AMOVB
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(mov)
|
2016-05-13 15:31:14 -04:00
|
|
|
p.Scond = arm.C_PBIT
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = arm.REG_R1
|
2016-06-27 16:54:57 -04:00
|
|
|
p.From.Offset = sz
|
2016-05-13 15:31:14 -04:00
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = arm.REGTMP
|
2017-03-20 08:01:28 -07:00
|
|
|
p2 := s.Prog(mov)
|
2016-05-13 15:31:14 -04:00
|
|
|
p2.Scond = arm.C_PBIT
|
|
|
|
|
p2.From.Type = obj.TYPE_REG
|
|
|
|
|
p2.From.Reg = arm.REGTMP
|
|
|
|
|
p2.To.Type = obj.TYPE_MEM
|
|
|
|
|
p2.To.Reg = arm.REG_R2
|
2016-06-27 16:54:57 -04:00
|
|
|
p2.To.Offset = sz
|
2017-03-20 08:01:28 -07:00
|
|
|
p3 := s.Prog(arm.ACMP)
|
2016-05-13 15:31:14 -04:00
|
|
|
p3.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p3.From.Reg = v.Args[2].Reg()
|
2016-05-13 15:31:14 -04:00
|
|
|
p3.Reg = arm.REG_R1
|
2017-03-20 08:01:28 -07:00
|
|
|
p4 := s.Prog(arm.ABLE)
|
2016-05-13 15:31:14 -04:00
|
|
|
p4.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
gc.Patch(p4, p)
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.OpARMEqual,
|
|
|
|
|
ssa.OpARMNotEqual,
|
|
|
|
|
ssa.OpARMLessThan,
|
|
|
|
|
ssa.OpARMLessEqual,
|
|
|
|
|
ssa.OpARMGreaterThan,
|
|
|
|
|
ssa.OpARMGreaterEqual,
|
|
|
|
|
ssa.OpARMLessThanU,
|
|
|
|
|
ssa.OpARMLessEqualU,
|
|
|
|
|
ssa.OpARMGreaterThanU,
|
|
|
|
|
ssa.OpARMGreaterEqualU:
|
2016-05-13 11:25:07 -04:00
|
|
|
// generate boolean values
|
|
|
|
|
// use conditional move
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(arm.AMOVW)
|
2016-05-13 11:25:07 -04:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = 0
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p = s.Prog(arm.AMOVW)
|
2016-05-13 11:25:07 -04:00
|
|
|
p.Scond = condBits[v.Op]
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = 1
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-05-25 09:49:28 -04:00
|
|
|
case ssa.OpARMLoweredGetClosurePtr:
|
2016-07-03 13:40:03 -07:00
|
|
|
// Closure pointer is R7 (arm.REGCTXT).
|
|
|
|
|
gc.CheckLoweredGetClosurePtr(v)
|
2016-06-13 16:49:09 -04:00
|
|
|
case ssa.OpARMFlagEQ,
|
|
|
|
|
ssa.OpARMFlagLT_ULT,
|
|
|
|
|
ssa.OpARMFlagLT_UGT,
|
|
|
|
|
ssa.OpARMFlagGT_ULT,
|
|
|
|
|
ssa.OpARMFlagGT_UGT:
|
|
|
|
|
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
|
|
|
|
|
case ssa.OpARMInvertFlags:
|
|
|
|
|
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
2016-03-21 22:57:26 -07:00
|
|
|
default:
|
2016-09-14 10:01:05 -07:00
|
|
|
v.Fatalf("genValue not implemented: %s", v.LongString())
|
2016-03-21 22:57:26 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 11:25:07 -04:00
|
|
|
var condBits = map[ssa.Op]uint8{
|
|
|
|
|
ssa.OpARMEqual: arm.C_SCOND_EQ,
|
|
|
|
|
ssa.OpARMNotEqual: arm.C_SCOND_NE,
|
|
|
|
|
ssa.OpARMLessThan: arm.C_SCOND_LT,
|
|
|
|
|
ssa.OpARMLessThanU: arm.C_SCOND_LO,
|
|
|
|
|
ssa.OpARMLessEqual: arm.C_SCOND_LE,
|
|
|
|
|
ssa.OpARMLessEqualU: arm.C_SCOND_LS,
|
|
|
|
|
ssa.OpARMGreaterThan: arm.C_SCOND_GT,
|
|
|
|
|
ssa.OpARMGreaterThanU: arm.C_SCOND_HI,
|
|
|
|
|
ssa.OpARMGreaterEqual: arm.C_SCOND_GE,
|
|
|
|
|
ssa.OpARMGreaterEqualU: arm.C_SCOND_HS,
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-06 10:13:31 -07:00
|
|
|
var blockJump = map[ssa.BlockKind]struct {
|
|
|
|
|
asm, invasm obj.As
|
|
|
|
|
}{
|
|
|
|
|
ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
|
|
|
|
|
ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
|
|
|
|
|
ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
|
|
|
|
|
ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
|
|
|
|
|
ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
|
|
|
|
|
ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
|
2016-05-13 11:25:07 -04:00
|
|
|
ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
|
|
|
|
|
ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
|
2016-05-06 10:13:31 -07:00
|
|
|
ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
|
|
|
|
|
ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 22:57:26 -07:00
|
|
|
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
|
|
|
|
switch b.Kind {
|
2016-09-13 17:01:01 -07:00
|
|
|
case ssa.BlockPlain:
|
2016-04-28 16:52:47 -07:00
|
|
|
if b.Succs[0].Block() != next {
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.AJMP)
|
2016-03-21 22:57:26 -07:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
2016-04-28 16:52:47 -07:00
|
|
|
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
|
2016-03-21 22:57:26 -07:00
|
|
|
}
|
2016-05-06 10:13:31 -07:00
|
|
|
|
2016-05-15 00:12:56 -04:00
|
|
|
case ssa.BlockDefer:
|
|
|
|
|
// defer returns in R0:
|
|
|
|
|
// 0 if we should continue executing
|
|
|
|
|
// 1 if we should jump to deferreturn call
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(arm.ACMP)
|
2016-05-15 00:12:56 -04:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = 0
|
|
|
|
|
p.Reg = arm.REG_R0
|
2017-03-20 08:01:28 -07:00
|
|
|
p = s.Prog(arm.ABNE)
|
2016-05-15 00:12:56 -04:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
|
|
|
|
|
if b.Succs[0].Block() != next {
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.AJMP)
|
2016-05-15 00:12:56 -04:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 15:22:56 -04:00
|
|
|
case ssa.BlockExit:
|
2017-03-20 08:01:28 -07:00
|
|
|
s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
|
2016-05-13 15:22:56 -04:00
|
|
|
|
2016-03-21 22:57:26 -07:00
|
|
|
case ssa.BlockRet:
|
2017-03-20 08:01:28 -07:00
|
|
|
s.Prog(obj.ARET)
|
2016-05-06 10:13:31 -07:00
|
|
|
|
2016-05-15 00:12:56 -04:00
|
|
|
case ssa.BlockRetJmp:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.ARET)
|
2016-05-15 00:12:56 -04:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
2017-02-06 13:30:40 -08:00
|
|
|
p.To.Sym = b.Aux.(*obj.LSym)
|
2016-05-15 00:12:56 -04:00
|
|
|
|
2016-05-06 10:13:31 -07:00
|
|
|
case ssa.BlockARMEQ, ssa.BlockARMNE,
|
|
|
|
|
ssa.BlockARMLT, ssa.BlockARMGE,
|
|
|
|
|
ssa.BlockARMLE, ssa.BlockARMGT,
|
|
|
|
|
ssa.BlockARMULT, ssa.BlockARMUGT,
|
|
|
|
|
ssa.BlockARMULE, ssa.BlockARMUGE:
|
|
|
|
|
jmp := blockJump[b.Kind]
|
|
|
|
|
var p *obj.Prog
|
|
|
|
|
switch next {
|
|
|
|
|
case b.Succs[0].Block():
|
2017-03-20 08:01:28 -07:00
|
|
|
p = s.Prog(jmp.invasm)
|
2016-05-06 10:13:31 -07:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
|
|
|
|
|
case b.Succs[1].Block():
|
2017-03-20 08:01:28 -07:00
|
|
|
p = s.Prog(jmp.asm)
|
2016-05-06 10:13:31 -07:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
|
|
|
|
|
default:
|
2017-03-20 08:01:28 -07:00
|
|
|
p = s.Prog(jmp.asm)
|
2016-05-06 10:13:31 -07:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
|
2017-03-20 08:01:28 -07:00
|
|
|
q := s.Prog(obj.AJMP)
|
2016-05-06 10:13:31 -07:00
|
|
|
q.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
2016-09-14 10:01:05 -07:00
|
|
|
b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
|
2016-03-21 22:57:26 -07:00
|
|
|
}
|
|
|
|
|
}
|