@@ -772,60 +772,54 @@ extern (C++) struct Target
772
772
}
773
773
774
774
/**
775
- * Determine which `in` parameters needs to be passed by `ref`
776
- *
777
- * Called from `TypeFunction` semantic with the full function type.
778
- * This routine must iterate over parameters, and may set `STC.ref_`
779
- * for any parameter which already have `STC.in_`.
780
- * This hook must never set `STC.ref_` if the parameter is not `STC.in_`,
781
- * nor should it ever change anything else.
782
- *
783
- * This hook will not be called when `-preview=in` wasn't passed to the
784
- * frontend, hence it needs not care about `global.params.previewIn`.
785
- *
775
+ * Decides whether an `in` parameter of the specified POD type is to be
776
+ * passed by reference or by value. To be used with `-preview=in` only!
786
777
* Params:
787
- * tf = Type of the function to inspect. The type will have its
788
- * parameter types semantically resolved, however other attributes
789
- * (return type, ` @safe` / `nothrow`, etc...) must not be used.
778
+ * t = type of the `in` parameter, must be a POD
779
+ * Returns:
780
+ * `true` if the `in` parameter is to be passed by reference
790
781
*/
791
- extern (C++ ) void applyInRefParams (TypeFunction tf )
782
+ extern (C++ ) bool preferPassByRef(Type t )
792
783
{
793
- foreach (_idx, p; tf.parameterList)
784
+ const size = t.size();
785
+ if (global.params.is64bit)
794
786
{
795
- // Ignore non-`in` or already-`ref` parameters
796
- if ((p.storageClass & (STC .in_ | STC .ref_)) != STC .in_)
797
- continue ;
798
-
799
- assert (p.type ! is null );
800
- // If it has a copy constructor / destructor / postblit,
801
- // it is always by ref
802
- if (p.type.needsDestruction() || p.type.needsCopyOrPostblit())
803
- p.storageClass |= STC .ref_;
804
- // If the type can't be copied, always by `ref`
805
- else if (! p.type.isCopyable())
806
- p.storageClass |= STC .ref_;
807
- // The Win64 ABI requires x87 real to be passed by ref
808
- else if (global.params.isWindows && global.params.is64bit &&
809
- p.type.ty == Tfloat80)
810
- p.storageClass |= STC .ref_;
811
-
812
- // If it's a dynamic array, use the value type as it
813
- // allows covariance between `in char[]` and `scope const(char)[]`
814
- // The same reasoning applies to pointers and classes,
815
- // but that is handled by the `(sz > 8)` below.
816
- else if (p.type.ty == Tarray)
817
- continue ;
818
- // Pass delegates by value to allow covariance
819
- // Function pointers are a single pointers and handled below.
820
- else if (p.type.ty == Tdelegate)
821
- continue ;
822
- else
787
+ if (global.params.isWindows)
788
+ {
789
+ // If size is larger than 8 or not a power-of-2, the Win64 ABI
790
+ // would require a hidden reference anyway.
791
+ return size > 8
792
+ || (size > 0 && (size & (size - 1 )) != 0 );
793
+ }
794
+ else // SysV x86_64 ABI
823
795
{
824
- const sz = p.type.size();
825
- if (global.params.is64bit ? (sz > 16 ) : (sz > 8 ))
826
- p.storageClass |= STC .ref_;
796
+ // Prefer a ref if the POD cannot be passed in registers, i.e.,
797
+ // would be passed on the stack, *and* the size is > 16.
798
+ if (size <= 16 )
799
+ return false ;
800
+
801
+ TypeTuple getArgTypes ()
802
+ {
803
+ import dmd.aggregate : Sizeok;
804
+ if (auto ts = t.toBasetype().isTypeStruct())
805
+ {
806
+ auto sd = ts.sym;
807
+ assert (sd.sizeok == Sizeok.done);
808
+ return sd.argTypes;
809
+ }
810
+ return toArgTypes (t);
811
+ }
812
+
813
+ TypeTuple argTypes = getArgTypes();
814
+ assert (argTypes ! is null , " size == 0 should already be handled" );
815
+ return argTypes.arguments.length == 0 ; // cannot be passed in registers
827
816
}
828
817
}
818
+ else // 32-bit x86 ABI
819
+ {
820
+ // Prefer a ref if the size is > 2 machine words.
821
+ return size > 8 ;
822
+ }
829
823
}
830
824
831
825
// this guarantees `getTargetInfo` and `allTargetInfos` remain in sync
0 commit comments