v0.7.0-alpha.1 0789956

struct_amd64.go RawHistoryFolder

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
3
4package purego
5
6import (
7	"math"
8	"reflect"
9)
10
11// https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
12// https://gitlab.com/x86-psABIs/x86-64-ABI
13// Class determines where the 8 byte value goes.
14// Higher value classes win over lower value classes
15const (
16	_NO_CLASS = 0b0000
17	_SSE      = 0b0001
18	_X87      = 0b0011 // long double not used in Go
19	_INTEGER  = 0b0111
20	_MEMORY   = 0b1111
21)
22
23func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} {
24	if v.Type().Size() == 0 {
25		return keepAlive
26	}
27
28	// if greater than 64 bytes place on stack
29	if v.Type().Size() > 8*8 {
30		placeStack(v, addStack)
31		return keepAlive
32	}
33	var (
34		savedNumFloats = *numFloats
35		savedNumInts   = *numInts
36		savedNumStack  = *numStack
37	)
38	placeOnStack := postMerger(v.Type()) || !tryPlaceRegister(v, addFloat, addInt)
39	if placeOnStack {
40		// reset any values placed in registers
41		*numFloats = savedNumFloats
42		*numInts = savedNumInts
43		*numStack = savedNumStack
44		placeStack(v, addStack)
45	}
46	return keepAlive
47}
48
49func postMerger(t reflect.Type) bool {
50	// (c) If the size of the aggregate exceeds two eightbytes and the first eight- byte isn’t SSE or any other
51	// eightbyte isn’t SSEUP, the whole argument is passed in memory.
52	if t.Kind() != reflect.Struct {
53		return false
54	}
55	if t.Size() <= 2*8 {
56		return false
57	}
58	first := getFirst(t).Kind()
59	if first != reflect.Float32 && first != reflect.Float64 {
60		return false
61	}
62	return true
63}
64
65func getFirst(t reflect.Type) reflect.Type {
66	first := t.Field(0).Type
67	if first.Kind() == reflect.Struct {
68		return getFirst(first)
69	}
70	return first
71}
72
73func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) {
74	ok = true
75	var val uint64
76	var shift byte // # of bits to shift
77	var flushed bool
78	class := _NO_CLASS
79	flushIfNeeded := func() {
80		if flushed {
81			return
82		}
83		flushed = true
84		if class == _SSE {
85			addFloat(uintptr(val))
86		} else {
87			addInt(uintptr(val))
88		}
89		val = 0
90		shift = 0
91		class = _NO_CLASS
92	}
93	var place func(v reflect.Value)
94	place = func(v reflect.Value) {
95		var numFields int
96		if v.Kind() == reflect.Struct {
97			numFields = v.Type().NumField()
98		} else {
99			numFields = v.Type().Len()
100		}
101
102		for i := 0; i < numFields; i++ {
103			flushed = false
104			var f reflect.Value
105			if v.Kind() == reflect.Struct {
106				f = v.Field(i)
107			} else {
108				f = v.Index(i)
109			}
110			switch f.Kind() {
111			case reflect.Struct:
112				place(f)
113			case reflect.Bool:
114				if f.Bool() {
115					val |= 1
116				}
117				shift += 8
118				class |= _INTEGER
119			case reflect.Pointer:
120				ok = false
121				return
122			case reflect.Int8:
123				val |= uint64(f.Int()&0xFF) << shift
124				shift += 8
125				class |= _INTEGER
126			case reflect.Int16:
127				val |= uint64(f.Int()&0xFFFF) << shift
128				shift += 16
129				class |= _INTEGER
130			case reflect.Int32:
131				val |= uint64(f.Int()&0xFFFF_FFFF) << shift
132				shift += 32
133				class |= _INTEGER
134			case reflect.Int64:
135				val = uint64(f.Int())
136				shift = 64
137				class = _INTEGER
138			case reflect.Uint8:
139				val |= f.Uint() << shift
140				shift += 8
141				class |= _INTEGER
142			case reflect.Uint16:
143				val |= f.Uint() << shift
144				shift += 16
145				class |= _INTEGER
146			case reflect.Uint32:
147				val |= f.Uint() << shift
148				shift += 32
149				class |= _INTEGER
150			case reflect.Uint64:
151				val = f.Uint()
152				shift = 64
153				class = _INTEGER
154			case reflect.Float32:
155				val |= uint64(math.Float32bits(float32(f.Float()))) << shift
156				shift += 32
157				class |= _SSE
158			case reflect.Float64:
159				if v.Type().Size() > 16 {
160					ok = false
161					return
162				}
163				val = uint64(math.Float64bits(f.Float()))
164				shift = 64
165				class = _SSE
166			case reflect.Array:
167				place(f)
168			default:
169				panic("purego: unsupported kind " + f.Kind().String())
170			}
171
172			if shift == 64 {
173				flushIfNeeded()
174			} else if shift > 64 {
175				// Should never happen, but may if we forget to reset shift after flush (or forget to flush),
176				// better fall apart here, than corrupt arguments.
177				panic("purego: tryPlaceRegisters shift > 64")
178			}
179		}
180	}
181
182	place(v)
183	flushIfNeeded()
184	return ok
185}
186
187func placeStack(v reflect.Value, addStack func(uintptr)) {
188	for i := 0; i < v.Type().NumField(); i++ {
189		f := v.Field(i)
190		switch f.Kind() {
191		case reflect.Pointer:
192			addStack(f.Pointer())
193		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
194			addStack(uintptr(f.Int()))
195		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
196			addStack(uintptr(f.Uint()))
197		case reflect.Float32:
198			addStack(uintptr(math.Float32bits(float32(f.Float()))))
199		case reflect.Float64:
200			addStack(uintptr(math.Float64bits(f.Float())))
201		case reflect.Struct:
202			placeStack(f, addStack)
203		default:
204			panic("purego: unsupported kind " + f.Kind().String())
205		}
206	}
207}

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