2015-02-13 14:40:36 -05:00
|
|
|
// Derived from Inferno utils/8c/txt.c
|
|
|
|
|
// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c
|
|
|
|
|
//
|
|
|
|
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
|
|
|
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
|
|
|
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
|
|
|
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
|
|
|
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
|
|
|
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
|
|
|
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
|
|
|
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
//
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
|
//
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
|
// THE SOFTWARE.
|
|
|
|
|
|
2015-05-21 13:28:10 -04:00
|
|
|
package x86
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
import (
|
2015-05-21 13:28:10 -04:00
|
|
|
"cmd/compile/internal/big"
|
|
|
|
|
"cmd/compile/internal/gc"
|
2015-02-13 14:40:36 -05:00
|
|
|
"cmd/internal/obj"
|
2015-03-04 22:58:27 -05:00
|
|
|
"cmd/internal/obj/x86"
|
2015-02-13 14:40:36 -05:00
|
|
|
"fmt"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// TODO(rsc): Can make this bigger if we move
|
|
|
|
|
// the text segment up higher in 8l for all GOOS.
|
|
|
|
|
// At the same time, can raise StackBig in ../../runtime/stack.h.
|
|
|
|
|
var unmappedzero uint32 = 4096
|
|
|
|
|
|
2015-04-13 18:26:08 -05:00
|
|
|
// foptoas flags
|
|
|
|
|
const (
|
|
|
|
|
Frev = 1 << 0
|
|
|
|
|
Fpop = 1 << 1
|
|
|
|
|
Fpop2 = 1 << 2
|
|
|
|
|
)
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
/*
|
|
|
|
|
* return Axxx for Oxxx on type t.
|
|
|
|
|
*/
|
2016-03-07 18:00:08 -08:00
|
|
|
func optoas(op gc.Op, t *gc.Type) obj.As {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("optoas: t is nil")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
// avoid constant conversions in switches below
|
|
|
|
|
const (
|
|
|
|
|
OMINUS_ = uint32(gc.OMINUS) << 16
|
|
|
|
|
OLSH_ = uint32(gc.OLSH) << 16
|
|
|
|
|
ORSH_ = uint32(gc.ORSH) << 16
|
|
|
|
|
OADD_ = uint32(gc.OADD) << 16
|
|
|
|
|
OSUB_ = uint32(gc.OSUB) << 16
|
|
|
|
|
OMUL_ = uint32(gc.OMUL) << 16
|
|
|
|
|
ODIV_ = uint32(gc.ODIV) << 16
|
|
|
|
|
OMOD_ = uint32(gc.OMOD) << 16
|
|
|
|
|
OOR_ = uint32(gc.OOR) << 16
|
|
|
|
|
OAND_ = uint32(gc.OAND) << 16
|
|
|
|
|
OXOR_ = uint32(gc.OXOR) << 16
|
|
|
|
|
OEQ_ = uint32(gc.OEQ) << 16
|
|
|
|
|
ONE_ = uint32(gc.ONE) << 16
|
|
|
|
|
OLT_ = uint32(gc.OLT) << 16
|
|
|
|
|
OLE_ = uint32(gc.OLE) << 16
|
|
|
|
|
OGE_ = uint32(gc.OGE) << 16
|
|
|
|
|
OGT_ = uint32(gc.OGT) << 16
|
|
|
|
|
OCMP_ = uint32(gc.OCMP) << 16
|
|
|
|
|
OAS_ = uint32(gc.OAS) << 16
|
|
|
|
|
OHMUL_ = uint32(gc.OHMUL) << 16
|
|
|
|
|
OADDR_ = uint32(gc.OADDR) << 16
|
|
|
|
|
OINC_ = uint32(gc.OINC) << 16
|
|
|
|
|
ODEC_ = uint32(gc.ODEC) << 16
|
|
|
|
|
OLROT_ = uint32(gc.OLROT) << 16
|
|
|
|
|
OEXTEND_ = uint32(gc.OEXTEND) << 16
|
|
|
|
|
OCOM_ = uint32(gc.OCOM) << 16
|
|
|
|
|
)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
a := obj.AXXX
|
2015-02-13 14:40:36 -05:00
|
|
|
switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
|
|
|
|
|
default:
|
2016-03-07 08:23:55 -08:00
|
|
|
gc.Fatalf("optoas: no entry %v-%v", gc.Oconv(op, 0), t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADDR_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ALEAL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OEQ_ | gc.TBOOL,
|
|
|
|
|
OEQ_ | gc.TINT8,
|
|
|
|
|
OEQ_ | gc.TUINT8,
|
|
|
|
|
OEQ_ | gc.TINT16,
|
|
|
|
|
OEQ_ | gc.TUINT16,
|
|
|
|
|
OEQ_ | gc.TINT32,
|
|
|
|
|
OEQ_ | gc.TUINT32,
|
|
|
|
|
OEQ_ | gc.TINT64,
|
|
|
|
|
OEQ_ | gc.TUINT64,
|
|
|
|
|
OEQ_ | gc.TPTR32,
|
|
|
|
|
OEQ_ | gc.TPTR64,
|
|
|
|
|
OEQ_ | gc.TFLOAT32,
|
|
|
|
|
OEQ_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJEQ
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ONE_ | gc.TBOOL,
|
|
|
|
|
ONE_ | gc.TINT8,
|
|
|
|
|
ONE_ | gc.TUINT8,
|
|
|
|
|
ONE_ | gc.TINT16,
|
|
|
|
|
ONE_ | gc.TUINT16,
|
|
|
|
|
ONE_ | gc.TINT32,
|
|
|
|
|
ONE_ | gc.TUINT32,
|
|
|
|
|
ONE_ | gc.TINT64,
|
|
|
|
|
ONE_ | gc.TUINT64,
|
|
|
|
|
ONE_ | gc.TPTR32,
|
|
|
|
|
ONE_ | gc.TPTR64,
|
|
|
|
|
ONE_ | gc.TFLOAT32,
|
|
|
|
|
ONE_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJNE
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLT_ | gc.TINT8,
|
|
|
|
|
OLT_ | gc.TINT16,
|
|
|
|
|
OLT_ | gc.TINT32,
|
|
|
|
|
OLT_ | gc.TINT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJLT
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLT_ | gc.TUINT8,
|
|
|
|
|
OLT_ | gc.TUINT16,
|
|
|
|
|
OLT_ | gc.TUINT32,
|
|
|
|
|
OLT_ | gc.TUINT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJCS
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLE_ | gc.TINT8,
|
|
|
|
|
OLE_ | gc.TINT16,
|
|
|
|
|
OLE_ | gc.TINT32,
|
|
|
|
|
OLE_ | gc.TINT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJLE
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLE_ | gc.TUINT8,
|
|
|
|
|
OLE_ | gc.TUINT16,
|
|
|
|
|
OLE_ | gc.TUINT32,
|
|
|
|
|
OLE_ | gc.TUINT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJLS
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OGT_ | gc.TINT8,
|
|
|
|
|
OGT_ | gc.TINT16,
|
|
|
|
|
OGT_ | gc.TINT32,
|
|
|
|
|
OGT_ | gc.TINT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJGT
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OGT_ | gc.TUINT8,
|
|
|
|
|
OGT_ | gc.TUINT16,
|
|
|
|
|
OGT_ | gc.TUINT32,
|
|
|
|
|
OGT_ | gc.TUINT64,
|
|
|
|
|
OLT_ | gc.TFLOAT32,
|
|
|
|
|
OLT_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJHI
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OGE_ | gc.TINT8,
|
|
|
|
|
OGE_ | gc.TINT16,
|
|
|
|
|
OGE_ | gc.TINT32,
|
|
|
|
|
OGE_ | gc.TINT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJGE
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OGE_ | gc.TUINT8,
|
|
|
|
|
OGE_ | gc.TUINT16,
|
|
|
|
|
OGE_ | gc.TUINT32,
|
|
|
|
|
OGE_ | gc.TUINT64,
|
|
|
|
|
OLE_ | gc.TFLOAT32,
|
|
|
|
|
OLE_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AJCC
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | gc.TBOOL,
|
|
|
|
|
OCMP_ | gc.TINT8,
|
|
|
|
|
OCMP_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACMPB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | gc.TINT16,
|
|
|
|
|
OCMP_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACMPW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | gc.TINT32,
|
|
|
|
|
OCMP_ | gc.TUINT32,
|
|
|
|
|
OCMP_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACMPL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAS_ | gc.TBOOL,
|
|
|
|
|
OAS_ | gc.TINT8,
|
|
|
|
|
OAS_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAS_ | gc.TINT16,
|
|
|
|
|
OAS_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAS_ | gc.TINT32,
|
|
|
|
|
OAS_ | gc.TUINT32,
|
|
|
|
|
OAS_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAS_ | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVSS
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAS_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVSD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADD_ | gc.TINT8,
|
|
|
|
|
OADD_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AADDB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADD_ | gc.TINT16,
|
|
|
|
|
OADD_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AADDW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADD_ | gc.TINT32,
|
|
|
|
|
OADD_ | gc.TUINT32,
|
|
|
|
|
OADD_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AADDL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | gc.TINT8,
|
|
|
|
|
OSUB_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASUBB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | gc.TINT16,
|
|
|
|
|
OSUB_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASUBW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | gc.TINT32,
|
|
|
|
|
OSUB_ | gc.TUINT32,
|
|
|
|
|
OSUB_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASUBL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OINC_ | gc.TINT8,
|
|
|
|
|
OINC_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AINCB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OINC_ | gc.TINT16,
|
|
|
|
|
OINC_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AINCW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OINC_ | gc.TINT32,
|
|
|
|
|
OINC_ | gc.TUINT32,
|
|
|
|
|
OINC_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AINCL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODEC_ | gc.TINT8,
|
|
|
|
|
ODEC_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ADECB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODEC_ | gc.TINT16,
|
|
|
|
|
ODEC_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ADECW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODEC_ | gc.TINT32,
|
|
|
|
|
ODEC_ | gc.TUINT32,
|
|
|
|
|
ODEC_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ADECL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCOM_ | gc.TINT8,
|
|
|
|
|
OCOM_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ANOTB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCOM_ | gc.TINT16,
|
|
|
|
|
OCOM_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ANOTW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCOM_ | gc.TINT32,
|
|
|
|
|
OCOM_ | gc.TUINT32,
|
|
|
|
|
OCOM_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ANOTL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMINUS_ | gc.TINT8,
|
|
|
|
|
OMINUS_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ANEGB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMINUS_ | gc.TINT16,
|
|
|
|
|
OMINUS_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ANEGW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMINUS_ | gc.TINT32,
|
|
|
|
|
OMINUS_ | gc.TUINT32,
|
|
|
|
|
OMINUS_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ANEGL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAND_ | gc.TINT8,
|
|
|
|
|
OAND_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AANDB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAND_ | gc.TINT16,
|
|
|
|
|
OAND_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AANDW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAND_ | gc.TINT32,
|
|
|
|
|
OAND_ | gc.TUINT32,
|
|
|
|
|
OAND_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AANDL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OOR_ | gc.TINT8,
|
|
|
|
|
OOR_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AORB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OOR_ | gc.TINT16,
|
|
|
|
|
OOR_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AORW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OOR_ | gc.TINT32,
|
|
|
|
|
OOR_ | gc.TUINT32,
|
|
|
|
|
OOR_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AORL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OXOR_ | gc.TINT8,
|
|
|
|
|
OXOR_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AXORB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OXOR_ | gc.TINT16,
|
|
|
|
|
OXOR_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AXORW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OXOR_ | gc.TINT32,
|
|
|
|
|
OXOR_ | gc.TUINT32,
|
|
|
|
|
OXOR_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AXORL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLROT_ | gc.TINT8,
|
|
|
|
|
OLROT_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AROLB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLROT_ | gc.TINT16,
|
|
|
|
|
OLROT_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AROLW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLROT_ | gc.TINT32,
|
|
|
|
|
OLROT_ | gc.TUINT32,
|
|
|
|
|
OLROT_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AROLL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLSH_ | gc.TINT8,
|
|
|
|
|
OLSH_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASHLB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLSH_ | gc.TINT16,
|
|
|
|
|
OLSH_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASHLW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OLSH_ | gc.TINT32,
|
|
|
|
|
OLSH_ | gc.TUINT32,
|
|
|
|
|
OLSH_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASHLL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ORSH_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASHRB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ORSH_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASHRW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ORSH_ | gc.TUINT32,
|
|
|
|
|
ORSH_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASHRL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ORSH_ | gc.TINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASARB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ORSH_ | gc.TINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASARW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ORSH_ | gc.TINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASARL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OHMUL_ | gc.TINT8,
|
|
|
|
|
OMUL_ | gc.TINT8,
|
|
|
|
|
OMUL_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AIMULB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OHMUL_ | gc.TINT16,
|
|
|
|
|
OMUL_ | gc.TINT16,
|
|
|
|
|
OMUL_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AIMULW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OHMUL_ | gc.TINT32,
|
|
|
|
|
OMUL_ | gc.TINT32,
|
|
|
|
|
OMUL_ | gc.TUINT32,
|
|
|
|
|
OMUL_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AIMULL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OHMUL_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMULB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OHMUL_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMULW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OHMUL_ | gc.TUINT32,
|
|
|
|
|
OHMUL_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMULL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | gc.TINT8,
|
|
|
|
|
OMOD_ | gc.TINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AIDIVB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | gc.TUINT8,
|
|
|
|
|
OMOD_ | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ADIVB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | gc.TINT16,
|
|
|
|
|
OMOD_ | gc.TINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AIDIVW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | gc.TUINT16,
|
|
|
|
|
OMOD_ | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ADIVW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | gc.TINT32,
|
|
|
|
|
OMOD_ | gc.TINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AIDIVL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | gc.TUINT32,
|
|
|
|
|
ODIV_ | gc.TPTR32,
|
|
|
|
|
OMOD_ | gc.TUINT32,
|
|
|
|
|
OMOD_ | gc.TPTR32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ADIVL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OEXTEND_ | gc.TINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACWD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OEXTEND_ | gc.TINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACDQ
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return a
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-07 18:00:08 -08:00
|
|
|
func foptoas(op gc.Op, t *gc.Type, flg int) obj.As {
|
2015-02-23 16:07:24 -05:00
|
|
|
a := obj.AXXX
|
2015-09-24 23:21:18 +02:00
|
|
|
et := gc.Simtype[t.Etype]
|
|
|
|
|
|
|
|
|
|
// avoid constant conversions in switches below
|
|
|
|
|
const (
|
|
|
|
|
OCMP_ = uint32(gc.OCMP) << 16
|
|
|
|
|
OAS_ = uint32(gc.OAS) << 16
|
|
|
|
|
OADD_ = uint32(gc.OADD) << 16
|
|
|
|
|
OSUB_ = uint32(gc.OSUB) << 16
|
|
|
|
|
OMUL_ = uint32(gc.OMUL) << 16
|
|
|
|
|
ODIV_ = uint32(gc.ODIV) << 16
|
|
|
|
|
OMINUS_ = uint32(gc.OMINUS) << 16
|
|
|
|
|
)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-25 09:17:09 +11:00
|
|
|
if !gc.Thearch.Use387 {
|
2015-03-02 12:35:15 -05:00
|
|
|
switch uint32(op)<<16 | uint32(et) {
|
|
|
|
|
default:
|
2016-03-07 08:23:55 -08:00
|
|
|
gc.Fatalf("foptoas-sse: no entry %v-%v", gc.Oconv(op, 0), t)
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AUCOMISS
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AUCOMISD
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAS_ | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVSS
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OAS_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVSD
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADD_ | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AADDSS
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADD_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AADDSD
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASUBSS
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ASUBSD
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMUL_ | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMULSS
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMUL_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMULSD
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ADIVSS
|
2015-03-02 12:35:15 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ADIVSD
|
2015-03-02 12:35:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return a
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we need Fpop, it means we're working on
|
|
|
|
|
// two different floating-point registers, not memory.
|
|
|
|
|
// There the instruction only has a float64 form.
|
|
|
|
|
if flg&Fpop != 0 {
|
|
|
|
|
et = gc.TFLOAT64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clear Frev if unneeded
|
|
|
|
|
switch op {
|
|
|
|
|
case gc.OADD,
|
|
|
|
|
gc.OMUL:
|
|
|
|
|
flg &^= Frev
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch uint32(op)<<16 | (uint32(et)<<8 | uint32(flg)) {
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADD_ | (gc.TFLOAT32<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFADDF
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADD_ | (gc.TFLOAT64<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFADDD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OADD_ | (gc.TFLOAT64<<8 | Fpop):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFADDDP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | (gc.TFLOAT32<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFSUBF
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | (gc.TFLOAT32<<8 | Frev):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFSUBRF
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | (gc.TFLOAT64<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFSUBD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | (gc.TFLOAT64<<8 | Frev):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFSUBRD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | (gc.TFLOAT64<<8 | Fpop):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFSUBDP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OSUB_ | (gc.TFLOAT64<<8 | (Fpop | Frev)):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFSUBRDP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMUL_ | (gc.TFLOAT32<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFMULF
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMUL_ | (gc.TFLOAT64<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFMULD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMUL_ | (gc.TFLOAT64<<8 | Fpop):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFMULDP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | (gc.TFLOAT32<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFDIVF
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | (gc.TFLOAT32<<8 | Frev):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFDIVRF
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | (gc.TFLOAT64<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFDIVD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | (gc.TFLOAT64<<8 | Frev):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFDIVRD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | (gc.TFLOAT64<<8 | Fpop):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFDIVDP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case ODIV_ | (gc.TFLOAT64<<8 | (Fpop | Frev)):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFDIVRDP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | (gc.TFLOAT32<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFCOMF
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | (gc.TFLOAT32<<8 | Fpop):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFCOMFP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | (gc.TFLOAT64<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFCOMD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | (gc.TFLOAT64<<8 | Fpop):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFCOMDP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OCMP_ | (gc.TFLOAT64<<8 | Fpop2):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFCOMDPP
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMINUS_ | (gc.TFLOAT32<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFCHS
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
case OMINUS_ | (gc.TFLOAT64<<8 | 0):
|
2015-03-04 22:58:27 -05:00
|
|
|
return x86.AFCHS
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-07 08:23:55 -08:00
|
|
|
gc.Fatalf("foptoas %v %v %#x", gc.Oconv(op, 0), t, flg)
|
2015-02-13 14:40:36 -05:00
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var resvd = []int{
|
|
|
|
|
// REG_DI, // for movstring
|
|
|
|
|
// REG_SI, // for movstring
|
|
|
|
|
|
2015-03-04 22:58:27 -05:00
|
|
|
x86.REG_AX, // for divide
|
|
|
|
|
x86.REG_CX, // for shift
|
2015-06-29 13:56:27 -04:00
|
|
|
x86.REG_DX, // for divide, context
|
2015-03-04 22:58:27 -05:00
|
|
|
x86.REG_SP, // for stack
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* generate
|
|
|
|
|
* as $c, reg
|
|
|
|
|
*/
|
2016-03-07 18:00:08 -08:00
|
|
|
func gconreg(as obj.As, c int64, reg int) {
|
2015-02-13 14:40:36 -05:00
|
|
|
var n1 gc.Node
|
|
|
|
|
var n2 gc.Node
|
|
|
|
|
|
|
|
|
|
gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
|
|
|
|
|
gc.Nodreg(&n2, gc.Types[gc.TINT64], reg)
|
|
|
|
|
gins(as, &n1, &n2)
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
/*
|
|
|
|
|
* generate
|
|
|
|
|
* as $c, n
|
|
|
|
|
*/
|
2016-03-07 18:00:08 -08:00
|
|
|
func ginscon(as obj.As, c int64, n2 *gc.Node) {
|
2015-03-18 17:26:36 -04:00
|
|
|
var n1 gc.Node
|
|
|
|
|
gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
|
|
|
|
|
gins(as, &n1, n2)
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
|
|
|
|
if gc.Isint[t.Etype] || t.Etype == gc.Tptr {
|
2015-05-06 12:28:19 -04:00
|
|
|
if (n1.Op == gc.OLITERAL || n1.Op == gc.OADDR && n1.Left.Op == gc.ONAME) && n2.Op != gc.OLITERAL {
|
|
|
|
|
// Reverse comparison to place constant (including address constant) last.
|
|
|
|
|
op = gc.Brrev(op)
|
|
|
|
|
n1, n2 = n2, n1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// General case.
|
|
|
|
|
var r1, r2, g1, g2 gc.Node
|
2015-11-16 10:57:07 -08:00
|
|
|
|
|
|
|
|
// A special case to make write barriers more efficient.
|
|
|
|
|
// Comparing the first field of a named struct can be done directly.
|
|
|
|
|
base := n1
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Sym {
|
2015-11-16 10:57:07 -08:00
|
|
|
base = n1.Left
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if base.Op == gc.ONAME && base.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
|
2015-05-06 12:28:19 -04:00
|
|
|
r1 = *n1
|
|
|
|
|
} else {
|
|
|
|
|
gc.Regalloc(&r1, t, n1)
|
|
|
|
|
gc.Regalloc(&g1, n1.Type, &r1)
|
|
|
|
|
gc.Cgen(n1, &g1)
|
|
|
|
|
gmove(&g1, &r1)
|
|
|
|
|
}
|
|
|
|
|
if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] || n2.Op == gc.OADDR && n2.Left.Op == gc.ONAME && n2.Left.Class == gc.PEXTERN {
|
|
|
|
|
r2 = *n2
|
|
|
|
|
} else {
|
|
|
|
|
gc.Regalloc(&r2, t, n2)
|
|
|
|
|
gc.Regalloc(&g2, n1.Type, &r2)
|
|
|
|
|
gc.Cgen(n2, &g2)
|
|
|
|
|
gmove(&g2, &r2)
|
|
|
|
|
}
|
|
|
|
|
gins(optoas(gc.OCMP, t), &r1, &r2)
|
|
|
|
|
if r1.Op == gc.OREGISTER {
|
|
|
|
|
gc.Regfree(&g1)
|
|
|
|
|
gc.Regfree(&r1)
|
|
|
|
|
}
|
|
|
|
|
if r2.Op == gc.OREGISTER {
|
|
|
|
|
gc.Regfree(&g2)
|
|
|
|
|
gc.Regfree(&r2)
|
|
|
|
|
}
|
|
|
|
|
return gc.Gbranch(optoas(op, t), nil, likely)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
/*
|
|
|
|
|
* swap node contents
|
|
|
|
|
*/
|
|
|
|
|
func nswap(a *gc.Node, b *gc.Node) {
|
2015-02-23 16:07:24 -05:00
|
|
|
t := *a
|
2015-02-13 14:40:36 -05:00
|
|
|
*a = *b
|
|
|
|
|
*b = t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* return constant i node.
|
|
|
|
|
* overwritten by next call, but useful in calls to gins.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var ncon_n gc.Node
|
|
|
|
|
|
|
|
|
|
func ncon(i uint32) *gc.Node {
|
|
|
|
|
if ncon_n.Type == nil {
|
|
|
|
|
gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0)
|
|
|
|
|
}
|
2015-04-22 20:08:03 -07:00
|
|
|
ncon_n.SetInt(int64(i))
|
2015-02-13 14:40:36 -05:00
|
|
|
return &ncon_n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var sclean [10]gc.Node
|
|
|
|
|
|
|
|
|
|
var nsclean int
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
|
|
|
|
|
*/
|
|
|
|
|
func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
|
2015-02-17 22:13:49 -05:00
|
|
|
if !gc.Is64(n.Type) {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("split64 %v", n.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nsclean >= len(sclean) {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("split64 clean")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
sclean[nsclean].Op = gc.OEMPTY
|
|
|
|
|
nsclean++
|
|
|
|
|
switch n.Op {
|
|
|
|
|
default:
|
|
|
|
|
switch n.Op {
|
|
|
|
|
default:
|
2015-02-23 16:07:24 -05:00
|
|
|
var n1 gc.Node
|
2015-02-17 22:13:49 -05:00
|
|
|
if !dotaddable(n, &n1) {
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Igen(n, &n1, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
sclean[nsclean-1] = n1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = &n1
|
|
|
|
|
|
|
|
|
|
case gc.ONAME:
|
|
|
|
|
if n.Class == gc.PPARAMREF {
|
2015-02-23 16:07:24 -05:00
|
|
|
var n1 gc.Node
|
2015-05-15 10:02:19 -07:00
|
|
|
gc.Cgen(n.Name.Heapaddr, &n1)
|
2015-02-13 14:40:36 -05:00
|
|
|
sclean[nsclean-1] = n1
|
|
|
|
|
n = &n1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// nothing
|
|
|
|
|
case gc.OINDREG:
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*lo = *n
|
|
|
|
|
*hi = *n
|
|
|
|
|
lo.Type = gc.Types[gc.TUINT32]
|
|
|
|
|
if n.Type.Etype == gc.TINT64 {
|
|
|
|
|
hi.Type = gc.Types[gc.TINT32]
|
|
|
|
|
} else {
|
|
|
|
|
hi.Type = gc.Types[gc.TUINT32]
|
|
|
|
|
}
|
|
|
|
|
hi.Xoffset += 4
|
|
|
|
|
|
|
|
|
|
case gc.OLITERAL:
|
2015-02-23 16:07:24 -05:00
|
|
|
var n1 gc.Node
|
2015-05-07 18:43:03 -07:00
|
|
|
n.Convconst(&n1, n.Type)
|
2015-04-22 20:08:03 -07:00
|
|
|
i := n1.Int()
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
|
|
|
|
|
i >>= 32
|
|
|
|
|
if n.Type.Etype == gc.TINT64 {
|
|
|
|
|
gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i)))
|
|
|
|
|
} else {
|
|
|
|
|
gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func splitclean() {
|
|
|
|
|
if nsclean <= 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("splitclean")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
nsclean--
|
|
|
|
|
if sclean[nsclean].Op != gc.OEMPTY {
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&sclean[nsclean])
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-22 20:08:03 -07:00
|
|
|
// set up nodes representing fp constants
|
|
|
|
|
var (
|
|
|
|
|
zerof gc.Node
|
|
|
|
|
two63f gc.Node
|
|
|
|
|
two64f gc.Node
|
|
|
|
|
bignodes_did bool
|
|
|
|
|
)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
func bignodes() {
|
2015-04-22 20:08:03 -07:00
|
|
|
if bignodes_did {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
2015-04-22 20:08:03 -07:00
|
|
|
bignodes_did = true
|
|
|
|
|
|
|
|
|
|
gc.Nodconst(&zerof, gc.Types[gc.TINT64], 0)
|
2015-05-07 18:43:03 -07:00
|
|
|
zerof.Convconst(&zerof, gc.Types[gc.TFLOAT64])
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-22 20:08:03 -07:00
|
|
|
var i big.Int
|
|
|
|
|
i.SetInt64(1)
|
|
|
|
|
i.Lsh(&i, 63)
|
|
|
|
|
var bigi gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-22 20:08:03 -07:00
|
|
|
gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
|
|
|
|
|
bigi.SetBigInt(&i)
|
2015-05-07 18:43:03 -07:00
|
|
|
bigi.Convconst(&two63f, gc.Types[gc.TFLOAT64])
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-22 20:08:03 -07:00
|
|
|
gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
|
|
|
|
|
i.Lsh(&i, 1)
|
|
|
|
|
bigi.SetBigInt(&i)
|
2015-05-07 18:43:03 -07:00
|
|
|
bigi.Convconst(&two64f, gc.Types[gc.TFLOAT64])
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func memname(n *gc.Node, t *gc.Type) {
|
|
|
|
|
gc.Tempname(n, t)
|
|
|
|
|
n.Sym = gc.Lookup("." + n.Sym.Name[1:]) // keep optimizer from registerizing
|
|
|
|
|
n.Orig.Sym = n.Sym
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func gmove(f *gc.Node, t *gc.Node) {
|
|
|
|
|
if gc.Debug['M'] != 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("gmove %v -> %v\n", f, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
ft := gc.Simsimtype(f.Type)
|
|
|
|
|
tt := gc.Simsimtype(t.Type)
|
|
|
|
|
cvt := t.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Complexmove(f, t)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-01 07:54:01 +00:00
|
|
|
if gc.Isfloat[ft] || gc.Isfloat[tt] {
|
2015-02-13 14:40:36 -05:00
|
|
|
floatmove(f, t)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cannot have two integer memory operands;
|
|
|
|
|
// except 64-bit, which always copies via registers anyway.
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2016-03-07 18:00:08 -08:00
|
|
|
var a obj.As
|
2015-03-01 07:54:01 +00:00
|
|
|
if gc.Isint[ft] && gc.Isint[tt] && !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto hard
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// convert constant to desired type
|
|
|
|
|
if f.Op == gc.OLITERAL {
|
2015-02-23 16:07:24 -05:00
|
|
|
var con gc.Node
|
2015-05-07 18:43:03 -07:00
|
|
|
f.Convconst(&con, t.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
f = &con
|
|
|
|
|
ft = gc.Simsimtype(con.Type)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// value -> value copy, only one memory operand.
|
|
|
|
|
// figure out the instruction to use.
|
|
|
|
|
// break out of switch for one-instruction gins.
|
|
|
|
|
// goto rdst for "destination must be register".
|
|
|
|
|
// goto hard for "convert to cvt type first".
|
|
|
|
|
// otherwise handle and return.
|
|
|
|
|
|
|
|
|
|
switch uint32(ft)<<16 | uint32(tt) {
|
|
|
|
|
default:
|
2015-03-02 12:35:15 -05:00
|
|
|
// should not happen
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("gmove %v -> %v", f, t)
|
2015-03-02 12:35:15 -05:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* integer copy and truncate
|
|
|
|
|
*/
|
|
|
|
|
case gc.TINT8<<16 | gc.TINT8, // same size
|
|
|
|
|
gc.TINT8<<16 | gc.TUINT8,
|
|
|
|
|
gc.TUINT8<<16 | gc.TINT8,
|
|
|
|
|
gc.TUINT8<<16 | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case gc.TINT16<<16 | gc.TINT8, // truncate
|
|
|
|
|
gc.TUINT16<<16 | gc.TINT8,
|
|
|
|
|
gc.TINT32<<16 | gc.TINT8,
|
|
|
|
|
gc.TUINT32<<16 | gc.TINT8,
|
|
|
|
|
gc.TINT16<<16 | gc.TUINT8,
|
|
|
|
|
gc.TUINT16<<16 | gc.TUINT8,
|
|
|
|
|
gc.TINT32<<16 | gc.TUINT8,
|
|
|
|
|
gc.TUINT32<<16 | gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVB
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
goto rsrc
|
|
|
|
|
|
|
|
|
|
case gc.TINT64<<16 | gc.TINT8, // truncate low word
|
|
|
|
|
gc.TUINT64<<16 | gc.TINT8,
|
|
|
|
|
gc.TINT64<<16 | gc.TUINT8,
|
|
|
|
|
gc.TUINT64<<16 | gc.TUINT8:
|
2015-02-23 16:07:24 -05:00
|
|
|
var flo gc.Node
|
|
|
|
|
var fhi gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(f, &flo, &fhi)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r1, t.Type, x86.REG_AX)
|
2015-02-13 14:40:36 -05:00
|
|
|
gmove(&flo, &r1)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AMOVB, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
splitclean()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
case gc.TINT16<<16 | gc.TINT16, // same size
|
|
|
|
|
gc.TINT16<<16 | gc.TUINT16,
|
|
|
|
|
gc.TUINT16<<16 | gc.TINT16,
|
|
|
|
|
gc.TUINT16<<16 | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case gc.TINT32<<16 | gc.TINT16, // truncate
|
|
|
|
|
gc.TUINT32<<16 | gc.TINT16,
|
|
|
|
|
gc.TINT32<<16 | gc.TUINT16,
|
|
|
|
|
gc.TUINT32<<16 | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
goto rsrc
|
|
|
|
|
|
|
|
|
|
case gc.TINT64<<16 | gc.TINT16, // truncate low word
|
|
|
|
|
gc.TUINT64<<16 | gc.TINT16,
|
|
|
|
|
gc.TINT64<<16 | gc.TUINT16,
|
|
|
|
|
gc.TUINT64<<16 | gc.TUINT16:
|
2015-02-23 16:07:24 -05:00
|
|
|
var flo gc.Node
|
|
|
|
|
var fhi gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(f, &flo, &fhi)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r1, t.Type, x86.REG_AX)
|
2015-02-13 14:40:36 -05:00
|
|
|
gmove(&flo, &r1)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AMOVW, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
splitclean()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
case gc.TINT32<<16 | gc.TINT32, // same size
|
|
|
|
|
gc.TINT32<<16 | gc.TUINT32,
|
|
|
|
|
gc.TUINT32<<16 | gc.TINT32,
|
|
|
|
|
gc.TUINT32<<16 | gc.TUINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case gc.TINT64<<16 | gc.TINT32, // truncate
|
|
|
|
|
gc.TUINT64<<16 | gc.TINT32,
|
|
|
|
|
gc.TINT64<<16 | gc.TUINT32,
|
|
|
|
|
gc.TUINT64<<16 | gc.TUINT32:
|
2015-02-23 16:07:24 -05:00
|
|
|
var fhi gc.Node
|
|
|
|
|
var flo gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(f, &flo, &fhi)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r1, t.Type, x86.REG_AX)
|
2015-02-13 14:40:36 -05:00
|
|
|
gmove(&flo, &r1)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AMOVL, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
splitclean()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
case gc.TINT64<<16 | gc.TINT64, // same size
|
|
|
|
|
gc.TINT64<<16 | gc.TUINT64,
|
|
|
|
|
gc.TUINT64<<16 | gc.TINT64,
|
|
|
|
|
gc.TUINT64<<16 | gc.TUINT64:
|
2015-02-23 16:07:24 -05:00
|
|
|
var fhi gc.Node
|
|
|
|
|
var flo gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(f, &flo, &fhi)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var tlo gc.Node
|
|
|
|
|
var thi gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(t, &tlo, &thi)
|
|
|
|
|
if f.Op == gc.OLITERAL {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AMOVL, &flo, &tlo)
|
|
|
|
|
gins(x86.AMOVL, &fhi, &thi)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-06-29 13:56:27 -04:00
|
|
|
// Implementation of conversion-free x = y for int64 or uint64 x.
|
|
|
|
|
// This is generated by the code that copies small values out of closures,
|
2015-10-28 10:40:46 +13:00
|
|
|
// and that code has DX live, so avoid DX and just use AX twice.
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r1, gc.Types[gc.TUINT32], x86.REG_AX)
|
|
|
|
|
gins(x86.AMOVL, &flo, &r1)
|
|
|
|
|
gins(x86.AMOVL, &r1, &tlo)
|
2015-10-28 10:40:46 +13:00
|
|
|
gins(x86.AMOVL, &fhi, &r1)
|
|
|
|
|
gins(x86.AMOVL, &r1, &thi)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
splitclean()
|
|
|
|
|
splitclean()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* integer up-conversions
|
|
|
|
|
*/
|
|
|
|
|
case gc.TINT8<<16 | gc.TINT16, // sign extend int8
|
|
|
|
|
gc.TINT8<<16 | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVBWSX
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TINT8<<16 | gc.TINT32,
|
|
|
|
|
gc.TINT8<<16 | gc.TUINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVBLSX
|
2015-02-13 14:40:36 -05:00
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TINT8<<16 | gc.TINT64, // convert via int32
|
|
|
|
|
gc.TINT8<<16 | gc.TUINT64:
|
|
|
|
|
cvt = gc.Types[gc.TINT32]
|
|
|
|
|
|
|
|
|
|
goto hard
|
|
|
|
|
|
|
|
|
|
case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
|
|
|
|
|
gc.TUINT8<<16 | gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVBWZX
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TUINT8<<16 | gc.TINT32,
|
|
|
|
|
gc.TUINT8<<16 | gc.TUINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVBLZX
|
2015-02-13 14:40:36 -05:00
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TUINT8<<16 | gc.TINT64, // convert via uint32
|
|
|
|
|
gc.TUINT8<<16 | gc.TUINT64:
|
|
|
|
|
cvt = gc.Types[gc.TUINT32]
|
|
|
|
|
|
|
|
|
|
goto hard
|
|
|
|
|
|
|
|
|
|
case gc.TINT16<<16 | gc.TINT32, // sign extend int16
|
|
|
|
|
gc.TINT16<<16 | gc.TUINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVWLSX
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TINT16<<16 | gc.TINT64, // convert via int32
|
|
|
|
|
gc.TINT16<<16 | gc.TUINT64:
|
|
|
|
|
cvt = gc.Types[gc.TINT32]
|
|
|
|
|
|
|
|
|
|
goto hard
|
|
|
|
|
|
|
|
|
|
case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
|
|
|
|
|
gc.TUINT16<<16 | gc.TUINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVWLZX
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TUINT16<<16 | gc.TINT64, // convert via uint32
|
|
|
|
|
gc.TUINT16<<16 | gc.TUINT64:
|
|
|
|
|
cvt = gc.Types[gc.TUINT32]
|
|
|
|
|
|
|
|
|
|
goto hard
|
|
|
|
|
|
|
|
|
|
case gc.TINT32<<16 | gc.TINT64, // sign extend int32
|
|
|
|
|
gc.TINT32<<16 | gc.TUINT64:
|
2015-02-23 16:07:24 -05:00
|
|
|
var thi gc.Node
|
|
|
|
|
var tlo gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(t, &tlo, &thi)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var flo gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&flo, tlo.Type, x86.REG_AX)
|
2015-02-23 16:07:24 -05:00
|
|
|
var fhi gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&fhi, thi.Type, x86.REG_DX)
|
2015-02-13 14:40:36 -05:00
|
|
|
gmove(f, &flo)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.ACDQ, nil, nil)
|
|
|
|
|
gins(x86.AMOVL, &flo, &tlo)
|
|
|
|
|
gins(x86.AMOVL, &fhi, &thi)
|
2015-02-13 14:40:36 -05:00
|
|
|
splitclean()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
|
|
|
|
|
gc.TUINT32<<16 | gc.TUINT64:
|
2015-02-23 16:07:24 -05:00
|
|
|
var tlo gc.Node
|
|
|
|
|
var thi gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(t, &tlo, &thi)
|
|
|
|
|
|
|
|
|
|
gmove(f, &tlo)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AMOVL, ncon(0), &thi)
|
2015-02-13 14:40:36 -05:00
|
|
|
splitclean()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gins(a, f, t)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// requires register source
|
|
|
|
|
rsrc:
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&r1, f.Type, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gmove(f, &r1)
|
|
|
|
|
gins(a, &r1, t)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// requires register destination
|
|
|
|
|
rdst:
|
2015-03-02 20:34:22 -05:00
|
|
|
{
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&r1, t.Type, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-02 20:34:22 -05:00
|
|
|
gins(a, f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&r1)
|
2015-03-02 20:34:22 -05:00
|
|
|
return
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// requires register intermediate
|
|
|
|
|
hard:
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&r1, cvt, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gmove(f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func floatmove(f *gc.Node, t *gc.Node) {
|
|
|
|
|
var r1 gc.Node
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
ft := gc.Simsimtype(f.Type)
|
|
|
|
|
tt := gc.Simsimtype(t.Type)
|
|
|
|
|
cvt := t.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// cannot have two floating point memory operands.
|
2015-03-01 07:54:01 +00:00
|
|
|
if gc.Isfloat[ft] && gc.Isfloat[tt] && gc.Ismem(f) && gc.Ismem(t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto hard
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// convert constant to desired type
|
|
|
|
|
if f.Op == gc.OLITERAL {
|
2015-02-23 16:07:24 -05:00
|
|
|
var con gc.Node
|
2015-05-07 18:43:03 -07:00
|
|
|
f.Convconst(&con, t.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
f = &con
|
|
|
|
|
ft = gc.Simsimtype(con.Type)
|
|
|
|
|
|
|
|
|
|
// some constants can't move directly to memory.
|
2015-02-17 22:13:49 -05:00
|
|
|
if gc.Ismem(t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// float constants come from memory.
|
2015-03-01 07:54:01 +00:00
|
|
|
if gc.Isfloat[tt] {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto hard
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// value -> value copy, only one memory operand.
|
|
|
|
|
// figure out the instruction to use.
|
|
|
|
|
// break out of switch for one-instruction gins.
|
|
|
|
|
// goto rdst for "destination must be register".
|
|
|
|
|
// goto hard for "convert to cvt type first".
|
|
|
|
|
// otherwise handle and return.
|
|
|
|
|
|
|
|
|
|
switch uint32(ft)<<16 | uint32(tt) {
|
|
|
|
|
default:
|
2015-03-25 09:17:09 +11:00
|
|
|
if gc.Thearch.Use387 {
|
2015-02-13 14:40:36 -05:00
|
|
|
floatmove_387(f, t)
|
2015-03-25 09:17:09 +11:00
|
|
|
} else {
|
|
|
|
|
floatmove_sse(f, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// float to very long integer.
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TINT64,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TINT64:
|
|
|
|
|
if f.Op == gc.OREGISTER {
|
|
|
|
|
cvt = f.Type
|
|
|
|
|
goto hardmem
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r1, gc.Types[ft], x86.REG_F0)
|
2015-02-13 14:40:36 -05:00
|
|
|
if ft == gc.TFLOAT32 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVF, f, &r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVD, f, &r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set round to zero mode during conversion
|
2015-02-23 16:07:24 -05:00
|
|
|
var t1 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
memname(&t1, gc.Types[gc.TUINT16])
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var t2 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
memname(&t2, gc.Types[gc.TUINT16])
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFSTCW, nil, &t1)
|
|
|
|
|
gins(x86.AMOVW, ncon(0xf7f), &t2)
|
|
|
|
|
gins(x86.AFLDCW, &t2, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
if tt == gc.TINT16 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVWP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else if tt == gc.TINT32 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVLP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVVP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFLDCW, &t1, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TUINT64,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TUINT64:
|
2015-02-17 22:13:49 -05:00
|
|
|
if !gc.Ismem(f) {
|
2015-02-13 14:40:36 -05:00
|
|
|
cvt = f.Type
|
|
|
|
|
goto hardmem
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bignodes()
|
2015-02-23 16:07:24 -05:00
|
|
|
var f0 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&f0, gc.Types[ft], x86.REG_F0)
|
2015-02-23 16:07:24 -05:00
|
|
|
var f1 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&f1, gc.Types[ft], x86.REG_F0+1)
|
2015-02-23 16:07:24 -05:00
|
|
|
var ax gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if ft == gc.TFLOAT32 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVF, f, &f0)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVD, f, &f0)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if 0 > v { answer = 0 }
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVD, &zerof, &f0)
|
2016-01-12 12:42:28 -08:00
|
|
|
gins(x86.AFUCOMP, &f0, &f1)
|
|
|
|
|
gins(x86.AFSTSW, nil, &ax)
|
|
|
|
|
gins(x86.ASAHF, nil, nil)
|
2015-02-23 16:07:24 -05:00
|
|
|
p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// if 1<<64 <= v { answer = 0 too }
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVD, &two64f, &f0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-01-12 12:42:28 -08:00
|
|
|
gins(x86.AFUCOMP, &f0, &f1)
|
|
|
|
|
gins(x86.AFSTSW, nil, &ax)
|
|
|
|
|
gins(x86.ASAHF, nil, nil)
|
2015-02-23 16:07:24 -05:00
|
|
|
p2 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Patch(p1, gc.Pc)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVVP, &f0, t) // don't care about t, but will pop the stack
|
2015-02-23 16:07:24 -05:00
|
|
|
var thi gc.Node
|
|
|
|
|
var tlo gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(t, &tlo, &thi)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AMOVL, ncon(0), &tlo)
|
|
|
|
|
gins(x86.AMOVL, ncon(0), &thi)
|
2015-02-13 14:40:36 -05:00
|
|
|
splitclean()
|
|
|
|
|
p1 = gc.Gbranch(obj.AJMP, nil, 0)
|
|
|
|
|
gc.Patch(p2, gc.Pc)
|
|
|
|
|
|
|
|
|
|
// in range; algorithm is:
|
|
|
|
|
// if small enough, use native float64 -> int64 conversion.
|
|
|
|
|
// otherwise, subtract 2^63, convert, and add it back.
|
|
|
|
|
|
|
|
|
|
// set round to zero mode during conversion
|
2015-02-23 16:07:24 -05:00
|
|
|
var t1 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
memname(&t1, gc.Types[gc.TUINT16])
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var t2 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
memname(&t2, gc.Types[gc.TUINT16])
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFSTCW, nil, &t1)
|
|
|
|
|
gins(x86.AMOVW, ncon(0xf7f), &t2)
|
|
|
|
|
gins(x86.AFLDCW, &t2, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// actual work
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVD, &two63f, &f0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-01-12 12:42:28 -08:00
|
|
|
gins(x86.AFUCOMP, &f0, &f1)
|
|
|
|
|
gins(x86.AFSTSW, nil, &ax)
|
|
|
|
|
gins(x86.ASAHF, nil, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
p2 = gc.Gbranch(optoas(gc.OLE, gc.Types[tt]), nil, 0)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVVP, &f0, t)
|
2015-02-23 16:07:24 -05:00
|
|
|
p3 := gc.Gbranch(obj.AJMP, nil, 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Patch(p2, gc.Pc)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVD, &two63f, &f0)
|
|
|
|
|
gins(x86.AFSUBDP, &f0, &f1)
|
|
|
|
|
gins(x86.AFMOVVP, &f0, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(t, &tlo, &thi)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AXORL, ncon(0x80000000), &thi) // + 2^63
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Patch(p3, gc.Pc)
|
|
|
|
|
splitclean()
|
|
|
|
|
|
|
|
|
|
// restore rounding mode
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFLDCW, &t1, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gc.Patch(p1, gc.Pc)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* integer to float
|
|
|
|
|
*/
|
|
|
|
|
case gc.TINT64<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TINT64<<16 | gc.TFLOAT64:
|
|
|
|
|
if t.Op == gc.OREGISTER {
|
|
|
|
|
goto hardmem
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
var f0 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&f0, t.Type, x86.REG_F0)
|
|
|
|
|
gins(x86.AFMOVV, f, &f0)
|
2015-02-13 14:40:36 -05:00
|
|
|
if tt == gc.TFLOAT32 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVFP, &f0, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVDP, &f0, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// algorithm is:
|
|
|
|
|
// if small enough, use native int64 -> float64 conversion.
|
|
|
|
|
// otherwise, halve (rounding to odd?), convert, and double.
|
|
|
|
|
case gc.TUINT64<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TUINT64<<16 | gc.TFLOAT64:
|
2015-02-23 16:07:24 -05:00
|
|
|
var ax gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&ax, gc.Types[gc.TUINT32], x86.REG_AX)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var dx gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&dx, gc.Types[gc.TUINT32], x86.REG_DX)
|
2015-02-23 16:07:24 -05:00
|
|
|
var cx gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&cx, gc.Types[gc.TUINT32], x86.REG_CX)
|
2015-02-23 16:07:24 -05:00
|
|
|
var t1 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Tempname(&t1, f.Type)
|
2015-02-23 16:07:24 -05:00
|
|
|
var tlo gc.Node
|
|
|
|
|
var thi gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(&t1, &tlo, &thi)
|
|
|
|
|
gmove(f, &t1)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.ACMPL, &thi, ncon(0))
|
|
|
|
|
p1 := gc.Gbranch(x86.AJLT, nil, 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// native
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r1, gc.Types[tt], x86.REG_F0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVV, &t1, &r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
if tt == gc.TFLOAT32 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVFP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVDP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
p2 := gc.Gbranch(obj.AJMP, nil, 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// simulated
|
|
|
|
|
gc.Patch(p1, gc.Pc)
|
|
|
|
|
|
|
|
|
|
gmove(&tlo, &ax)
|
|
|
|
|
gmove(&thi, &dx)
|
2015-03-04 22:58:27 -05:00
|
|
|
p1 = gins(x86.ASHRL, ncon(1), &ax)
|
|
|
|
|
p1.From.Index = x86.REG_DX // double-width shift DX -> AX
|
2015-02-13 14:40:36 -05:00
|
|
|
p1.From.Scale = 0
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AMOVL, ncon(0), &cx)
|
|
|
|
|
gins(x86.ASETCC, nil, &cx)
|
|
|
|
|
gins(x86.AORL, &cx, &ax)
|
|
|
|
|
gins(x86.ASHRL, ncon(1), &dx)
|
2015-02-13 14:40:36 -05:00
|
|
|
gmove(&dx, &thi)
|
|
|
|
|
gmove(&ax, &tlo)
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r1, gc.Types[tt], x86.REG_F0)
|
2015-02-23 16:07:24 -05:00
|
|
|
var r2 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r2, gc.Types[tt], x86.REG_F0+1)
|
|
|
|
|
gins(x86.AFMOVV, &t1, &r1)
|
|
|
|
|
gins(x86.AFMOVD, &r1, &r1)
|
|
|
|
|
gins(x86.AFADDDP, &r1, &r2)
|
2015-02-13 14:40:36 -05:00
|
|
|
if tt == gc.TFLOAT32 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVFP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVDP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
gc.Patch(p2, gc.Pc)
|
|
|
|
|
splitclean()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// requires register intermediate
|
|
|
|
|
hard:
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&r1, cvt, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gmove(f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// requires memory intermediate
|
|
|
|
|
hardmem:
|
|
|
|
|
gc.Tempname(&r1, cvt)
|
|
|
|
|
|
|
|
|
|
gmove(f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func floatmove_387(f *gc.Node, t *gc.Node) {
|
|
|
|
|
var r1 gc.Node
|
2016-03-07 18:00:08 -08:00
|
|
|
var a obj.As
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
ft := gc.Simsimtype(f.Type)
|
|
|
|
|
tt := gc.Simsimtype(t.Type)
|
|
|
|
|
cvt := t.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
switch uint32(ft)<<16 | uint32(tt) {
|
|
|
|
|
default:
|
|
|
|
|
goto fatal
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* float to integer
|
|
|
|
|
*/
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TINT16,
|
|
|
|
|
gc.TFLOAT32<<16 | gc.TINT32,
|
|
|
|
|
gc.TFLOAT32<<16 | gc.TINT64,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TINT16,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TINT32,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TINT64:
|
|
|
|
|
if t.Op == gc.OREGISTER {
|
|
|
|
|
goto hardmem
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-03-04 22:58:27 -05:00
|
|
|
gc.Nodreg(&r1, gc.Types[ft], x86.REG_F0)
|
2015-02-13 14:40:36 -05:00
|
|
|
if f.Op != gc.OREGISTER {
|
|
|
|
|
if ft == gc.TFLOAT32 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVF, f, &r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVD, f, &r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set round to zero mode during conversion
|
2015-02-23 16:07:24 -05:00
|
|
|
var t1 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
memname(&t1, gc.Types[gc.TUINT16])
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var t2 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
memname(&t2, gc.Types[gc.TUINT16])
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFSTCW, nil, &t1)
|
|
|
|
|
gins(x86.AMOVW, ncon(0xf7f), &t2)
|
|
|
|
|
gins(x86.AFLDCW, &t2, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
if tt == gc.TINT16 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVWP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else if tt == gc.TINT32 {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVLP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVVP, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFLDCW, &t1, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// convert via int32.
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TINT8,
|
|
|
|
|
gc.TFLOAT32<<16 | gc.TUINT16,
|
|
|
|
|
gc.TFLOAT32<<16 | gc.TUINT8,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TINT8,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TUINT16,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TUINT8:
|
2015-02-23 16:07:24 -05:00
|
|
|
var t1 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Tempname(&t1, gc.Types[gc.TINT32])
|
|
|
|
|
|
|
|
|
|
gmove(f, &t1)
|
|
|
|
|
switch tt {
|
|
|
|
|
default:
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("gmove %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case gc.TINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.ACMPL, &t1, ncon(-0x80&(1<<32-1)))
|
2015-02-23 16:07:24 -05:00
|
|
|
p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TINT32]), nil, -1)
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.ACMPL, &t1, ncon(0x7f))
|
2015-02-23 16:07:24 -05:00
|
|
|
p2 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TINT32]), nil, -1)
|
|
|
|
|
p3 := gc.Gbranch(obj.AJMP, nil, 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Patch(p1, gc.Pc)
|
|
|
|
|
gc.Patch(p2, gc.Pc)
|
|
|
|
|
gmove(ncon(-0x80&(1<<32-1)), &t1)
|
|
|
|
|
gc.Patch(p3, gc.Pc)
|
|
|
|
|
gmove(&t1, t)
|
|
|
|
|
|
|
|
|
|
case gc.TUINT8:
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.ATESTL, ncon(0xffffff00), &t1)
|
|
|
|
|
p1 := gc.Gbranch(x86.AJEQ, nil, +1)
|
|
|
|
|
gins(x86.AMOVL, ncon(0), &t1)
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Patch(p1, gc.Pc)
|
|
|
|
|
gmove(&t1, t)
|
|
|
|
|
|
|
|
|
|
case gc.TUINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.ATESTL, ncon(0xffff0000), &t1)
|
|
|
|
|
p1 := gc.Gbranch(x86.AJEQ, nil, +1)
|
|
|
|
|
gins(x86.AMOVL, ncon(0), &t1)
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Patch(p1, gc.Pc)
|
|
|
|
|
gmove(&t1, t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// convert via int64.
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TUINT32,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TUINT32:
|
|
|
|
|
cvt = gc.Types[gc.TINT64]
|
|
|
|
|
|
|
|
|
|
goto hardmem
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* integer to float
|
|
|
|
|
*/
|
|
|
|
|
case gc.TINT16<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TINT16<<16 | gc.TFLOAT64,
|
|
|
|
|
gc.TINT32<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TINT32<<16 | gc.TFLOAT64,
|
|
|
|
|
gc.TINT64<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TINT64<<16 | gc.TFLOAT64:
|
|
|
|
|
if t.Op != gc.OREGISTER {
|
|
|
|
|
goto hard
|
|
|
|
|
}
|
|
|
|
|
if f.Op == gc.OREGISTER {
|
|
|
|
|
cvt = f.Type
|
|
|
|
|
goto hardmem
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ft {
|
|
|
|
|
case gc.TINT16:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AFMOVW
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case gc.TINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AFMOVL
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
default:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AFMOVV
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// convert via int32 memory
|
|
|
|
|
case gc.TINT8<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TINT8<<16 | gc.TFLOAT64,
|
|
|
|
|
gc.TUINT16<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TUINT16<<16 | gc.TFLOAT64,
|
|
|
|
|
gc.TUINT8<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TUINT8<<16 | gc.TFLOAT64:
|
|
|
|
|
cvt = gc.Types[gc.TINT32]
|
|
|
|
|
|
|
|
|
|
goto hardmem
|
|
|
|
|
|
|
|
|
|
// convert via int64 memory
|
|
|
|
|
case gc.TUINT32<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TUINT32<<16 | gc.TFLOAT64:
|
|
|
|
|
cvt = gc.Types[gc.TINT64]
|
|
|
|
|
|
|
|
|
|
goto hardmem
|
|
|
|
|
|
|
|
|
|
// The way the code generator uses floating-point
|
|
|
|
|
// registers, a move from F0 to F0 is intended as a no-op.
|
|
|
|
|
// On the x86, it's not: it pushes a second copy of F0
|
2016-03-01 23:21:55 +00:00
|
|
|
// on the floating point stack. So toss it away here.
|
2015-02-13 14:40:36 -05:00
|
|
|
// Also, F0 is the *only* register we ever evaluate
|
|
|
|
|
// into, so we should only see register/register as F0/F0.
|
|
|
|
|
/*
|
|
|
|
|
* float to float
|
|
|
|
|
*/
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TFLOAT64:
|
2015-02-17 22:13:49 -05:00
|
|
|
if gc.Ismem(f) && gc.Ismem(t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto hard
|
|
|
|
|
}
|
|
|
|
|
if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
|
2015-04-13 10:28:57 -07:00
|
|
|
if f.Reg != x86.REG_F0 || t.Reg != x86.REG_F0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto fatal
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AFMOVF
|
2015-02-13 14:40:36 -05:00
|
|
|
if ft == gc.TFLOAT64 {
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AFMOVD
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if gc.Ismem(t) {
|
2015-04-13 10:28:57 -07:00
|
|
|
if f.Op != gc.OREGISTER || f.Reg != x86.REG_F0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("gmove %v", f)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AFMOVFP
|
2015-02-13 14:40:36 -05:00
|
|
|
if ft == gc.TFLOAT64 {
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AFMOVDP
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TFLOAT64:
|
2015-02-17 22:13:49 -05:00
|
|
|
if gc.Ismem(f) && gc.Ismem(t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto hard
|
|
|
|
|
}
|
|
|
|
|
if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
|
2015-04-13 10:28:57 -07:00
|
|
|
if f.Reg != x86.REG_F0 || t.Reg != x86.REG_F0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto fatal
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if f.Op == gc.OREGISTER {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVDP, f, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVF, f, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
case gc.TFLOAT64<<16 | gc.TFLOAT32:
|
2015-02-17 22:13:49 -05:00
|
|
|
if gc.Ismem(f) && gc.Ismem(t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto hard
|
|
|
|
|
}
|
|
|
|
|
if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Tempname(&r1, gc.Types[gc.TFLOAT32])
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVFP, f, &r1)
|
|
|
|
|
gins(x86.AFMOVF, &r1, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if f.Op == gc.OREGISTER {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVFP, f, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-04 22:58:27 -05:00
|
|
|
gins(x86.AFMOVD, f, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gins(a, f, t)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// requires register intermediate
|
|
|
|
|
hard:
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&r1, cvt, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gmove(f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// requires memory intermediate
|
|
|
|
|
hardmem:
|
|
|
|
|
gc.Tempname(&r1, cvt)
|
|
|
|
|
|
|
|
|
|
gmove(f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// should not happen
|
|
|
|
|
fatal:
|
2016-03-15 13:06:58 -07:00
|
|
|
gc.Fatalf("gmove %v -> %v", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func floatmove_sse(f *gc.Node, t *gc.Node) {
|
|
|
|
|
var r1 gc.Node
|
|
|
|
|
var cvt *gc.Type
|
2016-03-07 18:00:08 -08:00
|
|
|
var a obj.As
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
ft := gc.Simsimtype(f.Type)
|
|
|
|
|
tt := gc.Simsimtype(t.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
switch uint32(ft)<<16 | uint32(tt) {
|
|
|
|
|
// should not happen
|
|
|
|
|
default:
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("gmove %v -> %v", f, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// convert via int32.
|
|
|
|
|
/*
|
|
|
|
|
* float to integer
|
|
|
|
|
*/
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TINT16,
|
|
|
|
|
gc.TFLOAT32<<16 | gc.TINT8,
|
|
|
|
|
gc.TFLOAT32<<16 | gc.TUINT16,
|
|
|
|
|
gc.TFLOAT32<<16 | gc.TUINT8,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TINT16,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TINT8,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TUINT16,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TUINT8:
|
|
|
|
|
cvt = gc.Types[gc.TINT32]
|
|
|
|
|
|
|
|
|
|
goto hard
|
|
|
|
|
|
|
|
|
|
// convert via int64.
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TUINT32,
|
|
|
|
|
gc.TFLOAT64<<16 | gc.TUINT32:
|
|
|
|
|
cvt = gc.Types[gc.TINT64]
|
|
|
|
|
|
|
|
|
|
goto hardmem
|
|
|
|
|
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACVTTSS2SL
|
2015-02-13 14:40:36 -05:00
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TFLOAT64<<16 | gc.TINT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACVTTSD2SL
|
2015-02-13 14:40:36 -05:00
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
// convert via int32 memory
|
|
|
|
|
/*
|
|
|
|
|
* integer to float
|
|
|
|
|
*/
|
|
|
|
|
case gc.TINT8<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TINT8<<16 | gc.TFLOAT64,
|
|
|
|
|
gc.TINT16<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TINT16<<16 | gc.TFLOAT64,
|
|
|
|
|
gc.TUINT16<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TUINT16<<16 | gc.TFLOAT64,
|
|
|
|
|
gc.TUINT8<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TUINT8<<16 | gc.TFLOAT64:
|
|
|
|
|
cvt = gc.Types[gc.TINT32]
|
|
|
|
|
|
|
|
|
|
goto hard
|
|
|
|
|
|
|
|
|
|
// convert via int64 memory
|
|
|
|
|
case gc.TUINT32<<16 | gc.TFLOAT32,
|
|
|
|
|
gc.TUINT32<<16 | gc.TFLOAT64:
|
|
|
|
|
cvt = gc.Types[gc.TINT64]
|
|
|
|
|
|
|
|
|
|
goto hardmem
|
|
|
|
|
|
|
|
|
|
case gc.TINT32<<16 | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACVTSL2SS
|
2015-02-13 14:40:36 -05:00
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TINT32<<16 | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACVTSL2SD
|
2015-02-13 14:40:36 -05:00
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* float to float
|
|
|
|
|
*/
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVSS
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case gc.TFLOAT64<<16 | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.AMOVSD
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case gc.TFLOAT32<<16 | gc.TFLOAT64:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACVTSS2SD
|
2015-02-13 14:40:36 -05:00
|
|
|
goto rdst
|
|
|
|
|
|
|
|
|
|
case gc.TFLOAT64<<16 | gc.TFLOAT32:
|
2015-03-04 22:58:27 -05:00
|
|
|
a = x86.ACVTSD2SS
|
2015-02-13 14:40:36 -05:00
|
|
|
goto rdst
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gins(a, f, t)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// requires register intermediate
|
|
|
|
|
hard:
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&r1, cvt, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gmove(f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// requires memory intermediate
|
|
|
|
|
hardmem:
|
|
|
|
|
gc.Tempname(&r1, cvt)
|
|
|
|
|
|
|
|
|
|
gmove(f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
// requires register destination
|
|
|
|
|
rdst:
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&r1, t.Type, t)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gins(a, f, &r1)
|
|
|
|
|
gmove(&r1, t)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&r1)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func samaddr(f *gc.Node, t *gc.Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if f.Op != t.Op {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch f.Op {
|
|
|
|
|
case gc.OREGISTER:
|
2015-04-13 10:28:57 -07:00
|
|
|
if f.Reg != t.Reg {
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* generate one instruction:
|
|
|
|
|
* as f, t
|
|
|
|
|
*/
|
2016-03-07 18:00:08 -08:00
|
|
|
func gins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
|
2015-03-04 22:58:27 -05:00
|
|
|
if as == x86.AFMOVF && f != nil && f.Op == gc.OREGISTER && t != nil && t.Op == gc.OREGISTER {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("gins MOVF reg, reg")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-04 22:58:27 -05:00
|
|
|
if as == x86.ACVTSD2SS && f != nil && f.Op == gc.OLITERAL {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("gins CVTSD2SS const")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-04-13 10:28:57 -07:00
|
|
|
if as == x86.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.Reg == x86.REG_F0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("gins MOVSD into F0")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
if as == x86.AMOVL && f != nil && f.Op == gc.OADDR && f.Left.Op == gc.ONAME && f.Left.Class != gc.PEXTERN && f.Left.Class != gc.PFUNC {
|
|
|
|
|
// Turn MOVL $xxx(FP/SP) into LEAL xxx.
|
|
|
|
|
// These should be equivalent but most of the backend
|
|
|
|
|
// only expects to see LEAL, because that's what we had
|
|
|
|
|
// historically generated. Various hidden assumptions are baked in by now.
|
|
|
|
|
as = x86.ALEAL
|
|
|
|
|
f = f.Left
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
switch as {
|
2015-03-04 22:58:27 -05:00
|
|
|
case x86.AMOVB,
|
|
|
|
|
x86.AMOVW,
|
|
|
|
|
x86.AMOVL:
|
2015-02-17 22:13:49 -05:00
|
|
|
if f != nil && t != nil && samaddr(f, t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 22:58:27 -05:00
|
|
|
case x86.ALEAL:
|
2015-02-17 22:13:49 -05:00
|
|
|
if f != nil && gc.Isconst(f, gc.CTNIL) {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("gins LEAL nil %v", f.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
p := gc.Prog(as)
|
2015-03-16 15:27:19 -04:00
|
|
|
gc.Naddr(&p.From, f)
|
|
|
|
|
gc.Naddr(&p.To, t)
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
if gc.Debug['g'] != 0 {
|
|
|
|
|
fmt.Printf("%v\n", p)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
w := 0
|
2015-02-13 14:40:36 -05:00
|
|
|
switch as {
|
2015-03-04 22:58:27 -05:00
|
|
|
case x86.AMOVB:
|
2015-02-13 14:40:36 -05:00
|
|
|
w = 1
|
|
|
|
|
|
2015-03-04 22:58:27 -05:00
|
|
|
case x86.AMOVW:
|
2015-02-13 14:40:36 -05:00
|
|
|
w = 2
|
|
|
|
|
|
2015-03-04 22:58:27 -05:00
|
|
|
case x86.AMOVL:
|
2015-02-13 14:40:36 -05:00
|
|
|
w = 4
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-16 15:27:19 -04:00
|
|
|
if true && w != 0 && f != nil && (p.From.Width > int64(w) || p.To.Width > int64(w)) {
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Dump("bad width from:", f)
|
|
|
|
|
gc.Dump("bad width to:", t)
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if p.To.Type == obj.TYPE_ADDR && w > 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("bad use of addr: %v", p)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
func ginsnop() {
|
|
|
|
|
var reg gc.Node
|
|
|
|
|
gc.Nodreg(®, gc.Types[gc.TINT], x86.REG_AX)
|
|
|
|
|
gins(x86.AXCHGL, ®, ®)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func dotaddable(n *gc.Node, n1 *gc.Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Op != gc.ODOT {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var oary [10]int64
|
|
|
|
|
var nn *gc.Node
|
|
|
|
|
o := gc.Dotoffset(n, oary[:], &nn)
|
2015-04-02 19:58:37 -07:00
|
|
|
if nn != nil && nn.Addable && o == 1 && oary[0] >= 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
*n1 = *nn
|
|
|
|
|
n1.Type = n.Type
|
|
|
|
|
n1.Xoffset += oary[0]
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func sudoclean() {
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-07 18:00:08 -08:00
|
|
|
func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
*a = obj.Addr{}
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|