MOVDBR R1, R2 // b90f0021
MOVWBR R3, R4 // b91f0043
+ MOVDEQ R0, R1 // b9e28010
+ MOVDGE R2, R3 // b9e2a032
+ MOVDGT R4, R5 // b9e22054
+ MOVDLE R6, R7 // b9e2c076
+ MOVDLT R8, R9 // b9e24098
+ MOVDNE R10, R11 // b9e270ba
+
MOVD (R15), R1 // e310f0000004
MOVW (R15), R2 // e320f0000014
MOVH (R15), R3 // e330f0000015
ADDC R1, R2 // b9ea1022
ADDC $1, R1, R2 // b9040021c22a00000001
ADDC R1, R2, R3 // b9ea1032
+ ADDW R1, R2 // 1a21
+ ADDW R1, R2, R3 // b9f81032
+ ADDW $8192, R1 // c21900002000
+ ADDW $8192, R1, R2 // ec21200000d8
SUB R3, R4 // b9090043
SUB R3, R4, R5 // b9e93054
SUB $8192, R3 // c238ffffe000
SUBC R1, R2 // b90b0021
SUBC $1, R1, R2 // b9040021c22affffffff
SUBC R2, R3, R4 // b9eb2043
+ SUBW R3, R4 // 1b43
+ SUBW R3, R4, R5 // b9f93054
+ SUBW $8192, R1 // c21500002000
+ SUBW $8192, R1, R2 // 1821c22500002000
MULLW R6, R7 // b91c0076
MULLW R6, R7, R8 // b9040087b91c0086
MULLW $8192, R6 // a76d2000
DIVD R1, R2, R3 // b90400b2b90d00a1b904003b
DIVW R4, R5 // b90400b5b91d00a4b904005b
DIVW R4, R5, R6 // b90400b5b91d00a4b904006b
- DIVDU R7, R8 // b90400a0b90400b8b98700a7b904008b
- DIVDU R7, R8, R9 // b90400a0b90400b8b98700a7b904009b
- DIVWU R1, R2 // b90400a0b90400b2b99700a1b904002b
- DIVWU R1, R2, R3 // b90400a0b90400b2b99700a1b904003b
+ DIVDU R7, R8 // a7a90000b90400b8b98700a7b904008b
+ DIVDU R7, R8, R9 // a7a90000b90400b8b98700a7b904009b
+ DIVWU R1, R2 // a7a90000b90400b2b99700a1b904002b
+ DIVWU R1, R2, R3 // a7a90000b90400b2b99700a1b904003b
+ MODD R1, R2 // b90400b2b90d00a1b904002a
+ MODD R1, R2, R3 // b90400b2b90d00a1b904003a
+ MODW R4, R5 // b90400b5b91d00a4b904005a
+ MODW R4, R5, R6 // b90400b5b91d00a4b904006a
+ MODDU R7, R8 // a7a90000b90400b8b98700a7b904008a
+ MODDU R7, R8, R9 // a7a90000b90400b8b98700a7b904009a
+ MODWU R1, R2 // a7a90000b90400b2b99700a1b904002a
+ MODWU R1, R2, R3 // a7a90000b90400b2b99700a1b904003a
+ NEG R1 // b9030011
+ NEG R1, R2 // b9030021
+ NEGW R1 // b9130011
+ NEGW R1, R2 // b9130021
LAA R1, R2, 524287(R3) // eb213fff7ff8
LAAG R4, R5, -524288(R6) // eb54600080e8
Optab{AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 0},
Optab{AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 0},
Optab{AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 0},
+ Optab{ASUB, C_LCON, C_REG, C_NONE, C_REG, 22, 0},
+ Optab{ASUB, C_LCON, C_NONE, C_NONE, C_REG, 22, 0},
Optab{AMULHD, C_REG, C_NONE, C_NONE, C_REG, 4, 0},
Optab{AMULHD, C_REG, C_REG, C_NONE, C_REG, 4, 0},
- Optab{ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 0},
- Optab{ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 0},
Optab{ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 0},
Optab{ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 0},
Optab{ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 0},
Optab{ACMPUBEQ, C_REG, C_REG, C_NONE, C_SBRA, 89, 0},
Optab{ACMPUBEQ, C_REG, C_NONE, C_ANDCON, C_SBRA, 90, 0},
+ // move on condition
+ Optab{AMOVDEQ, C_REG, C_NONE, C_NONE, C_REG, 17, 0},
+
// compare
Optab{ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 0},
Optab{ACMP, C_REG, C_NONE, C_NONE, C_LCON, 71, 0},
switch r {
case AADD:
opset(AADDC, r)
+ opset(AADDW, r)
opset(AMULLD, r)
opset(AMULLW, r)
case ADIVW:
opset(ADIVD, r)
opset(ADIVDU, r)
opset(ADIVWU, r)
+ opset(AMODD, r)
+ opset(AMODDU, r)
+ opset(AMODW, r)
+ opset(AMODWU, r)
case AMULHD:
opset(AMULHDU, r)
case AMOVBZ:
opset(ABNE, r)
opset(ABVC, r)
opset(ABVS, r)
+ opset(ABLEU, r)
+ opset(ABLTU, r)
case ABR:
opset(ABL, r)
case ABC:
case AFABS:
opset(AFNABS, r)
opset(AFNEG, r)
+ opset(AFNEGS, r)
opset(ALEDBR, r)
opset(ALDEBR, r)
opset(AFSQRT, r)
case ASUB:
opset(ASUBC, r)
opset(ASUBE, r)
+ opset(ASUBW, r)
+ case ANEG:
+ opset(ANEGW, r)
case AFMOVD:
opset(AFMOVS, r)
case AMOVDBR:
opset(ACMPUBLE, r)
opset(ACMPUBLT, r)
opset(ACMPUBNE, r)
+ case AMOVDEQ:
+ opset(AMOVDGE, r)
+ opset(AMOVDGT, r)
+ opset(AMOVDLE, r)
+ opset(AMOVDLT, r)
+ opset(AMOVDNE, r)
case AVL:
opset(AVLLEZB, r)
opset(AVLLEZH, r)
func branchMask(ctxt *obj.Link, p *obj.Prog) uint32 {
switch p.As {
- case ABEQ, ACMPBEQ, ACMPUBEQ:
+ case ABEQ, ACMPBEQ, ACMPUBEQ, AMOVDEQ:
return 0x8
- case ABGE, ACMPBGE, ACMPUBGE:
+ case ABGE, ACMPBGE, ACMPUBGE, AMOVDGE:
return 0xA
- case ABGT, ACMPBGT, ACMPUBGT:
+ case ABGT, ACMPBGT, ACMPUBGT, AMOVDGT:
return 0x2
- case ABLE, ACMPBLE, ACMPUBLE:
+ case ABLE, ACMPBLE, ACMPUBLE, AMOVDLE:
return 0xC
- case ABLT, ACMPBLT, ACMPUBLT:
+ case ABLT, ACMPBLT, ACMPUBLT, AMOVDLT:
return 0x4
- case ABNE, ACMPBNE, ACMPUBNE:
+ case ABNE, ACMPBNE, ACMPUBNE, AMOVDNE:
return 0x7
+ case ABLEU: // LE or unordered
+ return 0xD
+ case ABLTU: // LT or unordered
+ return 0x5
case ABVC:
- return 0x0 //needs extra instruction
+ return 0x0 // needs extra instruction
case ABVS:
- return 0x1
+ return 0x1 // unordered
}
ctxt.Diag("unknown conditional branch %v", p.As)
return 0xF
}
case 2: // arithmetic op reg [reg] reg
- r := int(p.Reg)
+ r := p.Reg
if r == 0 {
- r = int(p.To.Reg)
+ r = p.To.Reg
}
var opcode uint32
opcode = op_ALGRK
case AADDE:
opcode = op_ALCGR
+ case AADDW:
+ opcode = op_ARK
case AMULLW:
opcode = op_MSGFR
case AMULLD:
opcode = op_MSGR
- case ADIVW:
+ case ADIVW, AMODW:
opcode = op_DSGFR
- case ADIVWU:
+ case ADIVWU, AMODWU:
opcode = op_DLR
- case ADIVD:
+ case ADIVD, AMODD:
opcode = op_DSGR
- case ADIVDU:
+ case ADIVDU, AMODDU:
opcode = op_DLGR
case AFADD:
opcode = op_ADBR
switch p.As {
default:
- case AADD, AADDC:
- zRRF(opcode, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+ case AADD, AADDC, AADDW:
+ if p.As == AADDW && r == p.To.Reg {
+ zRR(op_AR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+ } else {
+ zRRF(opcode, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+ }
case AADDE, AMULLW, AMULLD:
- if r == int(p.To.Reg) {
+ if r == p.To.Reg {
zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
} else if p.From.Reg == p.To.Reg {
zRRE(opcode, uint32(p.To.Reg), uint32(r), asm)
case ADIVW, ADIVWU, ADIVD, ADIVDU:
if p.As == ADIVWU || p.As == ADIVDU {
- zRRE(op_LGR, REGTMP, REGZERO, asm)
+ zRI(op_LGHI, REGTMP, 0, asm)
}
zRRE(op_LGR, REGTMP2, uint32(r), asm)
zRRE(opcode, REGTMP, uint32(p.From.Reg), asm)
zRRE(op_LGR, uint32(p.To.Reg), REGTMP2, asm)
+ case AMODW, AMODWU, AMODD, AMODDU:
+ if p.As == AMODWU || p.As == AMODDU {
+ zRI(op_LGHI, REGTMP, 0, asm)
+ }
+ zRRE(op_LGR, REGTMP2, uint32(r), asm)
+ zRRE(opcode, REGTMP, uint32(p.From.Reg), asm)
+ zRRE(op_LGR, uint32(p.To.Reg), REGTMP, asm)
+
case AFADD, AFADDS:
- if r == int(p.To.Reg) {
+ if r == p.To.Reg {
zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
} else if p.From.Reg == p.To.Reg {
zRRE(opcode, uint32(p.To.Reg), uint32(r), asm)
}
case AFSUB, AFSUBS, AFDIV, AFDIVS:
- if r == int(p.To.Reg) {
+ if r == p.To.Reg {
zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
} else if p.From.Reg == p.To.Reg {
zRRE(op_LGDR, REGTMP, uint32(r), asm)
case AMOVW:
v = int64(int32(v))
}
- if v&0xffff == v {
- zRI(op_LLILL, uint32(p.To.Reg), uint32(v), asm)
+ if int64(int16(v)) == v {
+ zRI(op_LGHI, uint32(p.To.Reg), uint32(v), asm)
} else if v&0xffff0000 == v {
zRI(op_LLILH, uint32(p.To.Reg), uint32(v>>16), asm)
} else if v&0xffff00000000 == v {
zRI(op_LLIHL, uint32(p.To.Reg), uint32(v>>32), asm)
} else if uint64(v)&0xffff000000000000 == uint64(v) {
zRI(op_LLIHH, uint32(p.To.Reg), uint32(v>>48), asm)
- } else if int64(int16(v)) == v {
- zRI(op_LGHI, uint32(p.To.Reg), uint32(v), asm)
} else if int64(int32(v)) == v {
zRIL(_a, op_LGFI, uint32(p.To.Reg), uint32(v), asm)
} else if int64(uint32(v)) == v {
} else {
zRRF(op_SLGRK, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
}
-
case ASUBE:
if r == 0 {
r = int(p.To.Reg)
zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
zRRE(op_SLBGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
}
+ case ASUBW:
+ if r == 0 {
+ zRR(op_SR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+ } else {
+ zRRF(op_SRK, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+ }
}
case 11: // br/bl
addrilreloc(ctxt, p.To.Sym, p.To.Offset)
}
+ case 17: // move on condition
+ m3 := branchMask(ctxt, p)
+ zRRF(op_LOCGR, m3, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+
case 18: // br/bl reg
if p.As == ABL {
zRR(op_BASR, uint32(REG_LR), uint32(p.To.Reg), asm)
zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
}
zRIL(_a, op_ALGFI, uint32(p.To.Reg), uint32(v), asm)
+ case AADDW:
+ i2 := int32(v)
+ if r == p.To.Reg {
+ zRIL(_a, op_AFI, uint32(p.To.Reg), uint32(i2), asm)
+ } else if int32(int16(i2)) == i2 {
+ zRIE(_d, op_AHIK, uint32(p.To.Reg), uint32(r), uint32(i2), 0, 0, 0, 0, asm)
+ } else {
+ zRR(op_LR, uint32(p.To.Reg), uint32(r), asm)
+ zRIL(_a, op_AFI, uint32(p.To.Reg), uint32(i2), asm)
+ }
+ case ASUB:
+ zRIL(_a, op_LGFI, uint32(REGTMP), uint32(v), asm)
+ zRRF(op_SLGRK, uint32(REGTMP), 0, uint32(p.To.Reg), uint32(r), asm)
+ case ASUBC:
+ if r != p.To.Reg {
+ zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
+ }
+ zRIL(_a, op_SLGFI, uint32(p.To.Reg), uint32(v), asm)
+ case ASUBW:
+ if r != p.To.Reg {
+ zRR(op_LR, uint32(p.To.Reg), uint32(r), asm)
+ }
+ zRIL(_a, op_SLFI, uint32(p.To.Reg), uint32(v), asm)
case AMULLW, AMULLD:
if r != p.To.Reg {
zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
zRRF(opcode, uint32(r), 0, uint32(p.To.Reg), REGTMP, asm)
}
- case 26: // mov $addr/sym reg
+ case 26: // MOVD $offset(base)(index), reg
v := regoff(ctxt, &p.From)
r := p.From.Reg
if r == 0 {
r = o.param
}
+ i := p.From.Index
if v >= 0 && v < DISP12 {
- zRX(op_LA, uint32(p.To.Reg), uint32(r), 0, uint32(v), asm)
+ zRX(op_LA, uint32(p.To.Reg), uint32(r), uint32(i), uint32(v), asm)
} else if v >= -DISP20/2 && v < DISP20/2 {
- zRXY(op_LAY, uint32(p.To.Reg), uint32(r), 0, uint32(v), asm)
+ zRXY(op_LAY, uint32(p.To.Reg), uint32(r), uint32(i), uint32(v), asm)
} else {
zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
- zRX(op_LA, uint32(p.To.Reg), uint32(r), REGTMP, 0, asm)
+ zRX(op_LA, uint32(p.To.Reg), uint32(r), REGTMP, uint32(i), asm)
}
case 31: // dword
opcode = op_LNDBR
case AFNEG:
opcode = op_LCDFR
+ case AFNEGS:
+ opcode = op_LCEBR
case ALEDBR:
opcode = op_LEDBR
case ALDEBR:
}
case 47: // arithmetic op (carry) reg [reg] reg
+ r := p.From.Reg
switch p.As {
default:
-
case AADDME:
- r := int(p.From.Reg)
if p.To.Reg == p.From.Reg {
zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
r = REGTMP
}
zRIL(_a, op_LGFI, uint32(p.To.Reg), 0xffffffff, asm) // p.To.Reg <- -1
zRRE(op_ALCGR, uint32(p.To.Reg), uint32(r), asm)
-
case AADDZE:
- r := int(p.From.Reg)
if p.To.Reg == p.From.Reg {
zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
r = REGTMP
}
- zRRE(op_LGR, uint32(p.To.Reg), REGZERO, asm) // p.To.Reg <- 0
+ zRI(op_LGHI, uint32(p.To.Reg), 0, asm)
zRRE(op_ALCGR, uint32(p.To.Reg), uint32(r), asm)
-
case ASUBME:
- r := int(p.From.Reg)
if p.To.Reg == p.From.Reg {
zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
r = REGTMP
}
zRIL(_a, op_LGFI, uint32(p.To.Reg), 0xffffffff, asm) // p.To.Reg <- -1
zRRE(op_SLBGR, uint32(p.To.Reg), uint32(r), asm)
-
case ASUBZE:
- r := int(p.From.Reg)
if p.To.Reg == p.From.Reg {
zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
r = REGTMP
}
- zRRE(op_LGR, uint32(p.To.Reg), REGZERO, asm) // p.To.Reg <- 0
+ zRI(op_LGHI, uint32(p.To.Reg), 0, asm)
zRRE(op_SLBGR, uint32(p.To.Reg), uint32(r), asm)
-
case ANEG:
- r := int(p.From.Reg)
+ r := p.From.Reg
if r == 0 {
- r = int(p.To.Reg)
+ r = p.To.Reg
}
zRRE(op_LCGR, uint32(p.To.Reg), uint32(r), asm)
+ case ANEGW:
+ r := p.From.Reg
+ if r == 0 {
+ r = p.To.Reg
+ }
+ zRRE(op_LCGFR, uint32(p.To.Reg), uint32(r), asm)
}
case 48: // floating-point round to integer