Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3218.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3218 Author: eem Time: 23 July 2022, 7:19:39.045502 pm UUID: 7674c9a8-b612-4cd3-b49c-96fc53f0f0c6 Ancestors: VMMaker.oscog-eem.3217
Merge VMMaker.oscog-KenD.3218. Implement what I think Ken wants for ThreadedRiscV64FFIPlugin>>ffiCalloutTo:SpecOnStack:in:, i.e. to treat float & double differently from the array of float/double.
=============== Diff against VMMaker.oscog-eem.3217 ===============
Item was added: + ----- Method: ThreadedRiscV64FFIPlugin>>ffiCalloutTo:SpecOnStack:in: (in category 'callout support') ----- + ffiCalloutTo: procAddr SpecOnStack: specOnStack in: calloutState + <var: #procAddr type: #'void *'> + <var: #calloutState type: #'CalloutState *'> + <var: #loadFloatRegs declareC: 'extern void loadFloatRegs(double, double, double, double, double, double, double, double)'> + "Go out, call this guy and create the return value. This *must* be inlined because of + the alloca of the outgoing stack frame in ffiCall:WithFlags:NumArgs:Args:AndTypes:" + | myThreadIndex atomicType floatRet intRet structRet specSize | + <var: #doubleRet type: #double> + <var: #floatRet type: 'union { struct { float floats[8]; } f; struct dprr { double doubles[4]; } d; }'> + <var: #structRet type: #SixteenByteReturnII> + <var: #intRet type: #usqLong> + <inline: #always> + self cCode: [] inSmalltalk: [floatRet := ByteArray new: 32]. "Just a hack to placate the Smalltalk compiler; these should be proper struct types..." + myThreadIndex := interpreterProxy disownVM: (self disownFlagsFor: calloutState). + + calloutState floatRegisterIndex > 0 ifTrue: + [self loadFloatRegs: + (calloutState floatRegisters at: 0) + _: (calloutState floatRegisters at: 1) + _: (calloutState floatRegisters at: 2) + _: (calloutState floatRegisters at: 3) + _: (calloutState floatRegisters at: 4) + _: (calloutState floatRegisters at: 5) + _: (calloutState floatRegisters at: 6) + _: (calloutState floatRegisters at: 7)]. + + (self allocaLiesSoSetSpBeforeCall or: [self mustAlignStack]) ifTrue: + [self setsp: calloutState argVector]. + + "float or double returns" + atomicType := self atomicTypeOf: calloutState ffiRetHeader. + (atomicType >> 1) = (FFITypeSingleFloat >> 1) ifTrue: + [| doubleRet | + atomicType = FFITypeDoubleFloat ifTrue: + [doubleRet := (self + dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)') + with: (calloutState integerRegisters at: 0) + with: (calloutState integerRegisters at: 1) + with: (calloutState integerRegisters at: 2) + with: (calloutState integerRegisters at: 3) + with: (calloutState integerRegisters at: 4) + with: (calloutState integerRegisters at: 5) + with: (calloutState integerRegisters at: 6) + with: (calloutState integerRegisters at: 7))] + ifFalse: + [doubleRet := (self + dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)') + with: (calloutState integerRegisters at: 0) + with: (calloutState integerRegisters at: 1) + with: (calloutState integerRegisters at: 2) + with: (calloutState integerRegisters at: 3) + with: (calloutState integerRegisters at: 4) + with: (calloutState integerRegisters at: 5) + with: (calloutState integerRegisters at: 6) + with: (calloutState integerRegisters at: 7))]. + "undo any callee argument pops because it may confuse stack management with the alloca." + (self isCalleePopsConvention: calloutState callFlags) ifTrue: + [self setsp: calloutState argVector]. + interpreterProxy ownVM: myThreadIndex. + ^self floatObjectOf: doubleRet]. + + "homogenous array of float/double returns" + ((calloutState ffiRetHeader bitAnd: FFIFlagPointer+FFIFlagStructure) = FFIFlagStructure + and: [self structIsHomogenousFloatArrayOfSize: (calloutState ffiRetHeader bitAnd: FFIStructSizeMask) + typeSpec: (self cCoerce: (interpreterProxy firstIndexableField: calloutState ffiRetSpec) to: #'unsigned int *') + ofLength: (specSize := interpreterProxy byteSizeOf: calloutState ffiRetSpec) / (self sizeof: #'unsigned int')]) ifTrue: + [floatRet d: (self + dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'struct dprr (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)') + with: (calloutState integerRegisters at: 0) + with: (calloutState integerRegisters at: 1) + with: (calloutState integerRegisters at: 2) + with: (calloutState integerRegisters at: 3) + with: (calloutState integerRegisters at: 4) + with: (calloutState integerRegisters at: 5) + with: (calloutState integerRegisters at: 6) + with: (calloutState integerRegisters at: 7)). + + "undo any callee argument pops because it may confuse stack management with the alloca." + (self isCalleePopsConvention: calloutState callFlags) ifTrue: + [self setsp: calloutState argVector]. + interpreterProxy ownVM: myThreadIndex. + + "If the struct is a vector of floats then move float[2] to float[1], float[4] to float[2] and float[6] to float[3], + to pack the float data in the double fields. We can tell if the struct is composed of floats if its size is less + than the spec size, since the spec size is (1 + n fields) * 4 bytes, and the struct size is n fields * 4 bytes + for floats and n fields * 8 bytes for doubles. We can't access the spec post call because it may have moved." + specSize > calloutState structReturnSize ifTrue: + [floatRet f floats at: 1 put: (floatRet f floats at: 2). + floatRet f floats at: 2 put: (floatRet f floats at: 4). + floatRet f floats at: 3 put: (floatRet f floats at: 6)]. + ^self ffiReturnStruct: (self addressOf: floatRet) ofType: (self ffiReturnType: specOnStack) in: calloutState]. + + "Integer and Structure returns..." + (self mustReturnStructOnStack: calloutState structReturnSize) + ifTrue: + [intRet := 0. + self setReturnRegister: (self cCoerceSimple: calloutState limit to: #sqLong) "stack alloca'd struct" + andCall: (self cCoerceSimple: procAddr to: #sqLong) + withArgsArray: (self cCoerceSimple: (self addressOf: calloutState integerRegisters) to: #sqLong)] + ifFalse: + [structRet := self + dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'SixteenByteReturnII (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)') + with: (calloutState integerRegisters at: 0) + with: (calloutState integerRegisters at: 1) + with: (calloutState integerRegisters at: 2) + with: (calloutState integerRegisters at: 3) + with: (calloutState integerRegisters at: 4) + with: (calloutState integerRegisters at: 5) + with: (calloutState integerRegisters at: 6) + with: (calloutState integerRegisters at: 7). + intRet := structRet a]. "X1" + + "undo any callee argument pops because it may confuse stack management with the alloca." + (self isCalleePopsConvention: calloutState callFlags) ifTrue: + [self setsp: calloutState argVector]. + interpreterProxy ownVM: myThreadIndex. + + (calloutState ffiRetHeader anyMask: FFIFlagPointer+FFIFlagStructure) ifTrue: + ["Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent + 'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct." + (calloutState ffiRetHeader anyMask: FFIFlagPointer) ifTrue: + [^self ffiReturnPointer: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState]. + ^self ffiReturnStruct: (((self returnStructInRegisters: calloutState) + ifTrue: [self cCoerceSimple: (self addressOf: structRet) to: #'char *'] + ifFalse: [calloutState limit])) + ofType: (self ffiReturnType: specOnStack) + in: calloutState]. + + ^self ffiCreateIntegralResultOop: intRet ofAtomicType: atomicType in: calloutState!
Item was changed: ----- Method: ThreadedRiscV64FFIPlugin>>ffiPushFloat32:in: (in category 'marshalling') ----- ffiPushFloat32: value in: calloutState <var: #value type: #float> <var: #calloutState type: #'CalloutState *'> <inline: #always> "N.B. the RISCV ABI states that unused part should be -1, [RISC-V Instruction Set Manual - Volume I: User Level ISA, 12.2 NaN Boxing of Narrower Value" calloutState floatRegisterIndex < NumFloatRegArgs ifTrue: "Note: this is a 'memcopy', so size is preserved. Casting to #double changes the size" [(self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: calloutState floatRegisterIndex)) to: #'long *') at: 0 put: -1. (self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: calloutState floatRegisterIndex)) to: #'float *') at: 0 put: value. + calloutState floatRegisterIndex: calloutState floatRegisterIndex + 1 + ] + ifFalse: "Use integer register if available" + [ (calloutState integerRegisterIndex < NumIntRegArgs) + ifTrue: + [calloutState integerRegisters + at: calloutState integerRegisterIndex + put: -1. + self storeSingleFloatAtPointer: (self addressOf: (calloutState integerRegisters at: calloutState integerRegisterIndex)) + from: value. + calloutState integerRegisterIndex: calloutState integerRegisterIndex + 1 + ] + ifFalse: + [calloutState currentArg + self wordSize > calloutState limit ifTrue: [^FFIErrorCallFrameTooBig]. + interpreterProxy longAt: calloutState currentArg put: value. + calloutState currentArg: calloutState currentArg + self wordSize + ]. + ]. - calloutState floatRegisterIndex: calloutState floatRegisterIndex + 1] - ifFalse: - [calloutState currentArg + self wordSize > calloutState limit ifTrue: - [^FFIErrorCallFrameTooBig]. - interpreterProxy - longAt: calloutState currentArg put: -1; - storeSingleFloatAtPointer: calloutState currentArg from: value. - calloutState currentArg: calloutState currentArg + self wordSize]. ^0!
Item was added: + ----- Method: ThreadedRiscV64FFIPlugin>>ffiPushFloat64:in: (in category 'marshalling') ----- + ffiPushFloat64: value in: calloutState + <var: #value type: #double> + <var: #calloutState type: #'CalloutState *'> + <inline: #always> + + calloutState floatRegisterIndex < NumFloatRegArgs + ifTrue: + [calloutState floatRegisters + at: calloutState floatRegisterIndex + put: value. + calloutState floatRegisterIndex: calloutState floatRegisterIndex + 1 + ] + ifFalse: "Use integer register if available" + [(calloutState integerRegisterIndex < NumIntRegArgs) + ifTrue: [ + self storeFloatAtPointer: (self addressOf: (calloutState integerRegisters at: calloutState integerRegisterIndex)) + from: value. + calloutState integerRegisterIndex: calloutState integerRegisterIndex + 1 + ] + ifFalse: [ + calloutState currentArg + self wordSize > calloutState limit ifTrue: [^FFIErrorCallFrameTooBig]. + interpreterProxy longAt: calloutState currentArg put: value. + calloutState currentArg: calloutState currentArg + self wordSize + ] + ]. + ^0!
vm-dev@lists.squeakfoundation.org