v0.11.0-bnema.4 cf1b83e

struct_loong64.go RawHistoryFolder

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
3
4package purego
5
6import (
7	"math"
8	"reflect"
9	"unsafe"
10)
11
12func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
13	outSize := outType.Size()
14	switch {
15	case outSize == 0:
16		return reflect.New(outType).Elem()
17	case outSize <= 8:
18		r1 := syscall.a1
19		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
20			r1 = syscall.f1
21			if numFields == 2 {
22				r1 = packFloat32Pair(syscall.f1, syscall.f2)
23			}
24		}
25		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{r1})).Elem()
26	case outSize <= 16:
27		r1, r2 := syscall.a1, syscall.a2
28		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
29			switch numFields {
30			case 4:
31				r1 = packFloat32Pair(syscall.f1, syscall.f2)
32				r2 = packFloat32Pair(syscall.f3, syscall.f4)
33			case 3:
34				r1 = packFloat32Pair(syscall.f1, syscall.f2)
35				r2 = syscall.f3
36			case 2:
37				r1 = syscall.f1
38				r2 = syscall.f2
39			default:
40				panic("not reached")
41			}
42		}
43		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b uintptr }{r1, r2})).Elem()
44	default:
45		// create struct from the Go pointer created above
46		// weird pointer dereference to circumvent go vet
47		return reflect.NewAt(outType, *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))).Elem()
48	}
49}
50
51const (
52	_NO_CLASS = 0b00
53	_FLOAT    = 0b01
54	_INT      = 0b11
55)
56
57func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
58	if v.Type().Size() == 0 {
59		return keepAlive
60	}
61
62	if size := v.Type().Size(); size <= 16 {
63		placeRegisters(v, addFloat, addInt)
64	} else {
65		keepAlive = placeStack(v, keepAlive, addInt)
66	}
67	return keepAlive // the struct was allocated so don't panic
68}
69
70func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
71	var val uint64
72	var shift byte
73	var flushed bool
74	class := _NO_CLASS
75	var place func(v reflect.Value)
76	place = func(v reflect.Value) {
77		var numFields int
78		if v.Kind() == reflect.Struct {
79			numFields = v.Type().NumField()
80		} else {
81			numFields = v.Type().Len()
82		}
83		for k := 0; k < numFields; k++ {
84			flushed = false
85			var f reflect.Value
86			if v.Kind() == reflect.Struct {
87				f = v.Field(k)
88			} else {
89				f = v.Index(k)
90			}
91			align := byte(f.Type().Align()*8 - 1)
92			shift = (shift + align) &^ align
93			if shift >= 64 {
94				flushPackedWord(&val, &shift, &flushed, class == _FLOAT, addFloat, addInt)
95				class = _NO_CLASS
96			}
97			switch f.Type().Kind() {
98			case reflect.Struct:
99				place(f)
100			case reflect.Bool:
101				if f.Bool() {
102					val |= 1 << shift
103				}
104				shift += 8
105				class |= _INT
106			case reflect.Uint8:
107				val |= f.Uint() << shift
108				shift += 8
109				class |= _INT
110			case reflect.Uint16:
111				val |= f.Uint() << shift
112				shift += 16
113				class |= _INT
114			case reflect.Uint32:
115				val |= f.Uint() << shift
116				shift += 32
117				class |= _INT
118			case reflect.Uint64, reflect.Uint, reflect.Uintptr:
119				addInt(uintptr(f.Uint()))
120				shift = 0
121				flushed = true
122				class = _NO_CLASS
123			case reflect.Int8:
124				val |= uint64(f.Int()&0xFF) << shift
125				shift += 8
126				class |= _INT
127			case reflect.Int16:
128				val |= uint64(f.Int()&0xFFFF) << shift
129				shift += 16
130				class |= _INT
131			case reflect.Int32:
132				val |= uint64(f.Int()&0xFFFF_FFFF) << shift
133				shift += 32
134				class |= _INT
135			case reflect.Int64, reflect.Int:
136				addInt(uintptr(f.Int()))
137				shift = 0
138				flushed = true
139				class = _NO_CLASS
140			case reflect.Float32:
141				if class == _FLOAT {
142					addFloat(uintptr(val))
143					val = 0
144					shift = 0
145				}
146				val |= uint64(math.Float32bits(float32(f.Float()))) << shift
147				shift += 32
148				class |= _FLOAT
149			case reflect.Float64:
150				addFloat(uintptr(math.Float64bits(float64(f.Float()))))
151				shift = 0
152				flushed = true
153				class = _NO_CLASS
154			case reflect.Ptr, reflect.UnsafePointer:
155				addInt(f.Pointer())
156				shift = 0
157				flushed = true
158				class = _NO_CLASS
159			case reflect.Array:
160				place(f)
161			default:
162				panic("purego: unsupported kind " + f.Kind().String())
163			}
164		}
165	}
166	place(v)
167	if !flushed {
168		if class == _FLOAT {
169			addFloat(uintptr(val))
170		} else {
171			addInt(uintptr(val))
172		}
173	}
174}
175
176func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
177	// Struct is too big to be placed in registers.
178	// Copy to heap and place the pointer in register
179	ptrStruct := reflect.New(v.Type())
180	ptrStruct.Elem().Set(v)
181	ptr := ptrStruct.Elem().Addr().UnsafePointer()
182	keepAlive = append(keepAlive, ptr)
183	addInt(uintptr(ptr))
184	return keepAlive
185}
186
187// shouldBundleStackArgs always returns false on loong64
188// since C-style stack argument bundling is only needed on Darwin ARM64.
189func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
190	return false
191}
192
193// structFitsInRegisters is not used on loong64.
194func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
195	panic("purego: structFitsInRegisters should not be called on loong64")
196}
197
198// collectStackArgs is not used on loong64.
199func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
200	keepAlive []any, addInt, addFloat, addStack func(uintptr),
201	pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
202	panic("purego: collectStackArgs should not be called on loong64")
203}
204
205// bundleStackArgs is not used on loong64.
206func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
207	panic("purego: bundleStackArgs should not be called on loong64")
208}
209
210func getCallbackStruct(inType reflect.Type, frame unsafe.Pointer, floatsN *int, intsN *int, stackSlot *int, stackByteOffset *uintptr) reflect.Value {
211	panic("purego: struct callback arguments are not supported on loong64")
212}
213
214func setStruct(a *callbackArgs, ret reflect.Value) {
215	panic("purego: struct returns are not supported on loong64")
216}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close