Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ldc-developers/ldc
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ecea7631ae9ffc869a6127c5aca003ddf154d82a
Choose a base ref
..
head repository: ldc-developers/ldc
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c0cd3a27653329deaaffdf092670b34f6d67d687
Choose a head ref
Showing with 136 additions and 8 deletions.
  1. +2 −0 dmd/argtypes.h
  2. +74 −0 dmd/argtypes_s390x.d
  3. +9 −0 dmd/cxxfrontend.d
  4. +2 −0 gen/target.cpp
  5. +46 −5 runtime/druntime/src/core/internal/vararg/s390x.d
  6. +3 −3 runtime/druntime/src/core/threadasm.S
2 changes: 2 additions & 0 deletions dmd/argtypes.h
Original file line number Diff line number Diff line change
@@ -21,5 +21,7 @@ namespace dmd
TypeTuple *toArgTypes_sysv_x64(Type *t);
// in argtypes_aarch64.d
TypeTuple *toArgTypes_aarch64(Type *t);
// in argtypes_s390x.d
TypeTuple *toArgTypes_s390x(Type *t);
bool isHFVA(Type *t, int maxNumElements = 4, Type **rewriteType = nullptr);
}
74 changes: 74 additions & 0 deletions dmd/argtypes_s390x.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Break down a D type into basic (register) types for the IBM Z ELF ABI.
*
* Copyright: Copyright (C) 2024-2025 by The D Language Foundation, All Rights Reserved
* Authors: Martin Kinkelin
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_s390x.d, _argtypes_s390x.d)
* Documentation: https://dlang.org/phobos/dmd_argtypes_s390x.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/argtypes_s390x.d
*/

module dmd.argtypes_s390x;

import dmd.astenums;
import dmd.mtype;
import dmd.typesem;

/****************************************************
* This breaks a type down into 'simpler' types that can be passed to a function
* in registers, and returned in registers.
* This is the implementation for the IBM Z ELF ABI,
* based on https://github.com/IBM/s390x-abi/releases/download/v1.6/lzsabi_s390x.pdf.
* Params:
* t = type to break down
* Returns:
* tuple of types, each element can be passed in a register.
* A tuple of zero length means the type cannot be passed/returned in registers.
* null indicates a `void`.
*/
TypeTuple toArgTypes_s390x(Type t)
{
if (t == Type.terror)
return new TypeTuple(t);

const size = cast(size_t) t.size();
if (size == 0)
return null;

// TODO
// Implement the rest of the va args passing
//...
Type tb = t.toBasetype();
const isAggregate = tb.ty == Tstruct || tb.ty == Tsarray || tb.ty == Tarray || tb.ty == Tdelegate || tb.iscomplex();
if (!isAggregate)
return new TypeTuple(t);
// unwrap single-float struct per ABI requirements
if (auto tstruct = t.isTypeStruct())
{
if (tstruct.sym.fields.length == 1)
{
Type fieldType = tstruct.sym.fields[0].type.toBasetype();
if (fieldType.isfloating())
{
return new TypeTuple(fieldType);
}
}
}

// pass remaining aggregates in 1 or 2 GP registers
static Type getGPType(size_t size)
{
switch (size)
{
case 1: return Type.tint8;
case 2: return Type.tint16;
case 4: return Type.tint32;
case 8: return Type.tint64;
default:
import dmd.typesem : sarrayOf;
return Type.tint64.sarrayOf((size + 7) / 8);
}
}
return new TypeTuple(getGPType(size));
}
9 changes: 9 additions & 0 deletions dmd/cxxfrontend.d
Original file line number Diff line number Diff line change
@@ -698,4 +698,13 @@ version (IN_LLVM)
import dmd.argtypes_x86;
return dmd.argtypes_x86.toArgTypes_x86(t);
}

/***********************************************************
* argtypes_s390x.d
*/
TypeTuple toArgTypes_s390x(Type t)
{
import dmd.argtypes_s390x;
return dmd.argtypes_s390x.toArgTypes_s390x(t);
}
}
2 changes: 2 additions & 0 deletions gen/target.cpp
Original file line number Diff line number Diff line change
@@ -258,6 +258,8 @@ TypeTuple *Target::toArgTypes(Type *t) {
return toArgTypes_sysv_x64(t);
if (arch == llvm::Triple::aarch64 || arch == llvm::Triple::aarch64_be)
return toArgTypes_aarch64(t);
if (arch == llvm::Triple::systemz)
return toArgTypes_s390x(t);
return nullptr;
}

51 changes: 46 additions & 5 deletions runtime/druntime/src/core/internal/vararg/s390x.d
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ T va_arg(T)(va_list ap)
{
static if (is(T U == __argTypes))
{
static if (U.length == 0 || U[0].sizeof > 8 || is(T1 == __vector))
static if (U.length == 0 || U[0].sizeof > 8 || is(U[0] == __vector))
{
// Always passed in memory (varying vectors are passed in parameter area)
auto p = *cast(T*) ap.__overflow_arg_area;
@@ -45,7 +45,7 @@ T va_arg(T)(va_list ap)
// Passed in $fr registers (FPR region starts at +0x80)
auto p = cast(T*) ap.__reg_save_area + 128 + ap.__fpr * 8;
ap.__fpr++;
return p;
return *p;
}
else
{
@@ -54,7 +54,7 @@ T va_arg(T)(va_list ap)
// no matter the actual size of the fp variable
// parameter slot is always 8-byte-wide (f32 is extended to f64)
ap.__overflow_arg_area += 8;
return p;
return *p;
}
}
else
@@ -65,7 +65,7 @@ T va_arg(T)(va_list ap)
// Passed in $gpr registers (GPR region starts at +0x10)
auto p = cast(T*) ap.__reg_save_area + 16 + ap.__gpr * 8;
ap.__gpr++;
return p;
return *p;
}
else
{
@@ -74,7 +74,7 @@ T va_arg(T)(va_list ap)
// no matter the actual size of the gpr variable
// parameter slot is always 8-byte-wide (after ABI adjustments)
ap.__overflow_arg_area += 8;
return p;
return *p;
}
}
}
@@ -93,6 +93,23 @@ T va_arg(T)(va_list ap)
void va_arg()(va_list ap, TypeInfo ti, void* parmn)
{
TypeInfo arg1, arg2;
if (TypeInfo_Struct ti_struct = cast(TypeInfo_Struct) ti)
{
// handle single-float element struct
const rtFields = ti_struct.offTi();
if (rtFields && rtFields.length == 1)
{
TypeInfo field1TypeInfo = rtFields[0].ti;
if (field1TypeInfo is typeid(float) || field1TypeInfo is typeid(double))
{
auto tsize = field1TypeInfo.tsize;
auto toffset = rtFields[0].offset;
parmn[0..tsize] = p[toffset..tsize];
return;
}
}
}

if (!ti.argTypes(arg1, arg2))
{
TypeInfo_Vector v1 = arg1 ? cast(TypeInfo_Vector) arg1 : null;
@@ -117,6 +134,30 @@ void va_arg()(va_list ap, TypeInfo ti, void* parmn)
parmn[0..tsize] = p[0..tsize];
}
}
else if (arg1 && (arg1 is typeid(float) || arg1 is typeid(double)))
{
// Maybe passed in $fr registers
if (ap.__fpr <= 4)
{
// Passed in $fr registers (FPR region starts at +0x80)
auto p = cast(T*) ap.__reg_save_area + 128 + ap.__fpr * 8;
ap.__fpr++;
parmn[0..tsize] = p[0..tsize];
}
else
{
// overflow arguments
auto p = cast(T*) ap.__overflow_arg_area;
// no matter the actual size of the fp variable
// parameter slot is always 8-byte-wide (f32 is extended to f64)
ap.__overflow_arg_area += 8;
parmn[0..tsize] = p[0..tsize];
}
}
else
{
assert(false, "unhandled va_arg type!");
}
assert(!arg2);
}
else
6 changes: 3 additions & 3 deletions runtime/druntime/src/core/threadasm.S
Original file line number Diff line number Diff line change
@@ -771,15 +771,15 @@ fiber_switchContext:
std %f15, 56(%r1)
.cfi_offset 31, -168
/* Save stack pointer */
la %r0, 224(%r15)
la %r0, 168(%r15)
stg %r0, 0(%r2)

/* Load the new context pointer as stack pointer. */
lgr %r15, %r3
.cfi_def_cfa 3, 160
.cfi_def_cfa 3, 216
/* Store the new stack pointer location to the parameter area */
stg %r15, 120(%r15)
aghi %r15, -224
aghi %r15, -168
.cfi_def_cfa 15, 384

/* Restore call-saved floating point registers. */