diff options
Diffstat (limited to 'src/cmd/asm/internal/arch')
-rw-r--r-- | src/cmd/asm/internal/arch/arch.go | 719 | ||||
-rw-r--r-- | src/cmd/asm/internal/arch/arm.go | 257 | ||||
-rw-r--r-- | src/cmd/asm/internal/arch/arm64.go | 365 | ||||
-rw-r--r-- | src/cmd/asm/internal/arch/mips.go | 72 | ||||
-rw-r--r-- | src/cmd/asm/internal/arch/ppc64.go | 102 | ||||
-rw-r--r-- | src/cmd/asm/internal/arch/riscv64.go | 28 | ||||
-rw-r--r-- | src/cmd/asm/internal/arch/s390x.go | 81 |
7 files changed, 1624 insertions, 0 deletions
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go new file mode 100644 index 0000000..a62e551 --- /dev/null +++ b/src/cmd/asm/internal/arch/arch.go @@ -0,0 +1,719 @@ +// 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 arch defines architecture-specific information and support functions. +package arch + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm" + "cmd/internal/obj/arm64" + "cmd/internal/obj/mips" + "cmd/internal/obj/ppc64" + "cmd/internal/obj/riscv" + "cmd/internal/obj/s390x" + "cmd/internal/obj/wasm" + "cmd/internal/obj/x86" + "fmt" + "strings" +) + +// Pseudo-registers whose names are the constant name without the leading R. +const ( + RFP = -(iota + 1) + RSB + RSP + RPC +) + +// Arch wraps the link architecture object with more architecture-specific information. +type Arch struct { + *obj.LinkArch + // Map of instruction names to enumeration. + Instructions map[string]obj.As + // Map of register names to enumeration. + Register map[string]int16 + // Table of register prefix names. These are things like R for R(0) and SPR for SPR(268). + RegisterPrefix map[string]bool + // RegisterNumber converts R(10) into arm.REG_R10. + RegisterNumber func(string, int16) (int16, bool) + // Instruction is a jump. + IsJump func(word string) bool +} + +// nilRegisterNumber is the register number function for architectures +// that do not accept the R(N) notation. It always returns failure. +func nilRegisterNumber(name string, n int16) (int16, bool) { + return 0, false +} + +// Set configures the architecture specified by GOARCH and returns its representation. +// It returns nil if GOARCH is not recognized. +func Set(GOARCH string) *Arch { + switch GOARCH { + case "386": + return archX86(&x86.Link386) + case "amd64": + return archX86(&x86.Linkamd64) + case "arm": + return archArm() + case "arm64": + return archArm64() + case "mips": + return archMips(&mips.Linkmips) + case "mipsle": + return archMips(&mips.Linkmipsle) + case "mips64": + return archMips64(&mips.Linkmips64) + case "mips64le": + return archMips64(&mips.Linkmips64le) + case "ppc64": + return archPPC64(&ppc64.Linkppc64) + case "ppc64le": + return archPPC64(&ppc64.Linkppc64le) + case "riscv64": + return archRISCV64() + case "s390x": + return archS390x() + case "wasm": + return archWasm() + } + return nil +} + +func jumpX86(word string) bool { + return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP") || word == "XBEGIN" +} + +func jumpRISCV(word string) bool { + switch word { + case "BEQ", "BEQZ", "BGE", "BGEU", "BGEZ", "BGT", "BGTU", "BGTZ", "BLE", "BLEU", "BLEZ", + "BLT", "BLTU", "BLTZ", "BNE", "BNEZ", "CALL", "JAL", "JALR", "JMP": + return true + } + return false +} + +func jumpWasm(word string) bool { + return word == "JMP" || word == "CALL" || word == "Call" || word == "Br" || word == "BrIf" +} + +func archX86(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + for i, s := range x86.Register { + register[s] = int16(i + x86.REG_AL) + } + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Register prefix not used on this architecture. + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range x86.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseAMD64 + } + } + // Annoying aliases. + instructions["JA"] = x86.AJHI /* alternate */ + instructions["JAE"] = x86.AJCC /* alternate */ + instructions["JB"] = x86.AJCS /* alternate */ + instructions["JBE"] = x86.AJLS /* alternate */ + instructions["JC"] = x86.AJCS /* alternate */ + instructions["JCC"] = x86.AJCC /* carry clear (CF = 0) */ + instructions["JCS"] = x86.AJCS /* carry set (CF = 1) */ + instructions["JE"] = x86.AJEQ /* alternate */ + instructions["JEQ"] = x86.AJEQ /* equal (ZF = 1) */ + instructions["JG"] = x86.AJGT /* alternate */ + instructions["JGE"] = x86.AJGE /* greater than or equal (signed) (SF = OF) */ + instructions["JGT"] = x86.AJGT /* greater than (signed) (ZF = 0 && SF = OF) */ + instructions["JHI"] = x86.AJHI /* higher (unsigned) (CF = 0 && ZF = 0) */ + instructions["JHS"] = x86.AJCC /* alternate */ + instructions["JL"] = x86.AJLT /* alternate */ + instructions["JLE"] = x86.AJLE /* less than or equal (signed) (ZF = 1 || SF != OF) */ + instructions["JLO"] = x86.AJCS /* alternate */ + instructions["JLS"] = x86.AJLS /* lower or same (unsigned) (CF = 1 || ZF = 1) */ + instructions["JLT"] = x86.AJLT /* less than (signed) (SF != OF) */ + instructions["JMI"] = x86.AJMI /* negative (minus) (SF = 1) */ + instructions["JNA"] = x86.AJLS /* alternate */ + instructions["JNAE"] = x86.AJCS /* alternate */ + instructions["JNB"] = x86.AJCC /* alternate */ + instructions["JNBE"] = x86.AJHI /* alternate */ + instructions["JNC"] = x86.AJCC /* alternate */ + instructions["JNE"] = x86.AJNE /* not equal (ZF = 0) */ + instructions["JNG"] = x86.AJLE /* alternate */ + instructions["JNGE"] = x86.AJLT /* alternate */ + instructions["JNL"] = x86.AJGE /* alternate */ + instructions["JNLE"] = x86.AJGT /* alternate */ + instructions["JNO"] = x86.AJOC /* alternate */ + instructions["JNP"] = x86.AJPC /* alternate */ + instructions["JNS"] = x86.AJPL /* alternate */ + instructions["JNZ"] = x86.AJNE /* alternate */ + instructions["JO"] = x86.AJOS /* alternate */ + instructions["JOC"] = x86.AJOC /* overflow clear (OF = 0) */ + instructions["JOS"] = x86.AJOS /* overflow set (OF = 1) */ + instructions["JP"] = x86.AJPS /* alternate */ + instructions["JPC"] = x86.AJPC /* parity clear (PF = 0) */ + instructions["JPE"] = x86.AJPS /* alternate */ + instructions["JPL"] = x86.AJPL /* non-negative (plus) (SF = 0) */ + instructions["JPO"] = x86.AJPC /* alternate */ + instructions["JPS"] = x86.AJPS /* parity set (PF = 1) */ + instructions["JS"] = x86.AJMI /* alternate */ + instructions["JZ"] = x86.AJEQ /* alternate */ + instructions["MASKMOVDQU"] = x86.AMASKMOVOU + instructions["MOVD"] = x86.AMOVQ + instructions["MOVDQ2Q"] = x86.AMOVQ + instructions["MOVNTDQ"] = x86.AMOVNTO + instructions["MOVOA"] = x86.AMOVO + instructions["PSLLDQ"] = x86.APSLLO + instructions["PSRLDQ"] = x86.APSRLO + instructions["PADDD"] = x86.APADDL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: nil, + RegisterNumber: nilRegisterNumber, + IsJump: jumpX86, + } +} + +func archArm() *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := arm.REG_R0; i < arm.REG_SPSR; i++ { + register[obj.Rconv(i)] = int16(i) + } + // Avoid unintentionally clobbering g using R10. + delete(register, "R10") + register["g"] = arm.REG_R10 + for i := 0; i < 16; i++ { + register[fmt.Sprintf("C%d", i)] = int16(i) + } + + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + register["SP"] = RSP + registerPrefix := map[string]bool{ + "F": true, + "R": true, + } + + // special operands for DMB/DSB instructions + register["MB_SY"] = arm.REG_MB_SY + register["MB_ST"] = arm.REG_MB_ST + register["MB_ISH"] = arm.REG_MB_ISH + register["MB_ISHST"] = arm.REG_MB_ISHST + register["MB_NSH"] = arm.REG_MB_NSH + register["MB_NSHST"] = arm.REG_MB_NSHST + register["MB_OSH"] = arm.REG_MB_OSH + register["MB_OSHST"] = arm.REG_MB_OSHST + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range arm.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseARM + } + } + // Annoying aliases. + instructions["B"] = obj.AJMP + instructions["BL"] = obj.ACALL + // MCR differs from MRC by the way fields of the word are encoded. + // (Details in arm.go). Here we add the instruction so parse will find + // it, but give it an opcode number known only to us. + instructions["MCR"] = aMCR + + return &Arch{ + LinkArch: &arm.Linkarm, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: armRegisterNumber, + IsJump: jumpArm, + } +} + +func archArm64() *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for 386 and amd64. + register[obj.Rconv(arm64.REGSP)] = int16(arm64.REGSP) + for i := arm64.REG_R0; i <= arm64.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + // Rename R18 to R18_PLATFORM to avoid accidental use. + register["R18_PLATFORM"] = register["R18"] + delete(register, "R18") + for i := arm64.REG_F0; i <= arm64.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := arm64.REG_V0; i <= arm64.REG_V31; i++ { + register[obj.Rconv(i)] = int16(i) + } + + // System registers. + for i := 0; i < len(arm64.SystemReg); i++ { + register[arm64.SystemReg[i].Name] = arm64.SystemReg[i].Reg + } + + register["LR"] = arm64.REGLINK + register["DAIFSet"] = arm64.REG_DAIFSet + register["DAIFClr"] = arm64.REG_DAIFClr + register["PLDL1KEEP"] = arm64.REG_PLDL1KEEP + register["PLDL1STRM"] = arm64.REG_PLDL1STRM + register["PLDL2KEEP"] = arm64.REG_PLDL2KEEP + register["PLDL2STRM"] = arm64.REG_PLDL2STRM + register["PLDL3KEEP"] = arm64.REG_PLDL3KEEP + register["PLDL3STRM"] = arm64.REG_PLDL3STRM + register["PLIL1KEEP"] = arm64.REG_PLIL1KEEP + register["PLIL1STRM"] = arm64.REG_PLIL1STRM + register["PLIL2KEEP"] = arm64.REG_PLIL2KEEP + register["PLIL2STRM"] = arm64.REG_PLIL2STRM + register["PLIL3KEEP"] = arm64.REG_PLIL3KEEP + register["PLIL3STRM"] = arm64.REG_PLIL3STRM + register["PSTL1KEEP"] = arm64.REG_PSTL1KEEP + register["PSTL1STRM"] = arm64.REG_PSTL1STRM + register["PSTL2KEEP"] = arm64.REG_PSTL2KEEP + register["PSTL2STRM"] = arm64.REG_PSTL2STRM + register["PSTL3KEEP"] = arm64.REG_PSTL3KEEP + register["PSTL3STRM"] = arm64.REG_PSTL3STRM + + // Conditional operators, like EQ, NE, etc. + register["EQ"] = arm64.COND_EQ + register["NE"] = arm64.COND_NE + register["HS"] = arm64.COND_HS + register["CS"] = arm64.COND_HS + register["LO"] = arm64.COND_LO + register["CC"] = arm64.COND_LO + register["MI"] = arm64.COND_MI + register["PL"] = arm64.COND_PL + register["VS"] = arm64.COND_VS + register["VC"] = arm64.COND_VC + register["HI"] = arm64.COND_HI + register["LS"] = arm64.COND_LS + register["GE"] = arm64.COND_GE + register["LT"] = arm64.COND_LT + register["GT"] = arm64.COND_GT + register["LE"] = arm64.COND_LE + register["AL"] = arm64.COND_AL + register["NV"] = arm64.COND_NV + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + register["SP"] = RSP + // Avoid unintentionally clobbering g using R28. + delete(register, "R28") + register["g"] = arm64.REG_R28 + registerPrefix := map[string]bool{ + "F": true, + "R": true, + "V": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range arm64.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseARM64 + } + } + // Annoying aliases. + instructions["B"] = arm64.AB + instructions["BL"] = arm64.ABL + + return &Arch{ + LinkArch: &arm64.Linkarm64, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: arm64RegisterNumber, + IsJump: jumpArm64, + } + +} + +func archPPC64(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := ppc64.REG_R0; i <= ppc64.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_F0; i <= ppc64.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_V0; i <= ppc64.REG_V31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_VS0; i <= ppc64.REG_VS63; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_CR0; i <= ppc64.REG_CR7; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := ppc64.REG_MSR; i <= ppc64.REG_CR; i++ { + register[obj.Rconv(i)] = int16(i) + } + register["CR"] = ppc64.REG_CR + register["XER"] = ppc64.REG_XER + register["LR"] = ppc64.REG_LR + register["CTR"] = ppc64.REG_CTR + register["FPSCR"] = ppc64.REG_FPSCR + register["MSR"] = ppc64.REG_MSR + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R30. + delete(register, "R30") + register["g"] = ppc64.REG_R30 + registerPrefix := map[string]bool{ + "CR": true, + "F": true, + "R": true, + "SPR": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range ppc64.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABasePPC64 + } + } + // Annoying aliases. + instructions["BR"] = ppc64.ABR + instructions["BL"] = ppc64.ABL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: ppc64RegisterNumber, + IsJump: jumpPPC64, + } +} + +func archMips(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := mips.REG_R0; i <= mips.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + + for i := mips.REG_F0; i <= mips.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_M0; i <= mips.REG_M31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ { + register[obj.Rconv(i)] = int16(i) + } + register["HI"] = mips.REG_HI + register["LO"] = mips.REG_LO + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R30. + delete(register, "R30") + register["g"] = mips.REG_R30 + + registerPrefix := map[string]bool{ + "F": true, + "FCR": true, + "M": true, + "R": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range mips.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseMIPS + } + } + // Annoying alias. + instructions["JAL"] = mips.AJAL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: mipsRegisterNumber, + IsJump: jumpMIPS, + } +} + +func archMips64(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := mips.REG_R0; i <= mips.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_F0; i <= mips.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_M0; i <= mips.REG_M31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := mips.REG_W0; i <= mips.REG_W31; i++ { + register[obj.Rconv(i)] = int16(i) + } + register["HI"] = mips.REG_HI + register["LO"] = mips.REG_LO + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R30. + delete(register, "R30") + register["g"] = mips.REG_R30 + // Avoid unintentionally clobbering RSB using R28. + delete(register, "R28") + register["RSB"] = mips.REG_R28 + registerPrefix := map[string]bool{ + "F": true, + "FCR": true, + "M": true, + "R": true, + "W": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range mips.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseMIPS + } + } + // Annoying alias. + instructions["JAL"] = mips.AJAL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: mipsRegisterNumber, + IsJump: jumpMIPS, + } +} + +func archRISCV64() *Arch { + register := make(map[string]int16) + + // Standard register names. + for i := riscv.REG_X0; i <= riscv.REG_X31; i++ { + if i == riscv.REG_G { + continue + } + name := fmt.Sprintf("X%d", i-riscv.REG_X0) + register[name] = int16(i) + } + for i := riscv.REG_F0; i <= riscv.REG_F31; i++ { + name := fmt.Sprintf("F%d", i-riscv.REG_F0) + register[name] = int16(i) + } + + // General registers with ABI names. + register["ZERO"] = riscv.REG_ZERO + register["RA"] = riscv.REG_RA + register["SP"] = riscv.REG_SP + register["GP"] = riscv.REG_GP + register["TP"] = riscv.REG_TP + register["T0"] = riscv.REG_T0 + register["T1"] = riscv.REG_T1 + register["T2"] = riscv.REG_T2 + register["S0"] = riscv.REG_S0 + register["S1"] = riscv.REG_S1 + register["A0"] = riscv.REG_A0 + register["A1"] = riscv.REG_A1 + register["A2"] = riscv.REG_A2 + register["A3"] = riscv.REG_A3 + register["A4"] = riscv.REG_A4 + register["A5"] = riscv.REG_A5 + register["A6"] = riscv.REG_A6 + register["A7"] = riscv.REG_A7 + register["S2"] = riscv.REG_S2 + register["S3"] = riscv.REG_S3 + register["S4"] = riscv.REG_S4 + register["S5"] = riscv.REG_S5 + register["S6"] = riscv.REG_S6 + register["S7"] = riscv.REG_S7 + register["S8"] = riscv.REG_S8 + register["S9"] = riscv.REG_S9 + register["S10"] = riscv.REG_S10 + // Skip S11 as it is the g register. + register["T3"] = riscv.REG_T3 + register["T4"] = riscv.REG_T4 + register["T5"] = riscv.REG_T5 + register["T6"] = riscv.REG_T6 + + // Go runtime register names. + register["g"] = riscv.REG_G + register["CTXT"] = riscv.REG_CTXT + register["TMP"] = riscv.REG_TMP + + // ABI names for floating point register. + register["FT0"] = riscv.REG_FT0 + register["FT1"] = riscv.REG_FT1 + register["FT2"] = riscv.REG_FT2 + register["FT3"] = riscv.REG_FT3 + register["FT4"] = riscv.REG_FT4 + register["FT5"] = riscv.REG_FT5 + register["FT6"] = riscv.REG_FT6 + register["FT7"] = riscv.REG_FT7 + register["FS0"] = riscv.REG_FS0 + register["FS1"] = riscv.REG_FS1 + register["FA0"] = riscv.REG_FA0 + register["FA1"] = riscv.REG_FA1 + register["FA2"] = riscv.REG_FA2 + register["FA3"] = riscv.REG_FA3 + register["FA4"] = riscv.REG_FA4 + register["FA5"] = riscv.REG_FA5 + register["FA6"] = riscv.REG_FA6 + register["FA7"] = riscv.REG_FA7 + register["FS2"] = riscv.REG_FS2 + register["FS3"] = riscv.REG_FS3 + register["FS4"] = riscv.REG_FS4 + register["FS5"] = riscv.REG_FS5 + register["FS6"] = riscv.REG_FS6 + register["FS7"] = riscv.REG_FS7 + register["FS8"] = riscv.REG_FS8 + register["FS9"] = riscv.REG_FS9 + register["FS10"] = riscv.REG_FS10 + register["FS11"] = riscv.REG_FS11 + register["FT8"] = riscv.REG_FT8 + register["FT9"] = riscv.REG_FT9 + register["FT10"] = riscv.REG_FT10 + register["FT11"] = riscv.REG_FT11 + + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range riscv.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseRISCV + } + } + + return &Arch{ + LinkArch: &riscv.LinkRISCV64, + Instructions: instructions, + Register: register, + RegisterPrefix: nil, + RegisterNumber: nilRegisterNumber, + IsJump: jumpRISCV, + } +} + +func archS390x() *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := s390x.REG_R0; i <= s390x.REG_R15; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := s390x.REG_F0; i <= s390x.REG_F15; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := s390x.REG_V0; i <= s390x.REG_V31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := s390x.REG_AR0; i <= s390x.REG_AR15; i++ { + register[obj.Rconv(i)] = int16(i) + } + register["LR"] = s390x.REG_LR + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R13. + delete(register, "R13") + register["g"] = s390x.REG_R13 + registerPrefix := map[string]bool{ + "AR": true, + "F": true, + "R": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range s390x.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseS390X + } + } + // Annoying aliases. + instructions["BR"] = s390x.ABR + instructions["BL"] = s390x.ABL + + return &Arch{ + LinkArch: &s390x.Links390x, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: s390xRegisterNumber, + IsJump: jumpS390x, + } +} + +func archWasm() *Arch { + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range wasm.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseWasm + } + } + + return &Arch{ + LinkArch: &wasm.Linkwasm, + Instructions: instructions, + Register: wasm.Register, + RegisterPrefix: nil, + RegisterNumber: nilRegisterNumber, + IsJump: jumpWasm, + } +} diff --git a/src/cmd/asm/internal/arch/arm.go b/src/cmd/asm/internal/arch/arm.go new file mode 100644 index 0000000..b0e985f --- /dev/null +++ b/src/cmd/asm/internal/arch/arm.go @@ -0,0 +1,257 @@ +// 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. + +// This file encapsulates some of the odd characteristics of the ARM +// instruction set, to minimize its interaction with the core of the +// assembler. + +package arch + +import ( + "strings" + + "cmd/internal/obj" + "cmd/internal/obj/arm" +) + +var armLS = map[string]uint8{ + "U": arm.C_UBIT, + "S": arm.C_SBIT, + "W": arm.C_WBIT, + "P": arm.C_PBIT, + "PW": arm.C_WBIT | arm.C_PBIT, + "WP": arm.C_WBIT | arm.C_PBIT, +} + +var armSCOND = map[string]uint8{ + "EQ": arm.C_SCOND_EQ, + "NE": arm.C_SCOND_NE, + "CS": arm.C_SCOND_HS, + "HS": arm.C_SCOND_HS, + "CC": arm.C_SCOND_LO, + "LO": arm.C_SCOND_LO, + "MI": arm.C_SCOND_MI, + "PL": arm.C_SCOND_PL, + "VS": arm.C_SCOND_VS, + "VC": arm.C_SCOND_VC, + "HI": arm.C_SCOND_HI, + "LS": arm.C_SCOND_LS, + "GE": arm.C_SCOND_GE, + "LT": arm.C_SCOND_LT, + "GT": arm.C_SCOND_GT, + "LE": arm.C_SCOND_LE, + "AL": arm.C_SCOND_NONE, + "U": arm.C_UBIT, + "S": arm.C_SBIT, + "W": arm.C_WBIT, + "P": arm.C_PBIT, + "PW": arm.C_WBIT | arm.C_PBIT, + "WP": arm.C_WBIT | arm.C_PBIT, + "F": arm.C_FBIT, + "IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT, + "IAW": arm.C_WBIT | arm.C_UBIT, + "DBW": arm.C_WBIT | arm.C_PBIT, + "DAW": arm.C_WBIT, + "IB": arm.C_PBIT | arm.C_UBIT, + "IA": arm.C_UBIT, + "DB": arm.C_PBIT, + "DA": 0, +} + +var armJump = map[string]bool{ + "B": true, + "BL": true, + "BX": true, + "BEQ": true, + "BNE": true, + "BCS": true, + "BHS": true, + "BCC": true, + "BLO": true, + "BMI": true, + "BPL": true, + "BVS": true, + "BVC": true, + "BHI": true, + "BLS": true, + "BGE": true, + "BLT": true, + "BGT": true, + "BLE": true, + "CALL": true, + "JMP": true, +} + +func jumpArm(word string) bool { + return armJump[word] +} + +// IsARMCMP reports whether the op (as defined by an arm.A* constant) is +// one of the comparison instructions that require special handling. +func IsARMCMP(op obj.As) bool { + switch op { + case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST: + return true + } + return false +} + +// IsARMSTREX reports whether the op (as defined by an arm.A* constant) is +// one of the STREX-like instructions that require special handling. +func IsARMSTREX(op obj.As) bool { + switch op { + case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU: + return true + } + return false +} + +// MCR is not defined by the obj/arm; instead we define it privately here. +// It is encoded as an MRC with a bit inside the instruction word, +// passed to arch.ARMMRCOffset. +const aMCR = arm.ALAST + 1 + +// IsARMMRC reports whether the op (as defined by an arm.A* constant) is +// MRC or MCR +func IsARMMRC(op obj.As) bool { + switch op { + case arm.AMRC, aMCR: // Note: aMCR is defined in this package. + return true + } + return false +} + +// IsARMBFX reports whether the op (as defined by an arm.A* constant) is one the +// BFX-like instructions which are in the form of "op $width, $LSB, (Reg,) Reg". +func IsARMBFX(op obj.As) bool { + switch op { + case arm.ABFX, arm.ABFXU, arm.ABFC, arm.ABFI: + return true + } + return false +} + +// IsARMFloatCmp reports whether the op is a floating comparison instruction. +func IsARMFloatCmp(op obj.As) bool { + switch op { + case arm.ACMPF, arm.ACMPD: + return true + } + return false +} + +// ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions. +// The difference between MRC and MCR is represented by a bit high in the word, not +// in the usual way by the opcode itself. Asm must use AMRC for both instructions, so +// we return the opcode for MRC so that asm doesn't need to import obj/arm. +func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) { + op1 := int64(0) + if op == arm.AMRC { + op1 = 1 + } + bits, ok := ParseARMCondition(cond) + if !ok { + return + } + offset = (0xe << 24) | // opcode + (op1 << 20) | // MCR/MRC + ((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond + ((x0 & 15) << 8) | //coprocessor number + ((x1 & 7) << 21) | // coprocessor operation + ((x2 & 15) << 12) | // ARM register + ((x3 & 15) << 16) | // Crn + ((x4 & 15) << 0) | // Crm + ((x5 & 7) << 5) | // coprocessor information + (1 << 4) /* must be set */ + return offset, arm.AMRC, true +} + +// IsARMMULA reports whether the op (as defined by an arm.A* constant) is +// MULA, MULS, MMULA, MMULS, MULABB, MULAWB or MULAWT, the 4-operand instructions. +func IsARMMULA(op obj.As) bool { + switch op { + case arm.AMULA, arm.AMULS, arm.AMMULA, arm.AMMULS, arm.AMULABB, arm.AMULAWB, arm.AMULAWT: + return true + } + return false +} + +var bcode = []obj.As{ + arm.ABEQ, + arm.ABNE, + arm.ABCS, + arm.ABCC, + arm.ABMI, + arm.ABPL, + arm.ABVS, + arm.ABVC, + arm.ABHI, + arm.ABLS, + arm.ABGE, + arm.ABLT, + arm.ABGT, + arm.ABLE, + arm.AB, + obj.ANOP, +} + +// ARMConditionCodes handles the special condition code situation for the ARM. +// It returns a boolean to indicate success; failure means cond was unrecognized. +func ARMConditionCodes(prog *obj.Prog, cond string) bool { + if cond == "" { + return true + } + bits, ok := ParseARMCondition(cond) + if !ok { + return false + } + /* hack to make B.NE etc. work: turn it into the corresponding conditional */ + if prog.As == arm.AB { + prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf] + bits = (bits &^ 0xf) | arm.C_SCOND_NONE + } + prog.Scond = bits + return true +} + +// ParseARMCondition parses the conditions attached to an ARM instruction. +// The input is a single string consisting of period-separated condition +// codes, such as ".P.W". An initial period is ignored. +func ParseARMCondition(cond string) (uint8, bool) { + return parseARMCondition(cond, armLS, armSCOND) +} + +func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) { + cond = strings.TrimPrefix(cond, ".") + if cond == "" { + return arm.C_SCOND_NONE, true + } + names := strings.Split(cond, ".") + bits := uint8(0) + for _, name := range names { + if b, present := ls[name]; present { + bits |= b + continue + } + if b, present := scond[name]; present { + bits = (bits &^ arm.C_SCOND) | b + continue + } + return 0, false + } + return bits, true +} + +func armRegisterNumber(name string, n int16) (int16, bool) { + if n < 0 || 15 < n { + return 0, false + } + switch name { + case "R": + return arm.REG_R0 + n, true + case "F": + return arm.REG_F0 + n, true + } + return 0, false +} diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go new file mode 100644 index 0000000..e557630 --- /dev/null +++ b/src/cmd/asm/internal/arch/arm64.go @@ -0,0 +1,365 @@ +// 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. + +// This file encapsulates some of the odd characteristics of the ARM64 +// instruction set, to minimize its interaction with the core of the +// assembler. + +package arch + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm64" + "errors" +) + +var arm64LS = map[string]uint8{ + "P": arm64.C_XPOST, + "W": arm64.C_XPRE, +} + +var arm64Jump = map[string]bool{ + "B": true, + "BL": true, + "BEQ": true, + "BNE": true, + "BCS": true, + "BHS": true, + "BCC": true, + "BLO": true, + "BMI": true, + "BPL": true, + "BVS": true, + "BVC": true, + "BHI": true, + "BLS": true, + "BGE": true, + "BLT": true, + "BGT": true, + "BLE": true, + "CALL": true, + "CBZ": true, + "CBZW": true, + "CBNZ": true, + "CBNZW": true, + "JMP": true, + "TBNZ": true, + "TBZ": true, +} + +func jumpArm64(word string) bool { + return arm64Jump[word] +} + +// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is +// one of the comparison instructions that require special handling. +func IsARM64CMP(op obj.As) bool { + switch op { + case arm64.ACMN, arm64.ACMP, arm64.ATST, + arm64.ACMNW, arm64.ACMPW, arm64.ATSTW, + arm64.AFCMPS, arm64.AFCMPD, + arm64.AFCMPES, arm64.AFCMPED: + return true + } + return false +} + +// IsARM64STLXR reports whether the op (as defined by an arm64.A* +// constant) is one of the STLXR-like instructions that require special +// handling. +func IsARM64STLXR(op obj.As) bool { + switch op { + case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR, + arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR, + arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW: + return true + } + // LDADDx/SWPx/CASx atomic instructions + if arm64.IsAtomicInstruction(op) { + return true + } + return false +} + +// IsARM64TBL reports whether the op (as defined by an arm64.A* +// constant) is one of the TBL-like instructions and one of its +// inputs does not fit into prog.Reg, so require special handling. +func IsARM64TBL(op obj.As) bool { + switch op { + case arm64.AVTBL, arm64.AVMOVQ: + return true + } + return false +} + +// IsARM64CASP reports whether the op (as defined by an arm64.A* +// constant) is one of the CASP-like instructions, and its 2nd +// destination is a register pair that require special handling. +func IsARM64CASP(op obj.As) bool { + switch op { + case arm64.ACASPD, arm64.ACASPW: + return true + } + return false +} + +// ARM64Suffix handles the special suffix for the ARM64. +// It returns a boolean to indicate success; failure means +// cond was unrecognized. +func ARM64Suffix(prog *obj.Prog, cond string) bool { + if cond == "" { + return true + } + bits, ok := parseARM64Suffix(cond) + if !ok { + return false + } + prog.Scond = bits + return true +} + +// parseARM64Suffix parses the suffix attached to an ARM64 instruction. +// The input is a single string consisting of period-separated condition +// codes, such as ".P.W". An initial period is ignored. +func parseARM64Suffix(cond string) (uint8, bool) { + if cond == "" { + return 0, true + } + return parseARMCondition(cond, arm64LS, nil) +} + +func arm64RegisterNumber(name string, n int16) (int16, bool) { + switch name { + case "F": + if 0 <= n && n <= 31 { + return arm64.REG_F0 + n, true + } + case "R": + if 0 <= n && n <= 30 { // not 31 + return arm64.REG_R0 + n, true + } + case "V": + if 0 <= n && n <= 31 { + return arm64.REG_V0 + n, true + } + } + return 0, false +} + +// ARM64RegisterExtension parses an ARM64 register with extension or arrangement. +func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error { + Rnum := (reg & 31) + int16(num<<5) + if isAmount { + if num < 0 || num > 7 { + return errors.New("index shift amount is out of range") + } + } + switch ext { + case "UXTB": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + return errors.New("invalid shift for the register offset addressing mode") + } + a.Reg = arm64.REG_UXTB + Rnum + case "UXTH": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + return errors.New("invalid shift for the register offset addressing mode") + } + a.Reg = arm64.REG_UXTH + Rnum + case "UXTW": + if !isAmount { + return errors.New("invalid register extension") + } + // effective address of memory is a base register value and an offset register value. + if a.Type == obj.TYPE_MEM { + a.Index = arm64.REG_UXTW + Rnum + } else { + a.Reg = arm64.REG_UXTW + Rnum + } + case "UXTX": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + return errors.New("invalid shift for the register offset addressing mode") + } + a.Reg = arm64.REG_UXTX + Rnum + case "SXTB": + if !isAmount { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_SXTB + Rnum + case "SXTH": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + return errors.New("invalid shift for the register offset addressing mode") + } + a.Reg = arm64.REG_SXTH + Rnum + case "SXTW": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + a.Index = arm64.REG_SXTW + Rnum + } else { + a.Reg = arm64.REG_SXTW + Rnum + } + case "SXTX": + if !isAmount { + return errors.New("invalid register extension") + } + if a.Type == obj.TYPE_MEM { + a.Index = arm64.REG_SXTX + Rnum + } else { + a.Reg = arm64.REG_SXTX + Rnum + } + case "LSL": + if !isAmount { + return errors.New("invalid register extension") + } + a.Index = arm64.REG_LSL + Rnum + case "B8": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5) + case "B16": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5) + case "H4": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5) + case "H8": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5) + case "S2": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5) + case "S4": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5) + case "D1": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5) + case "D2": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5) + case "Q1": + if isIndex { + return errors.New("invalid register extension") + } + a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5) + case "B": + if !isIndex { + return nil + } + a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5) + a.Index = num + case "H": + if !isIndex { + return nil + } + a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5) + a.Index = num + case "S": + if !isIndex { + return nil + } + a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5) + a.Index = num + case "D": + if !isIndex { + return nil + } + a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5) + a.Index = num + default: + return errors.New("unsupported register extension type: " + ext) + } + + return nil +} + +// ARM64RegisterArrangement parses an ARM64 vector register arrangement. +func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) { + var curQ, curSize uint16 + if name[0] != 'V' { + return 0, errors.New("expect V0 through V31; found: " + name) + } + if reg < 0 { + return 0, errors.New("invalid register number: " + name) + } + switch arng { + case "B8": + curSize = 0 + curQ = 0 + case "B16": + curSize = 0 + curQ = 1 + case "H4": + curSize = 1 + curQ = 0 + case "H8": + curSize = 1 + curQ = 1 + case "S2": + curSize = 2 + curQ = 0 + case "S4": + curSize = 2 + curQ = 1 + case "D1": + curSize = 3 + curQ = 0 + case "D2": + curSize = 3 + curQ = 1 + default: + return 0, errors.New("invalid arrangement in ARM64 register list") + } + return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil +} + +// ARM64RegisterListOffset generates offset encoding according to AArch64 specification. +func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) { + offset := int64(firstReg) + switch regCnt { + case 1: + offset |= 0x7 << 12 + case 2: + offset |= 0xa << 12 + case 3: + offset |= 0x6 << 12 + case 4: + offset |= 0x2 << 12 + default: + return 0, errors.New("invalid register numbers in ARM64 register list") + } + offset |= arrangement + // arm64 uses the 60th bit to differentiate from other archs + // For more details, refer to: obj/arm64/list7.go + offset |= 1 << 60 + return offset, nil +} diff --git a/src/cmd/asm/internal/arch/mips.go b/src/cmd/asm/internal/arch/mips.go new file mode 100644 index 0000000..5d71f40 --- /dev/null +++ b/src/cmd/asm/internal/arch/mips.go @@ -0,0 +1,72 @@ +// 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. + +// This file encapsulates some of the odd characteristics of the +// MIPS (MIPS64) instruction set, to minimize its interaction +// with the core of the assembler. + +package arch + +import ( + "cmd/internal/obj" + "cmd/internal/obj/mips" +) + +func jumpMIPS(word string) bool { + switch word { + case "BEQ", "BFPF", "BFPT", "BGEZ", "BGEZAL", "BGTZ", "BLEZ", "BLTZ", "BLTZAL", "BNE", "JMP", "JAL", "CALL": + return true + } + return false +} + +// IsMIPSCMP reports whether the op (as defined by an mips.A* constant) is +// one of the CMP instructions that require special handling. +func IsMIPSCMP(op obj.As) bool { + switch op { + case mips.ACMPEQF, mips.ACMPEQD, mips.ACMPGEF, mips.ACMPGED, + mips.ACMPGTF, mips.ACMPGTD: + return true + } + return false +} + +// IsMIPSMUL reports whether the op (as defined by an mips.A* constant) is +// one of the MUL/DIV/REM/MADD/MSUB instructions that require special handling. +func IsMIPSMUL(op obj.As) bool { + switch op { + case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU, + mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU, + mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU, + mips.AMADD, mips.AMSUB: + return true + } + return false +} + +func mipsRegisterNumber(name string, n int16) (int16, bool) { + switch name { + case "F": + if 0 <= n && n <= 31 { + return mips.REG_F0 + n, true + } + case "FCR": + if 0 <= n && n <= 31 { + return mips.REG_FCR0 + n, true + } + case "M": + if 0 <= n && n <= 31 { + return mips.REG_M0 + n, true + } + case "R": + if 0 <= n && n <= 31 { + return mips.REG_R0 + n, true + } + case "W": + if 0 <= n && n <= 31 { + return mips.REG_W0 + n, true + } + } + return 0, false +} diff --git a/src/cmd/asm/internal/arch/ppc64.go b/src/cmd/asm/internal/arch/ppc64.go new file mode 100644 index 0000000..3139665 --- /dev/null +++ b/src/cmd/asm/internal/arch/ppc64.go @@ -0,0 +1,102 @@ +// 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. + +// This file encapsulates some of the odd characteristics of the +// 64-bit PowerPC (PPC64) instruction set, to minimize its interaction +// with the core of the assembler. + +package arch + +import ( + "cmd/internal/obj" + "cmd/internal/obj/ppc64" +) + +func jumpPPC64(word string) bool { + switch word { + case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "CALL", "JMP": + return true + } + return false +} + +// IsPPC64RLD reports whether the op (as defined by an ppc64.A* constant) is +// one of the RLD-like instructions that require special handling. +// The FMADD-like instructions behave similarly. +func IsPPC64RLD(op obj.As) bool { + switch op { + case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC, + ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC, + ppc64.ARLWMI, ppc64.ARLWMICC, ppc64.ARLWNM, ppc64.ARLWNMCC: + return true + case ppc64.AFMADD, ppc64.AFMADDCC, ppc64.AFMADDS, ppc64.AFMADDSCC, + ppc64.AFMSUB, ppc64.AFMSUBCC, ppc64.AFMSUBS, ppc64.AFMSUBSCC, + ppc64.AFNMADD, ppc64.AFNMADDCC, ppc64.AFNMADDS, ppc64.AFNMADDSCC, + ppc64.AFNMSUB, ppc64.AFNMSUBCC, ppc64.AFNMSUBS, ppc64.AFNMSUBSCC: + return true + } + return false +} + +func IsPPC64ISEL(op obj.As) bool { + return op == ppc64.AISEL +} + +// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is +// one of the CMP instructions that require special handling. +func IsPPC64CMP(op obj.As) bool { + switch op { + case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU, ppc64.AFCMPU: + return true + } + return false +} + +// IsPPC64NEG reports whether the op (as defined by an ppc64.A* constant) is +// one of the NEG-like instructions that require special handling. +func IsPPC64NEG(op obj.As) bool { + switch op { + case ppc64.AADDMECC, ppc64.AADDMEVCC, ppc64.AADDMEV, ppc64.AADDME, + ppc64.AADDZECC, ppc64.AADDZEVCC, ppc64.AADDZEV, ppc64.AADDZE, + ppc64.ACNTLZDCC, ppc64.ACNTLZD, ppc64.ACNTLZWCC, ppc64.ACNTLZW, + ppc64.AEXTSBCC, ppc64.AEXTSB, ppc64.AEXTSHCC, ppc64.AEXTSH, + ppc64.AEXTSWCC, ppc64.AEXTSW, ppc64.ANEGCC, ppc64.ANEGVCC, + ppc64.ANEGV, ppc64.ANEG, ppc64.ASLBMFEE, ppc64.ASLBMFEV, + ppc64.ASLBMTE, ppc64.ASUBMECC, ppc64.ASUBMEVCC, ppc64.ASUBMEV, + ppc64.ASUBME, ppc64.ASUBZECC, ppc64.ASUBZEVCC, ppc64.ASUBZEV, + ppc64.ASUBZE: + return true + } + return false +} + +func ppc64RegisterNumber(name string, n int16) (int16, bool) { + switch name { + case "CR": + if 0 <= n && n <= 7 { + return ppc64.REG_CR0 + n, true + } + case "VS": + if 0 <= n && n <= 63 { + return ppc64.REG_VS0 + n, true + } + case "V": + if 0 <= n && n <= 31 { + return ppc64.REG_V0 + n, true + } + case "F": + if 0 <= n && n <= 31 { + return ppc64.REG_F0 + n, true + } + case "R": + if 0 <= n && n <= 31 { + return ppc64.REG_R0 + n, true + } + case "SPR": + if 0 <= n && n <= 1024 { + return ppc64.REG_SPR0 + n, true + } + } + return 0, false +} diff --git a/src/cmd/asm/internal/arch/riscv64.go b/src/cmd/asm/internal/arch/riscv64.go new file mode 100644 index 0000000..27a66c5 --- /dev/null +++ b/src/cmd/asm/internal/arch/riscv64.go @@ -0,0 +1,28 @@ +// Copyright 2020 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. + +// This file encapsulates some of the odd characteristics of the RISCV64 +// instruction set, to minimize its interaction with the core of the +// assembler. + +package arch + +import ( + "cmd/internal/obj" + "cmd/internal/obj/riscv" +) + +// IsRISCV64AMO reports whether the op (as defined by a riscv.A* +// constant) is one of the AMO instructions that requires special +// handling. +func IsRISCV64AMO(op obj.As) bool { + switch op { + case riscv.ASCW, riscv.ASCD, riscv.AAMOSWAPW, riscv.AAMOSWAPD, riscv.AAMOADDW, riscv.AAMOADDD, + riscv.AAMOANDW, riscv.AAMOANDD, riscv.AAMOORW, riscv.AAMOORD, riscv.AAMOXORW, riscv.AAMOXORD, + riscv.AAMOMINW, riscv.AAMOMIND, riscv.AAMOMINUW, riscv.AAMOMINUD, + riscv.AAMOMAXW, riscv.AAMOMAXD, riscv.AAMOMAXUW, riscv.AAMOMAXUD: + return true + } + return false +} diff --git a/src/cmd/asm/internal/arch/s390x.go b/src/cmd/asm/internal/arch/s390x.go new file mode 100644 index 0000000..519d208 --- /dev/null +++ b/src/cmd/asm/internal/arch/s390x.go @@ -0,0 +1,81 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file encapsulates some of the odd characteristics of the +// s390x instruction set, to minimize its interaction +// with the core of the assembler. + +package arch + +import ( + "cmd/internal/obj/s390x" +) + +func jumpS390x(word string) bool { + switch word { + case "BRC", + "BC", + "BCL", + "BEQ", + "BGE", + "BGT", + "BL", + "BLE", + "BLEU", + "BLT", + "BLTU", + "BNE", + "BR", + "BVC", + "BVS", + "BRCT", + "BRCTG", + "CMPBEQ", + "CMPBGE", + "CMPBGT", + "CMPBLE", + "CMPBLT", + "CMPBNE", + "CMPUBEQ", + "CMPUBGE", + "CMPUBGT", + "CMPUBLE", + "CMPUBLT", + "CMPUBNE", + "CRJ", + "CGRJ", + "CLRJ", + "CLGRJ", + "CIJ", + "CGIJ", + "CLIJ", + "CLGIJ", + "CALL", + "JMP": + return true + } + return false +} + +func s390xRegisterNumber(name string, n int16) (int16, bool) { + switch name { + case "AR": + if 0 <= n && n <= 15 { + return s390x.REG_AR0 + n, true + } + case "F": + if 0 <= n && n <= 15 { + return s390x.REG_F0 + n, true + } + case "R": + if 0 <= n && n <= 15 { + return s390x.REG_R0 + n, true + } + case "V": + if 0 <= n && n <= 31 { + return s390x.REG_V0 + n, true + } + } + return 0, false +} |