Skip to content

Commit 4220a1b

Browse files
authored
wasm: Add a preliminary TargetABI implementation (#4758)
To resolve #4757 and make our wasm ABI a bit more compatible with clang/emscripten's. This includes switching to 128-bit `real`.
1 parent 8a30f4d commit 4220a1b

File tree

5 files changed

+98
-1
lines changed

5 files changed

+98
-1
lines changed

gen/abi/abi.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ TargetABI *TargetABI::getTarget() {
273273
case llvm::Triple::loongarch64:
274274
return getLoongArch64TargetABI();
275275
#endif // LDC_LLVM_VER >= 1600
276+
case llvm::Triple::wasm32:
277+
case llvm::Triple::wasm64:
278+
return getWasmTargetABI();
276279
default:
277280
Logger::cout() << "WARNING: Unknown ABI, guessing...\n";
278281
return new UnknownTargetABI;

gen/abi/targets.h

+2
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,5 @@ TargetABI *getX86_64TargetABI();
3838
TargetABI *getX86TargetABI();
3939

4040
TargetABI *getLoongArch64TargetABI();
41+
42+
TargetABI *getWasmTargetABI();

gen/abi/wasm.cpp

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===-- wasm.cpp ----------------------------------------------------------===//
2+
//
3+
// LDC – the LLVM D compiler
4+
//
5+
// This file is distributed under the BSD-style LDC license. See the LICENSE
6+
// file for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// see https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "gen/abi/generic.h"
15+
16+
using namespace dmd;
17+
18+
namespace {
19+
Type *getSingleWrappedScalarType(Type *t) {
20+
t = t->toBasetype();
21+
22+
if (auto ts = t->isTypeStruct()) {
23+
if (ts->sym->fields.length != 1)
24+
return nullptr;
25+
return getSingleWrappedScalarType(ts->sym->fields[0]->type);
26+
}
27+
28+
if (auto tsa = t->isTypeSArray()) {
29+
if (tsa->dim->toInteger() != 1)
30+
return nullptr;
31+
return getSingleWrappedScalarType(tsa->nextOf());
32+
}
33+
34+
return t->isscalar()
35+
// some more pointers:
36+
|| t->ty == TY::Tclass || t->ty == TY::Taarray
37+
? t
38+
: nullptr;
39+
}
40+
}
41+
42+
struct WasmTargetABI : TargetABI {
43+
static bool isDirectlyPassedAggregate(Type *t) {
44+
// Structs and static arrays are generally passed byval, except for POD
45+
// aggregates wrapping a single scalar type.
46+
47+
if (!DtoIsInMemoryOnly(t)) // not a struct or static array
48+
return false;
49+
50+
// max scalar type size is 16 (`real`); return early if larger
51+
if (size(t) > 16 || !isPOD(t))
52+
return false;
53+
54+
Type *singleWrappedScalarType = getSingleWrappedScalarType(t);
55+
return singleWrappedScalarType &&
56+
// not passed directly if over-aligned
57+
DtoAlignment(t) <= DtoAlignment(singleWrappedScalarType);
58+
}
59+
60+
bool returnInArg(TypeFunction *tf, bool) override {
61+
if (tf->isref()) {
62+
return false;
63+
}
64+
65+
Type *rt = tf->next->toBasetype();
66+
return passByVal(tf, rt);
67+
}
68+
69+
bool passByVal(TypeFunction *, Type *t) override {
70+
return DtoIsInMemoryOnly(t) && !isDirectlyPassedAggregate(t);
71+
}
72+
73+
void rewriteFunctionType(IrFuncTy &) override {}
74+
};
75+
76+
// The public getter for abi.cpp.
77+
TargetABI *getWasmTargetABI() { return new WasmTargetABI; }

gen/target.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ llvm::Type *getRealType(const llvm::Triple &triple) {
6060
#endif // LDC_LLVM_VER >= 1600
6161
return LLType::getFP128Ty(ctx);
6262

63+
case Triple::wasm32:
64+
case Triple::wasm64:
65+
return LLType::getFP128Ty(ctx);
66+
6367
default:
6468
// 64-bit double precision for all other targets
6569
// FIXME: PowerPC, SystemZ, ...

tests/codegen/emscripten.d

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// REQUIRES: target_WebAssembly
22

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

56

67
// test predefined versions:
@@ -19,3 +20,13 @@ import core.stdc.stdio;
1920
extern(C) void _start() {
2021
puts("Hello world");
2122
}
23+
24+
25+
// ABI smoke test for directly passed aggregates:
26+
27+
struct S {
28+
double[1] x;
29+
}
30+
31+
// CHECK: .functype _D10emscripten3fooFSQs1SZQg (f64) -> (f64)
32+
S foo(S s) { return s; }

0 commit comments

Comments
 (0)