13
cl/_testrt/map/in.go
Normal file
13
cl/_testrt/map/in.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
import (
|
||||
"github.com/goplus/llgo/internal/runtime/c"
|
||||
)
|
||||
*/
|
||||
|
||||
func main() {
|
||||
a := map[int]int{23: 100, 7: 29}
|
||||
_ = a
|
||||
// c.Printf(c.Str("Hello %d\n"), a[23])
|
||||
}
|
||||
26
cl/_testrt/map/out.ll
Normal file
26
cl/_testrt/map/out.ll
Normal file
@@ -0,0 +1,26 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
@"main.init$guard" = global ptr null
|
||||
|
||||
define void @main.init() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"main.init$guard", align 1
|
||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||
|
||||
_llgo_1: ; preds = %_llgo_0
|
||||
store i1 true, ptr @"main.init$guard", align 1
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @main() {
|
||||
_llgo_0:
|
||||
call void @main.init()
|
||||
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.MakeSmallMap"()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.MakeSmallMap"()
|
||||
@@ -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,11 @@ 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:
|
||||
m := p.compileValue(b, v.Map)
|
||||
key := p.compileValue(b, v.Key)
|
||||
val := p.compileValue(b, v.Value)
|
||||
b.MapUpdate(m, key, val)
|
||||
case *ssa.Panic:
|
||||
arg := p.compileValue(b, v.X).Do()
|
||||
b.Panic(arg)
|
||||
|
||||
14
internal/abi/map.go
Normal file
14
internal/abi/map.go
Normal 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.
|
||||
)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ source_filename = "github.com/goplus/llgo/internal/runtime"
|
||||
%"github.com/goplus/llgo/internal/runtime.itab" = type { ptr, ptr, i32, [4 x i8], [1 x i64] }
|
||||
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
|
||||
%"github.com/goplus/llgo/internal/abi.Type" = type { i64, i64, i32, i8, i8, i8, i8, ptr, ptr, i32, i32 }
|
||||
%"github.com/goplus/llgo/internal/runtime.hmap" = type { i64, i8, i8, i16, i32, ptr, ptr, i64, ptr }
|
||||
|
||||
@"github.com/goplus/llgo/internal/runtime.TyAny" = global ptr null
|
||||
@"github.com/goplus/llgo/internal/runtime.basicTypes" = global ptr null
|
||||
@@ -201,6 +202,12 @@ _llgo_0:
|
||||
ret %"github.com/goplus/llgo/internal/runtime.iface" %12
|
||||
}
|
||||
|
||||
define ptr @"github.com/goplus/llgo/internal/runtime.MakeSmallMap"() {
|
||||
_llgo_0:
|
||||
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.makemap_small"()
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr %0, i64 %1, i64 %2) {
|
||||
_llgo_0:
|
||||
%3 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
|
||||
@@ -287,6 +294,12 @@ _llgo_0:
|
||||
ret ptr %1
|
||||
}
|
||||
|
||||
define i32 @"github.com/goplus/llgo/internal/runtime.fastrand"() {
|
||||
_llgo_0:
|
||||
%0 = call i32 @rand()
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
define void @"github.com/goplus/llgo/internal/runtime.init"() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1
|
||||
@@ -354,8 +367,25 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
define i1 @"github.com/goplus/llgo/internal/runtime.isEmpty"(i8 %0) {
|
||||
_llgo_0:
|
||||
%1 = icmp ule i8 %0, 1
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
define ptr @"github.com/goplus/llgo/internal/runtime.makemap_small"() {
|
||||
_llgo_0:
|
||||
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||
%1 = call i32 @"github.com/goplus/llgo/internal/runtime.fastrand"()
|
||||
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.hmap", ptr %0, i32 0, i32 4
|
||||
store i32 %1, ptr %2, align 4
|
||||
ret ptr %0
|
||||
}
|
||||
|
||||
declare ptr @malloc(i64)
|
||||
|
||||
declare ptr @memcpy(ptr, ptr, i64)
|
||||
|
||||
declare i32 @rand()
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/abi.init"()
|
||||
|
||||
1726
internal/runtime/map.go
Normal file
1726
internal/runtime/map.go
Normal file
File diff suppressed because it is too large
Load Diff
39
internal/runtime/stubs.go
Normal file
39
internal/runtime/stubs.go
Normal 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
|
||||
*/
|
||||
}
|
||||
@@ -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
25
internal/runtime/z_map.go
Normal 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()
|
||||
}
|
||||
27
ssa/expr.go
27
ssa/expr.go
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -126,4 +126,21 @@ 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)
|
||||
}
|
||||
// TODO(xsw)
|
||||
// panic("todo")
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user