llgo/ssa: support string/cstring; panic

This commit is contained in:
xushiwei
2024-04-28 09:55:54 +08:00
parent 510f2f4769
commit 7039cb3bc2
7 changed files with 109 additions and 7 deletions

View File

@@ -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))
} }

View File

@@ -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}
} }

View 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}
}

View File

@@ -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")

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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}
} }