ldc icon indicating copy to clipboard operation
ldc copied to clipboard

In optimized WASM build, recursive function mutates an immutable variable

Open andy-hanson opened this issue 2 years ago • 1 comments

a.d:

immutable struct S {
	immutable int x;
}

void countTo2(immutable S a) {
	if (a.x < 2)
		countTo2(S(a.x + 1));
}

extern(C) void _start() {}

extern(C) int test() {
	immutable S a = S(0);
	immutable S b = a;
	countTo2(a);
	return a.x - b.x;
}

test.js:

const fs = require("fs")

const main = async () => {
	const debug = await WebAssembly.instantiate(fs.readFileSync("./a-debug.wasm"))
	console.log("DEBUG:", debug.instance.exports.test())

	const opt = await WebAssembly.instantiate(fs.readFileSync("./a-O2.wasm"))
	console.log("OPTIMIZED:", opt.instance.exports.test())
}

main().catch(e => { console.error("ERROR", e) })

Now run:

ldc2 -ofa-debug.wasm -w -betterC -mtriple=wasm32-unknown-unknown-wasm a.d 
ldc2 -of a-O2.wasm -w -betterC -mtriple=wasm32-unknown-unknown-wasm -O2 a.d
node test.js

The output is:

DEBUG: 0
OPTIMIZED: 2

a and b are immutable and b = a, so the difference should be 0. But in an optimized WASM build, apparently a changes after countTo2(a). (And it was passed by value too.) Tested with LDC 1.33.0-git-aa64fad.

andy-hanson avatar May 17 '23 04:05 andy-hanson

I can't see any obvious bug in our unoptimized IR. I suspect a wasm-specific LLVM issue wrt. the byval IR attribute; the optimizer 'optimizes' the function to a return 2.

kinke avatar Aug 05 '23 13:08 kinke