Skip to content

Commit

Permalink
Builtin copy as an AST type.
Browse files Browse the repository at this point in the history
  • Loading branch information
markkurossi committed Jul 24, 2024
1 parent d3b2ce0 commit de353db
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 1 deletion.
12 changes: 12 additions & 0 deletions compiler/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var (
_ AST = &BasicLit{}
_ AST = &CompositeLit{}
_ AST = &Make{}
_ AST = &Copy{}
)

func indent(w io.Writer, indent int) {
Expand Down Expand Up @@ -904,3 +905,14 @@ func (ast *Make) String() string {
}
return str + ")"
}

// Copy implements the builtin function copy.
type Copy struct {
utils.Point
Dst AST
Src AST
}

func (ast *Copy) String() string {
return fmt.Sprintf("copy(%v, %v)", ast.Dst, ast.Src)
}
8 changes: 7 additions & 1 deletion compiler/ast/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const (
// Eval implements the compiler.ast.AST.Eval for list statements.
func (ast List) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) (
ssa.Value, bool, error) {
return ssa.Undefined, false, fmt.Errorf("List.Eval not implemented yet")
return ssa.Undefined, false, ctx.Errorf(ast, "List.Eval not implemented")
}

// Eval implements the compiler.ast.AST.Eval for function definitions.
Expand Down Expand Up @@ -673,3 +673,9 @@ func (ast *Make) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) (
// Create typeref constant.
return gen.Constant(typeInfo, types.Undefined), true, nil
}

// Eval implements the compiler.ast.AST.Eval for the builtin function copy.
func (ast *Copy) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) (
ssa.Value, bool, error) {
return ssa.Undefined, false, nil
}
111 changes: 111 additions & 0 deletions compiler/ast/ssagen.go
Original file line number Diff line number Diff line change
Expand Up @@ -2161,3 +2161,114 @@ func (ast *Make) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) (

return block, []ssa.Value{v}, nil
}

// SSA implements the compiler.ast.AST.SSA for the builtin function copy.
func (ast *Copy) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) (
*ssa.Block, []ssa.Value, error) {

var lrv *LRValue
var err error

// Resolve destination.
switch lv := ast.Dst.(type) {
case *VariableRef:
lrv, _, _, err = ctx.LookupVar(block, gen, block.Bindings, lv)
if err != nil {
return nil, nil, ctx.Error(ast.Dst, err.Error())
}

default:
return nil, nil, ctx.Errorf(ast.Dst,

Check failure on line 2181 in compiler/ast/ssagen.go

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

MCPLC error:

Check failure on line 2181 in compiler/ast/ssagen.go

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

MCPLC error:

Check failure on line 2181 in compiler/ast/ssagen.go

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

MCPLC error:

Check failure on line 2181 in compiler/ast/ssagen.go

View workflow job for this annotation

GitHub Actions / Build (macos-latest)

MCPLC error:
"invalid argument: copy expects slice arguments: got %T", ast.Dst)
}
dst := lrv.RValue()
if !dst.Type.Type.Array() {
return nil, nil, ctx.Errorf(ast.Dst,
"invalid argument: copy expects slice arguments: got %v", dst.Type)
}
dstFrom := types.Size(0)
dstTo := dst.Type.ArraySize
dstCount := dstTo - dstFrom
elSize := dst.Type.ElementType.Bits

// Resolve source.
block, v, err := ast.Src.SSA(block, ctx, gen)
if err != nil {
return nil, nil, err
}
if len(v) != 1 {
return nil, nil, ctx.Errorf(ast.Src,
"invalid argument: copy expects slice arguments: got multivalue %T",
ast.Src)
}
src := v[0]
var srcType types.Info
if src.Type.Type == types.TPtr {
srcType = *src.Type.ElementType
} else {
srcType = src.Type
}
if !srcType.Type.Array() {
return nil, nil, ctx.Errorf(ast.Src,
"invalid argument: copy expects slice arguments: got %T", src.Type)
}
if !dst.Type.ElementType.Equal(*srcType.ElementType) {
return nil, nil, ctx.Errorf(ast,
"arguments to copy have different element types: %s and %s",
dst.Type.ElementType, src.Type.ElementType)
}
srcCount := src.Type.ArraySize

fmt.Printf("copy(%v[%d-%d], %v[0-%d])\n",
dst, dstFrom, dstTo, src, srcCount)

var ret ssa.Value

if dstFrom == 0 && srcCount >= dstCount {
// Src overwrites dst fully.
bits := dstCount * elSize
ti := types.Info{
Type: dst.Type.Type,
IsConcrete: true,
Bits: bits,
MinBits: bits,
ElementType: dst.Type.ElementType,
ArraySize: dstCount,
}
fromConst := gen.Constant(int64(0), types.Undefined)
toConst := gen.Constant(int64(dstCount*elSize), types.Undefined)
ret = gen.Constant(int64(dstCount), types.Undefined)

tmp := gen.AnonVal(ti)
block.AddInstr(ssa.NewSliceInstr(src, fromConst, toConst, tmp))
err := lrv.Set(tmp)
if err != nil {
return nil, nil, err
}
} else {
// Src overwrites part of dst.
tmp := gen.AnonVal(dst.Type)
block.AddInstr(ssa.NewMovInstr(dst, tmp))

count := srcCount
if count > dstCount {
count = dstCount
}
ret = gen.Constant(int64(count), types.Undefined)

// The amov sets tmp[from:to]=src i.e. it automatically slices
// src to to-from bits.

tmp2 := gen.AnonVal(dst.Type)
fromConst := gen.Constant(int64(dstFrom*elSize), types.Undefined)
toConst := gen.Constant(int64((dstFrom+count)*elSize), types.Undefined)
block.AddInstr(ssa.NewAmovInstr(src, tmp, fromConst, toConst, tmp2))

err := lrv.Set(tmp2)
if err != nil {
return nil, nil, err
}
}

return block, []ssa.Value{ret}, nil
}
11 changes: 11 additions & 0 deletions compiler/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,17 @@ primary:
Type: ti,
Exprs: arguments,
}
} else if vr.String() == "copy" {
if len(arguments) != 2 {
return nil, p.errf(primary.Location(),
"invalid arguments for copy (expected 2, found %v)",
len(arguments))
}
primary = &ast.Copy{
Point: primary.Location(),
Dst: arguments[0],
Src: arguments[1],
}
} else {
primary = &ast.Call{
Point: primary.Location(),
Expand Down

0 comments on commit de353db

Please sign in to comment.