llgo/ssa: support string/cstring; panic
This commit is contained in:
@@ -387,6 +387,9 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
|||||||
thenb := fn.Block(succs[0].Index)
|
thenb := fn.Block(succs[0].Index)
|
||||||
elseb := fn.Block(succs[1].Index)
|
elseb := fn.Block(succs[1].Index)
|
||||||
b.If(cond, thenb, elseb)
|
b.If(cond, thenb, elseb)
|
||||||
|
case *ssa.Panic:
|
||||||
|
arg := p.compileValue(b, v.X).Do()
|
||||||
|
b.Panic(arg)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr))
|
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
// Slice is the runtime representation of a slice.
|
||||||
type Slice = slice
|
type Slice = slice
|
||||||
|
|
||||||
func MakeEmptySlice() Slice {
|
// NilSlice returns a nil slice.
|
||||||
|
func NilSlice() Slice {
|
||||||
return Slice{nil, 0, 0}
|
return Slice{nil, 0, 0}
|
||||||
}
|
}
|
||||||
|
|||||||
37
internal/runtime/z_string.go
Normal file
37
internal/runtime/z_string.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// String is the runtime representation of a string.
|
||||||
|
// It cannot be used safely or portably and its representation may
|
||||||
|
// change in a later release.
|
||||||
|
//
|
||||||
|
// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the
|
||||||
|
// data it references will not be garbage collected.
|
||||||
|
type String struct {
|
||||||
|
data unsafe.Pointer
|
||||||
|
len int
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyString returns an empty string.
|
||||||
|
func EmptyString() String {
|
||||||
|
return String{nil, 0}
|
||||||
|
}
|
||||||
23
ssa/expr.go
23
ssa/expr.go
@@ -82,6 +82,20 @@ func (p Program) Null(t Type) Expr {
|
|||||||
return Expr{llvm.ConstNull(t.ll), t}
|
return Expr{llvm.ConstNull(t.ll), t}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CStringVal returns a c-style string constant expression.
|
||||||
|
func (p Program) CStringVal(v string) Expr {
|
||||||
|
t := p.CString()
|
||||||
|
return Expr{llvm.ConstString(v, true), t}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringVal returns string constant expression.
|
||||||
|
func (p Program) StringVal(v string) Expr {
|
||||||
|
t := p.String()
|
||||||
|
cstr := llvm.ConstString(v, true)
|
||||||
|
// TODO(xsw): cstr => gostring
|
||||||
|
return Expr{cstr, t}
|
||||||
|
}
|
||||||
|
|
||||||
// BoolVal returns a boolean constant expression.
|
// BoolVal returns a boolean constant expression.
|
||||||
func (p Program) BoolVal(v bool) Expr {
|
func (p Program) BoolVal(v bool) Expr {
|
||||||
t := p.Bool()
|
t := p.Bool()
|
||||||
@@ -118,19 +132,22 @@ func (p Program) Val(v interface{}) Expr {
|
|||||||
|
|
||||||
// Const returns a constant expression.
|
// Const returns a constant expression.
|
||||||
func (b Builder) Const(v constant.Value, typ Type) Expr {
|
func (b Builder) Const(v constant.Value, typ Type) Expr {
|
||||||
|
prog := b.prog
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return b.prog.Null(typ)
|
return prog.Null(typ)
|
||||||
}
|
}
|
||||||
switch t := typ.t.(type) {
|
switch t := typ.t.(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
kind := t.Kind()
|
kind := t.Kind()
|
||||||
switch {
|
switch {
|
||||||
case kind == types.Bool:
|
case kind == types.Bool:
|
||||||
return b.prog.BoolVal(constant.BoolVal(v))
|
return prog.BoolVal(constant.BoolVal(v))
|
||||||
case kind >= types.Int && kind <= types.Uintptr:
|
case kind >= types.Int && kind <= types.Uintptr:
|
||||||
if v, exact := constant.Uint64Val(v); exact {
|
if v, exact := constant.Uint64Val(v); exact {
|
||||||
return b.prog.IntVal(v, typ)
|
return prog.IntVal(v, typ)
|
||||||
}
|
}
|
||||||
|
case kind == types.String:
|
||||||
|
return prog.StringVal(constant.StringVal(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic("todo")
|
||||||
|
|||||||
@@ -110,12 +110,15 @@ type aProgram struct {
|
|||||||
voidType llvm.Type
|
voidType llvm.Type
|
||||||
voidPtrTy llvm.Type
|
voidPtrTy llvm.Type
|
||||||
|
|
||||||
|
rtStringTy llvm.Type
|
||||||
rtIfaceTy llvm.Type
|
rtIfaceTy llvm.Type
|
||||||
rtSliceTy llvm.Type
|
rtSliceTy llvm.Type
|
||||||
|
|
||||||
anyTy Type
|
anyTy Type
|
||||||
voidTy Type
|
voidTy Type
|
||||||
boolTy Type
|
boolTy Type
|
||||||
|
cstrTy Type
|
||||||
|
stringTy Type
|
||||||
uintptrTy Type
|
uintptrTy Type
|
||||||
intTy Type
|
intTy Type
|
||||||
f64Ty Type
|
f64Ty Type
|
||||||
@@ -170,6 +173,13 @@ func (p Program) rtSlice() llvm.Type {
|
|||||||
return p.rtSliceTy
|
return p.rtSliceTy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Program) rtString() llvm.Type {
|
||||||
|
if p.rtStringTy.IsNil() {
|
||||||
|
p.rtStringTy = p.rtType("String").ll
|
||||||
|
}
|
||||||
|
return p.rtStringTy
|
||||||
|
}
|
||||||
|
|
||||||
// NewPackage creates a new package.
|
// NewPackage creates a new package.
|
||||||
func (p Program) NewPackage(name, pkgPath string) Package {
|
func (p Program) NewPackage(name, pkgPath string) Package {
|
||||||
mod := p.ctx.NewModule(pkgPath)
|
mod := p.ctx.NewModule(pkgPath)
|
||||||
@@ -177,7 +187,7 @@ func (p Program) NewPackage(name, pkgPath string) Package {
|
|||||||
// mod.Finalize()
|
// mod.Finalize()
|
||||||
fns := make(map[string]Function)
|
fns := make(map[string]Function)
|
||||||
gbls := make(map[string]Global)
|
gbls := make(map[string]Global)
|
||||||
return &aPackage{mod, fns, gbls, p}
|
return &aPackage{mod, fns, gbls, p, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Void returns void type.
|
// Void returns void type.
|
||||||
@@ -196,6 +206,20 @@ func (p Program) Bool() Type {
|
|||||||
return p.boolTy
|
return p.boolTy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Program) CString() Type {
|
||||||
|
if p.cstrTy == nil { // *int8
|
||||||
|
p.cstrTy = p.Type(types.NewPointer(types.Typ[types.Int8]))
|
||||||
|
}
|
||||||
|
return p.cstrTy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) String() Type {
|
||||||
|
if p.stringTy == nil {
|
||||||
|
p.stringTy = p.Type(types.Typ[types.String])
|
||||||
|
}
|
||||||
|
return p.stringTy
|
||||||
|
}
|
||||||
|
|
||||||
// Any returns any type.
|
// Any returns any type.
|
||||||
func (p Program) Any() Type {
|
func (p Program) Any() Type {
|
||||||
if p.anyTy == nil {
|
if p.anyTy == nil {
|
||||||
@@ -243,6 +267,8 @@ type aPackage struct {
|
|||||||
fns map[string]Function
|
fns map[string]Function
|
||||||
vars map[string]Global
|
vars map[string]Global
|
||||||
prog Program
|
prog Program
|
||||||
|
|
||||||
|
abort Function
|
||||||
}
|
}
|
||||||
|
|
||||||
type Package = *aPackage
|
type Package = *aPackage
|
||||||
@@ -280,6 +306,13 @@ func (p Package) FuncOf(name string) Function {
|
|||||||
return p.fns[name]
|
return p.fns[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Package) rtAbort() Function {
|
||||||
|
if p.abort == nil {
|
||||||
|
p.abort = p.NewFunc("abort", types.NewSignatureType(nil, nil, nil, nil, nil, false))
|
||||||
|
}
|
||||||
|
return p.abort
|
||||||
|
}
|
||||||
|
|
||||||
func (p Package) rtFunc(fnName string) Expr {
|
func (p Package) rtFunc(fnName string) Expr {
|
||||||
fn := p.prog.runtime().Lookup(fnName).(*types.Func)
|
fn := p.prog.runtime().Lookup(fnName).(*types.Func)
|
||||||
name := FullName(fn.Pkg(), fnName)
|
name := FullName(fn.Pkg(), fnName)
|
||||||
|
|||||||
@@ -68,6 +68,15 @@ func (b Builder) SetBlock(blk BasicBlock) Builder {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Panic emits a panic instruction.
|
||||||
|
func (b Builder) Panic(v Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Panic %v\n", v.impl)
|
||||||
|
}
|
||||||
|
pkg := b.fn.pkg
|
||||||
|
b.Call(pkg.rtAbort().Expr)
|
||||||
|
}
|
||||||
|
|
||||||
// Return emits a return instruction.
|
// Return emits a return instruction.
|
||||||
func (b Builder) Return(results ...Expr) {
|
func (b Builder) Return(results ...Expr) {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
|
|||||||
@@ -237,6 +237,7 @@ func (p Program) toLLVMType(typ types.Type) Type {
|
|||||||
case types.Complex64:
|
case types.Complex64:
|
||||||
case types.Complex128:
|
case types.Complex128:
|
||||||
case types.String:
|
case types.String:
|
||||||
|
return &aType{p.rtString(), typ, vkString}
|
||||||
case types.UnsafePointer:
|
case types.UnsafePointer:
|
||||||
return &aType{p.tyVoidPtr(), typ, vkPtr}
|
return &aType{p.tyVoidPtr(), typ, vkPtr}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user