summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gops/internal/obj/arm
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/gops/internal/obj/arm')
-rw-r--r--vendor/github.com/google/gops/internal/obj/arm/a.out.go338
-rw-r--r--vendor/github.com/google/gops/internal/obj/arm/anames.go108
-rw-r--r--vendor/github.com/google/gops/internal/obj/arm/anames5.go73
-rw-r--r--vendor/github.com/google/gops/internal/obj/arm/asm5.go2846
-rw-r--r--vendor/github.com/google/gops/internal/obj/arm/list5.go84
-rw-r--r--vendor/github.com/google/gops/internal/obj/arm/obj5.go1055
6 files changed, 0 insertions, 4504 deletions
diff --git a/vendor/github.com/google/gops/internal/obj/arm/a.out.go b/vendor/github.com/google/gops/internal/obj/arm/a.out.go
deleted file mode 100644
index a3e0c180..00000000
--- a/vendor/github.com/google/gops/internal/obj/arm/a.out.go
+++ /dev/null
@@ -1,338 +0,0 @@
-// Inferno utils/5c/5.out.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/5.out.h
-//
-// 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.
-
-package arm
-
-import "github.com/google/gops/internal/obj"
-
-//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm
-
-const (
- NSNAME = 8
- NSYM = 50
- NREG = 16
-)
-
-/* -1 disables use of REGARG */
-const (
- REGARG = -1
-)
-
-const (
- REG_R0 = obj.RBaseARM + iota // must be 16-aligned
- REG_R1
- REG_R2
- REG_R3
- REG_R4
- REG_R5
- REG_R6
- REG_R7
- REG_R8
- REG_R9
- REG_R10
- REG_R11
- REG_R12
- REG_R13
- REG_R14
- REG_R15
-
- REG_F0 // must be 16-aligned
- REG_F1
- REG_F2
- REG_F3
- REG_F4
- REG_F5
- REG_F6
- REG_F7
- REG_F8
- REG_F9
- REG_F10
- REG_F11
- REG_F12
- REG_F13
- REG_F14
- REG_F15
-
- REG_FPSR // must be 2-aligned
- REG_FPCR
-
- REG_CPSR // must be 2-aligned
- REG_SPSR
-
- MAXREG
- REGRET = REG_R0
- /* compiler allocates R1 up as temps */
- /* compiler allocates register variables R3 up */
- /* compiler allocates external registers R10 down */
- REGEXT = REG_R10
- /* these two registers are declared in runtime.h */
- REGG = REGEXT - 0
- REGM = REGEXT - 1
-
- REGCTXT = REG_R7
- REGTMP = REG_R11
- REGSP = REG_R13
- REGLINK = REG_R14
- REGPC = REG_R15
-
- NFREG = 16
- /* compiler allocates register variables F0 up */
- /* compiler allocates external registers F7 down */
- FREGRET = REG_F0
- FREGEXT = REG_F7
- FREGTMP = REG_F15
-)
-
-const (
- C_NONE = iota
- C_REG
- C_REGREG
- C_REGREG2
- C_REGLIST
- C_SHIFT
- C_FREG
- C_PSR
- C_FCR
-
- C_RCON /* 0xff rotated */
- C_NCON /* ~RCON */
- C_SCON /* 0xffff */
- C_LCON
- C_LCONADDR
- C_ZFCON
- C_SFCON
- C_LFCON
-
- C_RACON
- C_LACON
-
- C_SBRA
- C_LBRA
-
- C_HAUTO /* halfword insn offset (-0xff to 0xff) */
- C_FAUTO /* float insn offset (0 to 0x3fc, word aligned) */
- C_HFAUTO /* both H and F */
- C_SAUTO /* -0xfff to 0xfff */
- C_LAUTO
-
- C_HOREG
- C_FOREG
- C_HFOREG
- C_SOREG
- C_ROREG
- C_SROREG /* both nil and R */
- C_LOREG
-
- C_PC
- C_SP
- C_HREG
-
- C_ADDR /* reference to relocatable address */
-
- // TLS "var" in local exec mode: will become a constant offset from
- // thread local base that is ultimately chosen by the program linker.
- C_TLS_LE
-
- // TLS "var" in initial exec mode: will become a memory address (chosen
- // by the program linker) that the dynamic linker will fill with the
- // offset from the thread local base.
- C_TLS_IE
-
- C_TEXTSIZE
-
- C_GOK
-
- C_NCLASS /* must be the last */
-)
-
-const (
- AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
- AEOR
- ASUB
- ARSB
- AADD
- AADC
- ASBC
- ARSC
- ATST
- ATEQ
- ACMP
- ACMN
- AORR
- ABIC
-
- AMVN
-
- /*
- * Do not reorder or fragment the conditional branch
- * opcodes, or the predication code will break
- */
- ABEQ
- ABNE
- ABCS
- ABHS
- ABCC
- ABLO
- ABMI
- ABPL
- ABVS
- ABVC
- ABHI
- ABLS
- ABGE
- ABLT
- ABGT
- ABLE
-
- AMOVWD
- AMOVWF
- AMOVDW
- AMOVFW
- AMOVFD
- AMOVDF
- AMOVF
- AMOVD
-
- ACMPF
- ACMPD
- AADDF
- AADDD
- ASUBF
- ASUBD
- AMULF
- AMULD
- ADIVF
- ADIVD
- ASQRTF
- ASQRTD
- AABSF
- AABSD
- ANEGF
- ANEGD
-
- ASRL
- ASRA
- ASLL
- AMULU
- ADIVU
- AMUL
- ADIV
- AMOD
- AMODU
-
- AMOVB
- AMOVBS
- AMOVBU
- AMOVH
- AMOVHS
- AMOVHU
- AMOVW
- AMOVM
- ASWPBU
- ASWPW
-
- ARFE
- ASWI
- AMULA
-
- AWORD
-
- AMULL
- AMULAL
- AMULLU
- AMULALU
-
- ABX
- ABXRET
- ADWORD
-
- ALDREX
- ASTREX
- ALDREXD
- ASTREXD
-
- APLD
-
- ACLZ
-
- AMULWT
- AMULWB
- AMULAWT
- AMULAWB
-
- ADATABUNDLE
- ADATABUNDLEEND
-
- AMRC // MRC/MCR
-
- ALAST
-
- // aliases
- AB = obj.AJMP
- ABL = obj.ACALL
-)
-
-/* scond byte */
-const (
- C_SCOND = (1 << 4) - 1
- C_SBIT = 1 << 4
- C_PBIT = 1 << 5
- C_WBIT = 1 << 6
- C_FBIT = 1 << 7 /* psr flags-only */
- C_UBIT = 1 << 7 /* up bit, unsigned bit */
-
- // These constants are the ARM condition codes encodings,
- // XORed with 14 so that C_SCOND_NONE has value 0,
- // so that a zeroed Prog.scond means "always execute".
- C_SCOND_XOR = 14
-
- C_SCOND_EQ = 0 ^ C_SCOND_XOR
- C_SCOND_NE = 1 ^ C_SCOND_XOR
- C_SCOND_HS = 2 ^ C_SCOND_XOR
- C_SCOND_LO = 3 ^ C_SCOND_XOR
- C_SCOND_MI = 4 ^ C_SCOND_XOR
- C_SCOND_PL = 5 ^ C_SCOND_XOR
- C_SCOND_VS = 6 ^ C_SCOND_XOR
- C_SCOND_VC = 7 ^ C_SCOND_XOR
- C_SCOND_HI = 8 ^ C_SCOND_XOR
- C_SCOND_LS = 9 ^ C_SCOND_XOR
- C_SCOND_GE = 10 ^ C_SCOND_XOR
- C_SCOND_LT = 11 ^ C_SCOND_XOR
- C_SCOND_GT = 12 ^ C_SCOND_XOR
- C_SCOND_LE = 13 ^ C_SCOND_XOR
- C_SCOND_NONE = 14 ^ C_SCOND_XOR
- C_SCOND_NV = 15 ^ C_SCOND_XOR
-
- /* D_SHIFT type */
- SHIFT_LL = 0 << 5
- SHIFT_LR = 1 << 5
- SHIFT_AR = 2 << 5
- SHIFT_RR = 3 << 5
-)
diff --git a/vendor/github.com/google/gops/internal/obj/arm/anames.go b/vendor/github.com/google/gops/internal/obj/arm/anames.go
deleted file mode 100644
index 42abc946..00000000
--- a/vendor/github.com/google/gops/internal/obj/arm/anames.go
+++ /dev/null
@@ -1,108 +0,0 @@
-// Generated by stringer -i a.out.go -o anames.go -p arm
-// Do not edit.
-
-package arm
-
-import "github.com/google/gops/internal/obj"
-
-var Anames = []string{
- obj.A_ARCHSPECIFIC: "AND",
- "EOR",
- "SUB",
- "RSB",
- "ADD",
- "ADC",
- "SBC",
- "RSC",
- "TST",
- "TEQ",
- "CMP",
- "CMN",
- "ORR",
- "BIC",
- "MVN",
- "BEQ",
- "BNE",
- "BCS",
- "BHS",
- "BCC",
- "BLO",
- "BMI",
- "BPL",
- "BVS",
- "BVC",
- "BHI",
- "BLS",
- "BGE",
- "BLT",
- "BGT",
- "BLE",
- "MOVWD",
- "MOVWF",
- "MOVDW",
- "MOVFW",
- "MOVFD",
- "MOVDF",
- "MOVF",
- "MOVD",
- "CMPF",
- "CMPD",
- "ADDF",
- "ADDD",
- "SUBF",
- "SUBD",
- "MULF",
- "MULD",
- "DIVF",
- "DIVD",
- "SQRTF",
- "SQRTD",
- "ABSF",
- "ABSD",
- "NEGF",
- "NEGD",
- "SRL",
- "SRA",
- "SLL",
- "MULU",
- "DIVU",
- "MUL",
- "DIV",
- "MOD",
- "MODU",
- "MOVB",
- "MOVBS",
- "MOVBU",
- "MOVH",
- "MOVHS",
- "MOVHU",
- "MOVW",
- "MOVM",
- "SWPBU",
- "SWPW",
- "RFE",
- "SWI",
- "MULA",
- "WORD",
- "MULL",
- "MULAL",
- "MULLU",
- "MULALU",
- "BX",
- "BXRET",
- "DWORD",
- "LDREX",
- "STREX",
- "LDREXD",
- "STREXD",
- "PLD",
- "CLZ",
- "MULWT",
- "MULWB",
- "MULAWT",
- "MULAWB",
- "DATABUNDLE",
- "DATABUNDLEEND",
- "MRC",
- "LAST",
-}
diff --git a/vendor/github.com/google/gops/internal/obj/arm/anames5.go b/vendor/github.com/google/gops/internal/obj/arm/anames5.go
deleted file mode 100644
index 7fdd9623..00000000
--- a/vendor/github.com/google/gops/internal/obj/arm/anames5.go
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package arm
-
-var cnames5 = []string{
- "NONE",
- "REG",
- "REGREG",
- "REGREG2",
- "REGLIST",
- "SHIFT",
- "FREG",
- "PSR",
- "FCR",
- "RCON",
- "NCON",
- "SCON",
- "LCON",
- "LCONADDR",
- "ZFCON",
- "SFCON",
- "LFCON",
- "RACON",
- "LACON",
- "SBRA",
- "LBRA",
- "HAUTO",
- "FAUTO",
- "HFAUTO",
- "SAUTO",
- "LAUTO",
- "HOREG",
- "FOREG",
- "HFOREG",
- "SOREG",
- "ROREG",
- "SROREG",
- "LOREG",
- "PC",
- "SP",
- "HREG",
- "ADDR",
- "C_TLS_LE",
- "C_TLS_IE",
- "TEXTSIZE",
- "GOK",
- "NCLASS",
- "SCOND = (1<<4)-1",
- "SBIT = 1<<4",
- "PBIT = 1<<5",
- "WBIT = 1<<6",
- "FBIT = 1<<7",
- "UBIT = 1<<7",
- "SCOND_XOR = 14",
- "SCOND_EQ = 0 ^ C_SCOND_XOR",
- "SCOND_NE = 1 ^ C_SCOND_XOR",
- "SCOND_HS = 2 ^ C_SCOND_XOR",
- "SCOND_LO = 3 ^ C_SCOND_XOR",
- "SCOND_MI = 4 ^ C_SCOND_XOR",
- "SCOND_PL = 5 ^ C_SCOND_XOR",
- "SCOND_VS = 6 ^ C_SCOND_XOR",
- "SCOND_VC = 7 ^ C_SCOND_XOR",
- "SCOND_HI = 8 ^ C_SCOND_XOR",
- "SCOND_LS = 9 ^ C_SCOND_XOR",
- "SCOND_GE = 10 ^ C_SCOND_XOR",
- "SCOND_LT = 11 ^ C_SCOND_XOR",
- "SCOND_GT = 12 ^ C_SCOND_XOR",
- "SCOND_LE = 13 ^ C_SCOND_XOR",
- "SCOND_NONE = 14 ^ C_SCOND_XOR",
- "SCOND_NV = 15 ^ C_SCOND_XOR",
-}
diff --git a/vendor/github.com/google/gops/internal/obj/arm/asm5.go b/vendor/github.com/google/gops/internal/obj/arm/asm5.go
deleted file mode 100644
index aa8149d5..00000000
--- a/vendor/github.com/google/gops/internal/obj/arm/asm5.go
+++ /dev/null
@@ -1,2846 +0,0 @@
-// Inferno utils/5l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/span.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.
-
-package arm
-
-import (
- "fmt"
- "log"
- "math"
- "sort"
-
- "github.com/google/gops/internal/obj"
-)
-
-type Optab struct {
- as obj.As
- a1 uint8
- a2 int8
- a3 uint8
- type_ uint8
- size int8
- param int16
- flag int8
- pcrelsiz uint8
-}
-
-type Opcross [32][2][32]uint8
-
-const (
- LFROM = 1 << 0
- LTO = 1 << 1
- LPOOL = 1 << 2
- LPCREL = 1 << 3
-)
-
-var optab = []Optab{
- /* struct Optab:
- OPCODE, from, prog->reg, to, type,size,param,flag */
- {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0},
- {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
- {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0},
- {AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0},
- {AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
- {AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
- {AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
- {ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0},
- {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
- {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0},
- {AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0},
- {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0},
- {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
- {ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0},
- {ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
- {ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // prediction hinted form, hint ignored
-
- {AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0},
- {ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0},
- {ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0},
- {ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0},
- {ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0},
- {ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0},
- {ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0},
- {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0},
- {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0},
- {ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
- {ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0, 0, 0},
- {ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0},
- {AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0},
- {AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
- {AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
- {AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0},
- {AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
- {AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
- {ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0},
- {AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0},
- {AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
- {AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
- {ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0},
- {AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
- {AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
- {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
- {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0},
- {ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0},
- {ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0},
- {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0},
- {AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
- {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
- {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
- {AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
- {AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
- {AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
- {AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
- {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
- {AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
- {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
- {AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0},
- {AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0},
- {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
- {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
- {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4},
- {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
- {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
- {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4},
- {AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0},
- {AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0},
- {AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0},
- {AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0},
- {AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0},
- {ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0},
- {ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0},
- {AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0},
- {AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0},
- {AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0},
- {AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0},
- {AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0},
- {AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0},
- {AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0},
- {AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0},
- {AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4},
- {AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
- {AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
- {AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0, 0, 0},
- {AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0},
- {AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0},
- {AMOVW, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0},
- {AMOVBU, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0},
- {AMOVB, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0},
- {AMOVBS, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
- {AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
- {AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
- {AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
- {AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
- {AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
- {AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
- {AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
- {AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
- {AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
- {AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
- {AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
- {AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
- {AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
- {AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
- {AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
- {AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
- {AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
- {AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
- {AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
- {AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
- {AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
- {AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
- {AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
- {AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
- {AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
- {AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
- {AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
- {AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
- {AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
- {AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
- {AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
- {AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
- {AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
- {AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
- {AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
- {AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
- {AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
- {AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
- {AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
- {AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
- {ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0},
- {ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0},
- {AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0},
- {AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0},
- {ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0, 0, 0},
- {ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0},
- {AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0},
- {AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0},
- {AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0},
- {AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0},
- {AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0},
- {ATST, C_REG, C_NONE, C_NONE, 90, 4, 0, 0, 0},
- {ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0},
- {ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0},
- {APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0},
- {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0},
- {ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0},
- {AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0},
- {AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0},
- {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0},
- {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0},
- {obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
- {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
- {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL
- {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL
-
- {ADATABUNDLE, C_NONE, C_NONE, C_NONE, 100, 4, 0, 0, 0},
- {ADATABUNDLEEND, C_NONE, C_NONE, C_NONE, 100, 0, 0, 0, 0},
- {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0},
-}
-
-var pool struct {
- start uint32
- size uint32
- extra uint32
-}
-
-var oprange [ALAST & obj.AMask][]Optab
-
-var xcmp [C_GOK + 1][C_GOK + 1]bool
-
-var deferreturn *obj.LSym
-
-// Note about encoding: Prog.scond holds the condition encoding,
-// but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0.
-// The code that shifts the value << 28 has the responsibility
-// for XORing with C_SCOND_XOR too.
-
-// asmoutnacl assembles the instruction p. It replaces asmout for NaCl.
-// It returns the total number of bytes put in out, and it can change
-// p->pc if extra padding is necessary.
-// In rare cases, asmoutnacl might split p into two instructions.
-// origPC is the PC for this Prog (no padding is taken into account).
-func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint32) int {
- size := int(o.size)
-
- // instruction specific
- switch p.As {
- default:
- if out != nil {
- asmout(ctxt, p, o, out)
- }
-
- case ADATABUNDLE, // align to 16-byte boundary
- ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary
- p.Pc = (p.Pc + 15) &^ 15
-
- if out != nil {
- asmout(ctxt, p, o, out)
- }
-
- case obj.AUNDEF,
- APLD:
- size = 4
- if out != nil {
- switch p.As {
- case obj.AUNDEF:
- out[0] = 0xe7fedef0 // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
-
- case APLD:
- out[0] = 0xe1a01001 // (MOVW R1, R1)
- }
- }
-
- case AB, ABL:
- if p.To.Type != obj.TYPE_MEM {
- if out != nil {
- asmout(ctxt, p, o, out)
- }
- } else {
- if p.To.Offset != 0 || size != 4 || p.To.Reg > REG_R15 || p.To.Reg < REG_R0 {
- ctxt.Diag("unsupported instruction: %v", p)
- }
- if p.Pc&15 == 12 {
- p.Pc += 4
- }
- if out != nil {
- out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c0013f | (uint32(p.To.Reg)&15)<<12 | (uint32(p.To.Reg)&15)<<16 // BIC $0xc000000f, Rx
- if p.As == AB {
- out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff10 | (uint32(p.To.Reg)&15)<<0 // BX Rx
- } else { // ABL
- out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff30 | (uint32(p.To.Reg)&15)<<0 // BLX Rx
- }
- }
-
- size = 8
- }
-
- // align the last instruction (the actual BL) to the last instruction in a bundle
- if p.As == ABL {
- if deferreturn == nil {
- deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0)
- }
- if p.To.Sym == deferreturn {
- p.Pc = ((int64(origPC) + 15) &^ 15) + 16 - int64(size)
- } else {
- p.Pc += (16 - ((p.Pc + int64(size)) & 15)) & 15
- }
- }
-
- case ALDREX,
- ALDREXD,
- AMOVB,
- AMOVBS,
- AMOVBU,
- AMOVD,
- AMOVF,
- AMOVH,
- AMOVHS,
- AMOVHU,
- AMOVM,
- AMOVW,
- ASTREX,
- ASTREXD:
- if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 && p.From.Reg == REG_R13 { // MOVW.W x(R13), PC
- if out != nil {
- asmout(ctxt, p, o, out)
- }
- if size == 4 {
- if out != nil {
- // Note: 5c and 5g reg.c know that DIV/MOD smashes R12
- // so that this return instruction expansion is valid.
- out[0] = out[0] &^ 0x3000 // change PC to R12
- out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12
- out[2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12
- }
-
- size += 8
- if (p.Pc+int64(size))&15 == 4 {
- p.Pc += 4
- }
- break
- } else {
- // if the instruction used more than 4 bytes, then it must have used a very large
- // offset to update R13, so we need to additionally mask R13.
- if out != nil {
- out[size/4-1] &^= 0x3000 // change PC to R12
- out[size/4] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03cdd103 // BIC $0xc0000000, R13
- out[size/4+1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12
- out[size/4+2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12
- }
-
- // p->pc+size is only ok at 4 or 12 mod 16.
- if (p.Pc+int64(size))%8 == 0 {
- p.Pc += 4
- }
- size += 12
- break
- }
- }
-
- if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 {
- ctxt.Diag("unsupported instruction (move to another register and use indirect jump instead): %v", p)
- }
-
- if p.To.Type == obj.TYPE_MEM && p.To.Reg == REG_R13 && (p.Scond&C_WBIT != 0) && size > 4 {
- // function prolog with very large frame size: MOVW.W R14,-100004(R13)
- // split it into two instructions:
- // ADD $-100004, R13
- // MOVW R14, 0(R13)
- q := ctxt.NewProg()
-
- p.Scond &^= C_WBIT
- *q = *p
- a := &p.To
- var a2 *obj.Addr
- if p.To.Type == obj.TYPE_MEM {
- a2 = &q.To
- } else {
- a2 = &q.From
- }
- nocache(q)
- nocache(p)
-
- // insert q after p
- q.Link = p.Link
-
- p.Link = q
- q.Pcond = nil
-
- // make p into ADD $X, R13
- p.As = AADD
-
- p.From = *a
- p.From.Reg = 0
- p.From.Type = obj.TYPE_CONST
- p.To = obj.Addr{}
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R13
-
- // make q into p but load/store from 0(R13)
- q.Spadj = 0
-
- *a2 = obj.Addr{}
- a2.Type = obj.TYPE_MEM
- a2.Reg = REG_R13
- a2.Sym = nil
- a2.Offset = 0
- size = int(oplook(ctxt, p).size)
- break
- }
-
- if (p.To.Type == obj.TYPE_MEM && p.To.Reg != REG_R9) || // MOVW Rx, X(Ry), y != 9
- (p.From.Type == obj.TYPE_MEM && p.From.Reg != REG_R9) { // MOVW X(Rx), Ry, x != 9
- var a *obj.Addr
- if p.To.Type == obj.TYPE_MEM {
- a = &p.To
- } else {
- a = &p.From
- }
- reg := int(a.Reg)
- if size == 4 {
- // if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify.
- if reg == 0 {
- if out != nil {
- asmout(ctxt, p, o, out)
- }
- } else {
- if out != nil {
- out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c00103 | (uint32(reg)&15)<<16 | (uint32(reg)&15)<<12 // BIC $0xc0000000, Rx
- }
- if p.Pc&15 == 12 {
- p.Pc += 4
- }
- size += 4
- if out != nil {
- asmout(ctxt, p, o, out[1:])
- }
- }
-
- break
- } else {
- // if a load/store instruction takes more than 1 word to implement, then
- // we need to separate the instruction into two:
- // 1. explicitly load the address into R11.
- // 2. load/store from R11.
- // This won't handle .W/.P, so we should reject such code.
- if p.Scond&(C_PBIT|C_WBIT) != 0 {
- ctxt.Diag("unsupported instruction (.P/.W): %v", p)
- }
- q := ctxt.NewProg()
- *q = *p
- var a2 *obj.Addr
- if p.To.Type == obj.TYPE_MEM {
- a2 = &q.To
- } else {
- a2 = &q.From
- }
- nocache(q)
- nocache(p)
-
- // insert q after p
- q.Link = p.Link
-
- p.Link = q
- q.Pcond = nil
-
- // make p into MOVW $X(R), R11
- p.As = AMOVW
-
- p.From = *a
- p.From.Type = obj.TYPE_ADDR
- p.To = obj.Addr{}
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R11
-
- // make q into p but load/store from 0(R11)
- *a2 = obj.Addr{}
-
- a2.Type = obj.TYPE_MEM
- a2.Reg = REG_R11
- a2.Sym = nil
- a2.Offset = 0
- size = int(oplook(ctxt, p).size)
- break
- }
- } else if out != nil {
- asmout(ctxt, p, o, out)
- }
- }
-
- // destination register specific
- if p.To.Type == obj.TYPE_REG {
- switch p.To.Reg {
- case REG_R9:
- ctxt.Diag("invalid instruction, cannot write to R9: %v", p)
-
- case REG_R13:
- if out != nil {
- out[size/4] = 0xe3cdd103 // BIC $0xc0000000, R13
- }
- if (p.Pc+int64(size))&15 == 0 {
- p.Pc += 4
- }
- size += 4
- }
- }
-
- return size
-}
-
-func span5(ctxt *obj.Link, cursym *obj.LSym) {
- var p *obj.Prog
- var op *obj.Prog
-
- p = cursym.Text
- if p == nil || p.Link == nil { // handle external functions and ELF section symbols
- return
- }
-
- if oprange[AAND&obj.AMask] == nil {
- buildop(ctxt)
- }
-
- ctxt.Cursym = cursym
-
- ctxt.Autosize = int32(p.To.Offset + 4)
- c := int32(0)
-
- op = p
- p = p.Link
- var i int
- var m int
- var o *Optab
- for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link {
- if p == nil {
- if checkpool(ctxt, op, 0) {
- p = op
- continue
- }
-
- // can't happen: blitrl is not nil, but checkpool didn't flushpool
- ctxt.Diag("internal inconsistency")
-
- break
- }
-
- ctxt.Curp = p
- p.Pc = int64(c)
- o = oplook(ctxt, p)
- if ctxt.Headtype != obj.Hnacl {
- m = int(o.size)
- } else {
- m = asmoutnacl(ctxt, c, p, o, nil)
- c = int32(p.Pc) // asmoutnacl might change pc for alignment
- o = oplook(ctxt, p) // asmoutnacl might change p in rare cases
- }
-
- if m%4 != 0 || p.Pc%4 != 0 {
- ctxt.Diag("!pc invalid: %v size=%d", p, m)
- }
-
- // must check literal pool here in case p generates many instructions
- if ctxt.Blitrl != nil {
- i = m
- if checkpool(ctxt, op, i) {
- p = op
- continue
- }
- }
-
- if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) {
- ctxt.Diag("zero-width instruction\n%v", p)
- continue
- }
-
- switch o.flag & (LFROM | LTO | LPOOL) {
- case LFROM:
- addpool(ctxt, p, &p.From)
-
- case LTO:
- addpool(ctxt, p, &p.To)
-
- case LPOOL:
- if p.Scond&C_SCOND == C_SCOND_NONE {
- flushpool(ctxt, p, 0, 0)
- }
- }
-
- if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE {
- flushpool(ctxt, p, 0, 0)
- }
- c += int32(m)
- }
-
- cursym.Size = int64(c)
-
- /*
- * if any procedure is large enough to
- * generate a large SBRA branch, then
- * generate extra passes putting branches
- * around jmps to fix. this is rare.
- */
- times := 0
-
- var bflag int
- var opc int32
- var out [6 + 3]uint32
- for {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("%5.2f span1\n", obj.Cputime())
- }
- bflag = 0
- c = 0
- times++
- cursym.Text.Pc = 0 // force re-layout the code.
- for p = cursym.Text; p != nil; p = p.Link {
- ctxt.Curp = p
- o = oplook(ctxt, p)
- if int64(c) > p.Pc {
- p.Pc = int64(c)
- }
-
- /* very large branches
- if(o->type == 6 && p->pcond) {
- otxt = p->pcond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = emallocz(sizeof(Prog));
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = TYPE_BRANCH;
- q->pcond = p->pcond;
- p->pcond = q;
- q = emallocz(sizeof(Prog));
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = TYPE_BRANCH;
- q->pcond = q->link->link;
- bflag = 1;
- }
- }
- */
- opc = int32(p.Pc)
-
- if ctxt.Headtype != obj.Hnacl {
- m = int(o.size)
- } else {
- m = asmoutnacl(ctxt, c, p, o, nil)
- }
- if p.Pc != int64(opc) {
- bflag = 1
- }
-
- //print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
- c = int32(p.Pc + int64(m))
-
- if m%4 != 0 || p.Pc%4 != 0 {
- ctxt.Diag("pc invalid: %v size=%d", p, m)
- }
-
- if m/4 > len(out) {
- ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
- }
- if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) {
- if p.As == obj.ATEXT {
- ctxt.Autosize = int32(p.To.Offset + 4)
- continue
- }
-
- ctxt.Diag("zero-width instruction\n%v", p)
- continue
- }
- }
-
- cursym.Size = int64(c)
- if bflag == 0 {
- break
- }
- }
-
- if c%4 != 0 {
- ctxt.Diag("sym->size=%d, invalid", c)
- }
-
- /*
- * lay out the code. all the pc-relative code references,
- * even cross-function, are resolved now;
- * only data references need to be relocated.
- * with more work we could leave cross-function
- * code references to be relocated too, and then
- * perhaps we'd be able to parallelize the span loop above.
- */
-
- p = cursym.Text
- ctxt.Autosize = int32(p.To.Offset + 4)
- cursym.Grow(cursym.Size)
-
- bp := cursym.P
- c = int32(p.Pc) // even p->link might need extra padding
- var v int
- for p = p.Link; p != nil; p = p.Link {
- ctxt.Pc = p.Pc
- ctxt.Curp = p
- o = oplook(ctxt, p)
- opc = int32(p.Pc)
- if ctxt.Headtype != obj.Hnacl {
- asmout(ctxt, p, o, out[:])
- m = int(o.size)
- } else {
- m = asmoutnacl(ctxt, c, p, o, out[:])
- if int64(opc) != p.Pc {
- ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p)
- }
- }
-
- if m%4 != 0 || p.Pc%4 != 0 {
- ctxt.Diag("final stage: pc invalid: %v size=%d", p, m)
- }
-
- if int64(c) > p.Pc {
- ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, c, p)
- }
- for int64(c) != p.Pc {
- // emit 0xe1a00000 (MOVW R0, R0)
- bp[0] = 0x00
- bp = bp[1:]
-
- bp[0] = 0x00
- bp = bp[1:]
- bp[0] = 0xa0
- bp = bp[1:]
- bp[0] = 0xe1
- bp = bp[1:]
- c += 4
- }
-
- for i = 0; i < m/4; i++ {
- v = int(out[i])
- bp[0] = byte(v)
- bp = bp[1:]
- bp[0] = byte(v >> 8)
- bp = bp[1:]
- bp[0] = byte(v >> 16)
- bp = bp[1:]
- bp[0] = byte(v >> 24)
- bp = bp[1:]
- }
-
- c += int32(m)
- }
-}
-
-/*
- * when the first reference to the literal pool threatens
- * to go out of range of a 12-bit PC-relative offset,
- * drop the pool now, and branch round it.
- * this happens only in extended basic blocks that exceed 4k.
- */
-func checkpool(ctxt *obj.Link, p *obj.Prog, sz int) bool {
- if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 {
- return flushpool(ctxt, p, 1, 0)
- } else if p.Link == nil {
- return flushpool(ctxt, p, 2, 0)
- }
- return false
-}
-
-func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool {
- if ctxt.Blitrl != nil {
- if skip != 0 {
- if false && skip == 1 {
- fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start)
- }
- q := ctxt.NewProg()
- q.As = AB
- q.To.Type = obj.TYPE_BRANCH
- q.Pcond = p.Link
- q.Link = ctxt.Blitrl
- q.Lineno = p.Lineno
- ctxt.Blitrl = q
- } else if force == 0 && (p.Pc+int64(12+pool.size)-int64(pool.start) < 2048) { // 12 take into account the maximum nacl literal pool alignment padding size
- return false
- }
- if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 {
- // if pool is not multiple of 16 bytes, add an alignment marker
- q := ctxt.NewProg()
-
- q.As = ADATABUNDLEEND
- ctxt.Elitrl.Link = q
- ctxt.Elitrl = q
- }
-
- // The line number for constant pool entries doesn't really matter.
- // We set it to the line number of the preceding instruction so that
- // there are no deltas to encode in the pc-line tables.
- for q := ctxt.Blitrl; q != nil; q = q.Link {
- q.Lineno = p.Lineno
- }
-
- ctxt.Elitrl.Link = p.Link
- p.Link = ctxt.Blitrl
-
- ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */
- ctxt.Elitrl = nil
- pool.size = 0
- pool.start = 0
- pool.extra = 0
- return true
- }
-
- return false
-}
-
-func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
- var t obj.Prog
-
- c := aclass(ctxt, a)
-
- t.Ctxt = ctxt
- t.As = AWORD
-
- switch c {
- default:
- t.To.Offset = a.Offset
- t.To.Sym = a.Sym
- t.To.Type = a.Type
- t.To.Name = a.Name
-
- if ctxt.Flag_shared && t.To.Sym != nil {
- t.Rel = p
- }
-
- case C_SROREG,
- C_LOREG,
- C_ROREG,
- C_FOREG,
- C_SOREG,
- C_HOREG,
- C_FAUTO,
- C_SAUTO,
- C_LAUTO,
- C_LACON:
- t.To.Type = obj.TYPE_CONST
- t.To.Offset = ctxt.Instoffset
- }
-
- if t.Rel == nil {
- for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
- if q.Rel == nil && q.To == t.To {
- p.Pcond = q
- return
- }
- }
- }
-
- if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 {
- // start a new data bundle
- q := ctxt.NewProg()
- q.As = ADATABUNDLE
- q.Pc = int64(pool.size)
- pool.size += 4
- if ctxt.Blitrl == nil {
- ctxt.Blitrl = q
- pool.start = uint32(p.Pc)
- } else {
- ctxt.Elitrl.Link = q
- }
-
- ctxt.Elitrl = q
- }
-
- q := ctxt.NewProg()
- *q = t
- q.Pc = int64(pool.size)
-
- if ctxt.Blitrl == nil {
- ctxt.Blitrl = q
- pool.start = uint32(p.Pc)
- } else {
- ctxt.Elitrl.Link = q
- }
- ctxt.Elitrl = q
- pool.size += 4
-
- p.Pcond = q
-}
-
-func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
- ctxt.Instoffset = 0
- aclass(ctxt, a)
- return int32(ctxt.Instoffset)
-}
-
-func immrot(v uint32) int32 {
- for i := 0; i < 16; i++ {
- if v&^0xff == 0 {
- return int32(uint32(int32(i)<<8) | v | 1<<25)
- }
- v = v<<2 | v>>30
- }
-
- return 0
-}
-
-func immaddr(v int32) int32 {
- if v >= 0 && v <= 0xfff {
- return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */
- }
- if v >= -0xfff && v < 0 {
- return -v&0xfff | 1<<24 /* pre indexing */
- }
- return 0
-}
-
-func immfloat(v int32) bool {
- return v&0xC03 == 0 /* offset will fit in floating-point load/store */
-}
-
-func immhalf(v int32) bool {
- if v >= 0 && v <= 0xff {
- return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */
- }
- if v >= -0xff && v < 0 {
- return -v&0xff|1<<24 != 0 /* pre indexing */
- }
- return false
-}
-
-func aclass(ctxt *obj.Link, a *obj.Addr) int {
- switch a.Type {
- case obj.TYPE_NONE:
- return C_NONE
-
- case obj.TYPE_REG:
- ctxt.Instoffset = 0
- if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
- return C_REG
- }
- if REG_F0 <= a.Reg && a.Reg <= REG_F15 {
- return C_FREG
- }
- if a.Reg == REG_FPSR || a.Reg == REG_FPCR {
- return C_FCR
- }
- if a.Reg == REG_CPSR || a.Reg == REG_SPSR {
- return C_PSR
- }
- return C_GOK
-
- case obj.TYPE_REGREG:
- return C_REGREG
-
- case obj.TYPE_REGREG2:
- return C_REGREG2
-
- case obj.TYPE_REGLIST:
- return C_REGLIST
-
- case obj.TYPE_SHIFT:
- return C_SHIFT
-
- case obj.TYPE_MEM:
- switch a.Name {
- case obj.NAME_EXTERN,
- obj.NAME_GOTREF,
- obj.NAME_STATIC:
- if a.Sym == nil || a.Sym.Name == "" {
- fmt.Printf("null sym external\n")
- return C_GOK
- }
-
- ctxt.Instoffset = 0 // s.b. unused but just in case
- if a.Sym.Type == obj.STLSBSS {
- if ctxt.Flag_shared {
- return C_TLS_IE
- } else {
- return C_TLS_LE
- }
- }
-
- return C_ADDR
-
- case obj.NAME_AUTO:
- ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
- if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
- if immhalf(int32(ctxt.Instoffset)) {
- if immfloat(t) {
- return C_HFAUTO
- }
- return C_HAUTO
- }
-
- if immfloat(t) {
- return C_FAUTO
- }
- return C_SAUTO
- }
-
- return C_LAUTO
-
- case obj.NAME_PARAM:
- ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
- if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
- if immhalf(int32(ctxt.Instoffset)) {
- if immfloat(t) {
- return C_HFAUTO
- }
- return C_HAUTO
- }
-
- if immfloat(t) {
- return C_FAUTO
- }
- return C_SAUTO
- }
-
- return C_LAUTO
-
- case obj.NAME_NONE:
- ctxt.Instoffset = a.Offset
- if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
- if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */
- if immfloat(t) {
- return C_HFOREG
- }
- return C_HOREG
- }
-
- if immfloat(t) {
- return C_FOREG /* n.b. that it will also satisfy immrot */
- }
- if immrot(uint32(ctxt.Instoffset)) != 0 {
- return C_SROREG
- }
- if immhalf(int32(ctxt.Instoffset)) {
- return C_HOREG
- }
- return C_SOREG
- }
-
- if immrot(uint32(ctxt.Instoffset)) != 0 {
- return C_ROREG
- }
- return C_LOREG
- }
-
- return C_GOK
-
- case obj.TYPE_FCONST:
- if chipzero5(ctxt, a.Val.(float64)) >= 0 {
- return C_ZFCON
- }
- if chipfloat5(ctxt, a.Val.(float64)) >= 0 {
- return C_SFCON
- }
- return C_LFCON
-
- case obj.TYPE_TEXTSIZE:
- return C_TEXTSIZE
-
- case obj.TYPE_CONST,
- obj.TYPE_ADDR:
- switch a.Name {
- case obj.NAME_NONE:
- ctxt.Instoffset = a.Offset
- if a.Reg != 0 {
- return aconsize(ctxt)
- }
-
- if immrot(uint32(ctxt.Instoffset)) != 0 {
- return C_RCON
- }
- if immrot(^uint32(ctxt.Instoffset)) != 0 {
- return C_NCON
- }
- return C_LCON
-
- case obj.NAME_EXTERN,
- obj.NAME_GOTREF,
- obj.NAME_STATIC:
- s := a.Sym
- if s == nil {
- break
- }
- ctxt.Instoffset = 0 // s.b. unused but just in case
- return C_LCONADDR
-
- case obj.NAME_AUTO:
- ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
- return aconsize(ctxt)
-
- case obj.NAME_PARAM:
- ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
- return aconsize(ctxt)
- }
-
- return C_GOK
-
- case obj.TYPE_BRANCH:
- return C_SBRA
- }
-
- return C_GOK
-}
-
-func aconsize(ctxt *obj.Link) int {
- if immrot(uint32(ctxt.Instoffset)) != 0 {
- return C_RACON
- }
- if immrot(uint32(-ctxt.Instoffset)) != 0 {
- return C_RACON
- }
- return C_LACON
-}
-
-func prasm(p *obj.Prog) {
- fmt.Printf("%v\n", p)
-}
-
-func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
- a1 := int(p.Optab)
- if a1 != 0 {
- return &optab[a1-1]
- }
- a1 = int(p.From.Class)
- if a1 == 0 {
- a1 = aclass(ctxt, &p.From) + 1
- p.From.Class = int8(a1)
- }
-
- a1--
- a3 := int(p.To.Class)
- if a3 == 0 {
- a3 = aclass(ctxt, &p.To) + 1
- p.To.Class = int8(a3)
- }
-
- a3--
- a2 := C_NONE
- if p.Reg != 0 {
- a2 = C_REG
- }
-
- if false { /*debug['O']*/
- fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
- fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
- }
-
- ops := oprange[p.As&obj.AMask]
- c1 := &xcmp[a1]
- c3 := &xcmp[a3]
- for i := range ops {
- op := &ops[i]
- if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
- p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
- return op
- }
- }
-
- ctxt.Diag("illegal combination %v; %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type)
- ctxt.Diag("from %d %d to %d %d\n", p.From.Type, p.From.Name, p.To.Type, p.To.Name)
- prasm(p)
- if ops == nil {
- ops = optab
- }
- return &ops[0]
-}
-
-func cmp(a int, b int) bool {
- if a == b {
- return true
- }
- switch a {
- case C_LCON:
- if b == C_RCON || b == C_NCON {
- return true
- }
-
- case C_LACON:
- if b == C_RACON {
- return true
- }
-
- case C_LFCON:
- if b == C_ZFCON || b == C_SFCON {
- return true
- }
-
- case C_HFAUTO:
- return b == C_HAUTO || b == C_FAUTO
-
- case C_FAUTO, C_HAUTO:
- return b == C_HFAUTO
-
- case C_SAUTO:
- return cmp(C_HFAUTO, b)
-
- case C_LAUTO:
- return cmp(C_SAUTO, b)
-
- case C_HFOREG:
- return b == C_HOREG || b == C_FOREG
-
- case C_FOREG, C_HOREG:
- return b == C_HFOREG
-
- case C_SROREG:
- return cmp(C_SOREG, b) || cmp(C_ROREG, b)
-
- case C_SOREG, C_ROREG:
- return b == C_SROREG || cmp(C_HFOREG, b)
-
- case C_LOREG:
- return cmp(C_SROREG, b)
-
- case C_LBRA:
- if b == C_SBRA {
- return true
- }
-
- case C_HREG:
- return cmp(C_SP, b) || cmp(C_PC, b)
- }
-
- return false
-}
-
-type ocmp []Optab
-
-func (x ocmp) Len() int {
- return len(x)
-}
-
-func (x ocmp) Swap(i, j int) {
- x[i], x[j] = x[j], x[i]
-}
-
-func (x ocmp) Less(i, j int) bool {
- p1 := &x[i]
- p2 := &x[j]
- n := int(p1.as) - int(p2.as)
- if n != 0 {
- return n < 0
- }
- n = int(p1.a1) - int(p2.a1)
- if n != 0 {
- return n < 0
- }
- n = int(p1.a2) - int(p2.a2)
- if n != 0 {
- return n < 0
- }
- n = int(p1.a3) - int(p2.a3)
- if n != 0 {
- return n < 0
- }
- return false
-}
-
-func opset(a, b0 obj.As) {
- oprange[a&obj.AMask] = oprange[b0]
-}
-
-func buildop(ctxt *obj.Link) {
- var n int
-
- for i := 0; i < C_GOK; i++ {
- for n = 0; n < C_GOK; n++ {
- if cmp(n, i) {
- xcmp[i][n] = true
- }
- }
- }
- for n = 0; optab[n].as != obj.AXXX; n++ {
- if optab[n].flag&LPCREL != 0 {
- if ctxt.Flag_shared {
- optab[n].size += int8(optab[n].pcrelsiz)
- } else {
- optab[n].flag &^= LPCREL
- }
- }
- }
-
- sort.Sort(ocmp(optab[:n]))
- for i := 0; i < n; i++ {
- r := optab[i].as
- r0 := r & obj.AMask
- start := i
- for optab[i].as == r {
- i++
- }
- oprange[r0] = optab[start:i]
- i--
-
- switch r {
- default:
- ctxt.Diag("unknown op in build: %v", r)
- log.Fatalf("bad code")
-
- case AADD:
- opset(AAND, r0)
- opset(AEOR, r0)
- opset(ASUB, r0)
- opset(ARSB, r0)
- opset(AADC, r0)
- opset(ASBC, r0)
- opset(ARSC, r0)
- opset(AORR, r0)
- opset(ABIC, r0)
-
- case ACMP:
- opset(ATEQ, r0)
- opset(ACMN, r0)
-
- case AMVN:
- break
-
- case ABEQ:
- opset(ABNE, r0)
- opset(ABCS, r0)
- opset(ABHS, r0)
- opset(ABCC, r0)
- opset(ABLO, r0)
- opset(ABMI, r0)
- opset(ABPL, r0)
- opset(ABVS, r0)
- opset(ABVC, r0)
- opset(ABHI, r0)
- opset(ABLS, r0)
- opset(ABGE, r0)
- opset(ABLT, r0)
- opset(ABGT, r0)
- opset(ABLE, r0)
-
- case ASLL:
- opset(ASRL, r0)
- opset(ASRA, r0)
-
- case AMUL:
- opset(AMULU, r0)
-
- case ADIV:
- opset(AMOD, r0)
- opset(AMODU, r0)
- opset(ADIVU, r0)
-
- case AMOVW,
- AMOVB,
- AMOVBS,
- AMOVBU,
- AMOVH,
- AMOVHS,
- AMOVHU:
- break
-
- case ASWPW:
- opset(ASWPBU, r0)
-
- case AB,
- ABL,
- ABX,
- ABXRET,
- obj.ADUFFZERO,
- obj.ADUFFCOPY,
- ASWI,
- AWORD,
- AMOVM,
- ARFE,
- obj.ATEXT,
- obj.AUSEFIELD,
- obj.ATYPE:
- break
-
- case AADDF:
- opset(AADDD, r0)
- opset(ASUBF, r0)
- opset(ASUBD, r0)
- opset(AMULF, r0)
- opset(AMULD, r0)
- opset(ADIVF, r0)
- opset(ADIVD, r0)
- opset(ASQRTF, r0)
- opset(ASQRTD, r0)
- opset(AMOVFD, r0)
- opset(AMOVDF, r0)
- opset(AABSF, r0)
- opset(AABSD, r0)
- opset(ANEGF, r0)
- opset(ANEGD, r0)
-
- case ACMPF:
- opset(ACMPD, r0)
-
- case AMOVF:
- opset(AMOVD, r0)
-
- case AMOVFW:
- opset(AMOVDW, r0)
-
- case AMOVWF:
- opset(AMOVWD, r0)
-
- case AMULL:
- opset(AMULAL, r0)
- opset(AMULLU, r0)
- opset(AMULALU, r0)
-
- case AMULWT:
- opset(AMULWB, r0)
-
- case AMULAWT:
- opset(AMULAWB, r0)
-
- case AMULA,
- ALDREX,
- ASTREX,
- ALDREXD,
- ASTREXD,
- ATST,
- APLD,
- obj.AUNDEF,
- ACLZ,
- obj.AFUNCDATA,
- obj.APCDATA,
- obj.ANOP,
- ADATABUNDLE,
- ADATABUNDLEEND:
- break
- }
- }
-}
-
-func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
- ctxt.Printp = p
- o1 := uint32(0)
- o2 := uint32(0)
- o3 := uint32(0)
- o4 := uint32(0)
- o5 := uint32(0)
- o6 := uint32(0)
- ctxt.Armsize += int32(o.size)
- if false { /*debug['P']*/
- fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
- }
- switch o.type_ {
- default:
- ctxt.Diag("unknown asm %d", o.type_)
- prasm(p)
-
- case 0: /* pseudo ops */
- if false { /*debug['G']*/
- fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
- }
-
- case 1: /* op R,[R],R */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = 0
- }
- if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
- r = 0
- } else if r == 0 {
- r = rt
- }
- o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
-
- case 2: /* movbu $I,[R],R */
- aclass(ctxt, &p.From)
-
- o1 = oprrr(ctxt, p.As, int(p.Scond))
- o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = 0
- }
- if p.As == AMOVW || p.As == AMVN {
- r = 0
- } else if r == 0 {
- r = rt
- }
- o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
-
- case 3: /* add R<<[IR],[R],R */
- o1 = mov(ctxt, p)
-
- case 4: /* MOVW $off(R), R -> add $off,[R],R */
- aclass(ctxt, &p.From)
- if ctxt.Instoffset < 0 {
- o1 = oprrr(ctxt, ASUB, int(p.Scond))
- o1 |= uint32(immrot(uint32(-ctxt.Instoffset)))
- } else {
- o1 = oprrr(ctxt, AADD, int(p.Scond))
- o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
- }
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 |= (uint32(r) & 15) << 16
- o1 |= (uint32(p.To.Reg) & 15) << 12
-
- case 5: /* bra s */
- o1 = opbra(ctxt, p, p.As, int(p.Scond))
-
- v := int32(-8)
- if p.To.Sym != nil {
- rel := obj.Addrel(ctxt.Cursym)
- rel.Off = int32(ctxt.Pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- v += int32(p.To.Offset)
- rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
- rel.Type = obj.R_CALLARM
- break
- }
-
- if p.Pcond != nil {
- v = int32((p.Pcond.Pc - ctxt.Pc) - 8)
- }
- o1 |= (uint32(v) >> 2) & 0xffffff
-
- case 6: /* b ,O(R) -> add $O,R,PC */
- aclass(ctxt, &p.To)
-
- o1 = oprrr(ctxt, AADD, int(p.Scond))
- o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
- o1 |= (uint32(p.To.Reg) & 15) << 16
- o1 |= (REGPC & 15) << 12
-
- case 7: /* bl (R) -> blx R */
- aclass(ctxt, &p.To)
-
- if ctxt.Instoffset != 0 {
- ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset)
- }
- o1 = oprrr(ctxt, ABL, int(p.Scond))
- o1 |= (uint32(p.To.Reg) & 15) << 0
- rel := obj.Addrel(ctxt.Cursym)
- rel.Off = int32(ctxt.Pc)
- rel.Siz = 0
- rel.Type = obj.R_CALLIND
-
- case 8: /* sll $c,[R],R -> mov (R<<$c),R */
- aclass(ctxt, &p.From)
-
- o1 = oprrr(ctxt, p.As, int(p.Scond))
- r := int(p.Reg)
- if r == 0 {
- r = int(p.To.Reg)
- }
- o1 |= (uint32(r) & 15) << 0
- o1 |= uint32((ctxt.Instoffset & 31) << 7)
- o1 |= (uint32(p.To.Reg) & 15) << 12
-
- case 9: /* sll R,[R],R -> mov (R<<R),R */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- r := int(p.Reg)
- if r == 0 {
- r = int(p.To.Reg)
- }
- o1 |= (uint32(r) & 15) << 0
- o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
- o1 |= (uint32(p.To.Reg) & 15) << 12
-
- case 10: /* swi [$con] */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- if p.To.Type != obj.TYPE_NONE {
- aclass(ctxt, &p.To)
- o1 |= uint32(ctxt.Instoffset & 0xffffff)
- }
-
- case 11: /* word */
- aclass(ctxt, &p.To)
-
- o1 = uint32(ctxt.Instoffset)
- if p.To.Sym != nil {
- // This case happens with words generated
- // in the PC stream as part of the literal pool.
- rel := obj.Addrel(ctxt.Cursym)
-
- rel.Off = int32(ctxt.Pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- rel.Add = p.To.Offset
-
- if ctxt.Flag_shared {
- if p.To.Name == obj.NAME_GOTREF {
- rel.Type = obj.R_GOTPCREL
- } else {
- rel.Type = obj.R_PCREL
- }
- rel.Add += ctxt.Pc - p.Rel.Pc - 8
- } else {
- rel.Type = obj.R_ADDR
- }
- o1 = 0
- }
-
- case 12: /* movw $lcon, reg */
- o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
-
- if o.flag&LPCREL != 0 {
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
- }
-
- case 13: /* op $lcon, [R], R */
- o1 = omvl(ctxt, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
- o2 = oprrr(ctxt, p.As, int(p.Scond))
- o2 |= REGTMP & 15
- r := int(p.Reg)
- if p.As == AMOVW || p.As == AMVN {
- r = 0
- } else if r == 0 {
- r = int(p.To.Reg)
- }
- o2 |= (uint32(r) & 15) << 16
- if p.To.Type != obj.TYPE_NONE {
- o2 |= (uint32(p.To.Reg) & 15) << 12
- }
-
- case 14: /* movb/movbu/movh/movhu R,R */
- o1 = oprrr(ctxt, ASLL, int(p.Scond))
-
- if p.As == AMOVBU || p.As == AMOVHU {
- o2 = oprrr(ctxt, ASRL, int(p.Scond))
- } else {
- o2 = oprrr(ctxt, ASRA, int(p.Scond))
- }
-
- r := int(p.To.Reg)
- o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12
- o2 |= uint32(r)&15 | (uint32(r)&15)<<12
- if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
- o1 |= 24 << 7
- o2 |= 24 << 7
- } else {
- o1 |= 16 << 7
- o2 |= 16 << 7
- }
-
- case 15: /* mul r,[r,]r */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if r == 0 {
- r = rt
- }
- if rt == r {
- r = rf
- rf = rt
- }
-
- if false {
- if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 {
- ctxt.Diag("bad registers in MUL")
- prasm(p)
- }
- }
-
- o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
-
- case 16: /* div r,[r,]r */
- o1 = 0xf << 28
-
- o2 = 0
-
- case 17:
- o1 = oprrr(ctxt, p.As, int(p.Scond))
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- rt2 := int(p.To.Offset)
- r := int(p.Reg)
- o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
-
- case 20: /* mov/movb/movbu R,O(R) */
- aclass(ctxt, &p.To)
-
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = osr(ctxt, p.As, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
-
- case 21: /* mov/movbu O(R),R -> lr */
- aclass(ctxt, &p.From)
-
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
- if p.As != AMOVW {
- o1 |= 1 << 22
- }
-
- case 30: /* mov/movb/movbu R,L(R) */
- o1 = omvl(ctxt, p, &p.To, REGTMP)
-
- if o1 == 0 {
- break
- }
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
- if p.As != AMOVW {
- o2 |= 1 << 22
- }
-
- case 31: /* mov/movbu L(R),R -> lr[b] */
- o1 = omvl(ctxt, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
- o2 |= 1 << 22
- }
-
- case 34: /* mov $lacon,R */
- o1 = omvl(ctxt, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
-
- o2 = oprrr(ctxt, AADD, int(p.Scond))
- o2 |= REGTMP & 15
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 |= (uint32(r) & 15) << 16
- if p.To.Type != obj.TYPE_NONE {
- o2 |= (uint32(p.To.Reg) & 15) << 12
- }
-
- case 35: /* mov PSR,R */
- o1 = 2<<23 | 0xf<<16 | 0<<0
-
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= (uint32(p.From.Reg) & 1) << 22
- o1 |= (uint32(p.To.Reg) & 15) << 12
-
- case 36: /* mov R,PSR */
- o1 = 2<<23 | 0x29f<<12 | 0<<4
-
- if p.Scond&C_FBIT != 0 {
- o1 ^= 0x010 << 12
- }
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= (uint32(p.To.Reg) & 1) << 22
- o1 |= (uint32(p.From.Reg) & 15) << 0
-
- case 37: /* mov $con,PSR */
- aclass(ctxt, &p.From)
-
- o1 = 2<<23 | 0x29f<<12 | 0<<4
- if p.Scond&C_FBIT != 0 {
- o1 ^= 0x010 << 12
- }
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
- o1 |= (uint32(p.To.Reg) & 1) << 22
- o1 |= (uint32(p.From.Reg) & 15) << 0
-
- case 38, 39:
- switch o.type_ {
- case 38: /* movm $con,oreg -> stm */
- o1 = 0x4 << 25
-
- o1 |= uint32(p.From.Offset & 0xffff)
- o1 |= (uint32(p.To.Reg) & 15) << 16
- aclass(ctxt, &p.To)
-
- case 39: /* movm oreg,$con -> ldm */
- o1 = 0x4<<25 | 1<<20
-
- o1 |= uint32(p.To.Offset & 0xffff)
- o1 |= (uint32(p.From.Reg) & 15) << 16
- aclass(ctxt, &p.From)
- }
-
- if ctxt.Instoffset != 0 {
- ctxt.Diag("offset must be zero in MOVM; %v", p)
- }
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- if p.Scond&C_PBIT != 0 {
- o1 |= 1 << 24
- }
- if p.Scond&C_UBIT != 0 {
- o1 |= 1 << 23
- }
- if p.Scond&C_SBIT != 0 {
- o1 |= 1 << 22
- }
- if p.Scond&C_WBIT != 0 {
- o1 |= 1 << 21
- }
-
- case 40: /* swp oreg,reg,reg */
- aclass(ctxt, &p.From)
-
- if ctxt.Instoffset != 0 {
- ctxt.Diag("offset must be zero in SWP")
- }
- o1 = 0x2<<23 | 0x9<<4
- if p.As != ASWPW {
- o1 |= 1 << 22
- }
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-
- case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
- o1 = 0xe8fd8000
-
- case 50: /* floating point store */
- v := regoff(ctxt, &p.To)
-
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = ofsr(ctxt, p.As, int(p.From.Reg), v, r, int(p.Scond), p)
-
- case 51: /* floating point load */
- v := regoff(ctxt, &p.From)
-
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = ofsr(ctxt, p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
-
- case 52: /* floating point store, int32 offset UGLY */
- o1 = omvl(ctxt, p, &p.To, REGTMP)
-
- if o1 == 0 {
- break
- }
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
- o3 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
-
- case 53: /* floating point load, int32 offset UGLY */
- o1 = omvl(ctxt, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
- o3 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
-
- case 54: /* floating point arith */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if r == 0 {
- r = rt
- if p.As == AMOVF || p.As == AMOVD || p.As == AMOVFD || p.As == AMOVDF || p.As == ASQRTF || p.As == ASQRTD || p.As == AABSF || p.As == AABSD || p.As == ANEGF || p.As == ANEGD {
- r = 0
- }
- }
-
- o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
-
- case 56: /* move to FP[CS]R */
- o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
-
- o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12
-
- case 57: /* move from FP[CS]R */
- o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
-
- o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20
-
- case 58: /* movbu R,R */
- o1 = oprrr(ctxt, AAND, int(p.Scond))
-
- o1 |= uint32(immrot(0xff))
- rt := int(p.To.Reg)
- r := int(p.From.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = 0
- }
- if r == 0 {
- r = rt
- }
- o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
-
- case 59: /* movw/bu R<<I(R),R -> ldr indexed */
- if p.From.Reg == 0 {
- if p.As != AMOVW {
- ctxt.Diag("byte MOV from shifter operand")
- }
- o1 = mov(ctxt, p)
- break
- }
-
- if p.From.Offset&(1<<4) != 0 {
- ctxt.Diag("bad shift in LDR")
- }
- o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
- if p.As == AMOVBU {
- o1 |= 1 << 22
- }
-
- case 60: /* movb R(R),R -> ldrsb indexed */
- if p.From.Reg == 0 {
- ctxt.Diag("byte MOV from shifter operand")
- o1 = mov(ctxt, p)
- break
- }
-
- if p.From.Offset&(^0xf) != 0 {
- ctxt.Diag("bad shift in LDRSB")
- }
- o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
- o1 ^= 1<<5 | 1<<6
-
- case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
- if p.To.Reg == 0 {
- ctxt.Diag("MOV to shifter operand")
- }
- o1 = osrr(ctxt, int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
- if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
- o1 |= 1 << 22
- }
-
- /* reloc ops */
- case 64: /* mov/movb/movbu R,addr */
- o1 = omvl(ctxt, p, &p.To, REGTMP)
-
- if o1 == 0 {
- break
- }
- o2 = osr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
-
- case 65: /* mov/movbu addr,R */
- o1 = omvl(ctxt, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
- o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
- o2 |= 1 << 22
- }
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
-
- case 101: /* movw tlsvar,R, local exec*/
- if p.Scond&C_SCOND != C_SCOND_NONE {
- ctxt.Diag("conditional tls")
- }
- o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
-
- case 102: /* movw tlsvar,R, initial exec*/
- if p.Scond&C_SCOND != C_SCOND_NONE {
- ctxt.Diag("conditional tls")
- }
- o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
- o2 = olrr(ctxt, int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
-
- case 103: /* word tlsvar, local exec */
- if p.To.Sym == nil {
- ctxt.Diag("nil sym in tls %v", p)
- }
- if p.To.Offset != 0 {
- ctxt.Diag("offset against tls var in %v", p)
- }
- // This case happens with words generated in the PC stream as part of
- // the literal pool.
- rel := obj.Addrel(ctxt.Cursym)
-
- rel.Off = int32(ctxt.Pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- rel.Type = obj.R_TLS_LE
- o1 = 0
-
- case 104: /* word tlsvar, initial exec */
- if p.To.Sym == nil {
- ctxt.Diag("nil sym in tls %v", p)
- }
- if p.To.Offset != 0 {
- ctxt.Diag("offset against tls var in %v", p)
- }
- rel := obj.Addrel(ctxt.Cursym)
- rel.Off = int32(ctxt.Pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- rel.Type = obj.R_TLS_IE
- rel.Add = ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz)
-
- case 68: /* floating point store -> ADDR */
- o1 = omvl(ctxt, p, &p.To, REGTMP)
-
- if o1 == 0 {
- break
- }
- o2 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
-
- case 69: /* floating point load <- ADDR */
- o1 = omvl(ctxt, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
- o2 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
-
- /* ArmV4 ops: */
- case 70: /* movh/movhu R,O(R) -> strh */
- aclass(ctxt, &p.To)
-
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
-
- case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
- aclass(ctxt, &p.From)
-
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVB || p.As == AMOVBS {
- o1 ^= 1<<5 | 1<<6
- } else if p.As == AMOVH || p.As == AMOVHS {
- o1 ^= (1 << 6)
- }
-
- case 72: /* movh/movhu R,L(R) -> strh */
- o1 = omvl(ctxt, p, &p.To, REGTMP)
-
- if o1 == 0 {
- break
- }
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
-
- case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
- o1 = omvl(ctxt, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVB || p.As == AMOVBS {
- o2 ^= 1<<5 | 1<<6
- } else if p.As == AMOVH || p.As == AMOVHS {
- o2 ^= (1 << 6)
- }
-
- case 74: /* bx $I */
- ctxt.Diag("ABX $I")
-
- case 75: /* bx O(R) */
- aclass(ctxt, &p.To)
-
- if ctxt.Instoffset != 0 {
- ctxt.Diag("non-zero offset in ABX")
- }
-
- /*
- o1 = oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR
- o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R
- */
- // p->to.reg may be REGLINK
- o1 = oprrr(ctxt, AADD, int(p.Scond))
-
- o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
- o1 |= (uint32(p.To.Reg) & 15) << 16
- o1 |= (REGTMP & 15) << 12
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
- o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp
-
- case 76: /* bx O(R) when returning from fn*/
- ctxt.Diag("ABXRET")
-
- case 77: /* ldrex oreg,reg */
- aclass(ctxt, &p.From)
-
- if ctxt.Instoffset != 0 {
- ctxt.Diag("offset must be zero in LDREX")
- }
- o1 = 0x19<<20 | 0xf9f
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-
- case 78: /* strex reg,oreg,reg */
- aclass(ctxt, &p.From)
-
- if ctxt.Instoffset != 0 {
- ctxt.Diag("offset must be zero in STREX")
- }
- o1 = 0x18<<20 | 0xf90
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-
- case 80: /* fmov zfcon,freg */
- if p.As == AMOVD {
- o1 = 0xeeb00b00 // VMOV imm 64
- o2 = oprrr(ctxt, ASUBD, int(p.Scond))
- } else {
- o1 = 0x0eb00a00 // VMOV imm 32
- o2 = oprrr(ctxt, ASUBF, int(p.Scond))
- }
-
- v := int32(0x70) // 1.0
- r := (int(p.To.Reg) & 15) << 0
-
- // movf $1.0, r
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-
- o1 |= (uint32(r) & 15) << 12
- o1 |= (uint32(v) & 0xf) << 0
- o1 |= (uint32(v) & 0xf0) << 12
-
- // subf r,r,r
- o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
-
- case 81: /* fmov sfcon,freg */
- o1 = 0x0eb00a00 // VMOV imm 32
- if p.As == AMOVD {
- o1 = 0xeeb00b00 // VMOV imm 64
- }
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
- o1 |= (uint32(p.To.Reg) & 15) << 12
- v := int32(chipfloat5(ctxt, p.From.Val.(float64)))
- o1 |= (uint32(v) & 0xf) << 0
- o1 |= (uint32(v) & 0xf0) << 12
-
- case 82: /* fcmp freg,freg, */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0
- o2 = 0x0ef1fa10 // VMRS R15
- o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-
- case 83: /* fcmp freg,, */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16
- o2 = 0x0ef1fa10 // VMRS R15
- o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-
- case 84: /* movfw freg,freg - truncate float-to-fix */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- o1 |= (uint32(p.From.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
-
- case 85: /* movwf freg,freg - fix-to-float */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- o1 |= (uint32(p.From.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
-
- // macro for movfw freg,FTMP; movw FTMP,reg
- case 86: /* movfw freg,reg - truncate float-to-fix */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- o1 |= (uint32(p.From.Reg) & 15) << 0
- o1 |= (FREGTMP & 15) << 12
- o2 = oprrr(ctxt, -AMOVFW, int(p.Scond))
- o2 |= (FREGTMP & 15) << 16
- o2 |= (uint32(p.To.Reg) & 15) << 12
-
- // macro for movw reg,FTMP; movwf FTMP,freg
- case 87: /* movwf reg,freg - fix-to-float */
- o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
-
- o1 |= (uint32(p.From.Reg) & 15) << 12
- o1 |= (FREGTMP & 15) << 16
- o2 = oprrr(ctxt, p.As, int(p.Scond))
- o2 |= (FREGTMP & 15) << 0
- o2 |= (uint32(p.To.Reg) & 15) << 12
-
- case 88: /* movw reg,freg */
- o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
-
- o1 |= (uint32(p.From.Reg) & 15) << 12
- o1 |= (uint32(p.To.Reg) & 15) << 16
-
- case 89: /* movw freg,reg */
- o1 = oprrr(ctxt, -AMOVFW, int(p.Scond))
-
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.To.Reg) & 15) << 12
-
- case 90: /* tst reg */
- o1 = oprrr(ctxt, -ACMP, int(p.Scond))
-
- o1 |= (uint32(p.From.Reg) & 15) << 16
-
- case 91: /* ldrexd oreg,reg */
- aclass(ctxt, &p.From)
-
- if ctxt.Instoffset != 0 {
- ctxt.Diag("offset must be zero in LDREX")
- }
- o1 = 0x1b<<20 | 0xf9f
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-
- case 92: /* strexd reg,oreg,reg */
- aclass(ctxt, &p.From)
-
- if ctxt.Instoffset != 0 {
- ctxt.Diag("offset must be zero in STREX")
- }
- o1 = 0x1a<<20 | 0xf90
- o1 |= (uint32(p.From.Reg) & 15) << 16
- o1 |= (uint32(p.Reg) & 15) << 0
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
-
- case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
- o1 = omvl(ctxt, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
- o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
- if p.As == AMOVB || p.As == AMOVBS {
- o2 ^= 1<<5 | 1<<6
- } else if p.As == AMOVH || p.As == AMOVHS {
- o2 ^= (1 << 6)
- }
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
-
- case 94: /* movh/movhu R,addr -> strh */
- o1 = omvl(ctxt, p, &p.To, REGTMP)
-
- if o1 == 0 {
- break
- }
- o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond))
- if o.flag&LPCREL != 0 {
- o3 = o2
- o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
- }
-
- case 95: /* PLD off(reg) */
- o1 = 0xf5d0f000
-
- o1 |= (uint32(p.From.Reg) & 15) << 16
- if p.From.Offset < 0 {
- o1 &^= (1 << 23)
- o1 |= uint32((-p.From.Offset) & 0xfff)
- } else {
- o1 |= uint32(p.From.Offset & 0xfff)
- }
-
- // This is supposed to be something that stops execution.
- // It's not supposed to be reached, ever, but if it is, we'd
- // like to be able to tell how we got there. Assemble as
- // 0xf7fabcfd which is guaranteed to raise undefined instruction
- // exception.
- case 96: /* UNDEF */
- o1 = 0xf7fabcfd
-
- case 97: /* CLZ Rm, Rd */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= (uint32(p.From.Reg) & 15) << 0
-
- case 98: /* MULW{T,B} Rs, Rm, Rd */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- o1 |= (uint32(p.To.Reg) & 15) << 16
- o1 |= (uint32(p.From.Reg) & 15) << 8
- o1 |= (uint32(p.Reg) & 15) << 0
-
- case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
- o1 = oprrr(ctxt, p.As, int(p.Scond))
-
- o1 |= (uint32(p.To.Reg) & 15) << 12
- o1 |= (uint32(p.From.Reg) & 15) << 8
- o1 |= (uint32(p.Reg) & 15) << 0
- o1 |= uint32((p.To.Offset & 15) << 16)
-
- // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
- // DATABUNDLEEND: zero width alignment marker
- case 100:
- if p.As == ADATABUNDLE {
- o1 = 0xe125be70
- }
- }
-
- out[0] = o1
- out[1] = o2
- out[2] = o3
- out[3] = o4
- out[4] = o5
- out[5] = o6
- return
-}
-
-func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
- aclass(ctxt, &p.From)
- o1 := oprrr(ctxt, p.As, int(p.Scond))
- o1 |= uint32(p.From.Offset)
- rt := int(p.To.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = 0
- }
- r := int(p.Reg)
- if p.As == AMOVW || p.As == AMVN {
- r = 0
- } else if r == 0 {
- r = rt
- }
- o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
- return o1
-}
-
-func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
- o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
- if sc&C_SBIT != 0 {
- o |= 1 << 20
- }
- if sc&(C_PBIT|C_WBIT) != 0 {
- ctxt.Diag(".nil/.W on dp instruction")
- }
- switch a {
- case AMULU, AMUL:
- return o | 0x0<<21 | 0x9<<4
- case AMULA:
- return o | 0x1<<21 | 0x9<<4
- case AMULLU:
- return o | 0x4<<21 | 0x9<<4
- case AMULL:
- return o | 0x6<<21 | 0x9<<4
- case AMULALU:
- return o | 0x5<<21 | 0x9<<4
- case AMULAL:
- return o | 0x7<<21 | 0x9<<4
- case AAND:
- return o | 0x0<<21
- case AEOR:
- return o | 0x1<<21
- case ASUB:
- return o | 0x2<<21
- case ARSB:
- return o | 0x3<<21
- case AADD:
- return o | 0x4<<21
- case AADC:
- return o | 0x5<<21
- case ASBC:
- return o | 0x6<<21
- case ARSC:
- return o | 0x7<<21
- case ATST:
- return o | 0x8<<21 | 1<<20
- case ATEQ:
- return o | 0x9<<21 | 1<<20
- case ACMP:
- return o | 0xa<<21 | 1<<20
- case ACMN:
- return o | 0xb<<21 | 1<<20
- case AORR:
- return o | 0xc<<21
-
- case AMOVB, AMOVH, AMOVW:
- return o | 0xd<<21
- case ABIC:
- return o | 0xe<<21
- case AMVN:
- return o | 0xf<<21
- case ASLL:
- return o | 0xd<<21 | 0<<5
- case ASRL:
- return o | 0xd<<21 | 1<<5
- case ASRA:
- return o | 0xd<<21 | 2<<5
- case ASWI:
- return o | 0xf<<24
-
- case AADDD:
- return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
- case AADDF:
- return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
- case ASUBD:
- return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
- case ASUBF:
- return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
- case AMULD:
- return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
- case AMULF:
- return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
- case ADIVD:
- return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
- case ADIVF:
- return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
- case ASQRTD:
- return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
- case ASQRTF:
- return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
- case AABSD:
- return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
- case AABSF:
- return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
- case ANEGD:
- return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4
- case ANEGF:
- return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4
- case ACMPD:
- return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
- case ACMPF:
- return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
-
- case AMOVF:
- return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
- case AMOVD:
- return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
-
- case AMOVDF:
- return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
- case AMOVFD:
- return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
-
- case AMOVWF:
- if sc&C_UBIT == 0 {
- o |= 1 << 7 /* signed */
- }
- return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
-
- case AMOVWD:
- if sc&C_UBIT == 0 {
- o |= 1 << 7 /* signed */
- }
- return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double
-
- case AMOVFW:
- if sc&C_UBIT == 0 {
- o |= 1 << 16 /* signed */
- }
- return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
-
- case AMOVDW:
- if sc&C_UBIT == 0 {
- o |= 1 << 16 /* signed */
- }
- return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc
-
- case -AMOVWF: // copy WtoF
- return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
-
- case -AMOVFW: // copy FtoW
- return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
-
- case -ACMP: // cmp imm
- return o | 0x3<<24 | 0x5<<20
-
- // CLZ doesn't support .nil
- case ACLZ:
- return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
-
- case AMULWT:
- return o&(0xf<<28) | 0x12<<20 | 0xe<<4
-
- case AMULWB:
- return o&(0xf<<28) | 0x12<<20 | 0xa<<4
-
- case AMULAWT:
- return o&(0xf<<28) | 0x12<<20 | 0xc<<4
-
- case AMULAWB:
- return o&(0xf<<28) | 0x12<<20 | 0x8<<4
-
- case ABL: // BLX REG
- return o&(0xf<<28) | 0x12fff3<<4
- }
-
- ctxt.Diag("bad rrr %d", a)
- prasm(ctxt.Curp)
- return 0
-}
-
-func opbra(ctxt *obj.Link, p *obj.Prog, a obj.As, sc int) uint32 {
- if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 {
- ctxt.Diag("%v: .nil/.nil/.W on bra instruction", p)
- }
- sc &= C_SCOND
- sc ^= C_SCOND_XOR
- if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
- return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
- }
- if sc != 0xe {
- ctxt.Diag("%v: .COND on bcond instruction", p)
- }
- switch a {
- case ABEQ:
- return 0x0<<28 | 0x5<<25
- case ABNE:
- return 0x1<<28 | 0x5<<25
- case ABCS:
- return 0x2<<28 | 0x5<<25
- case ABHS:
- return 0x2<<28 | 0x5<<25
- case ABCC:
- return 0x3<<28 | 0x5<<25
- case ABLO:
- return 0x3<<28 | 0x5<<25
- case ABMI:
- return 0x4<<28 | 0x5<<25
- case ABPL:
- return 0x5<<28 | 0x5<<25
- case ABVS:
- return 0x6<<28 | 0x5<<25
- case ABVC:
- return 0x7<<28 | 0x5<<25
- case ABHI:
- return 0x8<<28 | 0x5<<25
- case ABLS:
- return 0x9<<28 | 0x5<<25
- case ABGE:
- return 0xa<<28 | 0x5<<25
- case ABLT:
- return 0xb<<28 | 0x5<<25
- case ABGT:
- return 0xc<<28 | 0x5<<25
- case ABLE:
- return 0xd<<28 | 0x5<<25
- case AB:
- return 0xe<<28 | 0x5<<25
- }
-
- ctxt.Diag("bad bra %v", a)
- prasm(ctxt.Curp)
- return 0
-}
-
-func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
- if sc&C_SBIT != 0 {
- ctxt.Diag(".nil on LDR/STR instruction")
- }
- o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
- if sc&C_PBIT == 0 {
- o |= 1 << 24
- }
- if sc&C_UBIT == 0 {
- o |= 1 << 23
- }
- if sc&C_WBIT != 0 {
- o |= 1 << 21
- }
- o |= 1<<26 | 1<<20
- if v < 0 {
- if sc&C_UBIT != 0 {
- ctxt.Diag(".U on neg offset")
- }
- v = -v
- o ^= 1 << 23
- }
-
- if v >= 1<<12 || v < 0 {
- ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
- }
- o |= uint32(v)
- o |= (uint32(b) & 15) << 16
- o |= (uint32(r) & 15) << 12
- return o
-}
-
-func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
- if sc&C_SBIT != 0 {
- ctxt.Diag(".nil on LDRH/STRH instruction")
- }
- o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
- if sc&C_PBIT == 0 {
- o |= 1 << 24
- }
- if sc&C_WBIT != 0 {
- o |= 1 << 21
- }
- o |= 1<<23 | 1<<20 | 0xb<<4
- if v < 0 {
- v = -v
- o ^= 1 << 23
- }
-
- if v >= 1<<8 || v < 0 {
- ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
- }
- o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
- o |= (uint32(b) & 15) << 16
- o |= (uint32(r) & 15) << 12
- return o
-}
-
-func osr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int) uint32 {
- o := olr(ctxt, v, b, r, sc) ^ (1 << 20)
- if a != AMOVW {
- o |= 1 << 22
- }
- return o
-}
-
-func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 {
- o := olhr(ctxt, v, b, r, sc) ^ (1 << 20)
- return o
-}
-
-func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
- return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20)
-}
-
-func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
- return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20)
-}
-
-func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
- return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25)
-}
-
-func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
- return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22)
-}
-
-func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
- if sc&C_SBIT != 0 {
- ctxt.Diag(".nil on FLDR/FSTR instruction: %v", p)
- }
- o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
- if sc&C_PBIT == 0 {
- o |= 1 << 24
- }
- if sc&C_WBIT != 0 {
- o |= 1 << 21
- }
- o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
- if v < 0 {
- v = -v
- o ^= 1 << 23
- }
-
- if v&3 != 0 {
- ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
- } else if v >= 1<<10 || v < 0 {
- ctxt.Diag("literal span too large: %d\n%v", v, p)
- }
- o |= (uint32(v) >> 2) & 0xFF
- o |= (uint32(b) & 15) << 16
- o |= (uint32(r) & 15) << 12
-
- switch a {
- default:
- ctxt.Diag("bad fst %v", a)
- fallthrough
-
- case AMOVD:
- o |= 1 << 8
- fallthrough
-
- case AMOVF:
- break
- }
-
- return o
-}
-
-func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
- var o1 uint32
- if p.Pcond == nil {
- aclass(ctxt, a)
- v := immrot(^uint32(ctxt.Instoffset))
- if v == 0 {
- ctxt.Diag("missing literal")
- prasm(p)
- return 0
- }
-
- o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND)
- o1 |= uint32(v)
- o1 |= (uint32(dr) & 15) << 12
- } else {
- v := int32(p.Pcond.Pc - p.Pc - 8)
- o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND)
- }
-
- return o1
-}
-
-func chipzero5(ctxt *obj.Link, e float64) int {
- // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if obj.GOARM < 7 || e != 0 {
- return -1
- }
- return 0
-}
-
-func chipfloat5(ctxt *obj.Link, e float64) int {
- // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if obj.GOARM < 7 {
- return -1
- }
-
- ei := math.Float64bits(e)
- l := uint32(ei)
- h := uint32(ei >> 32)
-
- if l != 0 || h&0xffff != 0 {
- return -1
- }
- h1 := h & 0x7fc00000
- if h1 != 0x40000000 && h1 != 0x3fc00000 {
- return -1
- }
- n := 0
-
- // sign bit (a)
- if h&0x80000000 != 0 {
- n |= 1 << 7
- }
-
- // exp sign bit (b)
- if h1 == 0x3fc00000 {
- n |= 1 << 6
- }
-
- // rest of exp and mantissa (cd-efgh)
- n |= int((h >> 16) & 0x3f)
-
- //print("match %.8lux %.8lux %d\n", l, h, n);
- return n
-}
-
-func nocache(p *obj.Prog) {
- p.Optab = 0
- p.From.Class = 0
- if p.From3 != nil {
- p.From3.Class = 0
- }
- p.To.Class = 0
-}
diff --git a/vendor/github.com/google/gops/internal/obj/arm/list5.go b/vendor/github.com/google/gops/internal/obj/arm/list5.go
deleted file mode 100644
index f6c50168..00000000
--- a/vendor/github.com/google/gops/internal/obj/arm/list5.go
+++ /dev/null
@@ -1,84 +0,0 @@
-// Inferno utils/5c/list.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/list.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.
-
-package arm
-
-import (
- "fmt"
-
- "github.com/google/gops/internal/obj"
-)
-
-func init() {
- obj.RegisterRegister(obj.RBaseARM, MAXREG, Rconv)
- obj.RegisterOpcode(obj.ABaseARM, Anames)
-}
-
-func Rconv(r int) string {
- if r == 0 {
- return "NONE"
- }
- if r == REGG {
- // Special case.
- return "g"
- }
- if REG_R0 <= r && r <= REG_R15 {
- return fmt.Sprintf("R%d", r-REG_R0)
- }
- if REG_F0 <= r && r <= REG_F15 {
- return fmt.Sprintf("F%d", r-REG_F0)
- }
-
- switch r {
- case REG_FPSR:
- return "FPSR"
-
- case REG_FPCR:
- return "FPCR"
-
- case REG_CPSR:
- return "CPSR"
-
- case REG_SPSR:
- return "SPSR"
- }
-
- return fmt.Sprintf("Rgok(%d)", r-obj.RBaseARM)
-}
-
-func DRconv(a int) string {
- s := "C_??"
- if a >= C_NONE && a <= C_NCLASS {
- s = cnames5[a]
- }
- var fp string
- fp += s
- return fp
-}
diff --git a/vendor/github.com/google/gops/internal/obj/arm/obj5.go b/vendor/github.com/google/gops/internal/obj/arm/obj5.go
deleted file mode 100644
index 2c4e39b7..00000000
--- a/vendor/github.com/google/gops/internal/obj/arm/obj5.go
+++ /dev/null
@@ -1,1055 +0,0 @@
-// Derived from Inferno utils/5c/swt.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/swt.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.
-
-package arm
-
-import (
- "fmt"
- "log"
- "math"
-
- "github.com/google/gops/internal/obj"
- "github.com/google/gops/internal/sys"
-)
-
-var progedit_tlsfallback *obj.LSym
-
-func progedit(ctxt *obj.Link, p *obj.Prog) {
- p.From.Class = 0
- p.To.Class = 0
-
- // Rewrite B/BL to symbol as TYPE_BRANCH.
- switch p.As {
- case AB,
- ABL,
- obj.ADUFFZERO,
- obj.ADUFFCOPY:
- if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
- p.To.Type = obj.TYPE_BRANCH
- }
- }
-
- // Replace TLS register fetches on older ARM processors.
- switch p.As {
- // Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
- case AMRC:
- if p.To.Offset&0xffff0fff == 0xee1d0f70 {
- // Because the instruction might be rewritten to a BL which returns in R0
- // the register must be zero.
- if p.To.Offset&0xf000 != 0 {
- ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
- }
-
- if obj.GOARM < 7 {
- // Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
- if progedit_tlsfallback == nil {
- progedit_tlsfallback = obj.Linklookup(ctxt, "runtime.read_tls_fallback", 0)
- }
-
- // MOVW LR, R11
- p.As = AMOVW
-
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REGLINK
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REGTMP
-
- // BL runtime.read_tls_fallback(SB)
- p = obj.Appendp(ctxt, p)
-
- p.As = ABL
- p.To.Type = obj.TYPE_BRANCH
- p.To.Sym = progedit_tlsfallback
- p.To.Offset = 0
-
- // MOVW R11, LR
- p = obj.Appendp(ctxt, p)
-
- p.As = AMOVW
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REGTMP
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REGLINK
- break
- }
- }
-
- // Otherwise, MRC/MCR instructions need no further treatment.
- p.As = AWORD
- }
-
- // Rewrite float constants to values stored in memory.
- switch p.As {
- case AMOVF:
- if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
- f32 := float32(p.From.Val.(float64))
- i32 := math.Float32bits(f32)
- literal := fmt.Sprintf("$f32.%08x", i32)
- s := obj.Linklookup(ctxt, literal, 0)
- p.From.Type = obj.TYPE_MEM
- p.From.Sym = s
- p.From.Name = obj.NAME_EXTERN
- p.From.Offset = 0
- }
-
- case AMOVD:
- if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
- i64 := math.Float64bits(p.From.Val.(float64))
- literal := fmt.Sprintf("$f64.%016x", i64)
- s := obj.Linklookup(ctxt, literal, 0)
- p.From.Type = obj.TYPE_MEM
- p.From.Sym = s
- p.From.Name = obj.NAME_EXTERN
- p.From.Offset = 0
- }
- }
-
- if ctxt.Flag_dynlink {
- rewriteToUseGot(ctxt, p)
- }
-}
-
-// Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
- if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
- // ADUFFxxx $offset
- // becomes
- // MOVW runtime.duffxxx@GOT, R9
- // ADD $offset, R9
- // CALL (R9)
- var sym *obj.LSym
- if p.As == obj.ADUFFZERO {
- sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
- } else {
- sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
- }
- offset := p.To.Offset
- p.As = AMOVW
- p.From.Type = obj.TYPE_MEM
- p.From.Name = obj.NAME_GOTREF
- p.From.Sym = sym
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R9
- p.To.Name = obj.NAME_NONE
- p.To.Offset = 0
- p.To.Sym = nil
- p1 := obj.Appendp(ctxt, p)
- p1.As = AADD
- p1.From.Type = obj.TYPE_CONST
- p1.From.Offset = offset
- p1.To.Type = obj.TYPE_REG
- p1.To.Reg = REG_R9
- p2 := obj.Appendp(ctxt, p1)
- p2.As = obj.ACALL
- p2.To.Type = obj.TYPE_MEM
- p2.To.Reg = REG_R9
- return
- }
-
- // We only care about global data: NAME_EXTERN means a global
- // symbol in the Go sense, and p.Sym.Local is true for a few
- // internally defined symbols.
- if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
- // MOVW $sym, Rx becomes MOVW sym@GOT, Rx
- // MOVW $sym+<off>, Rx becomes MOVW sym@GOT, Rx; ADD <off>, Rx
- if p.As != AMOVW {
- ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
- }
- if p.To.Type != obj.TYPE_REG {
- ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
- }
- p.From.Type = obj.TYPE_MEM
- p.From.Name = obj.NAME_GOTREF
- if p.From.Offset != 0 {
- q := obj.Appendp(ctxt, p)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = p.From.Offset
- q.To = p.To
- p.From.Offset = 0
- }
- }
- if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
- ctxt.Diag("don't know how to handle %v with -dynlink", p)
- }
- var source *obj.Addr
- // MOVx sym, Ry becomes MOVW sym@GOT, R9; MOVx (R9), Ry
- // MOVx Ry, sym becomes MOVW sym@GOT, R9; MOVx Ry, (R9)
- // An addition may be inserted between the two MOVs if there is an offset.
- if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
- if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
- ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
- }
- source = &p.From
- } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
- source = &p.To
- } else {
- return
- }
- if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
- return
- }
- if source.Sym.Type == obj.STLSBSS {
- return
- }
- if source.Type != obj.TYPE_MEM {
- ctxt.Diag("don't know how to handle %v with -dynlink", p)
- }
- p1 := obj.Appendp(ctxt, p)
- p2 := obj.Appendp(ctxt, p1)
-
- p1.As = AMOVW
- p1.From.Type = obj.TYPE_MEM
- p1.From.Sym = source.Sym
- p1.From.Name = obj.NAME_GOTREF
- p1.To.Type = obj.TYPE_REG
- p1.To.Reg = REG_R9
-
- p2.As = p.As
- p2.From = p.From
- p2.To = p.To
- if p.From.Name == obj.NAME_EXTERN {
- p2.From.Reg = REG_R9
- p2.From.Name = obj.NAME_NONE
- p2.From.Sym = nil
- } else if p.To.Name == obj.NAME_EXTERN {
- p2.To.Reg = REG_R9
- p2.To.Name = obj.NAME_NONE
- p2.To.Sym = nil
- } else {
- return
- }
- obj.Nopout(p)
-}
-
-// Prog.mark
-const (
- FOLL = 1 << 0
- LABEL = 1 << 1
- LEAF = 1 << 2
-)
-
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
- autosize := int32(0)
-
- ctxt.Cursym = cursym
-
- if cursym.Text == nil || cursym.Text.Link == nil {
- return
- }
-
- softfloat(ctxt, cursym)
-
- p := cursym.Text
- autoffset := int32(p.To.Offset)
- if autoffset < 0 {
- autoffset = 0
- }
- cursym.Locals = autoffset
- cursym.Args = p.To.Val.(int32)
-
- /*
- * find leaf subroutines
- * strip NOPs
- * expand RET
- * expand BECOME pseudo
- */
- var q1 *obj.Prog
- var q *obj.Prog
- for p := cursym.Text; p != nil; p = p.Link {
- switch p.As {
- case obj.ATEXT:
- p.Mark |= LEAF
-
- case obj.ARET:
- break
-
- case ADIV, ADIVU, AMOD, AMODU:
- q = p
- if ctxt.Sym_div == nil {
- initdiv(ctxt)
- }
- cursym.Text.Mark &^= LEAF
- continue
-
- case obj.ANOP:
- q1 = p.Link
- q.Link = q1 /* q is non-nop */
- if q1 != nil {
- q1.Mark |= p.Mark
- }
- continue
-
- case ABL,
- ABX,
- obj.ADUFFZERO,
- obj.ADUFFCOPY:
- cursym.Text.Mark &^= LEAF
- fallthrough
-
- case AB,
- ABEQ,
- ABNE,
- ABCS,
- ABHS,
- ABCC,
- ABLO,
- ABMI,
- ABPL,
- ABVS,
- ABVC,
- ABHI,
- ABLS,
- ABGE,
- ABLT,
- ABGT,
- ABLE:
- q1 = p.Pcond
- if q1 != nil {
- for q1.As == obj.ANOP {
- q1 = q1.Link
- p.Pcond = q1
- }
- }
- }
-
- q = p
- }
-
- var p1 *obj.Prog
- var p2 *obj.Prog
- var q2 *obj.Prog
- for p := cursym.Text; p != nil; p = p.Link {
- o := p.As
- switch o {
- case obj.ATEXT:
- autosize = int32(p.To.Offset + 4)
- if autosize <= 4 {
- if cursym.Text.Mark&LEAF != 0 {
- p.To.Offset = -4
- autosize = 0
- }
- }
-
- if autosize == 0 && cursym.Text.Mark&LEAF == 0 {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("save suppressed in: %s\n", cursym.Name)
- }
-
- cursym.Text.Mark |= LEAF
- }
-
- if cursym.Text.Mark&LEAF != 0 {
- cursym.Set(obj.AttrLeaf, true)
- if autosize == 0 {
- break
- }
- }
-
- if p.From3.Offset&obj.NOSPLIT == 0 {
- p = stacksplit(ctxt, p, autosize) // emit split check
- }
-
- // MOVW.W R14,$-autosize(SP)
- p = obj.Appendp(ctxt, p)
-
- p.As = AMOVW
- p.Scond |= C_WBIT
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REGLINK
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(-autosize)
- p.To.Reg = REGSP
- p.Spadj = autosize
-
- if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVW g_panic(g), R1
- // CMP $0, R1
- // B.EQ end
- // MOVW panic_argp(R1), R2
- // ADD $(autosize+4), R13, R3
- // CMP R2, R3
- // B.NE end
- // ADD $4, R13, R4
- // MOVW R4, panic_argp(R1)
- // end:
- // NOP
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
-
- p = obj.Appendp(ctxt, p)
-
- p.As = AMOVW
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REGG
- p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R1
-
- p = obj.Appendp(ctxt, p)
- p.As = ACMP
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.Reg = REG_R1
-
- p = obj.Appendp(ctxt, p)
- p.As = ABEQ
- p.To.Type = obj.TYPE_BRANCH
- p1 = p
-
- p = obj.Appendp(ctxt, p)
- p.As = AMOVW
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REG_R1
- p.From.Offset = 0 // Panic.argp
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R2
-
- p = obj.Appendp(ctxt, p)
- p.As = AADD
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(autosize) + 4
- p.Reg = REG_R13
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R3
-
- p = obj.Appendp(ctxt, p)
- p.As = ACMP
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R2
- p.Reg = REG_R3
-
- p = obj.Appendp(ctxt, p)
- p.As = ABNE
- p.To.Type = obj.TYPE_BRANCH
- p2 = p
-
- p = obj.Appendp(ctxt, p)
- p.As = AADD
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 4
- p.Reg = REG_R13
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R4
-
- p = obj.Appendp(ctxt, p)
- p.As = AMOVW
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R4
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = REG_R1
- p.To.Offset = 0 // Panic.argp
-
- p = obj.Appendp(ctxt, p)
-
- p.As = obj.ANOP
- p1.Pcond = p
- p2.Pcond = p
- }
-
- case obj.ARET:
- nocache(p)
- if cursym.Text.Mark&LEAF != 0 {
- if autosize == 0 {
- p.As = AB
- p.From = obj.Addr{}
- if p.To.Sym != nil { // retjmp
- p.To.Type = obj.TYPE_BRANCH
- } else {
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = REGLINK
- }
-
- break
- }
- }
-
- p.As = AMOVW
- p.Scond |= C_PBIT
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(autosize)
- p.From.Reg = REGSP
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REGPC
-
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so no spadj.
- if p.To.Sym != nil { // retjmp
- p.To.Reg = REGLINK
- q2 = obj.Appendp(ctxt, p)
- q2.As = AB
- q2.To.Type = obj.TYPE_BRANCH
- q2.To.Sym = p.To.Sym
- p.To.Sym = nil
- p = q2
- }
-
- case AADD:
- if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
- p.Spadj = int32(-p.From.Offset)
- }
-
- case ASUB:
- if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
- p.Spadj = int32(p.From.Offset)
- }
-
- case ADIV, ADIVU, AMOD, AMODU:
- if cursym.Text.From3.Offset&obj.NOSPLIT != 0 {
- ctxt.Diag("cannot divide in NOSPLIT function")
- }
- if ctxt.Debugdivmod != 0 {
- break
- }
- if p.From.Type != obj.TYPE_REG {
- break
- }
- if p.To.Type != obj.TYPE_REG {
- break
- }
-
- // Make copy because we overwrite p below.
- q1 := *p
- if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP {
- ctxt.Diag("div already using REGTMP: %v", p)
- }
-
- /* MOV m(g),REGTMP */
- p.As = AMOVW
- p.Lineno = q1.Lineno
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REGG
- p.From.Offset = 6 * 4 // offset of g.m
- p.Reg = 0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REGTMP
-
- /* MOV a,m_divmod(REGTMP) */
- p = obj.Appendp(ctxt, p)
- p.As = AMOVW
- p.Lineno = q1.Lineno
- p.From.Type = obj.TYPE_REG
- p.From.Reg = q1.From.Reg
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = REGTMP
- p.To.Offset = 8 * 4 // offset of m.divmod
-
- /* MOV b, R8 */
- p = obj.Appendp(ctxt, p)
- p.As = AMOVW
- p.Lineno = q1.Lineno
- p.From.Type = obj.TYPE_REG
- p.From.Reg = q1.Reg
- if q1.Reg == 0 {
- p.From.Reg = q1.To.Reg
- }
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R8
- p.To.Offset = 0
-
- /* CALL appropriate */
- p = obj.Appendp(ctxt, p)
- p.As = ABL
- p.Lineno = q1.Lineno
- p.To.Type = obj.TYPE_BRANCH
- switch o {
- case ADIV:
- p.To.Sym = ctxt.Sym_div
-
- case ADIVU:
- p.To.Sym = ctxt.Sym_divu
-
- case AMOD:
- p.To.Sym = ctxt.Sym_mod
-
- case AMODU:
- p.To.Sym = ctxt.Sym_modu
- }
-
- /* MOV REGTMP, b */
- p = obj.Appendp(ctxt, p)
- p.As = AMOVW
- p.Lineno = q1.Lineno
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REGTMP
- p.From.Offset = 0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = q1.To.Reg
-
- case AMOVW:
- if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
- p.Spadj = int32(-p.To.Offset)
- }
- if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC {
- p.Spadj = int32(-p.From.Offset)
- }
- if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
- p.Spadj = int32(-p.From.Offset)
- }
- }
- }
-}
-
-func isfloatreg(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG && REG_F0 <= a.Reg && a.Reg <= REG_F15
-}
-
-func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
- if obj.GOARM > 5 {
- return
- }
-
- symsfloat := obj.Linklookup(ctxt, "_sfloat", 0)
-
- wasfloat := 0
- for p := cursym.Text; p != nil; p = p.Link {
- if p.Pcond != nil {
- p.Pcond.Mark |= LABEL
- }
- }
- var next *obj.Prog
- for p := cursym.Text; p != nil; p = p.Link {
- switch p.As {
- case AMOVW:
- if isfloatreg(&p.To) || isfloatreg(&p.From) {
- goto soft
- }
- goto notsoft
-
- case AMOVWD,
- AMOVWF,
- AMOVDW,
- AMOVFW,
- AMOVFD,
- AMOVDF,
- AMOVF,
- AMOVD,
- ACMPF,
- ACMPD,
- AADDF,
- AADDD,
- ASUBF,
- ASUBD,
- AMULF,
- AMULD,
- ADIVF,
- ADIVD,
- ASQRTF,
- ASQRTD,
- AABSF,
- AABSD,
- ANEGF,
- ANEGD:
- goto soft
-
- default:
- goto notsoft
- }
-
- soft:
- if wasfloat == 0 || (p.Mark&LABEL != 0) {
- next = ctxt.NewProg()
- *next = *p
-
- // BL _sfloat(SB)
- *p = obj.Prog{}
- p.Ctxt = ctxt
- p.Link = next
- p.As = ABL
- p.To.Type = obj.TYPE_BRANCH
- p.To.Sym = symsfloat
- p.Lineno = next.Lineno
-
- p = next
- wasfloat = 1
- }
-
- continue
-
- notsoft:
- wasfloat = 0
- }
-}
-
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
- // MOVW g_stackguard(g), R1
- p = obj.Appendp(ctxt, p)
-
- p.As = AMOVW
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REGG
- p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
- if ctxt.Cursym.CFunc() {
- p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
- }
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R1
-
- if framesize <= obj.StackSmall {
- // small stack: SP < stackguard
- // CMP stackguard, SP
- p = obj.Appendp(ctxt, p)
-
- p.As = ACMP
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R1
- p.Reg = REGSP
- } else if framesize <= obj.StackBig {
- // large stack: SP-framesize < stackguard-StackSmall
- // MOVW $-framesize(SP), R2
- // CMP stackguard, R2
- p = obj.Appendp(ctxt, p)
-
- p.As = AMOVW
- p.From.Type = obj.TYPE_ADDR
- p.From.Reg = REGSP
- p.From.Offset = int64(-framesize)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R2
-
- p = obj.Appendp(ctxt, p)
- p.As = ACMP
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R1
- p.Reg = REG_R2
- } else {
- // Such a large stack we need to protect against wraparound
- // if SP is close to zero.
- // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
- // The +StackGuard on both sides is required to keep the left side positive:
- // SP is allowed to be slightly below stackguard. See stack.h.
- // CMP $StackPreempt, R1
- // MOVW.NE $StackGuard(SP), R2
- // SUB.NE R1, R2
- // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
- // CMP.NE R3, R2
- p = obj.Appendp(ctxt, p)
-
- p.As = ACMP
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
- p.Reg = REG_R1
-
- p = obj.Appendp(ctxt, p)
- p.As = AMOVW
- p.From.Type = obj.TYPE_ADDR
- p.From.Reg = REGSP
- p.From.Offset = obj.StackGuard
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R2
- p.Scond = C_SCOND_NE
-
- p = obj.Appendp(ctxt, p)
- p.As = ASUB
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R1
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R2
- p.Scond = C_SCOND_NE
-
- p = obj.Appendp(ctxt, p)
- p.As = AMOVW
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R3
- p.Scond = C_SCOND_NE
-
- p = obj.Appendp(ctxt, p)
- p.As = ACMP
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R3
- p.Reg = REG_R2
- p.Scond = C_SCOND_NE
- }
-
- // BLS call-to-morestack
- bls := obj.Appendp(ctxt, p)
- bls.As = ABLS
- bls.To.Type = obj.TYPE_BRANCH
-
- var last *obj.Prog
- for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
- }
-
- // Now we are at the end of the function, but logically
- // we are still in function prologue. We need to fix the
- // SP data and PCDATA.
- spfix := obj.Appendp(ctxt, last)
- spfix.As = obj.ANOP
- spfix.Spadj = -framesize
-
- pcdata := obj.Appendp(ctxt, spfix)
- pcdata.Lineno = ctxt.Cursym.Text.Lineno
- pcdata.Mode = ctxt.Cursym.Text.Mode
- pcdata.As = obj.APCDATA
- pcdata.From.Type = obj.TYPE_CONST
- pcdata.From.Offset = obj.PCDATA_StackMapIndex
- pcdata.To.Type = obj.TYPE_CONST
- pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
-
- // MOVW LR, R3
- movw := obj.Appendp(ctxt, pcdata)
- movw.As = AMOVW
- movw.From.Type = obj.TYPE_REG
- movw.From.Reg = REGLINK
- movw.To.Type = obj.TYPE_REG
- movw.To.Reg = REG_R3
-
- bls.Pcond = movw
-
- // BL runtime.morestack
- call := obj.Appendp(ctxt, movw)
- call.As = obj.ACALL
- call.To.Type = obj.TYPE_BRANCH
- morestack := "runtime.morestack"
- switch {
- case ctxt.Cursym.CFunc():
- morestack = "runtime.morestackc"
- case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
- morestack = "runtime.morestack_noctxt"
- }
- call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
-
- // B start
- b := obj.Appendp(ctxt, call)
- b.As = obj.AJMP
- b.To.Type = obj.TYPE_BRANCH
- b.Pcond = ctxt.Cursym.Text.Link
- b.Spadj = +framesize
-
- return bls
-}
-
-func initdiv(ctxt *obj.Link) {
- if ctxt.Sym_div != nil {
- return
- }
- ctxt.Sym_div = obj.Linklookup(ctxt, "_div", 0)
- ctxt.Sym_divu = obj.Linklookup(ctxt, "_divu", 0)
- ctxt.Sym_mod = obj.Linklookup(ctxt, "_mod", 0)
- ctxt.Sym_modu = obj.Linklookup(ctxt, "_modu", 0)
-}
-
-func follow(ctxt *obj.Link, s *obj.LSym) {
- ctxt.Cursym = s
-
- firstp := ctxt.NewProg()
- lastp := firstp
- xfol(ctxt, s.Text, &lastp)
- lastp.Link = nil
- s.Text = firstp.Link
-}
-
-func relinv(a obj.As) obj.As {
- switch a {
- case ABEQ:
- return ABNE
- case ABNE:
- return ABEQ
- case ABCS:
- return ABCC
- case ABHS:
- return ABLO
- case ABCC:
- return ABCS
- case ABLO:
- return ABHS
- case ABMI:
- return ABPL
- case ABPL:
- return ABMI
- case ABVS:
- return ABVC
- case ABVC:
- return ABVS
- case ABHI:
- return ABLS
- case ABLS:
- return ABHI
- case ABGE:
- return ABLT
- case ABLT:
- return ABGE
- case ABGT:
- return ABLE
- case ABLE:
- return ABGT
- }
-
- log.Fatalf("unknown relation: %s", Anames[a])
- return 0
-}
-
-func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
- var q *obj.Prog
- var r *obj.Prog
- var i int
-
-loop:
- if p == nil {
- return
- }
- a := p.As
- if a == AB {
- q = p.Pcond
- if q != nil && q.As != obj.ATEXT {
- p.Mark |= FOLL
- p = q
- if p.Mark&FOLL == 0 {
- goto loop
- }
- }
- }
-
- if p.Mark&FOLL != 0 {
- i = 0
- q = p
- for ; i < 4; i, q = i+1, q.Link {
- if q == *last || q == nil {
- break
- }
- a = q.As
- if a == obj.ANOP {
- i--
- continue
- }
-
- if a == AB || (a == obj.ARET && q.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
- goto copy
- }
- if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
- continue
- }
- if a != ABEQ && a != ABNE {
- continue
- }
-
- copy:
- for {
- r = ctxt.NewProg()
- *r = *p
- if r.Mark&FOLL == 0 {
- fmt.Printf("can't happen 1\n")
- }
- r.Mark |= FOLL
- if p != q {
- p = p.Link
- (*last).Link = r
- *last = r
- continue
- }
-
- (*last).Link = r
- *last = r
- if a == AB || (a == obj.ARET && q.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
- return
- }
- r.As = ABNE
- if a == ABNE {
- r.As = ABEQ
- }
- r.Pcond = p.Link
- r.Link = p.Pcond
- if r.Link.Mark&FOLL == 0 {
- xfol(ctxt, r.Link, last)
- }
- if r.Pcond.Mark&FOLL == 0 {
- fmt.Printf("can't happen 2\n")
- }
- return
- }
- }
-
- a = AB
- q = ctxt.NewProg()
- q.As = a
- q.Lineno = p.Lineno
- q.To.Type = obj.TYPE_BRANCH
- q.To.Offset = p.Pc
- q.Pcond = p
- p = q
- }
-
- p.Mark |= FOLL
- (*last).Link = p
- *last = p
- if a == AB || (a == obj.ARET && p.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
- return
- }
-
- if p.Pcond != nil {
- if a != ABL && a != ABX && p.Link != nil {
- q = obj.Brchain(ctxt, p.Link)
- if a != obj.ATEXT {
- if q != nil && (q.Mark&FOLL != 0) {
- p.As = relinv(a)
- p.Link = p.Pcond
- p.Pcond = q
- }
- }
-
- xfol(ctxt, p.Link, last)
- q = obj.Brchain(ctxt, p.Pcond)
- if q == nil {
- q = p.Pcond
- }
- if q.Mark&FOLL != 0 {
- p.Pcond = q
- return
- }
-
- p = q
- goto loop
- }
- }
-
- p = p.Link
- goto loop
-}
-
-var unaryDst = map[obj.As]bool{
- ASWI: true,
- AWORD: true,
-}
-
-var Linkarm = obj.LinkArch{
- Arch: sys.ArchARM,
- Preprocess: preprocess,
- Assemble: span5,
- Follow: follow,
- Progedit: progedit,
- UnaryDst: unaryDst,
-}