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

Add some rudimentary WebAssembly support #2766

Merged
merged 6 commits into from
Jul 9, 2018
Merged

Conversation

kinke
Copy link
Member

@kinke kinke commented Jul 7, 2018

This gets some trivial code to compile to 32/64-bit WebAssembly via ldc2 -mtriple=wasm{32,64}-unknown-unknown-wasm -c -betterC:

struct S { int x; }
int add(S s, int b) { return s.x + b; }

@JohanEngelen
Copy link
Member

For testing, you can use the // REQUIRES: target_WebAssembly feature.

@kinke
Copy link
Member Author

kinke commented Jul 7, 2018

I did a quick experiment, and this works:

  1. Generate .wasm file for this D code:
extern(C) double add(double a, double b) { return a + b; }

// seems to be the required entry point
extern(C) void _start() {}

Compile: ldc2 -mtriple=wasm32-unknown-unknown-wasm -c -betterC wasm.d
Link manually for now: lld -flavor wasm wasm.o -o wasm.wasm

  1. Generate HTML page loading and executing the .wasm file (XMLHttpRequest to make it work for local files with Firefox), in the same dir as the .wasm file:
<html>
<head>
<script>
const request = new XMLHttpRequest();
request.open('GET', 'wasm.wasm');
request.responseType = 'arraybuffer';
request.send();
console.log('request sent');

request.onload = () => {
  console.log('response received');
  const bytes = request.response;
  const importObject = {};
  WebAssembly.instantiate(bytes, importObject).then(result => {
    console.log('instantiated');
    const { exports } = result.instance;
    // finally, call the add() function implemented in D:
    const r = exports.add(42, -2.5);
    console.log('r = ' + r);
  });
};
</script>
</head>
<body>
Test page
</body>
</html>
  1. Console output in latest Firefox:
request sent
response received
instantiated
r = 39.5

@kinke
Copy link
Member Author

kinke commented Jul 7, 2018

Unfortunately, LLD needs another command-line-parsing workaround for -link-internally to work for WebAssembly targets, so there'll be an LDC-LLVM 6.0.1-2. This then enables simple compile+link via ldc2 -mtriple=wasm32-unknown-unknown-wasm -betterC wasm.d -link-internally generating a wasm.wasm file; working here.

@kinke kinke force-pushed the wasm branch 2 times, most recently from 8a61805 to e46cf56 Compare July 7, 2018 20:42
driver/main.cpp Outdated
break;
case llvm::Triple::wasm64:
VersionCondition::addPredefinedGlobalIdent("WebAssembly64");
VersionCondition::addPredefinedGlobalIdent("D_HardFloat"); // right?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I tried a similar test yesterday, because of the forum post, and must have hit the error below: the 1.11 beta said it couldn't recognize the CPU wasm32. I doubt they're exposing the FPU to wasm, they only mention IEEE-754 compatibility. My guess is the wasm itself is agnostic to how floating-point is implemented, so better to just not set a predefined version for it.

Copy link
Member Author

@kinke kinke Jul 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is the result of me playing around after the forum post. ;) Erroring out for an unknown architecture (just because we don't know what predefined version to emit) was the first showstopper, hence the warning instead to ease future experiments. [It's already a warning when the target OS is unknown.]

Wrt. D_HardFloat, I thought it'd fit when slightly adapting the semantics from the target hardware has a floating point unit (spec) to the target has floating-point instructions (https://github.com/WebAssembly/design/blob/master/Semantics.md#floating-point-operators); the term 'hardware' in the context of WebAssembly is pretty nebulous/useless.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, hardware is what defines D_HardFloat, so I don't think it applies here. The point of the predefined version seems to be to allow you to write D code specialized to some FPU, which I don't think wasm allows. If you simply have floating-point instructions in your target, well, software implementations have those too.

My point is that I think both predefined versions are meaningless for wasm and shouldn't be defined. Those two predefined versions are hardly used in our stdlib anyway, doubt anyone outside is using them much.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll just remove them after seeing that D_{Hard,Soft}Float aren't defined for RISC-V either.

Well, hardware is what defines D_HardFloat [...] If you simply have floating-point instructions in your target, well, software implementations have those too.

Right, so currently it actually isn't the hardware alone that defines D_{Hard,Soft}Float, but the target architecture and, for some archs, the -float-abi setting.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's only because some arches are assumed to always have an FPU, unlike ARM.

@kinke kinke merged commit 6148b8a into ldc-developers:master Jul 9, 2018
@kinke kinke deleted the wasm branch July 9, 2018 20:50
@kinke kinke mentioned this pull request Jul 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants