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
89 changes: 60 additions & 29 deletions asm/alu.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ package asm

// Source of ALU / ALU64 / Branch operations
//
// msb lsb
// +----+-+---+
// |op |S|cls|
// +----+-+---+
type Source uint8
// msb lsb
// +------------+-+---+
// | op |S|cls|
// +------------+-+---+
type Source uint16

const sourceMask OpCode = 0x08
const sourceMask OpCode = 0x0008

// Source bitmask
const (
// InvalidSource is returned by getters when invoked
// on non ALU / branch OpCodes.
InvalidSource Source = 0xff
InvalidSource Source = 0xffff
// ImmSource src is from constant
ImmSource Source = 0x00
ImmSource Source = 0x0000
// RegSource src is from register
RegSource Source = 0x08
RegSource Source = 0x0008
)

// The Endianness of a byte swap instruction.
Expand All @@ -39,46 +39,56 @@ const (

// ALUOp are ALU / ALU64 operations
//
// msb lsb
// +----+-+---+
// |OP |s|cls|
// +----+-+---+
type ALUOp uint8
// msb lsb
// +-------+----+-+---+
// | EXT | OP |s|cls|
// +-------+----+-+---+
type ALUOp uint16

const aluMask OpCode = 0xf0
const aluMask OpCode = 0xfff0

const (
// InvalidALUOp is returned by getters when invoked
// on non ALU OpCodes
InvalidALUOp ALUOp = 0xff
// Add - addition
Add ALUOp = 0x00
Add ALUOp = 0x0000
// Sub - subtraction
Sub ALUOp = 0x10
Sub ALUOp = 0x0010
// Mul - multiplication
Mul ALUOp = 0x20
Mul ALUOp = 0x0020
// Div - division
Div ALUOp = 0x30
Div ALUOp = 0x0030
// SDiv - signed division
SDiv ALUOp = 0x0130
// Or - bitwise or
Or ALUOp = 0x40
Or ALUOp = 0x0040
// And - bitwise and
And ALUOp = 0x50
And ALUOp = 0x0050
// LSh - bitwise shift left
LSh ALUOp = 0x60
LSh ALUOp = 0x0060
// RSh - bitwise shift right
RSh ALUOp = 0x70
RSh ALUOp = 0x0070
// Neg - sign/unsign signing bit
Neg ALUOp = 0x80
Neg ALUOp = 0x0080
// Mod - modulo
Mod ALUOp = 0x90
Mod ALUOp = 0x0090
// SMod - signed modulo
SMod ALUOp = 0x0190
// Xor - bitwise xor
Xor ALUOp = 0xa0
Xor ALUOp = 0x00a0
// Mov - move value from one place to another
Mov ALUOp = 0xb0
Mov ALUOp = 0x00b0
// SMov8 - move lower 8 bits, sign extended upper bits of target
SMov8 ALUOp = 0x08b0
Comment thread
dylandreimerink marked this conversation as resolved.
// SMov16 - move lower 16 bits, sign extended upper bits of target
SMov16 ALUOp = 0x10b0
// SMov32 - move lower 32 bits, sign extended upper bits of target
SMov32 ALUOp = 0x20b0
// ArSh - arithmetic shift
ArSh ALUOp = 0xc0
ArSh ALUOp = 0x00c0
// Swap - endian conversions
Swap ALUOp = 0xd0
Swap ALUOp = 0x00d0
)

// HostTo converts from host to another endianness.
Expand All @@ -102,6 +112,27 @@ func HostTo(endian Endianness, dst Register, size Size) Instruction {
}
}

// BSwap unconditionally reverses the order of bytes in a register.
func BSwap(dst Register, size Size) Instruction {
var imm int64
switch size {
case Half:
imm = 16
case Word:
imm = 32
case DWord:
imm = 64
default:
return Instruction{OpCode: InvalidOpCode}
}

return Instruction{
OpCode: OpCode(ALU64Class).SetALUOp(Swap),
Dst: dst,
Constant: imm,
}
}

// Op returns the OpCode for an ALU operation with a given source.
func (op ALUOp) Op(source Source) OpCode {
return OpCode(ALU64Class).SetALUOp(op).SetSource(source)
Expand Down
46 changes: 28 additions & 18 deletions asm/alu_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

79 changes: 73 additions & 6 deletions asm/instruction.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,34 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
}

ins.Offset = int16(bo.Uint16(data[2:4]))

if ins.OpCode.Class().IsALU() {
Comment thread
dylandreimerink marked this conversation as resolved.
switch ins.OpCode.ALUOp() {
case Div:
if ins.Offset == 1 {
ins.OpCode = ins.OpCode.SetALUOp(SDiv)
ins.Offset = 0
}
case Mod:
if ins.Offset == 1 {
ins.OpCode = ins.OpCode.SetALUOp(SMod)
ins.Offset = 0
}
case Mov:
switch ins.Offset {
case 8:
ins.OpCode = ins.OpCode.SetALUOp(SMov8)
ins.Offset = 0
case 16:
ins.OpCode = ins.OpCode.SetALUOp(SMov16)
ins.Offset = 0
case 32:
ins.OpCode = ins.OpCode.SetALUOp(SMov32)
ins.Offset = 0
}
}
}

// Convert to int32 before widening to int64
// to ensure the signed bit is carried over.
ins.Constant = int64(int32(bo.Uint32(data[4:8])))
Expand Down Expand Up @@ -106,6 +134,26 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error)
return 0, fmt.Errorf("can't marshal registers: %s", err)
}

if ins.OpCode.Class().IsALU() {
switch ins.OpCode.ALUOp() {
Comment thread
lmb marked this conversation as resolved.
case SDiv:
ins.OpCode = ins.OpCode.SetALUOp(Div)
ins.Offset = 1
case SMod:
ins.OpCode = ins.OpCode.SetALUOp(Mod)
ins.Offset = 1
case SMov8:
ins.OpCode = ins.OpCode.SetALUOp(Mov)
ins.Offset = 8
case SMov16:
ins.OpCode = ins.OpCode.SetALUOp(Mov)
ins.Offset = 16
case SMov32:
ins.OpCode = ins.OpCode.SetALUOp(Mov)
ins.Offset = 32
}
}

data := make([]byte, InstructionSize)
data[0] = byte(ins.OpCode)
data[1] = byte(regs)
Expand Down Expand Up @@ -298,31 +346,40 @@ func (ins Instruction) Format(f fmt.State, c rune) {
goto ref
}

fmt.Fprintf(f, "%v ", op)
switch cls := op.Class(); {
case cls.isLoadOrStore():
fmt.Fprintf(f, "%v ", op)
switch op.Mode() {
case ImmMode:
fmt.Fprintf(f, "dst: %s imm: %d", ins.Dst, ins.Constant)
case AbsMode:
fmt.Fprintf(f, "imm: %d", ins.Constant)
case IndMode:
fmt.Fprintf(f, "dst: %s src: %s imm: %d", ins.Dst, ins.Src, ins.Constant)
case MemMode:
case MemMode, MemSXMode:
fmt.Fprintf(f, "dst: %s src: %s off: %d imm: %d", ins.Dst, ins.Src, ins.Offset, ins.Constant)
case XAddMode:
fmt.Fprintf(f, "dst: %s src: %s", ins.Dst, ins.Src)
}

case cls.IsALU():
fmt.Fprintf(f, "dst: %s ", ins.Dst)
if op.ALUOp() == Swap || op.Source() == ImmSource {
fmt.Fprintf(f, "%v", op)
if op == Swap.Op(ImmSource) {
fmt.Fprintf(f, "%d", ins.Constant)
}

fmt.Fprintf(f, " dst: %s ", ins.Dst)
switch {
case op.ALUOp() == Swap:
break
case op.Source() == ImmSource:
fmt.Fprintf(f, "imm: %d", ins.Constant)
} else {
default:
fmt.Fprintf(f, "src: %s", ins.Src)
}

case cls.IsJump():
fmt.Fprintf(f, "%v ", op)
switch jop := op.JumpOp(); jop {
case Call:
switch ins.Src {
Expand All @@ -336,6 +393,13 @@ func (ins Instruction) Format(f fmt.State, c rune) {
fmt.Fprint(f, BuiltinFunc(ins.Constant))
}

case Ja:
if ins.OpCode.Class() == Jump32Class {
fmt.Fprintf(f, "imm: %d", ins.Constant)
} else {
fmt.Fprintf(f, "off: %d", ins.Offset)
}

default:
fmt.Fprintf(f, "dst: %s off: %d ", ins.Dst, ins.Offset)
if op.Source() == ImmSource {
Expand All @@ -344,6 +408,8 @@ func (ins Instruction) Format(f fmt.State, c rune) {
fmt.Fprintf(f, "src: %s", ins.Src)
}
}
default:
fmt.Fprintf(f, "%v ", op)
}

ref:
Expand Down Expand Up @@ -772,7 +838,8 @@ func (insns Instructions) encodeFunctionReferences() error {
}

switch {
case ins.IsFunctionReference() && ins.Constant == -1:
case ins.IsFunctionReference() && ins.Constant == -1,
ins.OpCode == Ja.opCode(Jump32Class, ImmSource) && ins.Constant == -1:
symOffset, ok := symbolOffsets[ins.Reference()]
if !ok {
return fmt.Errorf("%s at insn %d: symbol %q: %w", ins.OpCode, i, ins.Reference(), ErrUnsatisfiedProgramReference)
Expand Down
Loading