struct_ppc64le.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: Apache-2.0
  2. // SPDX-FileCopyrightText: 2026 The Ebitengine Authors
  3. package purego
  4. import (
  5. "reflect"
  6. "unsafe"
  7. )
  8. func getStruct(outType reflect.Type, syscall syscall15Args) reflect.Value {
  9. outSize := outType.Size()
  10. switch {
  11. case outSize == 0:
  12. return reflect.New(outType).Elem()
  13. case outSize <= 16:
  14. // Reconstruct from registers by copying raw bytes
  15. var buf [16]byte
  16. // Integer registers
  17. *(*uintptr)(unsafe.Pointer(&buf[0])) = syscall.a1
  18. if outSize > 8 {
  19. *(*uintptr)(unsafe.Pointer(&buf[8])) = syscall.a2
  20. }
  21. // Homogeneous float aggregates override integer regs
  22. if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
  23. if outType.Field(0).Type.Kind() == reflect.Float32 {
  24. // float32 values in FP regs
  25. f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}
  26. for i := 0; i < numFields; i++ {
  27. *(*uint32)(unsafe.Pointer(&buf[i*4])) = uint32(f[i])
  28. }
  29. } else {
  30. // float64: whole register value is valid
  31. *(*uintptr)(unsafe.Pointer(&buf[0])) = syscall.f1
  32. if outSize > 8 {
  33. *(*uintptr)(unsafe.Pointer(&buf[8])) = syscall.f2
  34. }
  35. }
  36. }
  37. return reflect.NewAt(outType, unsafe.Pointer(&buf[0])).Elem()
  38. default:
  39. // Returned indirectly via pointer in a1
  40. ptr := *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))
  41. return reflect.NewAt(outType, ptr).Elem()
  42. }
  43. }
  44. func addStruct(
  45. v reflect.Value,
  46. numInts, numFloats, numStack *int,
  47. addInt, addFloat, addStack func(uintptr),
  48. keepAlive []any,
  49. ) []any {
  50. size := v.Type().Size()
  51. if size == 0 {
  52. return keepAlive
  53. }
  54. if size <= 16 {
  55. return placeSmallAggregatePPC64LE(v, addFloat, addInt, keepAlive)
  56. }
  57. return placeStack(v, keepAlive, addInt)
  58. }
  59. func placeSmallAggregatePPC64LE(
  60. v reflect.Value,
  61. addFloat, addInt func(uintptr),
  62. keepAlive []any,
  63. ) []any {
  64. size := v.Type().Size()
  65. var ptr unsafe.Pointer
  66. if v.CanAddr() {
  67. ptr = v.Addr().UnsafePointer()
  68. } else {
  69. tmp := reflect.New(v.Type())
  70. tmp.Elem().Set(v)
  71. ptr = tmp.UnsafePointer()
  72. keepAlive = append(keepAlive, tmp.Interface())
  73. }
  74. var buf [16]byte
  75. src := unsafe.Slice((*byte)(ptr), size)
  76. copy(buf[:], src)
  77. w0 := *(*uintptr)(unsafe.Pointer(&buf[0]))
  78. w1 := uintptr(0)
  79. if size > 8 {
  80. w1 = *(*uintptr)(unsafe.Pointer(&buf[8]))
  81. }
  82. if isFloats, _ := isAllSameFloat(v.Type()); isFloats {
  83. addFloat(w0)
  84. if size > 8 {
  85. addFloat(w1)
  86. }
  87. } else {
  88. addInt(w0)
  89. if size > 8 {
  90. addInt(w1)
  91. }
  92. }
  93. return keepAlive
  94. }
  95. // placeStack is a fallback for structs that are too large to fit in registers
  96. func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
  97. if v.CanAddr() {
  98. addInt(v.Addr().Pointer())
  99. return keepAlive
  100. }
  101. ptr := reflect.New(v.Type())
  102. ptr.Elem().Set(v)
  103. addInt(ptr.Pointer())
  104. return append(keepAlive, ptr.Interface())
  105. }
  106. func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
  107. // PPC64LE does not bundle stack args
  108. return false
  109. }
  110. func collectStackArgs(
  111. args []reflect.Value,
  112. i, numInts, numFloats int,
  113. keepAlive []any,
  114. addInt, addFloat, addStack func(uintptr),
  115. numIntsPtr, numFloatsPtr, numStackPtr *int,
  116. ) ([]reflect.Value, []any) {
  117. return nil, keepAlive
  118. }
  119. func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
  120. panic("bundleStackArgs not supported on PPC64LE")
  121. }