[CodeGen][WebAssembly] Better lowering for WASM_SYMBOL_TYPE_GLOBAL symbols

As we have been missing support for WebAssembly globals on the IR level,
the lowering of WASM_SYMBOL_TYPE_GLOBAL to IR was incomplete.  This
commit fleshes out the lowering support, lowering references to and
definitions of addrspace(1) values to correctly typed
WASM_SYMBOL_TYPE_GLOBAL symbols.

Depends on D101608.

Differential Revision: https://reviews.llvm.org/D101913
This commit is contained in:
Andy Wingo 2021-05-05 14:59:30 +02:00
parent b159987054
commit b2f21b145a
5 changed files with 124 additions and 31 deletions

View File

@ -170,13 +170,54 @@ MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction(
return WasmSym;
}
void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
if (!WebAssembly::isWasmVarAddressSpace(GV->getAddressSpace())) {
AsmPrinter::emitGlobalVariable(GV);
return;
}
assert(!GV->isThreadLocal());
MCSymbolWasm *Sym = cast<MCSymbolWasm>(getSymbol(GV));
if (!Sym->getType()) {
const WebAssemblyTargetLowering &TLI = *Subtarget->getTargetLowering();
SmallVector<EVT, 1> VTs;
ComputeValueVTs(TLI, GV->getParent()->getDataLayout(), GV->getValueType(),
VTs);
if (VTs.size() != 1 ||
TLI.getNumRegisters(GV->getParent()->getContext(), VTs[0]) != 1)
report_fatal_error("Aggregate globals not yet implemented");
MVT VT = TLI.getRegisterType(GV->getParent()->getContext(), VTs[0]);
bool Mutable = true;
wasm::ValType Type = WebAssembly::toValType(VT);
Sym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
Sym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), Mutable});
}
emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());
if (GV->hasInitializer()) {
assert(getSymbolPreferLocal(*GV) == Sym);
emitLinkage(GV, Sym);
getTargetStreamer()->emitGlobalType(Sym);
OutStreamer->emitLabel(Sym);
// TODO: Actually emit the initializer value. Otherwise the global has the
// default value for its type (0, ref.null, etc).
OutStreamer->AddBlankLine();
}
}
void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
for (auto &It : OutContext.getSymbols()) {
// Emit .globaltype, .eventtype, or .tabletype declarations.
auto Sym = cast<MCSymbolWasm>(It.getValue());
if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL)
getTargetStreamer()->emitGlobalType(Sym);
else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT)
if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) {
// .globaltype already handled by emitGlobalVariable for defined
// variables; here we make sure the types of external wasm globals get
// written to the file.
if (Sym->isUndefined())
getTargetStreamer()->emitGlobalType(Sym);
} else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT)
getTargetStreamer()->emitEventType(Sym);
else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_TABLE)
getTargetStreamer()->emitTableType(Sym);
@ -262,12 +303,12 @@ void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
}
for (const auto &G : M.globals()) {
if (!G.hasInitializer() && G.hasExternalLinkage()) {
if (G.getValueType()->isSized()) {
uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
OutStreamer->emitELFSize(getSymbol(&G),
MCConstantExpr::create(Size, OutContext));
}
if (!G.hasInitializer() && G.hasExternalLinkage() &&
!WebAssembly::isWasmVarAddressSpace(G.getAddressSpace()) &&
G.getValueType()->isSized()) {
uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
OutStreamer->emitELFSize(getSymbol(&G),
MCConstantExpr::create(Size, OutContext));
}
}

View File

@ -65,6 +65,7 @@ public:
void emitEndOfAsmFile(Module &M) override;
void EmitProducerInfo(Module &M);
void EmitTargetFeatures(Module &M);
void emitGlobalVariable(const GlobalVariable *GV) override;
void emitJumpTableInfo() override;
void emitConstantPool() override;
void emitFunctionBodyStart() override;

View File

@ -15,6 +15,7 @@
#include "WebAssemblyMCInstLower.h"
#include "TargetInfo/WebAssemblyTargetInfo.h"
#include "Utils/WebAssemblyTypeUtilities.h"
#include "Utils/WebAssemblyUtilities.h"
#include "WebAssemblyAsmPrinter.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyRuntimeLibcallSignatures.h"
@ -46,8 +47,28 @@ static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
MCSymbol *
WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
const GlobalValue *Global = MO.getGlobal();
if (!isa<Function>(Global))
return cast<MCSymbolWasm>(Printer.getSymbol(Global));
if (!isa<Function>(Global)) {
auto *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
// If the symbol doesn't have an explicit WasmSymbolType yet and the
// GlobalValue is actually a WebAssembly global, then ensure the symbol is a
// WASM_SYMBOL_TYPE_GLOBAL.
if (WebAssembly::isWasmVarAddressSpace(Global->getAddressSpace()) &&
!WasmSym->getType()) {
const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
const TargetMachine &TM = MF.getTarget();
const Function &CurrentFunc = MF.getFunction();
SmallVector<MVT, 1> VTs;
computeLegalValueVTs(CurrentFunc, TM, Global->getValueType(), VTs);
if (VTs.size() != 1)
report_fatal_error("Aggregate globals not yet implemented");
bool Mutable = true;
wasm::ValType Type = WebAssembly::toValType(VTs[0]);
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), Mutable});
}
return WasmSym;
}
const auto *FuncTy = cast<FunctionType>(Global->getValueType());
const MachineFunction &MF = *MO.getParent()->getParent()->getParent();

View File

@ -5,6 +5,9 @@
@f32_global = local_unnamed_addr addrspace(1) global float undef
@f64_global = local_unnamed_addr addrspace(1) global double undef
@i32_external_used = external addrspace(1) global i32
@i32_external_unused = external addrspace(1) global i32
define i32 @return_i32_global() {
; CHECK-LABEL: return_i32_global:
; CHECK-NEXT: functype return_i32_global () -> (i32)
@ -41,14 +44,36 @@ define double @return_f64_global() {
ret double %v
}
define i32 @return_extern_i32_global() {
; CHECK-LABEL: return_extern_i32_global:
; CHECK-NEXT: functype return_extern_i32_global () -> (i32)
; CHECK-NEXT: global.get i32_external_used
; CHECK-NEXT: end_function
%v = load i32, i32 addrspace(1)* @i32_external_used
ret i32 %v
}
;; LLVM doesn't yet declare proper WebAssembly globals for these values,
;; instead placing them in linear memory. To fix in a followup.
; FIXME-CHECK: .globl i32_global
; FIXME-CHECK: .globaltype i32_global, i32
; FIXME-CHECK: .globl i64_global
; FIXME-CHECK: .globaltype i64_global, i64
; FIXME-CHECK: .globl f32_global
; FIXME-CHECK: .globaltype f32_global, f32
; FIXME-CHECK: .globl f64_global
; FIXME-CHECK: .globaltype f64_global, f64
; CHECK: .globl i32_global
; CHECK: .globaltype i32_global, i32
; CHECK-LABEL: i32_global:
; CHECK: .globl i64_global
; CHECK: .globaltype i64_global, i64
; CHECK-LABEL: i64_global:
; CHECK: .globl f32_global
; CHECK: .globaltype f32_global, f32
; CHECK-LABEL: f32_global:
; CHECK: .globl f64_global
; CHECK: .globaltype f64_global, f64
; CHECK-LABEL: f64_global:
; CHECK-NOT: .global i32_external_used
; CHECK: .globaltype i32_external_used, i32
; CHECK-NOT: i32_external_used:
; CHECK-NOT: .global i32_external_unused
; CHECK: .globaltype i32_external_unused, i32
; CHECK-NOT: i32_external_unused:

View File

@ -45,13 +45,18 @@ define void @set_f64_global(double %v) {
ret void
}
;; LLVM doesn't yet declare proper WebAssembly globals for these values,
;; instead placing them in linear memory. To fix in a followup.
; FIXME-CHECK: .globl i32_global
; FIXME-CHECK: .globaltype i32_global, i32
; FIXME-CHECK: .globl i64_global
; FIXME-CHECK: .globaltype i64_global, i64
; FIXME-CHECK: .globl f32_global
; FIXME-CHECK: .globaltype f32_global, f32
; FIXME-CHECK: .globl f64_global
; FIXME-CHECK: .globaltype f64_global, f64
; CHECK: .globl i32_global
; CHECK: .globaltype i32_global, i32
; CHECK-LABEL: i32_global:
; CHECK: .globl i64_global
; CHECK: .globaltype i64_global, i64
; CHECK-LABEL: i64_global:
; CHECK: .globl f32_global
; CHECK: .globaltype f32_global, f32
; CHECK-LABEL: f32_global:
; CHECK: .globl f64_global
; CHECK: .globaltype f64_global, f64
; CHECK-LABEL: f64_global: