1
0
mirror of https://github.com/fumiama/gozel.git synced 2026-06-11 20:10:34 +08:00

feat(gen): impl. all specs except union

This commit is contained in:
源文雨
2026-03-24 00:49:26 +08:00
parent d42d758aeb
commit 1111b0ecc1
159 changed files with 9994 additions and 423 deletions

View File

@@ -3,14 +3,13 @@ package main
import (
"fmt"
"github.com/fumiama/gozel"
"github.com/fumiama/gozel/ze"
)
func main() {
err := gozel.InitZe()
hs, err := ze.InitGPUDrivers()
if err != nil {
panic(err)
}
desc := gozel.GPGPUDriverTypeDesc()
fmt.Println(gozel.InitDrivers(&desc))
fmt.Println(hs)
}

47
cmd/gen/api.go Normal file
View File

@@ -0,0 +1,47 @@
package main
import "os"
var apif *os.File
func init() {
f, err := os.Create("api.go")
if err != nil {
panic(err)
}
apif = f
apif.WriteString(`// Code generated by cmd/gen. DO NOT EDIT.
/*
*
* Copyright (C) 2026 Fumiama Minamoto
*
* SPDX-License-Identifier: MIT
*
* @file api.go
*
*/
package gozel
import (
"fmt"
"os"
"github.com/fumiama/gozel/internal/zecall"
)
func init() {
`)
}
func addAPI(name string) {
apif.WriteString("\n\tif err := zecall.Register(\"")
apif.WriteString(name)
apif.WriteString("\"); err != nil {\n\t\tfmt.Fprintln(os.Stderr, \"[gozel.warn]\", err)\n\t}\n")
}
func closeAPI() {
apif.WriteString("\n}\n")
apif.Close()
}

View File

@@ -42,6 +42,8 @@ func main() {
specdir = os.DirFS(*spec)
}
defer closeAPI()
fmt.Println("[main] parsing core APIs...")
f, err := specdir.Open("include/level_zero/ze_api.h")
if err != nil {

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"io"
"os"
"path"
"strings"
"unicode"
)
@@ -42,42 +41,52 @@ var (
"int": "int32",
"unsigned int": "uint32",
"float": "float32",
"double": "float64",
"float": "float32",
"double": "float64",
"float*": "*float32",
"double*": "*float64",
}
unsafeExcludeRegions = map[string]struct{}{
"bfloat16conversions": {},
"globaloffset": {},
"linkonceodr": {},
"subgroups": {},
"core_bfloat16conversions": {},
"core_globaloffset": {},
"core_linkonceodr": {},
"core_subgroups": {},
}
zecallExcludeRegions = map[string]struct{}{
"bandwidth": {},
"bfloat16conversions": {},
"CacheLineSize": {},
"callbacks": {},
"common": {},
"counterbasedeventpool": {},
"deviceipversion": {},
"deviceLUID": {},
"deviceusablememproperties": {},
"driverDDIHandles": {},
"EUCount": {},
"externalMemMap": {},
"floatAtomics": {},
"imageFormatSupport": {},
"imageviewplanar": {},
"kernelMaxGroupSizeProperties": {},
"linkonceodr": {},
"memoryCompressionHints": {},
"memoryProperties": {},
"powersavinghint": {},
"program": {},
"raytracing": {},
"relaxedAllocLimits": {},
"SRGB": {},
"subAllocationsProperties": {},
"subgroups": {},
"core_bandwidth": {},
"core_bfloat16conversions": {},
"core_CacheLineSize": {},
"core_callbacks": {},
"core_common": {},
"core_counterbasedeventpool": {},
"core_deviceipversion": {},
"core_deviceLUID": {},
"core_deviceusablememproperties": {},
"core_driverDDIHandles": {},
"core_EUCount": {},
"core_externalMemMap": {},
"core_floatAtomics": {},
"core_imageFormatSupport": {},
"core_imageviewplanar": {},
"core_kernelMaxGroupSizeProperties": {},
"core_linkonceodr": {},
"core_memoryCompressionHints": {},
"core_memoryProperties": {},
"core_powersavinghint": {},
"core_program": {},
"core_raytracing": {},
"core_relaxedAllocLimits": {},
"core_SRGB": {},
"core_subAllocationsProperties": {},
"core_subgroups": {},
"sysm_common": {},
"sysm_eccState": {},
"sysm_memoryBwCounterValidBits": {},
"sysm_memPageOfflineState": {},
"sysm_powerDomainProperties": {},
"tols_common": {},
}
)
@@ -95,18 +104,8 @@ func infh(name string) string {
func scanHeader(name string, scan *bufio.Scanner) {
ln := 0
var regionfile *os.File
symtab := symbolTable{
"ZE_APICALL": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_APICALL", []string{""}},
"ZE_APIEXPORT": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_APIEXPORT", []string{""}},
"ZE_DLLEXPORT": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_DLLEXPORT", []string{""}},
}
fileheadersb := strings.Builder{}
region := ""
_ = os.RemoveAll(name)
err := os.MkdirAll(name, 0755)
if err != nil {
panic(fmt.Sprintf("%s L%d: cannot create region folder %s, err: %v", name, ln, region, err))
}
for scan.Scan() {
ln++
t := scan.Text()
@@ -122,24 +121,23 @@ func scanHeader(name string, scan *bufio.Scanner) {
panic(fmt.Sprintf("%s L%d: unexpected empty region", name, ln))
}
fmt.Println(infh(name), "scanning region", region)
f, err := os.Create(path.Join(name, region+".go"))
k := fmt.Sprint(name, "_", region)
f, err := os.Create(fmt.Sprint(k, ".go"))
if err != nil {
panic(fmt.Sprintf("%s L%d: cannot create region %s, err: %v", name, ln, region, err))
}
f.WriteString("// Code generated by cmd/gen. DO NOT EDIT.\n\n")
f.WriteString(fileheadersb.String())
f.WriteString("\n")
f.WriteString("package ")
f.WriteString(name)
f.WriteString("\n\n")
f.WriteString("package gozel\n\n")
noimport := true
sb := strings.Builder{}
sb.WriteString("import (")
if _, ok := unsafeExcludeRegions[region]; !ok {
if _, ok := unsafeExcludeRegions[k]; !ok {
sb.WriteString("\n\t\"unsafe\"\n")
noimport = false
}
if _, ok := zecallExcludeRegions[region]; !ok {
if _, ok := zecallExcludeRegions[k]; !ok {
sb.WriteString("\n\t\"github.com/fumiama/gozel/internal/zecall\"\n")
noimport = false
}
@@ -151,7 +149,7 @@ func scanHeader(name string, scan *bufio.Scanner) {
// block barrier
case strings.HasPrefix(t, "///////////////////////////////////////////////////////////////////////////////"):
fmt.Println(" [scan] enter", region, "block")
ln = scanBlocks(name, scan, regionfile, ln, symtab)
ln = scanBlocks(name, scan, regionfile, ln)
fmt.Println(" [scan] leave", region, "block")
// pragma end
case strings.HasPrefix(t, "#pragma endregion"):
@@ -170,7 +168,7 @@ func scanHeader(name string, scan *bufio.Scanner) {
}
func checkSymbolName(
symtab symbolTable, ln int, name, sname, goname string,
ln int, name, sname, goname string,
sb *strings.Builder, f *os.File, eq func() *symbol) bool {
if _, ok := symtab[sname]; ok {
panic(fmt.Sprintf("%s L%d: func #define %s has been defined", name, ln, sname))
@@ -195,7 +193,7 @@ func checkSymbolName(
func scanBlocks(
name string, scan *bufio.Scanner, f *os.File,
ln int, symtab symbolTable,
ln int,
) int {
sb := strings.Builder{}
ppskip2nextblk := false
@@ -253,7 +251,7 @@ func scanBlocks(
if !strings.Contains(argn, "(") { // is const define
sname := strings.TrimSpace(argn)
val := symtab.apply(strings.TrimSpace(argv))
checkSymbolName(symtab, ln, name, sname, sname, &sb, f, func() *symbol {
checkSymbolName(ln, name, sname, sname, &sb, f, func() *symbol {
return newSymbolConst(sname, val, symbolSubTypeDefine)
})
f.WriteString("const ")
@@ -274,7 +272,7 @@ func scanBlocks(
sname = strings.TrimSpace(sname)
args = strings.TrimSpace(args)
eval := strings.TrimSpace(argseval[n+1:])
checkSymbolName(symtab, ln, name, sname, sname, &sb, f, func() *symbol {
checkSymbolName(ln, name, sname, sname, &sb, f, func() *symbol {
return newSymbolFunc(sname, args, eval, symbolSubTypeDefine)
})
f.WriteString("func ")
@@ -287,12 +285,45 @@ func scanBlocks(
f.WriteString(eval)
f.WriteString("\n}\n\n")
case strings.HasPrefix(t, "typedef "):
ln = scanTypedef(name, scan, f, ln, symtab, t, &sb)
ln = scanTypedef(name, scan, f, ln, t, &sb)
case strings.HasPrefix(t, "ZE_APIEXPORT "):
if !strings.HasSuffix(t, " ZE_APICALL") {
panic(fmt.Sprintf("%s L%d: unexpected func line %s", name, ln, t))
}
ln = scanFunc(name, scan, f, ln, symtab, t, &sb)
ln = scanFunc(name, scan, f, ln, t, &sb)
case strings.HasPrefix(t, "static const ") && strings.HasSuffix(t, "= {"):
t = strings.TrimSpace(t[13 : len(t)-3])
i := strings.LastIndex(t, " ")
if i <= 0 {
panic(fmt.Sprintf("%s L%d: unexpected short var %s", name, ln, t))
}
typ := symtab.apply(strings.TrimSpace(t[:i]))
rnam := []rune(strings.TrimSpace(t[i+1:]))
rnam[0] = unicode.ToUpper(rnam[0])
nam := string(rnam)
f.WriteString(strings.Replace(sb.String(), "/ @brief", " "+nam, 1))
sb.Reset()
f.WriteString("var ")
f.WriteString(nam)
f.WriteString(" = ")
f.WriteString(typ)
f.WriteString("{")
for {
f.WriteString("\n")
s, isfin := scanln(name, scan, &ln)
if isfin {
break
}
s = strings.TrimSpace(s)
f.WriteString("\t")
if strings.HasPrefix(s, "0,") && strings.Contains(s, "///< p") {
f.WriteString("nil,")
f.WriteString(s[2:])
} else {
f.WriteString(s)
}
}
f.WriteString("}\n\n")
default:
panic(fmt.Sprintf("%s L%d: unexpected line %s", name, ln, t))
}
@@ -302,7 +333,7 @@ func scanBlocks(
func scanTypedef(
name string, scan *bufio.Scanner, f *os.File,
ln int, symtab symbolTable, firstln string, sb *strings.Builder,
ln int, firstln string, sb *strings.Builder,
) int {
s, newln := get1sentence(firstln, scan, ln)
if newln < 0 {
@@ -326,7 +357,7 @@ func scanTypedef(
}
goname := us2camel(fnname)
fnname += "_t"
checkSymbolName(symtab, ln, name, fnname, goname, sb, f, func() *symbol {
checkSymbolName(ln, name, fnname, goname, sb, f, func() *symbol {
return newSymbolConst(fnname, goname, symbolSubTypeFuncPtr)
})
f.WriteString("// gozel warn: please use C function pointer loaded from C library!\n")
@@ -510,7 +541,7 @@ func scanTypedef(
}
sname := strings.TrimSuffix(strings.TrimSpace(lines[0][1:]), ";")
val := us2camel(strings.TrimSuffix(sname, "_t"))
checkSymbolName(symtab, ln, name, sname, val, sb, f, func() *symbol {
checkSymbolName(ln, name, sname, val, sb, f, func() *symbol {
return newSymbolConst(sname, val, symbolSubTypeLargeStruct)
})
f.WriteString("type ")
@@ -563,7 +594,7 @@ func scanTypedef(
}
sname := strings.TrimSuffix(strings.TrimSpace(lines[0][1:]), ";")
val := us2camel(strings.TrimSuffix(sname, "_t"))
redirect := checkSymbolName(symtab, ln, name, sname, val, sb, f, func() *symbol {
redirect := checkSymbolName(ln, name, sname, val, sb, f, func() *symbol {
return newSymbolConst(sname, val, symbolSubTypeEnum)
})
replaces := ""
@@ -611,7 +642,7 @@ func scanTypedef(
sname := strings.TrimSpace(strings.TrimSuffix(strings.TrimSpace(typs[1]), ";"))
val := us2camel(strings.TrimSuffix(sname, "_t"))
origtyp := strings.TrimSuffix(symtab.apply(strings.TrimSpace(typs[0])), "_t")
checkSymbolName(symtab, ln, name, sname, val, sb, f, func() *symbol {
checkSymbolName(ln, name, sname, val, sb, f, func() *symbol {
return newSymbolConst(sname, val, symbolSubTypeEmptyStruct)
})
f.WriteString("type ")
@@ -624,11 +655,11 @@ func scanTypedef(
func scanFunc(
name string, scan *bufio.Scanner, f *os.File,
ln int, symtab symbolTable, firstln string, sb *strings.Builder,
ln int, firstln string, sb *strings.Builder,
) int {
//TODO: register func
rettyp := strings.TrimSpace(firstln[13 : len(firstln)-11])
rettyp = symtab.apply(strings.TrimSpace(rettyp))
rettyp = strings.TrimSuffix(symtab.apply(strings.TrimSpace(rettyp)), "_t")
fnname, isfin := scanln(name, scan, &ln)
if isfin {
panic(fmt.Sprintf("%s L%d: unexpected early end func name line %s", name, ln, fnname))
@@ -661,6 +692,9 @@ func scanFunc(
f.WriteString(argln[4:])
continue
}
if argln == "void" {
continue
}
argtypnam, argcomment, ok := strings.Cut(argln, "//")
if !ok {
panic(fmt.Sprintf("%s L%d: unexpected non-comment func arg line %s", name, ln, argln))
@@ -675,13 +709,17 @@ func scanFunc(
argsb.WriteString(", uintptr(")
argtyp := strings.TrimSpace(strings.ReplaceAll(argtypnam[:i], "const ", ""))
isp := strings.HasSuffix(argtyp, "*") // is pointer
pmark := "*"
if strings.HasSuffix(argtyp, "**") { // is pointer's pointer
pmark = "**"
}
convtyp, ok := typemap[argtyp]
if ok {
argtyp = convtyp
}
if isp {
if !ok {
argtyp = "*" + argtyp[:len(argtyp)-1]
argtyp = pmark + argtyp[:len(argtyp)-len(pmark)]
}
argsb.WriteString("unsafe.Pointer(")
} else {
@@ -689,7 +727,7 @@ func scanFunc(
if ok && sym.sstype == symbolSubTypeLargeStruct &&
!strings.HasPrefix(argnam, "p") {
isp = true
argtyp = "*" + argtyp
argtyp = pmark + argtyp
argcomment += " (gozel hack: converted to a hidden pointer from a struct value)"
argsb.WriteString("unsafe.Pointer(")
}
@@ -716,5 +754,6 @@ func scanFunc(
f.WriteString("\"")
f.WriteString(argsb.String())
f.WriteString(")\n}\n\n")
addAPI(origfnname)
return ln
}

View File

@@ -1,9 +1,12 @@
package main
import (
"bytes"
"errors"
"regexp"
"strconv"
"strings"
"unicode"
)
var (
@@ -11,6 +14,13 @@ var (
errNoSuchSymbol = errors.New("no such sybmol")
)
var symtab = symbolTable{
"ZE_APICALL": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_APICALL", []string{""}},
"ZE_APIEXPORT": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_APIEXPORT", []string{""}},
"ZE_DLLEXPORT": &symbol{symbolTypeConst, symbolSubTypeDefine, "ZE_DLLEXPORT", []string{""}},
"~(0ULL": &symbol{symbolTypeConst, symbolSubTypeDefine, "~(0ULL", []string{"(^uint64(0)"}},
}
type symbolTable map[string]*symbol
func (st symbolTable) apply(t string) string {
@@ -96,7 +106,18 @@ func (s *symbol) extract1stFunc(txt string) (args []string, a, b int, err error)
func (s *symbol) replace(txt string) string {
switch s.stype {
case symbolTypeConst:
return strings.ReplaceAll(txt, s.name, s.fields[0])
escapes := regexp.QuoteMeta(s.name)
re := regexp.MustCompile(`(` + escapes + `[^\w_])|(` + escapes + `$)`)
return string(re.ReplaceAllFunc([]byte(txt), func(b []byte) []byte {
last := rune(b[len(b)-1])
if unicode.IsLetter(last) || last == '_' {
return []byte(s.fields[0])
}
buf := bytes.NewBuffer(make([]byte, 0, 128))
buf.WriteString(s.fields[0])
buf.WriteByte(b[len(b)-1])
return buf.Bytes()
}))
case symbolTypeFunc:
paras := strings.Split(s.fields[0], ",")
txts := []string{}