Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions arm64_eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ func (c *arm64Ctx) eval64(op Operand, postInc bool) (string, error) {
return c.imm64(op.Imm), nil
case OpReg:
return c.loadReg(op.Reg)
case OpRegExtend:
v, err := c.loadReg(op.Reg)
if err != nil {
return "", err
}
return c.extendReg64(v, op.Ext)
case OpRegShift:
v, err := c.loadReg(op.Reg)
if err != nil {
Expand Down Expand Up @@ -191,6 +197,38 @@ func (c *arm64Ctx) eval64(op Operand, postInc bool) (string, error) {
}
}

func (c *arm64Ctx) extendReg64(v string, ext ExtendOp) (string, error) {
switch ext {
case ExtendUXTX, ExtendSXTX:
return v, nil
}

var fromTy string
var extOp string
switch ext {
case ExtendUXTB:
fromTy, extOp = "i8", "zext"
case ExtendUXTH:
fromTy, extOp = "i16", "zext"
case ExtendUXTW:
fromTy, extOp = "i32", "zext"
case ExtendSXTB:
fromTy, extOp = "i8", "sext"
case ExtendSXTH:
fromTy, extOp = "i16", "sext"
case ExtendSXTW:
fromTy, extOp = "i32", "sext"
default:
return "", fmt.Errorf("arm64: unsupported register extension %q", ext)
}

tr := c.newTmp()
fmt.Fprintf(c.b, " %%%s = trunc i64 %s to %s\n", tr, v, fromTy)
ex := c.newTmp()
fmt.Fprintf(c.b, " %%%s = %s %s %%%s to i64\n", ex, extOp, fromTy, tr)
return "%" + ex, nil
}

func (c *arm64Ctx) evalFPValue64(op Operand) (string, error) {
slot, ok := c.fpParams[op.FPOffset]
if !ok {
Expand Down
11 changes: 11 additions & 0 deletions arm64_helper_edge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,14 @@ func TestARM64EvalCoverage(t *testing.T) {
ops := []Operand{
{Kind: OpImm, Imm: 7},
{Kind: OpReg, Reg: "R0"},
{Kind: OpRegExtend, Reg: "R2", Ext: ExtendUXTB},
{Kind: OpRegExtend, Reg: "R2", Ext: ExtendUXTH},
{Kind: OpRegExtend, Reg: "R2", Ext: ExtendUXTW},
{Kind: OpRegExtend, Reg: "R2", Ext: ExtendUXTX},
{Kind: OpRegExtend, Reg: "R3", Ext: ExtendSXTB},
{Kind: OpRegExtend, Reg: "R3", Ext: ExtendSXTH},
{Kind: OpRegExtend, Reg: "R3", Ext: ExtendSXTW},
{Kind: OpRegExtend, Reg: "R3", Ext: ExtendSXTX},
{Kind: OpRegShift, Reg: "R1", ShiftOp: ShiftLeft, ShiftAmount: 2},
{Kind: OpRegShift, Reg: "R1", ShiftOp: ShiftRight, ShiftAmount: 1},
{Kind: OpFP, FPOffset: 0},
Expand Down Expand Up @@ -1514,6 +1522,9 @@ func TestARM64EvalCoverage(t *testing.T) {
if _, err := c.eval64(Operand{Kind: OpRegShift, Reg: "R1", ShiftOp: ShiftRotate, ShiftReg: "R2"}, false); err == nil {
t.Fatalf("eval64(register shift) unexpectedly succeeded")
}
if _, err := c.eval64(Operand{Kind: OpRegExtend, Reg: "R1", Ext: ExtendOp("BAD")}, false); err == nil {
t.Fatalf("eval64(bad extension) unexpectedly succeeded")
}
if _, err := c.eval64(Operand{Kind: OpRegShift, Reg: "R1", ShiftOp: ShiftRotate, ShiftAmount: 1}, false); err == nil {
t.Fatalf("eval64(rotate) unexpectedly succeeded")
}
Expand Down
23 changes: 23 additions & 0 deletions arm64_new_opfamilies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,26 @@ TEXT featureprobe(SB),NOSPLIT,$0-0
t.Fatal(err)
}
}

func TestTranslateARM64CompareWithExtendedRegister(t *testing.T) {
src := `
TEXT countcmp(SB),NOSPLIT,$0-0
CMP R2.UXTB, R5
CINC EQ, R11, R11
RET
`
file, err := Parse(ArchARM64, src)
if err != nil {
t.Fatal(err)
}
_, err = Translate(file, Options{
TargetTriple: "aarch64-unknown-linux-gnu",
Sigs: map[string]FuncSig{
"countcmp": {Name: "countcmp", Ret: Void},
},
Goarch: "arm64",
})
if err != nil {
t.Fatal(err)
}
}
52 changes: 49 additions & 3 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const (
OpInvalid OperandKind = iota
OpImm
OpReg
OpRegExtend
OpRegShift
OpFP
OpFPAddr
Expand All @@ -159,6 +160,22 @@ const (
ShiftRotate ShiftOp = "@>"
)
Comment thread
cpunion marked this conversation as resolved.

// ExtendOp is an ARM64 register-extension modifier (for example UXTB, SXTW).
// The prefix U/S selects zero- or sign-extension; the suffix B/H/W/X selects
// the source width (8/16/32/64 bits).
type ExtendOp string

const (
ExtendUXTB ExtendOp = "UXTB"
ExtendUXTH ExtendOp = "UXTH"
ExtendUXTW ExtendOp = "UXTW"
ExtendUXTX ExtendOp = "UXTX"
ExtendSXTB ExtendOp = "SXTB"
ExtendSXTH ExtendOp = "SXTH"
ExtendSXTW ExtendOp = "SXTW"
ExtendSXTX ExtendOp = "SXTX"
)

// Operand models a minimal subset of Plan 9 asm operands.
//
// Supported:
Expand All @@ -168,9 +185,10 @@ const (
type Operand struct {
Kind OperandKind

Imm int64 // OpImm
ImmRaw string // OpImm unresolved symbolic placeholder, including leading '$'
Reg Reg // OpReg
Imm int64 // OpImm
ImmRaw string // OpImm unresolved symbolic placeholder, including leading '$'
Reg Reg // OpReg
Ext ExtendOp // OpRegExtend
// OpRegShift
ShiftOp ShiftOp
ShiftAmount int64
Expand Down Expand Up @@ -210,6 +228,8 @@ func (o Operand) String() string {
return fmt.Sprintf("$%d", o.Imm)
case OpReg:
return string(o.Reg)
case OpRegExtend:
return fmt.Sprintf("%s.%s", o.Reg, o.Ext)
case OpRegShift:
suffix := fmt.Sprintf("%d", o.ShiftAmount)
if o.ShiftReg != "" {
Expand Down Expand Up @@ -516,6 +536,9 @@ func parseOperand(s string) (Operand, error) {
if name, off, ok := parseFPAddr(s); ok {
return Operand{Kind: OpFPAddr, FPName: name, FPOffset: off}, nil
}
if r, ext, ok := parseRegExtend(s); ok {
return Operand{Kind: OpRegExtend, Reg: r, Ext: ext}, nil
}
if base, sop, amt, shiftReg, ok := parseRegShift(s); ok {
return Operand{Kind: OpRegShift, Reg: base, ShiftOp: sop, ShiftAmount: amt, ShiftReg: shiftReg}, nil
}
Expand Down Expand Up @@ -578,6 +601,29 @@ func parseOperand(s string) (Operand, error) {
return Operand{}, fmt.Errorf("unsupported operand: %q", s)
}

func parseRegExtend(s string) (Reg, ExtendOp, bool) {
s = strings.TrimSpace(s)
if s == "" {
return "", "", false
}
dot := strings.LastIndexByte(s, '.')
if dot <= 0 || dot == len(s)-1 {
return "", "", false
}
r, ok := parseReg(s[:dot])
if !ok {
return "", "", false
}
ext := ExtendOp(strings.ToUpper(strings.TrimSpace(s[dot+1:])))
switch ext {
case ExtendUXTB, ExtendUXTH, ExtendUXTW, ExtendUXTX,
ExtendSXTB, ExtendSXTH, ExtendSXTW, ExtendSXTX:
return r, ext, true
default:
return "", "", false
}
}

func parseRegShift(s string) (base Reg, sop ShiftOp, amt int64, shiftReg Reg, ok bool) {
s = strings.TrimSpace(s)
if s == "" {
Expand Down
8 changes: 8 additions & 0 deletions types_deep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ func TestTypeHelperCoverage(t *testing.T) {
{Operand{Kind: OpImm, Imm: 7}, "$7"},
{Operand{Kind: OpImm, ImmRaw: "$(A+1)"}, "$(A+1)"},
{Operand{Kind: OpReg, Reg: AX}, "AX"},
{Operand{Kind: OpRegExtend, Reg: "R2", Ext: ExtendUXTB}, "R2.UXTB"},
{Operand{Kind: OpRegShift, Reg: "R1", ShiftOp: ShiftLeft, ShiftAmount: 2}, "R1<<2"},
{Operand{Kind: OpRegShift, Reg: "R2", ShiftOp: ShiftRight, ShiftReg: "R3"}, "R2>>R3"},
{Operand{Kind: OpFP, FPName: "arg", FPOffset: 8}, "arg+8(FP)"},
Expand Down Expand Up @@ -203,12 +204,19 @@ func TestTypeParserEdgeCoverage(t *testing.T) {
{"MIDR_EL1", OpIdent},
{"helper<>(SB)", OpSym},
{"R1@>2", OpRegShift},
{"R2.UXTB", OpRegExtend},
} {
op, err := parseOperand(tc.in)
if err != nil || op.Kind != tc.want {
t.Fatalf("parseOperand(%q) = (%v, %v), want kind %v", tc.in, err, op.Kind, tc.want)
}
}
if reg, ext, ok := parseRegExtend("r3.sxtw"); !ok || reg != "R3" || ext != ExtendSXTW {
t.Fatalf("parseRegExtend(r3.sxtw) = (%q, %q, %v)", reg, ext, ok)
}
if _, _, ok := parseRegExtend("R2.BAD"); ok {
t.Fatalf("parseRegExtend(R2.BAD) unexpectedly succeeded")
}
if _, err := parseOperand("[]"); err == nil {
t.Fatalf("parseOperand([]) unexpectedly succeeded")
}
Expand Down
Loading