runtime: MakeMap

This commit is contained in:
xushiwei
2024-05-01 07:26:51 +08:00
parent d3fddfb634
commit ed8ffb228b
14 changed files with 1901 additions and 6 deletions

10
cl/_testrt/map/in.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import (
"github.com/goplus/llgo/internal/runtime/c"
)
func main() {
a := map[int]int{23: 100, 7: 29}
c.Printf(c.Str("Hello %d\n"), a[23])
}

0
cl/_testrt/map/out.ll Normal file
View File

View File

@@ -390,6 +390,12 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
case *ssa.FieldAddr:
x := p.compileValue(b, v.X)
ret = b.FieldAddr(x, v.Field)
case *ssa.Alloc:
t := v.Type().(*types.Pointer)
if p.checkVArgs(v, t) { // varargs: this is a varargs allocation
return
}
ret = b.Alloc(t, v.Heap)
case *ssa.IndexAddr:
vx := v.X
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index
@@ -415,12 +421,13 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
max = p.compileValue(b, v.Max)
}
ret = b.Slice(x, low, high, max)
case *ssa.Alloc:
t := v.Type().(*types.Pointer)
if p.checkVArgs(v, t) { // varargs: this is a varargs allocation
return
case *ssa.MakeMap:
var nReserve llssa.Expr
t := v.Type()
if v.Reserve != nil {
nReserve = p.compileValue(b, v.Reserve)
}
ret = b.Alloc(t, v.Heap)
ret = b.MakeMap(p.prog.Type(t), nReserve)
case *ssa.MakeInterface:
const (
delayExpr = true // varargs: don't need to convert an expr to any
@@ -481,6 +488,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
thenb := fn.Block(succs[0].Index)
elseb := fn.Block(succs[1].Index)
b.If(cond, thenb, elseb)
case *ssa.MapUpdate:
case *ssa.Panic:
arg := p.compileValue(b, v.X).Do()
b.Panic(arg)

View File

@@ -29,7 +29,7 @@ func testCompile(t *testing.T, src, expected string) {
}
func TestFromTestrt(t *testing.T) {
cltest.FromDir(t, "", "./_testrt", true)
cltest.FromDir(t, "map", "./_testrt", true)
}
func TestFromTestdata(t *testing.T) {

14
internal/abi/map.go Normal file
View File

@@ -0,0 +1,14 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package abi
// Map constants common to several packages
// runtime/runtime-gdb.py:MapTypePrinter contains its own copy
const (
MapBucketCountBits = 3 // log2 of number of elements in a bucket.
MapBucketCount = 1 << MapBucketCountBits
MapMaxKeyBytes = 128 // Must fit in a uint8.
MapMaxElemBytes = 128 // Must fit in a uint8.
)

View File

@@ -35,6 +35,9 @@ func AllocaCStr(s string) *int8
//go:linkname Unreachable llgo.unreachable
func Unreachable()
//go:linkname Rand C.rand
func Rand() C.int
//go:linkname Malloc C.malloc
func Malloc(size uintptr) unsafe.Pointer

1726
internal/runtime/map.go Normal file

File diff suppressed because it is too large Load Diff

39
internal/runtime/stubs.go Normal file
View File

@@ -0,0 +1,39 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import (
"github.com/goplus/llgo/internal/runtime/c"
)
func fastrand() uint32 {
return uint32(c.Rand())
/* TODO(xsw):
mp := getg().m
// Implement wyrand: https://github.com/wangyi-fudan/wyhash
// Only the platform that math.Mul64 can be lowered
// by the compiler should be in this list.
if goarch.IsAmd64|goarch.IsArm64|goarch.IsPpc64|
goarch.IsPpc64le|goarch.IsMips64|goarch.IsMips64le|
goarch.IsS390x|goarch.IsRiscv64|goarch.IsLoong64 == 1 {
mp.fastrand += 0xa0761d6478bd642f
hi, lo := math.Mul64(mp.fastrand, mp.fastrand^0xe7037ed1a0b428db)
return uint32(hi ^ lo)
}
// Implement xorshift64+: 2 32-bit xorshift sequences added together.
// Shift triplet [17,7,16] was calculated as indicated in Marsaglia's
// Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
// This generator passes the SmallCrush suite, part of TestU01 framework:
// http://simul.iro.umontreal.ca/testu01/tu01.html
t := (*[2]uint32)(unsafe.Pointer(&mp.fastrand))
s1, s0 := t[0], t[1]
s1 ^= s1 << 17
s1 = s1 ^ s0 ^ s1>>7 ^ s0>>16
t[0], t[1] = s0, s1
return s0 + s1
*/
}

View File

@@ -16,3 +16,21 @@ import (
type _type = abi.Type
type interfacetype = abi.InterfaceType
type maptype = abi.MapType
/*
type arraytype = abi.ArrayType
type chantype = abi.ChanType
type slicetype = abi.SliceType
type functype = abi.FuncType
type ptrtype = abi.PtrType
type name = abi.Name
type structtype = abi.StructType
*/

25
internal/runtime/z_map.go Normal file
View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package runtime
// Map represents a Go map.
type Map = hmap
// MakeSmallMap creates a new small map.
func MakeSmallMap() *Map {
return makemap_small()
}

View File

@@ -35,6 +35,8 @@ type Expr struct {
Type
}
var Nil Expr // Zero value is a nil Expr
// IsNil checks if the expression is nil or not.
func (v Expr) IsNil() bool {
return v.Type == nil
@@ -477,6 +479,31 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
// -----------------------------------------------------------------------------
// The MakeMap instruction creates a new hash-table-based map object
// and yields a value of kind map.
//
// t is a (possibly named) *types.Map.
//
// Pos() returns the ast.CallExpr.Lparen, if created by make(map), or
// the ast.CompositeLit.Lbrack if created by a literal.
//
// Example printed form:
//
// t1 = make map[string]int t0
// t1 = make StringIntMap t0
func (b Builder) MakeMap(t Type, nReserve Expr) (ret Expr) {
if debugInstr {
log.Printf("MakeMap %v, %v\n", t, nReserve.impl)
}
pkg := b.fn.pkg
ret.Type = t
ret.impl = b.InlineCall(pkg.rtFunc("MakeSmallMap")).impl
// TODO(xsw): nReserve
return
}
// -----------------------------------------------------------------------------
// The Alloc instruction reserves space for a variable of the given type,
// zero-initializes it, and yields its address.
//

View File

@@ -117,6 +117,7 @@ type aProgram struct {
rtStringTy llvm.Type
rtIfaceTy llvm.Type
rtSliceTy llvm.Type
rtMapTy llvm.Type
anyTy Type
voidTy Type
@@ -184,6 +185,13 @@ func (p Program) rtIface() llvm.Type {
return p.rtIfaceTy
}
func (p Program) rtMap() llvm.Type {
if p.rtMapTy.IsNil() {
p.rtMapTy = p.rtType("Map").ll
}
return p.rtMapTy
}
func (p Program) rtSlice() llvm.Type {
if p.rtSliceTy.IsNil() {
p.rtSliceTy = p.rtType("Slice").ll

View File

@@ -126,4 +126,20 @@ func (b Builder) If(cond Expr, thenb, elseb BasicBlock) {
b.impl.CreateCondBr(cond.impl, thenb.impl, elseb.impl)
}
// The MapUpdate instruction updates the association of Map[Key] to
// Value.
//
// Pos() returns the ast.KeyValueExpr.Colon or ast.IndexExpr.Lbrack,
// if explicit in the source.
//
// Example printed form:
//
// t0[t1] = t2
func (b Builder) MapUpdate(m, k, v Expr) {
if debugInstr {
log.Printf("MapUpdate %v[%v] = %v\n", m.impl, k.impl, v.impl)
}
panic("todo")
}
// -----------------------------------------------------------------------------

View File

@@ -256,6 +256,7 @@ func (p Program) toLLVMType(typ types.Type) Type {
case *types.Slice:
return &aType{p.rtSlice(), typ, vkInvalid}
case *types.Map:
return &aType{p.rtMap(), typ, vkInvalid}
case *types.Struct:
return p.toLLVMStruct(t)
case *types.Named: