Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Win64 extern(D) ABI: Pass/return Homogeneous Vector Aggregates in SIMD registers #3610

Merged
merged 1 commit into from
Nov 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions gen/abi-win64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,23 @@ struct Win64TargetABI : TargetABI {
const bool isMSVC;
IndirectByvalRewrite byvalRewrite;
IntegerRewrite integerRewrite;
HFVAToArray hfvaToArray;

bool isX87(Type *t) const {
return !isMSVC // 64-bit reals for MSVC targets
&& (t->ty == Tfloat80 || t->ty == Timaginary80);
}

bool passPointerToHiddenCopy(Type *t, bool isReturnValue, LINK linkage) const {
bool passPointerToHiddenCopy(Type *t, bool isReturnValue,
TypeFunction *tf) const {
// 80-bit real/ireal:
// * returned on the x87 stack (for DMD inline asm compliance and what LLVM
// defaults to)
// * passed by ref to hidden copy
if (isX87(t))
return !isReturnValue;

const bool isMSVCpp = isMSVC && linkage == LINKcpp;
const bool isMSVCpp = isMSVC && tf->linkage == LINKcpp;

// Handle non-PODs:
if (isReturnValue) {
Expand All @@ -74,6 +76,10 @@ struct Win64TargetABI : TargetABI {
}
}

// __vectorcall: Homogeneous Vector Aggregates are passed in registers
if (isExternD(tf) && isHVA(t, hfvaToArray.maxElements))
return false;

// Remaining aggregates which can NOT be rewritten as integers (size > 8
// bytes or not a power of 2) are passed by ref to hidden copy.
// LDC-specific exceptions: slices and delegates are left alone (as non-
Expand All @@ -85,7 +91,8 @@ struct Win64TargetABI : TargetABI {

public:
Win64TargetABI()
: isMSVC(global.params.targetTriple->isWindowsMSVCEnvironment()) {}
: isMSVC(global.params.targetTriple->isWindowsMSVCEnvironment()),
hfvaToArray(4) {}

llvm::CallingConv::ID callingConv(LINK l, TypeFunction *tf = nullptr,
FuncDeclaration *fd = nullptr) override {
Expand Down Expand Up @@ -123,8 +130,10 @@ struct Win64TargetABI : TargetABI {
// double/idouble)
// * 80-bit real/ireal are returned on the x87 stack
// * LDC-specific: slices and delegates are returned in RAX & RDX
// * for extern(D), vectors and Homogeneous Vector Aggregates are returned
// in SIMD register(s)
// * all other types are returned via sret
return passPointerToHiddenCopy(rt, /*isReturnValue=*/true, tf->linkage);
return passPointerToHiddenCopy(rt, /*isReturnValue=*/true, tf);
}

bool passByVal(TypeFunction *, Type *) override {
Expand Down Expand Up @@ -173,9 +182,12 @@ struct Win64TargetABI : TargetABI {
Type *t = arg.type->toBasetype();
LLType *originalLType = arg.ltype;

if (passPointerToHiddenCopy(t, isReturnValue, fty.type->linkage)) {
if (passPointerToHiddenCopy(t, isReturnValue, fty.type)) {
// the caller allocates a hidden copy and passes a pointer to that copy
byvalRewrite.applyTo(arg);
} else if (isExternD(fty.type) && isHVA(t, hfvaToArray.maxElements, &arg.ltype)) {
// rewrite Homogeneous Vector Aggregates as static array of vectors
hfvaToArray.applyTo(arg, arg.ltype);
} else if (isAggregate(t) && canRewriteAsInt(t)) {
integerRewrite.applyToIfNotObsolete(arg);
}
Expand Down
11 changes: 11 additions & 0 deletions gen/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ bool TargetABI::isHFVA(Type *t, int maxNumElements, LLType **hfvaType) {
return false;
}

bool TargetABI::isHVA(Type *t, int maxNumElements, LLType **hvaType) {
Type *rewriteType = nullptr;
if (::isHFVA(t, maxNumElements, &rewriteType) &&
rewriteType->nextOf()->ty == Tvector) {
if (hvaType)
*hvaType = DtoType(rewriteType);
return true;
}
return false;
}

//////////////////////////////////////////////////////////////////////////////

TypeTuple *TargetABI::getArgTypes(Type *t) {
Expand Down
5 changes: 5 additions & 0 deletions gen/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ struct TargetABI {
static bool isHFVA(Type *t, int maxNumElements,
llvm::Type **hfvaType = nullptr);

/// Check if `t` is a Homogeneous Vector Aggregate (HVA). If so, optionally
/// produce the rewriteType: an array of its fundamental type.
static bool isHVA(Type *t, int maxNumElements,
llvm::Type **hvaType = nullptr);

/// Uses the front-end toArgTypes* machinery and returns an appropriate LL
/// type if arguments of the specified D type are to be rewritten in order to
/// be passed correctly in registers.
Expand Down
34 changes: 27 additions & 7 deletions tests/codegen/vector_abi_x86.d
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,37 @@

// REQUIRES: host_X86

// RUN: %ldc -O -output-s -of=%t.s %s && FileCheck %s < %t.s
// RUN: %ldc -O -output-s -m32 -of=%t_32.s %s -mattr=+sse2
// RUN: FileCheck --check-prefix=COMMON %s < %t_32.s

// RUN: %ldc -O -output-s -m64 -of=%t_64.s %s
// RUN: FileCheck --check-prefix=COMMON --check-prefix=X64 %s < %t_64.s

import core.simd;

// CHECK: _D14vector_abi_x863foo
// COMMON: _D14vector_abi_x863foo
int4 foo(int4 param)
{
// CHECK-NOT: mov
// CHECK: paddd
// CHECK-SAME: %xmm0
// COMMON-NOT: mov
// COMMON: paddd
// COMMON-SAME: %xmm0
return param + 3;
// CHECK-NOT: mov
// CHECK: ret
// COMMON-NOT: mov
// COMMON: ret
}

version (X86_64)
{
struct Int4 { int4 v; }

// X64: _D14vector_abi_x863barFSQw4Int4ZQj
Int4 bar(Int4 param)
{
// X64-NOT: mov
// X64: paddd
// X64-SAME: %xmm0
return Int4(param.v + 3);
// X64-NOT: mov
// X64: ret
}
}