From b877bac5f31675cd4af67fc5c641c742a2bdf0c4 Mon Sep 17 00:00:00 2001 From: Mahdi Khosravi Date: Tue, 10 Oct 2023 10:57:11 +0300 Subject: [PATCH] changed the way to handle instructions with immediates --- pkg/assembler/assembler.go | 43 +++++++++++++++++++-------------- pkg/assembler/assembler_test.go | 7 +----- pkg/assembler/instruction.go | 33 +++++++++++++++---------- 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/pkg/assembler/assembler.go b/pkg/assembler/assembler.go index 16863a1a..40264ecc 100644 --- a/pkg/assembler/assembler.go +++ b/pkg/assembler/assembler.go @@ -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) { @@ -129,18 +135,18 @@ 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() { @@ -148,25 +154,26 @@ func setInstructionOp1(node *InstructionNode, instr *Instruction, expr Expressio } 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) } + return "", nil } func setInstructionFlags(node *InstructionNode, instr *Instruction, expression Expressioner) { diff --git a/pkg/assembler/assembler_test.go b/pkg/assembler/assembler_test.go index 9fd6e6bc..12e28e29 100644 --- a/pkg/assembler/assembler_test.go +++ b/pkg/assembler/assembler_test.go @@ -40,7 +40,6 @@ func TestCallRelToInstrList(t *testing.T) { PcUpdate: PcUpdateJumpRel, ApUpdate: SameAp, Opcode: OpCodeCall, - Imm: "123", } assert.Equal(t, expected, instrList[0]) } @@ -87,7 +86,6 @@ func TestJmpAbsToInstrList(t *testing.T) { OffDest: -1, OffOp0: -1, OffOp1: 1, - Imm: "123", DstRegister: Fp, Op0Register: Fp, Op1Source: Imm, @@ -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) @@ -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 } diff --git a/pkg/assembler/instruction.go b/pkg/assembler/instruction.go index 804dab59..237a73d7 100644 --- a/pkg/assembler/instruction.go +++ b/pkg/assembler/instruction.go @@ -146,6 +146,10 @@ const ( OpCodeAssertEq ) +type Word interface{} + +type Immediate = string + type Instruction struct { OffDest int16 OffOp0 int16 @@ -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 { @@ -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