Skip to content

Commit

Permalink
wasm: Add a preliminary TargetABI implementation (ldc-developers#4758)
Browse files Browse the repository at this point in the history
To resolve ldc-developers#4757 and make our wasm ABI a bit more compatible with
clang/emscripten's. This includes switching to 128-bit `real`.
  • Loading branch information
kinke authored Sep 24, 2024
1 parent 8a30f4d commit 4220a1b
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 1 deletion.
3 changes: 3 additions & 0 deletions gen/abi/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ TargetABI *TargetABI::getTarget() {
case llvm::Triple::loongarch64:
return getLoongArch64TargetABI();
#endif // LDC_LLVM_VER >= 1600
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
return getWasmTargetABI();
default:
Logger::cout() << "WARNING: Unknown ABI, guessing...\n";
return new UnknownTargetABI;
Expand Down
2 changes: 2 additions & 0 deletions gen/abi/targets.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ TargetABI *getX86_64TargetABI();
TargetABI *getX86TargetABI();

TargetABI *getLoongArch64TargetABI();

TargetABI *getWasmTargetABI();
77 changes: 77 additions & 0 deletions gen/abi/wasm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===-- wasm.cpp ----------------------------------------------------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
// see https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
//
//===----------------------------------------------------------------------===//

#include "gen/abi/generic.h"

using namespace dmd;

namespace {
Type *getSingleWrappedScalarType(Type *t) {
t = t->toBasetype();

if (auto ts = t->isTypeStruct()) {
if (ts->sym->fields.length != 1)
return nullptr;
return getSingleWrappedScalarType(ts->sym->fields[0]->type);
}

if (auto tsa = t->isTypeSArray()) {
if (tsa->dim->toInteger() != 1)
return nullptr;
return getSingleWrappedScalarType(tsa->nextOf());
}

return t->isscalar()
// some more pointers:
|| t->ty == TY::Tclass || t->ty == TY::Taarray
? t
: nullptr;
}
}

struct WasmTargetABI : TargetABI {
static bool isDirectlyPassedAggregate(Type *t) {
// Structs and static arrays are generally passed byval, except for POD
// aggregates wrapping a single scalar type.

if (!DtoIsInMemoryOnly(t)) // not a struct or static array
return false;

// max scalar type size is 16 (`real`); return early if larger
if (size(t) > 16 || !isPOD(t))
return false;

Type *singleWrappedScalarType = getSingleWrappedScalarType(t);
return singleWrappedScalarType &&
// not passed directly if over-aligned
DtoAlignment(t) <= DtoAlignment(singleWrappedScalarType);
}

bool returnInArg(TypeFunction *tf, bool) override {
if (tf->isref()) {
return false;
}

Type *rt = tf->next->toBasetype();
return passByVal(tf, rt);
}

bool passByVal(TypeFunction *, Type *t) override {
return DtoIsInMemoryOnly(t) && !isDirectlyPassedAggregate(t);
}

void rewriteFunctionType(IrFuncTy &) override {}
};

// The public getter for abi.cpp.
TargetABI *getWasmTargetABI() { return new WasmTargetABI; }
4 changes: 4 additions & 0 deletions gen/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ llvm::Type *getRealType(const llvm::Triple &triple) {
#endif // LDC_LLVM_VER >= 1600
return LLType::getFP128Ty(ctx);

case Triple::wasm32:
case Triple::wasm64:
return LLType::getFP128Ty(ctx);

default:
// 64-bit double precision for all other targets
// FIXME: PowerPC, SystemZ, ...
Expand Down
13 changes: 12 additions & 1 deletion tests/codegen/emscripten.d
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// REQUIRES: target_WebAssembly

// RUN: %ldc -mtriple=wasm32-unknown-emscripten -c %s
// RUN: %ldc -mtriple=wasm32-unknown-emscripten -output-s -of=%t.s %s
// RUN: FileCheck %s < %t.s


// test predefined versions:
Expand All @@ -19,3 +20,13 @@ import core.stdc.stdio;
extern(C) void _start() {
puts("Hello world");
}


// ABI smoke test for directly passed aggregates:

struct S {
double[1] x;
}

// CHECK: .functype _D10emscripten3fooFSQs1SZQg (f64) -> (f64)
S foo(S s) { return s; }

0 comments on commit 4220a1b

Please sign in to comment.