diff --git a/lld/test/wasm/globals.s b/lld/test/wasm/globals.s --- a/lld/test/wasm/globals.s +++ b/lld/test/wasm/globals.s @@ -8,10 +8,11 @@ .globaltype foo_global, i32 .globaltype bar_global, f32 +.globaltype immutable_global, i32, immutable read_global: .functype read_global () -> (i32) - global.get foo_global + global.get immutable_global end_function write_global: @@ -26,10 +27,13 @@ .functype _start () -> () i32.const 1 call write_global + call read_global + drop end_function foo_global: bar_global: +immutable_global: # CHECK: - Type: GLOBAL # CHECK-NEXT: Globals: @@ -39,13 +43,19 @@ # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST # CHECK-NEXT: Value: 66560 -# CHECK-NEXT: - Index: 1 +# CHECK-NEXT: - Index: 1 +# CHECK-NEXT: Type: I32 +# CHECK-NEXT: Mutable: false +# CHECK-NEXT: InitExpr: +# CHECK-NEXT: Opcode: I32_CONST +# CHECK-NEXT: Value: 0 +# CHECK-NEXT: - Index: 2 # CHECK-NEXT: Type: I32 # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: # CHECK-NEXT: Opcode: I32_CONST # CHECK-NEXT: Value: 0 -# CHECK-NEXT: - Index: 2 +# CHECK-NEXT: - Index: 3 # CHECK-NEXT: Type: F32 # CHECK-NEXT: Mutable: true # CHECK-NEXT: InitExpr: diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -689,11 +689,24 @@ auto Type = parseType(TypeName); if (!Type) return error("Unknown type in .globaltype directive: ", TypeTok); + // Optional mutable modifier. Default to mutable for historical reasons. + // Ideally we would have gone with immutable as the default and used `mut` + // as the modifier to match the `.wat` format. + bool Mutable = true; + if (isNext(AsmToken::Comma)) { + TypeTok = Lexer.getTok(); + auto Id = expectIdent(); + if (Id == "immutable") + Mutable = false; + else + // Should we also allow `mutable` and `mut` here for clarity? + return error("Unknown type in .globaltype modifier: ", TypeTok); + } // Now set this symbol with the correct type. auto WasmSym = cast(Ctx.getOrCreateSymbol(SymName)); WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); WasmSym->setGlobalType( - wasm::WasmGlobalType{uint8_t(Type.getValue()), true}); + wasm::WasmGlobalType{uint8_t(Type.getValue()), Mutable}); // And emit the directive again. TOut.emitGlobalType(WasmSym); return expect(AsmToken::EndOfStatement, "EOL"); diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -71,8 +71,10 @@ assert(Sym->isGlobal()); OS << "\t.globaltype\t" << Sym->getName() << ", " << WebAssembly::typeToString( - static_cast(Sym->getGlobalType().Type)) - << '\n'; + static_cast(Sym->getGlobalType().Type)); + if (!Sym->getGlobalType().Mutable) + OS << ", immutable"; + OS << '\n'; } void WebAssemblyTargetAsmStreamer::emitEventType(const MCSymbolWasm *Sym) { diff --git a/llvm/test/MC/WebAssembly/globals.s b/llvm/test/MC/WebAssembly/globals.s --- a/llvm/test/MC/WebAssembly/globals.s +++ b/llvm/test/MC/WebAssembly/globals.s @@ -6,7 +6,7 @@ .globl read_global .globl write_global .globaltype foo_global, i32 -.globaltype global2, i64 +.globaltype global2, i64, immutable .globaltype global3, f32 .globaltype global4, f64 @@ -42,6 +42,12 @@ # BIN-NEXT: InitExpr: # BIN-NEXT: Opcode: I32_CONST # BIN-NEXT: Value: 0 +# BIN-NEXT: - Index: 1 +# BIN-NEXT: Type: I64 +# BIN-NEXT: Mutable: false +# BIN-NEXT: InitExpr: +# BIN-NEXT: Opcode: I64_CONST +# BIN-NEXT: Value: 0 # BIN: - Type: CUSTOM # BIN-NEXT: Name: linking