forked from OSchip/llvm-project
[WebAssembly] 64-bit memory limits
This commit is contained in:
parent
fa1fecc73d
commit
4d135b0446
|
@ -1,7 +1,12 @@
|
|||
; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/hello.s -o %t.hello.o
|
||||
; RUN: llc -filetype=obj %s -o %t.o
|
||||
; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/hello.s -o %t.hello32.o
|
||||
; RUN: llc -mtriple=wasm32-unknown-unknown -filetype=obj %s -o %t32.o
|
||||
; RUN: wasm-ld -m wasm32 -no-gc-sections --export=__data_end --export=__heap_base --allow-undefined --no-entry -o %t32.wasm %t32.o %t.hello32.o
|
||||
; RUN: obj2yaml %t32.wasm | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
; RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-unknown %p/Inputs/hello.s -o %t.hello64.o
|
||||
; RUN: llc -mtriple=wasm64-unknown-unknown -filetype=obj %s -o %t64.o
|
||||
; RUN: wasm-ld -m wasm64 -no-gc-sections --export=__data_end --export=__heap_base --allow-undefined --no-entry -o %t64.wasm %t64.o %t.hello64.o
|
||||
; RUN: obj2yaml %t64.wasm | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
|
||||
@foo = hidden global i32 1, align 4
|
||||
@aligned_bar = hidden global i32 3, align 16
|
||||
|
@ -13,26 +18,28 @@ target triple = "wasm32-unknown-unknown"
|
|||
@local_struct = hidden global %struct.s zeroinitializer, align 4
|
||||
@local_struct_internal_ptr = hidden local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @local_struct, i32 0, i32 1), align 4
|
||||
|
||||
; RUN: wasm-ld -no-gc-sections --export=__data_end --export=__heap_base --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o
|
||||
; RUN: obj2yaml %t.wasm | FileCheck %s
|
||||
|
||||
; CHECK: - Type: MEMORY
|
||||
; CHECK-NEXT: Memories:
|
||||
; CHECK-NEXT: - Initial: 0x00000002
|
||||
; CHK32-NEXT: - Initial: 0x00000002
|
||||
; CHK64-NEXT: - Flags: [ IS_64 ]
|
||||
; CHK64-NEXT: Initial: 0x00000002
|
||||
; CHECK-NEXT: - Type: GLOBAL
|
||||
; CHECK-NEXT: Globals:
|
||||
; CHECK-NEXT: - Index: 0
|
||||
; CHECK-NEXT: Type: I32
|
||||
; CHK32-NEXT: Type: I32
|
||||
; CHK64-NEXT: Type: I64
|
||||
; CHECK-NEXT: Mutable: true
|
||||
; CHECK-NEXT: InitExpr:
|
||||
; CHECK-NEXT: Opcode: I32_CONST
|
||||
; CHK32-NEXT: Opcode: I32_CONST
|
||||
; CHK64-NEXT: Opcode: I64_CONST
|
||||
; CHECK-NEXT: Value: 66624
|
||||
; CHECK-NEXT: - Index: 1
|
||||
; CHECK-NEXT: Type: I32
|
||||
; CHECK-NEXT: Mutable: false
|
||||
; CHECK-NEXT: InitExpr:
|
||||
; CHECK-NEXT: Opcode: I32_CONST
|
||||
; CHECK-NEXT: Value: 1080
|
||||
; CHK32-NEXT: Value: 1080
|
||||
; CHK64-NEXT: Value: 1088
|
||||
; CHECK-NEXT: - Index: 2
|
||||
; CHECK-NEXT: Type: I32
|
||||
; CHECK-NEXT: Mutable: false
|
||||
|
@ -53,13 +60,11 @@ target triple = "wasm32-unknown-unknown"
|
|||
; CHECK-NEXT: Offset:
|
||||
; CHECK-NEXT: Opcode: I32_CONST
|
||||
; CHECK-NEXT: Value: 1040
|
||||
; CHECK-NEXT: Content: '0100000000000000000000000000000003000000000000000004000034040000'
|
||||
; CHECK-NEXT: - Type: CUSTOM
|
||||
|
||||
|
||||
; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry \
|
||||
; RUN: --initial-memory=131072 --max-memory=131072 -o %t_max.wasm %t.o \
|
||||
; RUN: %t.hello.o
|
||||
; RUN: --initial-memory=131072 --max-memory=131072 -o %t_max.wasm %t32.o \
|
||||
; RUN: %t.hello32.o
|
||||
; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX
|
||||
|
||||
; CHECK-MAX: - Type: MEMORY
|
||||
|
@ -70,7 +75,7 @@ target triple = "wasm32-unknown-unknown"
|
|||
|
||||
; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry --shared-memory \
|
||||
; RUN: --features=atomics,bulk-memory --initial-memory=131072 \
|
||||
; RUN: --max-memory=131072 -o %t_max.wasm %t.o %t.hello.o
|
||||
; RUN: --max-memory=131072 -o %t_max.wasm %t32.o %t.hello32.o
|
||||
; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-SHARED
|
||||
|
||||
; CHECK-SHARED: - Type: MEMORY
|
||||
|
@ -79,7 +84,7 @@ target triple = "wasm32-unknown-unknown"
|
|||
; CHECK-SHARED-NEXT: Initial: 0x00000002
|
||||
; CHECK-SHARED-NEXT: Maximum: 0x00000002
|
||||
|
||||
; RUN: wasm-ld --relocatable -o %t_reloc.wasm %t.o %t.hello.o
|
||||
; RUN: wasm-ld --relocatable -o %t_reloc.wasm %t32.o %t.hello32.o
|
||||
; RUN: obj2yaml %t_reloc.wasm | FileCheck %s -check-prefix=RELOC
|
||||
|
||||
; RELOC: - Type: DATA
|
||||
|
|
|
@ -139,6 +139,8 @@ void ImportSection::writeBody() {
|
|||
}
|
||||
if (config->sharedMemory)
|
||||
import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
|
||||
if (config->is64)
|
||||
import.Memory.Flags |= WASM_LIMITS_FLAG_IS_64;
|
||||
writeImport(os, import);
|
||||
}
|
||||
|
||||
|
@ -234,6 +236,8 @@ void MemorySection::writeBody() {
|
|||
flags |= WASM_LIMITS_FLAG_HAS_MAX;
|
||||
if (config->sharedMemory)
|
||||
flags |= WASM_LIMITS_FLAG_IS_SHARED;
|
||||
if (config->is64)
|
||||
flags |= WASM_LIMITS_FLAG_IS_64;
|
||||
writeUleb128(os, flags, "memory limits flags");
|
||||
writeUleb128(os, numMemoryPages, "initial pages");
|
||||
if (hasMax)
|
||||
|
|
|
@ -167,8 +167,8 @@ public:
|
|||
bool isNeeded() const override { return !config->importMemory; }
|
||||
void writeBody() override;
|
||||
|
||||
uint32_t numMemoryPages = 0;
|
||||
uint32_t maxMemoryPages = 0;
|
||||
uint64_t numMemoryPages = 0;
|
||||
uint64_t maxMemoryPages = 0;
|
||||
};
|
||||
|
||||
// The event section contains a list of declared wasm events associated with the
|
||||
|
|
|
@ -224,8 +224,16 @@ void Writer::layoutMemory() {
|
|||
log("mem: stack base = " + Twine(memoryPtr));
|
||||
memoryPtr += config->zStackSize;
|
||||
auto *sp = cast<DefinedGlobal>(WasmSym::stackPointer);
|
||||
assert(sp->global->global.InitExpr.Opcode == WASM_OPCODE_I32_CONST);
|
||||
sp->global->global.InitExpr.Value.Int32 = memoryPtr;
|
||||
switch (sp->global->global.InitExpr.Opcode) {
|
||||
case WASM_OPCODE_I32_CONST:
|
||||
sp->global->global.InitExpr.Value.Int32 = memoryPtr;
|
||||
break;
|
||||
case WASM_OPCODE_I64_CONST:
|
||||
sp->global->global.InitExpr.Value.Int64 = memoryPtr;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("init expr must be i32/i64.const");
|
||||
}
|
||||
log("mem: stack top = " + Twine(memoryPtr));
|
||||
};
|
||||
|
||||
|
@ -296,13 +304,16 @@ void Writer::layoutMemory() {
|
|||
if (WasmSym::heapBase)
|
||||
WasmSym::heapBase->setVirtualAddress(memoryPtr);
|
||||
|
||||
uint64_t maxMemorySetting = 1ULL << (config->is64 ? 48 : 32);
|
||||
|
||||
if (config->initialMemory != 0) {
|
||||
if (config->initialMemory != alignTo(config->initialMemory, WasmPageSize))
|
||||
error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned");
|
||||
if (memoryPtr > config->initialMemory)
|
||||
error("initial memory too small, " + Twine(memoryPtr) + " bytes needed");
|
||||
if (config->initialMemory > (1ULL << 32))
|
||||
error("initial memory too large, cannot be greater than 4294967296");
|
||||
if (config->initialMemory > maxMemorySetting)
|
||||
error("initial memory too large, cannot be greater than " +
|
||||
Twine(maxMemorySetting));
|
||||
memoryPtr = config->initialMemory;
|
||||
}
|
||||
out.dylinkSec->memSize = memoryPtr;
|
||||
|
@ -316,8 +327,9 @@ void Writer::layoutMemory() {
|
|||
error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
|
||||
if (memoryPtr > config->maxMemory)
|
||||
error("maximum memory too small, " + Twine(memoryPtr) + " bytes needed");
|
||||
if (config->maxMemory > (1ULL << 32))
|
||||
error("maximum memory too large, cannot be greater than 4294967296");
|
||||
if (config->maxMemory > maxMemorySetting)
|
||||
error("maximum memory too large, cannot be greater than " +
|
||||
Twine(maxMemorySetting));
|
||||
out.memorySec->maxMemoryPages = config->maxMemory / WasmPageSize;
|
||||
log("mem: max pages = " + Twine(out.memorySec->maxMemoryPages));
|
||||
}
|
||||
|
|
|
@ -63,8 +63,8 @@ struct WasmExport {
|
|||
|
||||
struct WasmLimits {
|
||||
uint8_t Flags;
|
||||
uint32_t Initial;
|
||||
uint32_t Maximum;
|
||||
uint64_t Initial;
|
||||
uint64_t Maximum;
|
||||
};
|
||||
|
||||
struct WasmTable {
|
||||
|
@ -282,6 +282,7 @@ enum : unsigned {
|
|||
enum : unsigned {
|
||||
WASM_LIMITS_FLAG_HAS_MAX = 0x1,
|
||||
WASM_LIMITS_FLAG_IS_SHARED = 0x2,
|
||||
WASM_LIMITS_FLAG_IS_64 = 0x4,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
|
|
|
@ -108,7 +108,7 @@ struct WasmDataSegment {
|
|||
MCSectionWasm *Section;
|
||||
StringRef Name;
|
||||
uint32_t InitFlags;
|
||||
uint32_t Offset;
|
||||
uint64_t Offset;
|
||||
uint32_t Alignment;
|
||||
uint32_t LinkerFlags;
|
||||
SmallVector<char, 4> Data;
|
||||
|
@ -326,7 +326,7 @@ private:
|
|||
void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); }
|
||||
|
||||
void writeTypeSection(ArrayRef<WasmSignature> Signatures);
|
||||
void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize,
|
||||
void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint64_t DataSize,
|
||||
uint32_t NumElements);
|
||||
void writeFunctionSection(ArrayRef<WasmFunction> Functions);
|
||||
void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
|
||||
|
@ -730,12 +730,12 @@ void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) {
|
|||
}
|
||||
|
||||
void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
|
||||
uint32_t DataSize,
|
||||
uint64_t DataSize,
|
||||
uint32_t NumElements) {
|
||||
if (Imports.empty())
|
||||
return;
|
||||
|
||||
uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
|
||||
uint64_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
|
||||
|
||||
SectionBookkeeping Section;
|
||||
startSection(Section, wasm::WASM_SEC_IMPORT);
|
||||
|
@ -755,8 +755,8 @@ void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
|
|||
W.OS << char(Import.Global.Mutable ? 1 : 0);
|
||||
break;
|
||||
case wasm::WASM_EXTERNAL_MEMORY:
|
||||
encodeULEB128(0, W.OS); // flags
|
||||
encodeULEB128(NumPages, W.OS); // initial
|
||||
encodeULEB128(Import.Memory.Flags, W.OS);
|
||||
encodeULEB128(NumPages, W.OS); // initial
|
||||
break;
|
||||
case wasm::WASM_EXTERNAL_TABLE:
|
||||
W.OS << char(Import.Table.ElemType);
|
||||
|
@ -935,7 +935,9 @@ uint32_t WasmObjectWriter::writeDataSection(const MCAsmLayout &Layout) {
|
|||
if (Segment.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX)
|
||||
encodeULEB128(0, W.OS); // memory index
|
||||
if ((Segment.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) {
|
||||
W.OS << char(wasm::WASM_OPCODE_I32_CONST);
|
||||
W.OS << char(Segment.Offset > std::numeric_limits<int32_t>().max()
|
||||
? wasm::WASM_OPCODE_I64_CONST
|
||||
: wasm::WASM_OPCODE_I32_CONST);
|
||||
encodeSLEB128(Segment.Offset, W.OS); // offset
|
||||
W.OS << char(wasm::WASM_OPCODE_END);
|
||||
}
|
||||
|
@ -1187,7 +1189,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
|
|||
SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
|
||||
SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
|
||||
std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
|
||||
uint32_t DataSize = 0;
|
||||
uint64_t DataSize = 0;
|
||||
|
||||
// For now, always emit the memory import, since loads and stores are not
|
||||
// valid without it. In the future, we could perhaps be more clever and omit
|
||||
|
@ -1196,6 +1198,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
|
|||
MemImport.Module = "env";
|
||||
MemImport.Field = "__linear_memory";
|
||||
MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
|
||||
MemImport.Memory.Flags = is64Bit() ? wasm::WASM_LIMITS_FLAG_IS_64 : 0;
|
||||
Imports.push_back(MemImport);
|
||||
|
||||
// For now, always emit the table section, since indirect calls are not
|
||||
|
|
|
@ -208,9 +208,9 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
|
|||
static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
|
||||
wasm::WasmLimits Result;
|
||||
Result.Flags = readVaruint32(Ctx);
|
||||
Result.Initial = readVaruint32(Ctx);
|
||||
Result.Initial = readVaruint64(Ctx);
|
||||
if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
|
||||
Result.Maximum = readVaruint32(Ctx);
|
||||
Result.Maximum = readVaruint64(Ctx);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
|
|
@ -522,6 +522,7 @@ void ScalarBitSetTraits<WasmYAML::LimitFlags>::bitset(
|
|||
#define BCase(X) IO.bitSetCase(Value, #X, wasm::WASM_LIMITS_FLAG_##X)
|
||||
BCase(HAS_MAX);
|
||||
BCase(IS_SHARED);
|
||||
BCase(IS_64);
|
||||
#undef BCase
|
||||
}
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ test:
|
|||
# BIN-NEXT: Field: __linear_memory
|
||||
# BIN-NEXT: Kind: MEMORY
|
||||
# BIN-NEXT: Memory:
|
||||
# BIN-NEXT: Flags: [ IS_64 ]
|
||||
# BIN-NEXT: Initial: 0x00000001
|
||||
# BIN-NEXT: - Module: env
|
||||
# BIN-NEXT: Field: __indirect_function_table
|
||||
|
|
Loading…
Reference in New Issue