diff --git a/cl/compile.go b/cl/compile.go index 3a4fd9fa..e6a5ed3d 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -387,6 +387,9 @@ 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.Panic: + arg := p.compileValue(b, v.X).Do() + b.Panic(arg) default: panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr)) } diff --git a/internal/runtime/z_slice.go b/internal/runtime/z_slice.go index b6d5cbf5..a3f59f6d 100644 --- a/internal/runtime/z_slice.go +++ b/internal/runtime/z_slice.go @@ -16,8 +16,10 @@ package runtime +// Slice is the runtime representation of a slice. type Slice = slice -func MakeEmptySlice() Slice { +// NilSlice returns a nil slice. +func NilSlice() Slice { return Slice{nil, 0, 0} } diff --git a/internal/runtime/z_string.go b/internal/runtime/z_string.go new file mode 100644 index 00000000..ed8ca0c1 --- /dev/null +++ b/internal/runtime/z_string.go @@ -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} +} diff --git a/ssa/expr.go b/ssa/expr.go index eda2c4dc..b1a2fe54 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -82,6 +82,20 @@ func (p Program) Null(t Type) Expr { 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. func (p Program) BoolVal(v bool) Expr { t := p.Bool() @@ -118,19 +132,22 @@ func (p Program) Val(v interface{}) Expr { // Const returns a constant expression. func (b Builder) Const(v constant.Value, typ Type) Expr { + prog := b.prog if v == nil { - return b.prog.Null(typ) + return prog.Null(typ) } switch t := typ.t.(type) { case *types.Basic: kind := t.Kind() switch { case kind == types.Bool: - return b.prog.BoolVal(constant.BoolVal(v)) + return prog.BoolVal(constant.BoolVal(v)) case kind >= types.Int && kind <= types.Uintptr: 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") diff --git a/ssa/package.go b/ssa/package.go index cd63b986..edddc5c6 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -110,12 +110,15 @@ type aProgram struct { voidType llvm.Type voidPtrTy llvm.Type - rtIfaceTy llvm.Type - rtSliceTy llvm.Type + rtStringTy llvm.Type + rtIfaceTy llvm.Type + rtSliceTy llvm.Type anyTy Type voidTy Type boolTy Type + cstrTy Type + stringTy Type uintptrTy Type intTy Type f64Ty Type @@ -170,6 +173,13 @@ func (p Program) rtSlice() llvm.Type { 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. func (p Program) NewPackage(name, pkgPath string) Package { mod := p.ctx.NewModule(pkgPath) @@ -177,7 +187,7 @@ func (p Program) NewPackage(name, pkgPath string) Package { // mod.Finalize() fns := make(map[string]Function) gbls := make(map[string]Global) - return &aPackage{mod, fns, gbls, p} + return &aPackage{mod, fns, gbls, p, nil} } // Void returns void type. @@ -196,6 +206,20 @@ func (p Program) Bool() Type { 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. func (p Program) Any() Type { if p.anyTy == nil { @@ -243,6 +267,8 @@ type aPackage struct { fns map[string]Function vars map[string]Global prog Program + + abort Function } type Package = *aPackage @@ -280,6 +306,13 @@ func (p Package) FuncOf(name string) Function { 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 { fn := p.prog.runtime().Lookup(fnName).(*types.Func) name := FullName(fn.Pkg(), fnName) diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index a5e2f1f2..9b165cfb 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -68,6 +68,15 @@ func (b Builder) SetBlock(blk BasicBlock) Builder { 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. func (b Builder) Return(results ...Expr) { if debugInstr { diff --git a/ssa/type.go b/ssa/type.go index dc5d20aa..fed294c7 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -237,6 +237,7 @@ func (p Program) toLLVMType(typ types.Type) Type { case types.Complex64: case types.Complex128: case types.String: + return &aType{p.rtString(), typ, vkString} case types.UnsafePointer: return &aType{p.tyVoidPtr(), typ, vkPtr} }