Skip to content

Commit

Permalink
changed the way to handle instructions with immediates
Browse files Browse the repository at this point in the history
  • Loading branch information
mmk-1 committed Oct 10, 2023
1 parent dd1d928 commit b877bac
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 37 deletions.
43 changes: 25 additions & 18 deletions pkg/assembler/assembler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,48 @@ func CasmToBytecode(code string) ([]*f.Element, error) {
return nil, err
}
// Ast To Instruction List
instructionList, err := astToInstruction(casmAst)
wordList, err := astToInstruction(casmAst)
if err != nil {
return nil, err
}
// Instruction to bytecode
return encodeInstructionListToBytecode(instructionList)
return encodeInstructionListToBytecode(wordList)
}

/*
* Casm to instruction list functions
*/
func astToInstruction(ast *CasmProgram) ([]Instruction, error) {
func astToInstruction(ast *CasmProgram) ([]Word, error) {
// Vist ast
n := len(ast.InstructionList)
// Slice with length 0 and capacity n
instructionList := make([]Instruction, 0, n)
wordList := make([]Word, 0, n)
// iterate over the AST
for i := range ast.InstructionList {
instruction, err := nodeToInstruction(ast.InstructionList[i])
instruction, imm, err := nodeToInstruction(ast.InstructionList[i])
if err != nil {
return nil, err
}
// Append instruction to list
instructionList = append(instructionList, instruction)
wordList = append(wordList, instruction)
if imm != "" {
wordList = append(wordList, imm)
}
}
return instructionList, nil
return wordList, nil
}

func nodeToInstruction(node InstructionNode) (Instruction, error) {
func nodeToInstruction(node InstructionNode) (Word, Immediate, error) {
var instr Instruction
expr := node.Expression()
setInstructionDst(&node, &instr)
setInstructionOp0(&node, &instr, expr)
setInstructionOp1(&node, &instr, expr)
imm, err := setInstructionOp1(&node, &instr, expr)
if err != nil {
return nil, "", err
}
setInstructionFlags(&node, &instr, expr)
return instr, nil
return instr, imm, nil
}

func setInstructionDst(node *InstructionNode, instr *Instruction) {
Expand Down Expand Up @@ -129,44 +135,45 @@ func setInstructionOp0(node *InstructionNode, instr *Instruction, expr Expressio

// Given the expression and the current encode returns an updated encode with the corresponding bit
// and offset of op1, an immediate if exists, and a possible error
func setInstructionOp1(node *InstructionNode, instr *Instruction, expr Expressioner) {
func setInstructionOp1(node *InstructionNode, instr *Instruction, expr Expressioner) (Immediate, error) {
if node != nil && node.Ret != nil {
// op1 is set as [fp - 1], where we read the previous pc
instr.OffOp1 = -1
instr.Op1Source = FpPlusOffOp1
return
return "", nil
}

if expr.AsDeref() != nil {
offset, err := expr.AsDeref().SignedOffset()
if err != nil {
return
return "", err
}
instr.OffOp1 = offset
if expr.AsDeref().IsFp() {
instr.Op1Source = FpPlusOffOp1
} else {
instr.Op1Source = ApPlusOffOp1
}
return
return "", nil
} else if expr.AsDoubleDeref() != nil {
offset, err := expr.AsDoubleDeref().SignedOffset()
if err != nil {
return
return "", err
}
instr.OffOp1 = offset
return
return "", nil
} else if expr.AsImmediate() != nil {
// immediate is converted to Felt during bytecode conversion
imm := expr.AsImmediate()
instr.OffOp1 = 1
instr.Op1Source = Imm
instr.Imm = *imm
return
// instr.Imm = *imm
return *imm, nil
} else {
// if it is a math operation, the op1 source is set by the right hand side
setInstructionOp1(node, instr, expr.AsMathOperation().Rhs)

Check failure on line 174 in pkg/assembler/assembler.go

View workflow job for this annotation

GitHub Actions / lint

Error return value is not checked (errcheck)
}
return "", nil
}

func setInstructionFlags(node *InstructionNode, instr *Instruction, expression Expressioner) {
Expand Down
7 changes: 1 addition & 6 deletions pkg/assembler/assembler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ func TestCallRelToInstrList(t *testing.T) {
PcUpdate: PcUpdateJumpRel,
ApUpdate: SameAp,
Opcode: OpCodeCall,
Imm: "123",
}
assert.Equal(t, expected, instrList[0])
}
Expand Down Expand Up @@ -87,7 +86,6 @@ func TestJmpAbsToInstrList(t *testing.T) {
OffDest: -1,
OffOp0: -1,
OffOp1: 1,
Imm: "123",
DstRegister: Fp,
Op0Register: Fp,
Op1Source: Imm,
Expand Down Expand Up @@ -565,7 +563,7 @@ func parseSingleInstruction(casmCode string) uint64 {
return instructions[0].Uint64()
}

func parseSingleInstructionToInstrList(casmCode string) []Instruction {
func parseSingleInstructionToInstrList(casmCode string) []Word {
casmAst, err := parser.ParseString("", casmCode)
if err != nil {
panic(err)
Expand All @@ -575,9 +573,6 @@ func parseSingleInstructionToInstrList(casmCode string) []Instruction {
panic(err)
}

// if len(instructions) != 1 {
// panic(fmt.Errorf("Expected 1 instruction, got %d", len(instructions)))
// }
return instructions
}

Expand Down
33 changes: 20 additions & 13 deletions pkg/assembler/instruction.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ const (
OpCodeAssertEq
)

type Word interface{}

type Immediate = string

type Instruction struct {
OffDest int16
OffOp0 int16
Expand All @@ -164,9 +168,6 @@ type Instruction struct {

// Defines which instruction needs to be executed
Opcode Opcode

// Immediate value for 2 word instructions
Imm string
}

func (instr Instruction) Size() uint8 {
Expand Down Expand Up @@ -356,22 +357,28 @@ func decodeInstructionFlags(instruction *Instruction, flags uint16) error {
/*
* Instruction list into bytecode functions
*/
func encodeInstructionListToBytecode(instruction []Instruction) ([]*f.Element, error) {
n := len(instruction)
func encodeInstructionListToBytecode(wordList []Word) ([]*f.Element, error) {
n := len(wordList)
bytecodes := make([]*f.Element, 0, n+(n/2)+1)

for i := range instruction {
bytecode, err := encodeOneInstruction(&instruction[i])
if err != nil {
return nil, err
}
bytecodes = append(bytecodes, bytecode)
if instruction[i].Imm != "" {
imm, err := new(f.Element).SetString(instruction[i].Imm)
for i, word := range wordList {
switch w := word.(type) {
case Instruction:
bytecode, err := encodeOneInstruction(&w)
if err != nil {
return nil, err
}
bytecodes = append(bytecodes, bytecode)

case Immediate:
imm, err := new(f.Element).SetString(w)
if err != nil {
return nil, err
}
bytecodes = append(bytecodes, imm)

default:
return nil, fmt.Errorf("word %d is not an instruction or immediate", i)
}
}
return bytecodes, nil
Expand Down

0 comments on commit b877bac

Please sign in to comment.