Skip to content

Commit

Permalink
Merge pull request #3800 from onflow/bastian/compile-bitwise-operators
Browse files Browse the repository at this point in the history
[Compiler] Compile remaining unary operators
  • Loading branch information
turbolent authored Feb 26, 2025
2 parents 83023aa + edc65ea commit 5a3d8c8
Show file tree
Hide file tree
Showing 12 changed files with 435 additions and 54 deletions.
16 changes: 12 additions & 4 deletions bbq/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1255,14 +1255,22 @@ func (c *Compiler[_, _]) VisitConditionalExpression(expression *ast.ConditionalE
}

func (c *Compiler[_, _]) VisitUnaryExpression(expression *ast.UnaryExpression) (_ struct{}) {
c.compileExpression(expression.Expression)

switch expression.Operation {
case ast.OperationMove:
c.compileExpression(expression.Expression)
case ast.OperationNegate:
c.compileExpression(expression.Expression)
c.codeGen.Emit(opcode.InstructionNot{})

case ast.OperationMinus:
c.codeGen.Emit(opcode.InstructionNegate{})

case ast.OperationMul:
c.codeGen.Emit(opcode.InstructionDeref{})

case ast.OperationMove:
// TODO: invalidate

default:
// TODO
panic(errors.NewUnreachableError())
}

Expand Down
129 changes: 113 additions & 16 deletions bbq/compiler/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1899,10 +1899,10 @@ func TestCompileIntegers(t *testing.T) {

checker, err := ParseAndCheck(t,
fmt.Sprintf(`
fun test() {
let v: %s = 2
}
`,
fun test() {
let v: %s = 2
}
`,
integerType,
),
)
Expand Down Expand Up @@ -1975,10 +1975,10 @@ func TestCompileFixedPoint(t *testing.T) {

checker, err := ParseAndCheck(t,
fmt.Sprintf(`
fun test() {
let v: %s = 2.3
}
`,
fun test() {
let v: %s = 2.3
}
`,
fixedPointType,
),
)
Expand Down Expand Up @@ -2047,12 +2047,11 @@ func TestCompileFixedPoint(t *testing.T) {
}
}

func TestCompileUnary(t *testing.T) {
func TestCompileUnaryNot(t *testing.T) {

t.Parallel()

checker, err := ParseAndCheck(t, `
fun test() {
let no = !true
}
Expand Down Expand Up @@ -2094,6 +2093,104 @@ func TestCompileUnary(t *testing.T) {
)
}

func TestCompileUnaryNegate(t *testing.T) {

t.Parallel()

checker, err := ParseAndCheck(t, `
fun test(x: Int) {
let v = -x
}
`)
require.NoError(t, err)

comp := compiler.NewInstructionCompiler(checker)
program := comp.Compile()

require.Len(t, program.Functions, 1)

functions := comp.ExportFunctions()
require.Equal(t, len(program.Functions), len(functions))

const parameterCount = 1

// xIndex is the index of the parameter `x`, which is the first parameter
const xIndex = 0

// resultIndex is the index of the $result variable
const resultIndex = parameterCount

// localsOffset is the offset of the first local variable
const localsOffset = resultIndex + 1

const (
// vIndex is the index of the local variable `v`, which is the first local variable
vIndex = localsOffset + iota
)

assert.Equal(t,
[]opcode.Instruction{
// let v = -x
opcode.InstructionGetLocal{LocalIndex: xIndex},
opcode.InstructionNegate{},
opcode.InstructionTransfer{TypeIndex: 0},
opcode.InstructionSetLocal{LocalIndex: vIndex},

opcode.InstructionReturn{},
},
functions[0].Code,
)
}

func TestCompileUnaryDeref(t *testing.T) {

t.Parallel()

checker, err := ParseAndCheck(t, `
fun test(ref: &Int) {
let v = *ref
}
`)
require.NoError(t, err)

comp := compiler.NewInstructionCompiler(checker)
program := comp.Compile()

require.Len(t, program.Functions, 1)

functions := comp.ExportFunctions()
require.Equal(t, len(program.Functions), len(functions))

const parameterCount = 1

// refIndex is the index of the parameter `ref`, which is the first parameter
const refIndex = 0

// resultIndex is the index of the $result variable
const resultIndex = parameterCount

// localsOffset is the offset of the first local variable
const localsOffset = resultIndex + 1

const (
// vIndex is the index of the local variable `v`, which is the first local variable
vIndex = localsOffset + iota
)

assert.Equal(t,
[]opcode.Instruction{
// let v = *ref
opcode.InstructionGetLocal{LocalIndex: refIndex},
opcode.InstructionDeref{},
opcode.InstructionTransfer{TypeIndex: 0},
opcode.InstructionSetLocal{LocalIndex: vIndex},

opcode.InstructionReturn{},
},
functions[0].Code,
)
}

func TestCompileBinary(t *testing.T) {

t.Parallel()
Expand Down Expand Up @@ -2139,7 +2236,7 @@ func TestCompileBinary(t *testing.T) {

assert.Equal(t,
[]opcode.Instruction{
// let three = 1 + 2
// let v = 6 ... 3
opcode.InstructionGetConstant{ConstantIndex: 0},
opcode.InstructionGetConstant{ConstantIndex: 1},
instruction,
Expand Down Expand Up @@ -3519,11 +3616,11 @@ func TestCompileIf(t *testing.T) {
checker, err := ParseAndCheck(t, `
fun test(x: Bool): Int {
var y = 0
if x {
y = 1
} else {
y = 2
}
if x {
y = 1
} else {
y = 2
}
return y
}
`)
Expand Down
44 changes: 44 additions & 0 deletions bbq/opcode/instructions.go

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

24 changes: 24 additions & 0 deletions bbq/opcode/instructions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,18 @@
- name: "value"
type: "value"

- name: deref
description:
Pops an (optional) reference off the stack, dereferences it,
and then pushes the value back on to the stack.
valueEffects:
pop:
- name: reference
type: value
push:
- name: value
type: value

# Control flow instructions

- name: "jump"
Expand Down Expand Up @@ -557,6 +569,18 @@
- name: "result"
type: "number"

- name: negate
description:
Pops a number value off the stack, negates it,
and then pushes the result back on to the stack.
valueEffects:
pop:
- name: value
type: number
push:
- name: result
type: number

# Integer comparison instructions

- name: "less"
Expand Down
9 changes: 6 additions & 3 deletions bbq/opcode/opcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ const (
_
_

// Int operations
// Number operations

Add
Subtract
Multiply
Divide
Mod
_
Negate
_
_
_
Expand Down Expand Up @@ -83,7 +83,7 @@ const (
SimpleCast
FailableCast
ForceCast
_
Deref
_
_
_
Expand Down Expand Up @@ -168,4 +168,7 @@ const (
// Other

EmitEvent

// NOTE: not an actual opcode, must be last item
OpcodeMax
)
Loading

0 comments on commit 5a3d8c8

Please sign in to comment.