...

Source file src/pkg/cmd/asm/internal/arch/arm.go

     1	// Copyright 2015 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// This file encapsulates some of the odd characteristics of the ARM
     6	// instruction set, to minimize its interaction with the core of the
     7	// assembler.
     8	
     9	package arch
    10	
    11	import (
    12		"strings"
    13	
    14		"cmd/internal/obj"
    15		"cmd/internal/obj/arm"
    16	)
    17	
    18	var armLS = map[string]uint8{
    19		"U":  arm.C_UBIT,
    20		"S":  arm.C_SBIT,
    21		"W":  arm.C_WBIT,
    22		"P":  arm.C_PBIT,
    23		"PW": arm.C_WBIT | arm.C_PBIT,
    24		"WP": arm.C_WBIT | arm.C_PBIT,
    25	}
    26	
    27	var armSCOND = map[string]uint8{
    28		"EQ":  arm.C_SCOND_EQ,
    29		"NE":  arm.C_SCOND_NE,
    30		"CS":  arm.C_SCOND_HS,
    31		"HS":  arm.C_SCOND_HS,
    32		"CC":  arm.C_SCOND_LO,
    33		"LO":  arm.C_SCOND_LO,
    34		"MI":  arm.C_SCOND_MI,
    35		"PL":  arm.C_SCOND_PL,
    36		"VS":  arm.C_SCOND_VS,
    37		"VC":  arm.C_SCOND_VC,
    38		"HI":  arm.C_SCOND_HI,
    39		"LS":  arm.C_SCOND_LS,
    40		"GE":  arm.C_SCOND_GE,
    41		"LT":  arm.C_SCOND_LT,
    42		"GT":  arm.C_SCOND_GT,
    43		"LE":  arm.C_SCOND_LE,
    44		"AL":  arm.C_SCOND_NONE,
    45		"U":   arm.C_UBIT,
    46		"S":   arm.C_SBIT,
    47		"W":   arm.C_WBIT,
    48		"P":   arm.C_PBIT,
    49		"PW":  arm.C_WBIT | arm.C_PBIT,
    50		"WP":  arm.C_WBIT | arm.C_PBIT,
    51		"F":   arm.C_FBIT,
    52		"IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT,
    53		"IAW": arm.C_WBIT | arm.C_UBIT,
    54		"DBW": arm.C_WBIT | arm.C_PBIT,
    55		"DAW": arm.C_WBIT,
    56		"IB":  arm.C_PBIT | arm.C_UBIT,
    57		"IA":  arm.C_UBIT,
    58		"DB":  arm.C_PBIT,
    59		"DA":  0,
    60	}
    61	
    62	var armJump = map[string]bool{
    63		"B":    true,
    64		"BL":   true,
    65		"BX":   true,
    66		"BEQ":  true,
    67		"BNE":  true,
    68		"BCS":  true,
    69		"BHS":  true,
    70		"BCC":  true,
    71		"BLO":  true,
    72		"BMI":  true,
    73		"BPL":  true,
    74		"BVS":  true,
    75		"BVC":  true,
    76		"BHI":  true,
    77		"BLS":  true,
    78		"BGE":  true,
    79		"BLT":  true,
    80		"BGT":  true,
    81		"BLE":  true,
    82		"CALL": true,
    83		"JMP":  true,
    84	}
    85	
    86	func jumpArm(word string) bool {
    87		return armJump[word]
    88	}
    89	
    90	// IsARMCMP reports whether the op (as defined by an arm.A* constant) is
    91	// one of the comparison instructions that require special handling.
    92	func IsARMCMP(op obj.As) bool {
    93		switch op {
    94		case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
    95			return true
    96		}
    97		return false
    98	}
    99	
   100	// IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
   101	// one of the STREX-like instructions that require special handling.
   102	func IsARMSTREX(op obj.As) bool {
   103		switch op {
   104		case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
   105			return true
   106		}
   107		return false
   108	}
   109	
   110	// MCR is not defined by the obj/arm; instead we define it privately here.
   111	// It is encoded as an MRC with a bit inside the instruction word,
   112	// passed to arch.ARMMRCOffset.
   113	const aMCR = arm.ALAST + 1
   114	
   115	// IsARMMRC reports whether the op (as defined by an arm.A* constant) is
   116	// MRC or MCR
   117	func IsARMMRC(op obj.As) bool {
   118		switch op {
   119		case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
   120			return true
   121		}
   122		return false
   123	}
   124	
   125	// IsARMBFX reports whether the op (as defined by an arm.A* constant) is one the
   126	// BFX-like instructions which are in the form of "op $width, $LSB, (Reg,) Reg".
   127	func IsARMBFX(op obj.As) bool {
   128		switch op {
   129		case arm.ABFX, arm.ABFXU, arm.ABFC, arm.ABFI:
   130			return true
   131		}
   132		return false
   133	}
   134	
   135	// IsARMFloatCmp reports whether the op is a floating comparison instruction.
   136	func IsARMFloatCmp(op obj.As) bool {
   137		switch op {
   138		case arm.ACMPF, arm.ACMPD:
   139			return true
   140		}
   141		return false
   142	}
   143	
   144	// ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
   145	// The difference between MRC and MCR is represented by a bit high in the word, not
   146	// in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
   147	// we return the opcode for MRC so that asm doesn't need to import obj/arm.
   148	func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) {
   149		op1 := int64(0)
   150		if op == arm.AMRC {
   151			op1 = 1
   152		}
   153		bits, ok := ParseARMCondition(cond)
   154		if !ok {
   155			return
   156		}
   157		offset = (0xe << 24) | // opcode
   158			(op1 << 20) | // MCR/MRC
   159			((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
   160			((x0 & 15) << 8) | //coprocessor number
   161			((x1 & 7) << 21) | // coprocessor operation
   162			((x2 & 15) << 12) | // ARM register
   163			((x3 & 15) << 16) | // Crn
   164			((x4 & 15) << 0) | // Crm
   165			((x5 & 7) << 5) | // coprocessor information
   166			(1 << 4) /* must be set */
   167		return offset, arm.AMRC, true
   168	}
   169	
   170	// IsARMMULA reports whether the op (as defined by an arm.A* constant) is
   171	// MULA, MULS, MMULA, MMULS, MULABB, MULAWB or MULAWT, the 4-operand instructions.
   172	func IsARMMULA(op obj.As) bool {
   173		switch op {
   174		case arm.AMULA, arm.AMULS, arm.AMMULA, arm.AMMULS, arm.AMULABB, arm.AMULAWB, arm.AMULAWT:
   175			return true
   176		}
   177		return false
   178	}
   179	
   180	var bcode = []obj.As{
   181		arm.ABEQ,
   182		arm.ABNE,
   183		arm.ABCS,
   184		arm.ABCC,
   185		arm.ABMI,
   186		arm.ABPL,
   187		arm.ABVS,
   188		arm.ABVC,
   189		arm.ABHI,
   190		arm.ABLS,
   191		arm.ABGE,
   192		arm.ABLT,
   193		arm.ABGT,
   194		arm.ABLE,
   195		arm.AB,
   196		obj.ANOP,
   197	}
   198	
   199	// ARMConditionCodes handles the special condition code situation for the ARM.
   200	// It returns a boolean to indicate success; failure means cond was unrecognized.
   201	func ARMConditionCodes(prog *obj.Prog, cond string) bool {
   202		if cond == "" {
   203			return true
   204		}
   205		bits, ok := ParseARMCondition(cond)
   206		if !ok {
   207			return false
   208		}
   209		/* hack to make B.NE etc. work: turn it into the corresponding conditional */
   210		if prog.As == arm.AB {
   211			prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf]
   212			bits = (bits &^ 0xf) | arm.C_SCOND_NONE
   213		}
   214		prog.Scond = bits
   215		return true
   216	}
   217	
   218	// ParseARMCondition parses the conditions attached to an ARM instruction.
   219	// The input is a single string consisting of period-separated condition
   220	// codes, such as ".P.W". An initial period is ignored.
   221	func ParseARMCondition(cond string) (uint8, bool) {
   222		return parseARMCondition(cond, armLS, armSCOND)
   223	}
   224	
   225	func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
   226		cond = strings.TrimPrefix(cond, ".")
   227		if cond == "" {
   228			return arm.C_SCOND_NONE, true
   229		}
   230		names := strings.Split(cond, ".")
   231		bits := uint8(0)
   232		for _, name := range names {
   233			if b, present := ls[name]; present {
   234				bits |= b
   235				continue
   236			}
   237			if b, present := scond[name]; present {
   238				bits = (bits &^ arm.C_SCOND) | b
   239				continue
   240			}
   241			return 0, false
   242		}
   243		return bits, true
   244	}
   245	
   246	func armRegisterNumber(name string, n int16) (int16, bool) {
   247		if n < 0 || 15 < n {
   248			return 0, false
   249		}
   250		switch name {
   251		case "R":
   252			return arm.REG_R0 + n, true
   253		case "F":
   254			return arm.REG_F0 + n, true
   255		}
   256		return 0, false
   257	}
   258	

View as plain text