c.AllocaCStrs; ssa: AllocaU/ArrayAlloca/Times/AllocaCStrs
This commit is contained in:
@@ -1,20 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := c.Str("ls")
|
||||
args := []*c.Char{ls, c.Str("-l"), nil}
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = c.Str("dir")
|
||||
args = []*c.Char{ls, nil}
|
||||
}
|
||||
|
||||
os.Execvp(ls, unsafe.SliceData(args))
|
||||
os.Execlp(ls, ls, c.Str("-l"), nil)
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
args := []string{"ls", "-l"}
|
||||
args := []string{ls, "-l"}
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
args = nil
|
||||
args = []string{ls}
|
||||
}
|
||||
lspath, _ := exec.LookPath(ls)
|
||||
if lspath != "" {
|
||||
|
||||
3
c/c.go
3
c/c.go
@@ -68,6 +68,9 @@ func Alloca(size uintptr) Pointer
|
||||
//go:linkname AllocaCStr llgo.allocaCStr
|
||||
func AllocaCStr(s string) *Char
|
||||
|
||||
//go:linkname AllocaCStrs llgo.allocaCStrs
|
||||
func AllocaCStrs(strs []string, endWithNil bool) **Char
|
||||
|
||||
// TODO(xsw):
|
||||
// llgo:link AllocaNew llgo.allocaNew
|
||||
func AllocaNew[T any]() *T { return nil }
|
||||
|
||||
21
c/syscall/unix/unix.go
Normal file
21
c/syscall/unix/unix.go
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 unix
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
)
|
||||
@@ -143,6 +143,7 @@ func TestErrBuiltin(t *testing.T) {
|
||||
test("advance", func(ctx *context) { ctx.advance(nil, nil) })
|
||||
test("alloca", func(ctx *context) { ctx.alloca(nil, nil) })
|
||||
test("allocaCStr", func(ctx *context) { ctx.allocaCStr(nil, nil) })
|
||||
test("allocaCStrs", func(ctx *context) { ctx.allocaCStrs(nil, nil) })
|
||||
test("string", func(ctx *context) { ctx.string(nil, nil) })
|
||||
test("stringData", func(ctx *context) { ctx.stringData(nil, nil) })
|
||||
test("funcAddr", func(ctx *context) { ctx.funcAddr(nil, nil) })
|
||||
|
||||
10
cl/import.go
10
cl/import.go
@@ -381,17 +381,19 @@ const (
|
||||
llgoCstr = llgoInstrBase + 1
|
||||
llgoAlloca = llgoInstrBase + 2
|
||||
llgoAllocaCStr = llgoInstrBase + 3
|
||||
llgoAdvance = llgoInstrBase + 4
|
||||
llgoIndex = llgoInstrBase + 5
|
||||
llgoDeferData = llgoInstrBase + 6
|
||||
llgoAllocaCStrs = llgoInstrBase + 4
|
||||
llgoAdvance = llgoInstrBase + 5
|
||||
llgoIndex = llgoInstrBase + 6
|
||||
llgoStringData = llgoInstrBase + 7
|
||||
llgoString = llgoInstrBase + 8
|
||||
llgoFuncAddr = llgoInstrBase + 9
|
||||
llgoDeferData = llgoInstrBase + 9
|
||||
|
||||
llgoSigjmpbuf = llgoInstrBase + 0xa
|
||||
llgoSigsetjmp = llgoInstrBase + 0xb
|
||||
llgoSiglongjmp = llgoInstrBase + 0xc
|
||||
|
||||
llgoFuncAddr = llgoInstrBase + 0xd
|
||||
|
||||
llgoPyList = llgoInstrBase + 0x10
|
||||
llgoPyStr = llgoInstrBase + 0x11
|
||||
|
||||
|
||||
48
cl/instr.go
48
cl/instr.go
@@ -28,14 +28,29 @@ import (
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
func constStr(v ssa.Value) (ret string, ok bool) {
|
||||
if c, ok := v.(*ssa.Const); ok {
|
||||
if v := c.Value; v.Kind() == constant.String {
|
||||
return constant.StringVal(v), true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func constBool(v ssa.Value) (ret bool, ok bool) {
|
||||
if c, ok := v.(*ssa.Const); ok {
|
||||
if v := c.Value; v.Kind() == constant.Bool {
|
||||
return constant.BoolVal(v), true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// func pystr(string) *py.Object
|
||||
func pystr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
if len(args) == 1 {
|
||||
if c, ok := args[0].(*ssa.Const); ok {
|
||||
if v := c.Value; v.Kind() == constant.String {
|
||||
sv := constant.StringVal(v)
|
||||
return b.PyStr(sv)
|
||||
}
|
||||
if sv, ok := constStr(args[0]); ok {
|
||||
return b.PyStr(sv)
|
||||
}
|
||||
}
|
||||
panic("pystr(<string-literal>): invalid arguments")
|
||||
@@ -44,11 +59,8 @@ func pystr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
// func cstr(string) *int8
|
||||
func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
if len(args) == 1 {
|
||||
if c, ok := args[0].(*ssa.Const); ok {
|
||||
if v := c.Value; v.Kind() == constant.String {
|
||||
sv := constant.StringVal(v)
|
||||
return b.CStr(sv)
|
||||
}
|
||||
if sv, ok := constStr(args[0]); ok {
|
||||
return b.CStr(sv)
|
||||
}
|
||||
}
|
||||
panic("cstr(<string-literal>): invalid arguments")
|
||||
@@ -87,6 +99,19 @@ func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr)
|
||||
panic("allocaCStr(s string): invalid arguments")
|
||||
}
|
||||
|
||||
// func allocaCStrs(strs []string, endWithNil bool) **int8
|
||||
func (p *context) allocaCStrs(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
if len(args) == 2 {
|
||||
endWithNil, ok := constBool(args[1])
|
||||
if !ok {
|
||||
panic("allocaCStrs(strs, endWithNil): endWithNil should be constant bool")
|
||||
}
|
||||
strs := p.compileValue(b, args[0])
|
||||
return b.AllocaCStrs(strs, endWithNil)
|
||||
}
|
||||
panic("allocaCStrs(strs []string, endWithNil bool): invalid arguments")
|
||||
}
|
||||
|
||||
// func string(cstr *int8, n ...int) *int8
|
||||
func (p *context) string(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
if len(args) == 2 {
|
||||
@@ -185,6 +210,7 @@ var llgoInstrs = map[string]int{
|
||||
"index": llgoIndex,
|
||||
"alloca": llgoAlloca,
|
||||
"allocaCStr": llgoAllocaCStr,
|
||||
"allocaCStrs": llgoAllocaCStrs,
|
||||
"string": llgoString,
|
||||
"stringData": llgoStringData,
|
||||
"funcAddr": llgoFuncAddr,
|
||||
@@ -340,6 +366,8 @@ func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon
|
||||
ret = p.alloca(b, args)
|
||||
case llgoAllocaCStr:
|
||||
ret = p.allocaCStr(b, args)
|
||||
case llgoAllocaCStrs:
|
||||
ret = p.allocaCStrs(b, args)
|
||||
case llgoString:
|
||||
ret = p.string(b, args)
|
||||
case llgoStringData:
|
||||
|
||||
@@ -10,6 +10,10 @@ package syscall
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
// ForkLock is used to synchronize creation of new file descriptors
|
||||
@@ -102,8 +106,10 @@ type ProcAttr struct {
|
||||
Sys *SysProcAttr
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
var zeroProcAttr ProcAttr
|
||||
var zeroSysProcAttr SysProcAttr
|
||||
*/
|
||||
|
||||
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
||||
/* TODO(xsw):
|
||||
@@ -237,47 +243,9 @@ var execveOpenBSD func(path *byte, argv **byte, envp **byte) error
|
||||
|
||||
// Exec invokes the execve(2) system call.
|
||||
func Exec(argv0 string, argv []string, envv []string) (err error) {
|
||||
/* TODO(xsw):
|
||||
argv0p, err := BytePtrFromString(argv0)
|
||||
if err != nil {
|
||||
return err
|
||||
ret := os.Execve(c.AllocaCStr(argv0), c.AllocaCStrs(argv, true), c.AllocaCStrs(envv, true))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
argvp, err := SlicePtrFromStrings(argv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
envvp, err := SlicePtrFromStrings(envv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runtime_BeforeExec()
|
||||
|
||||
rlim, rlimOK := origRlimitNofile.Load().(Rlimit)
|
||||
if rlimOK && rlim.Cur != 0 {
|
||||
Setrlimit(RLIMIT_NOFILE, &rlim)
|
||||
}
|
||||
|
||||
var err1 error
|
||||
if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" {
|
||||
// RawSyscall should never be used on Solaris, illumos, or AIX.
|
||||
err1 = execveLibc(
|
||||
uintptr(unsafe.Pointer(argv0p)),
|
||||
uintptr(unsafe.Pointer(&argvp[0])),
|
||||
uintptr(unsafe.Pointer(&envvp[0])))
|
||||
} else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
|
||||
// Similarly on Darwin.
|
||||
err1 = execveDarwin(argv0p, &argvp[0], &envvp[0])
|
||||
} else if runtime.GOOS == "openbsd" && (runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
|
||||
// Similarly on OpenBSD.
|
||||
err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0])
|
||||
} else {
|
||||
_, _, err1 = RawSyscall(SYS_EXECVE,
|
||||
uintptr(unsafe.Pointer(argv0p)),
|
||||
uintptr(unsafe.Pointer(&argvp[0])),
|
||||
uintptr(unsafe.Pointer(&envvp[0])))
|
||||
}
|
||||
runtime_AfterExec()
|
||||
return err1
|
||||
*/
|
||||
panic("todo: syscall.Exec")
|
||||
return syscall.Errno(ret)
|
||||
}
|
||||
|
||||
@@ -144,6 +144,13 @@ func (b Builder) Alloca(n Expr) (ret Expr) {
|
||||
return
|
||||
}
|
||||
|
||||
// AllocaU allocates uninitialized space for n*sizeof(elem) bytes.
|
||||
func (b Builder) AllocaU(elem Type, n ...int64) (ret Expr) {
|
||||
prog := b.Prog
|
||||
size := SizeOf(prog, elem, n...)
|
||||
return Expr{b.Alloca(size).impl, prog.Pointer(elem)}
|
||||
}
|
||||
|
||||
// AllocaCStr allocates space for copy it from a Go string.
|
||||
func (b Builder) AllocaCStr(gostr Expr) (ret Expr) {
|
||||
if debugInstr {
|
||||
@@ -155,6 +162,29 @@ func (b Builder) AllocaCStr(gostr Expr) (ret Expr) {
|
||||
return b.InlineCall(b.Pkg.rtFunc("CStrCopy"), cstr, gostr)
|
||||
}
|
||||
|
||||
// func allocaCStrs(strs []string, endWithNil bool) **int8
|
||||
func (b Builder) AllocaCStrs(strs Expr, endWithNil bool) (cstrs Expr) {
|
||||
if debugInstr {
|
||||
log.Printf("AllocaCStrs %v, %v\n", strs.impl, endWithNil)
|
||||
}
|
||||
prog := b.Prog
|
||||
n := b.SliceLen(strs)
|
||||
n1 := n
|
||||
if endWithNil {
|
||||
n1 = b.BinOp(token.ADD, n, prog.Val(1))
|
||||
}
|
||||
tcstr := prog.CStr()
|
||||
cstrs = b.ArrayAlloca(tcstr, n1)
|
||||
b.Times(n, func(i Expr) {
|
||||
s := b.Index(strs, i, nil)
|
||||
b.Store(b.Advance(cstrs, i), b.AllocaCStr(s))
|
||||
})
|
||||
if endWithNil {
|
||||
b.Store(b.Advance(cstrs, n), prog.Nil(tcstr))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
func (p Program) tyMalloc() *types.Signature {
|
||||
@@ -189,17 +219,15 @@ func (b Builder) free(ptr Expr) Expr {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
// ArrayAlloca reserves space for an array of n elements of type telem.
|
||||
func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) {
|
||||
if debugInstr {
|
||||
log.Printf("ArrayAlloca %v, %v\n", telem.t, n.impl)
|
||||
log.Printf("ArrayAlloca %v, %v\n", telem.raw.Type, n.impl)
|
||||
}
|
||||
ret.impl = llvm.CreateArrayAlloca(b.impl, telem.ll, n.impl)
|
||||
ret.Type = b.Prog.Pointer(telem)
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
// ArrayAlloc allocates zero initialized space for an array of n elements of type telem.
|
||||
func (b Builder) ArrayAlloc(telem Type, n Expr) (ret Expr) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package ssa
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
"strings"
|
||||
@@ -248,6 +249,44 @@ func (b Builder) IfThen(cond Expr, then func()) {
|
||||
b.blk.last = blks[1].last
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// For emits a for-loop instruction.
|
||||
func (b Builder) For(cond func() Expr, loop func()) {
|
||||
blks := b.Func.MakeBlocks(3)
|
||||
b.Jump(blks[0])
|
||||
b.SetBlockEx(blks[0], AtEnd, false)
|
||||
b.If(cond(), blks[1], blks[2])
|
||||
b.SetBlockEx(blks[1], AtEnd, false)
|
||||
loop()
|
||||
b.Jump(blks[0])
|
||||
b.SetBlockEx(blks[2], AtEnd, false)
|
||||
b.blk.last = blks[2].last
|
||||
}
|
||||
*/
|
||||
|
||||
// Times emits a times-loop instruction.
|
||||
func (b Builder) Times(n Expr, loop func(i Expr)) {
|
||||
at := b.blk
|
||||
blks := b.Func.MakeBlocks(3)
|
||||
b.Jump(blks[0])
|
||||
b.SetBlockEx(blks[0], AtEnd, false)
|
||||
typ := n.Type
|
||||
phi := b.Phi(typ)
|
||||
b.If(b.BinOp(token.LSS, phi.Expr, n), blks[1], blks[2])
|
||||
b.SetBlockEx(blks[1], AtEnd, false)
|
||||
loop(phi.Expr)
|
||||
post := b.BinOp(token.ADD, phi.Expr, b.Prog.IntVal(1, typ))
|
||||
b.Jump(blks[0])
|
||||
b.SetBlockEx(blks[2], AtEnd, false)
|
||||
b.blk.last = blks[2].last
|
||||
phi.AddIncoming(b, []BasicBlock{at, blks[1]}, func(i int, blk BasicBlock) Expr {
|
||||
if i == 0 {
|
||||
return b.Prog.IntVal(0, typ)
|
||||
}
|
||||
return post
|
||||
})
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/*
|
||||
type caseStmt struct {
|
||||
|
||||
Reference in New Issue
Block a user