Skip to content

Commit

Permalink
wasm: Add a preliminary TargetABI implementation
Browse files Browse the repository at this point in the history
To resolve #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 committed Sep 22, 2024
1 parent 8a30f4d commit d729de8
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 0 deletions.
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

0 comments on commit d729de8

Please sign in to comment.