diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -499,7 +499,7 @@ int value) { llvm::wasm::WasmGlobal wasmGlobal; wasmGlobal.Type = {WASM_TYPE_I32, isMutable}; - wasmGlobal.InitExpr.Value.Int32 = value; + wasmGlobal.InitExpr.Value.Int64 = value; wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; wasmGlobal.SymbolName = name; return symtab->addSyntheticGlobal(name, WASM_SYMBOL_VISIBILITY_HIDDEN, diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp --- a/lld/wasm/InputChunks.cpp +++ b/lld/wasm/InputChunks.cpp @@ -46,9 +46,9 @@ void InputChunk::verifyRelocTargets() const { for (const WasmRelocation &rel : relocations) { - uint32_t existingValue; + uint64_t existingValue; unsigned bytesRead = 0; - uint32_t offset = rel.Offset - getInputSectionOffset(); + auto offset = rel.Offset - getInputSectionOffset(); const uint8_t *loc = data().data() + offset; switch (rel.Type) { case R_WASM_TYPE_INDEX_LEB: @@ -56,20 +56,26 @@ case R_WASM_GLOBAL_INDEX_LEB: case R_WASM_EVENT_INDEX_LEB: case R_WASM_MEMORY_ADDR_LEB: + case R_WASM_MEMORY_ADDR_LEB64: existingValue = decodeULEB128(loc, &bytesRead); break; case R_WASM_TABLE_INDEX_SLEB: case R_WASM_TABLE_INDEX_REL_SLEB: case R_WASM_MEMORY_ADDR_SLEB: + case R_WASM_MEMORY_ADDR_SLEB64: case R_WASM_MEMORY_ADDR_REL_SLEB: - existingValue = static_cast(decodeSLEB128(loc, &bytesRead)); + case R_WASM_MEMORY_ADDR_REL_SLEB64: + existingValue = static_cast(decodeSLEB128(loc, &bytesRead)); break; case R_WASM_TABLE_INDEX_I32: case R_WASM_MEMORY_ADDR_I32: case R_WASM_FUNCTION_OFFSET_I32: case R_WASM_SECTION_OFFSET_I32: case R_WASM_GLOBAL_INDEX_I32: - existingValue = static_cast(read32le(loc)); + existingValue = read32le(loc); + break; + case R_WASM_MEMORY_ADDR_I64: + existingValue = read64le(loc); break; default: llvm_unreachable("unknown relocation type"); @@ -80,7 +86,7 @@ if (rel.Type != R_WASM_GLOBAL_INDEX_LEB && rel.Type != R_WASM_GLOBAL_INDEX_I32) { - uint32_t expectedValue = file->calcExpectedValue(rel); + auto expectedValue = file->calcExpectedValue(rel); if (expectedValue != existingValue) warn("unexpected existing value for " + relocTypeToString(rel.Type) + ": existing=" + Twine(existingValue) + @@ -108,7 +114,7 @@ for (const WasmRelocation &rel : relocations) { uint8_t *loc = buf + rel.Offset + off; - uint32_t value = file->calcNewValue(rel); + auto value = file->calcNewValue(rel); LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(rel.Type)); if (rel.Type != R_WASM_TYPE_INDEX_LEB) LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName()); @@ -124,12 +130,19 @@ case R_WASM_MEMORY_ADDR_LEB: encodeULEB128(value, loc, 5); break; + case R_WASM_MEMORY_ADDR_LEB64: + encodeULEB128(value, loc, 10); + break; case R_WASM_TABLE_INDEX_SLEB: case R_WASM_TABLE_INDEX_REL_SLEB: case R_WASM_MEMORY_ADDR_SLEB: case R_WASM_MEMORY_ADDR_REL_SLEB: encodeSLEB128(static_cast(value), loc, 5); break; + case R_WASM_MEMORY_ADDR_SLEB64: + case R_WASM_MEMORY_ADDR_REL_SLEB64: + encodeSLEB128(static_cast(value), loc, 10); + break; case R_WASM_TABLE_INDEX_I32: case R_WASM_MEMORY_ADDR_I32: case R_WASM_FUNCTION_OFFSET_I32: @@ -137,6 +150,9 @@ case R_WASM_GLOBAL_INDEX_I32: write32le(loc, value); break; + case R_WASM_MEMORY_ADDR_I64: + write64le(loc, value); + break; default: llvm_unreachable("unknown relocation type"); } @@ -181,17 +197,19 @@ // Write a relocation value without padding and return the number of bytes // witten. static unsigned writeCompressedReloc(uint8_t *buf, const WasmRelocation &rel, - uint32_t value) { + uint64_t value) { switch (rel.Type) { case R_WASM_TYPE_INDEX_LEB: case R_WASM_FUNCTION_INDEX_LEB: case R_WASM_GLOBAL_INDEX_LEB: case R_WASM_EVENT_INDEX_LEB: case R_WASM_MEMORY_ADDR_LEB: + case R_WASM_MEMORY_ADDR_LEB64: return encodeULEB128(value, buf); case R_WASM_TABLE_INDEX_SLEB: case R_WASM_MEMORY_ADDR_SLEB: - return encodeSLEB128(static_cast(value), buf); + case R_WASM_MEMORY_ADDR_SLEB64: + return encodeSLEB128(static_cast(value), buf); default: llvm_unreachable("unexpected relocation type"); } @@ -207,13 +225,16 @@ case R_WASM_TABLE_INDEX_SLEB: case R_WASM_MEMORY_ADDR_SLEB: return 5; + case R_WASM_MEMORY_ADDR_LEB64: + case R_WASM_MEMORY_ADDR_SLEB64: + return 10; default: llvm_unreachable("unexpected relocation type"); } } -static unsigned getRelocWidth(const WasmRelocation &rel, uint32_t value) { - uint8_t buf[5]; +static unsigned getRelocWidth(const WasmRelocation &rel, uint64_t value) { + uint8_t buf[10]; return writeCompressedReloc(buf, rel, value); } diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h --- a/lld/wasm/InputFiles.h +++ b/lld/wasm/InputFiles.h @@ -103,9 +103,9 @@ void dumpInfo() const; uint32_t calcNewIndex(const WasmRelocation &reloc) const; - uint32_t calcNewValue(const WasmRelocation &reloc) const; - uint32_t calcNewAddend(const WasmRelocation &reloc) const; - uint32_t calcExpectedValue(const WasmRelocation &reloc) const; + uint64_t calcNewValue(const WasmRelocation &reloc) const; + uint64_t calcNewAddend(const WasmRelocation &reloc) const; + uint64_t calcExpectedValue(const WasmRelocation &reloc) const; Symbol *getSymbol(const WasmRelocation &reloc) const { return symbols[reloc.Index]; }; diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -101,12 +101,16 @@ // Relocations can contain addend for combined sections. This function takes a // relocation and returns updated addend by offset in the output section. -uint32_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const { +uint64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const { switch (reloc.Type) { case R_WASM_MEMORY_ADDR_LEB: + case R_WASM_MEMORY_ADDR_LEB64: + case R_WASM_MEMORY_ADDR_SLEB64: case R_WASM_MEMORY_ADDR_SLEB: case R_WASM_MEMORY_ADDR_REL_SLEB: + case R_WASM_MEMORY_ADDR_REL_SLEB64: case R_WASM_MEMORY_ADDR_I32: + case R_WASM_MEMORY_ADDR_I64: case R_WASM_FUNCTION_OFFSET_I32: return reloc.Addend; case R_WASM_SECTION_OFFSET_I32: @@ -119,27 +123,34 @@ // Calculate the value we expect to find at the relocation location. // This is used as a sanity check before applying a relocation to a given // location. It is useful for catching bugs in the compiler and linker. -uint32_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const { +uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const { switch (reloc.Type) { case R_WASM_TABLE_INDEX_I32: case R_WASM_TABLE_INDEX_SLEB: { const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; return tableEntries[sym.Info.ElementIndex]; } +<<<<<<< HEAD case R_WASM_TABLE_INDEX_REL_SLEB: { const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; return tableEntriesRel[sym.Info.ElementIndex]; } +======= + case R_WASM_MEMORY_ADDR_LEB: + case R_WASM_MEMORY_ADDR_LEB64: +>>>>>>> [WebAssembly] Adding 64-bit version of R_WASM_MEMORY_ADDR_* relocs case R_WASM_MEMORY_ADDR_SLEB: + case R_WASM_MEMORY_ADDR_SLEB64: + case R_WASM_MEMORY_ADDR_REL_SLEB: + case R_WASM_MEMORY_ADDR_REL_SLEB64: case R_WASM_MEMORY_ADDR_I32: - case R_WASM_MEMORY_ADDR_LEB: - case R_WASM_MEMORY_ADDR_REL_SLEB: { + case R_WASM_MEMORY_ADDR_I64: { const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; if (sym.isUndefined()) return 0; const WasmSegment &segment = wasmObj->dataSegments()[sym.Info.DataRef.Segment]; - return segment.Data.Offset.Value.Int32 + sym.Info.DataRef.Offset + + return segment.Data.Offset.Value.Int64 + sym.Info.DataRef.Offset + reloc.Addend; } case R_WASM_FUNCTION_OFFSET_I32: { @@ -166,7 +177,7 @@ } // Translate from the relocation's index into the final linked output value. -uint32_t ObjFile::calcNewValue(const WasmRelocation &reloc) const { +uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc) const { const Symbol* sym = nullptr; if (reloc.Type != R_WASM_TYPE_INDEX_LEB) { sym = symbols[reloc.Index]; @@ -191,10 +202,14 @@ return index; } - case R_WASM_MEMORY_ADDR_SLEB: - case R_WASM_MEMORY_ADDR_I32: case R_WASM_MEMORY_ADDR_LEB: + case R_WASM_MEMORY_ADDR_LEB64: + case R_WASM_MEMORY_ADDR_SLEB: + case R_WASM_MEMORY_ADDR_SLEB64: case R_WASM_MEMORY_ADDR_REL_SLEB: + case R_WASM_MEMORY_ADDR_REL_SLEB64: + case R_WASM_MEMORY_ADDR_I32: + case R_WASM_MEMORY_ADDR_I64: if (isa(sym) || sym->isUndefWeak()) return 0; return cast(sym)->getVirtualAddress() + reloc.Addend; @@ -211,8 +226,8 @@ return getEventSymbol(reloc.Index)->getEventIndex(); case R_WASM_FUNCTION_OFFSET_I32: { auto *f = cast(sym); - return f->function->outputOffset + f->function->getFunctionCodeOffset() + - reloc.Addend; + return f->function->outputOffset + + (f->function->getFunctionCodeOffset() + reloc.Addend); } case R_WASM_SECTION_OFFSET_I32: return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend; @@ -274,10 +289,9 @@ for (const WasmElemSegment &seg : wasmObj->elements()) { if (seg.Offset.Opcode != WASM_OPCODE_I32_CONST) fatal(toString(this) + ": invalid table elements"); - uint32_t offset = seg.Offset.Value.Int32; - for (uint32_t index = 0; index < seg.Functions.size(); index++) { - - uint32_t functionIndex = seg.Functions[index]; + auto offset = seg.Offset.Value.Int64; + for (size_t index = 0; index < seg.Functions.size(); index++) { + auto functionIndex = seg.Functions[index]; tableEntriesRel[functionIndex] = index; tableEntries[functionIndex] = offset + index; } @@ -411,8 +425,8 @@ } case WASM_SYMBOL_TYPE_DATA: { InputSegment *seg = segments[sym.Info.DataRef.Segment]; - uint32_t offset = sym.Info.DataRef.Offset; - uint32_t size = sym.Info.DataRef.Size; + auto offset = sym.Info.DataRef.Offset; + auto size = sym.Info.DataRef.Size; if (sym.isBindingLocal()) return make(name, flags, this, seg, offset, size); if (seg->discarded) diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -153,7 +153,7 @@ initExpr.Value.Global = WasmSym::memoryBase->getGlobalIndex(); } else { initExpr.Opcode = WASM_OPCODE_I32_CONST; - initExpr.Value.Int32 = segment->startVA; + initExpr.Value.Int64 = segment->startVA; } writeInitExpr(os, initExpr); } diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp --- a/lld/wasm/Relocations.cpp +++ b/lld/wasm/Relocations.cpp @@ -88,6 +88,8 @@ case R_WASM_TABLE_INDEX_SLEB: case R_WASM_MEMORY_ADDR_SLEB: case R_WASM_MEMORY_ADDR_LEB: + case R_WASM_MEMORY_ADDR_SLEB64: + case R_WASM_MEMORY_ADDR_LEB64: // Certain relocation types can't be used when building PIC output, // since they would require absolute symbol addresses at link time. error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + @@ -96,6 +98,7 @@ break; case R_WASM_TABLE_INDEX_I32: case R_WASM_MEMORY_ADDR_I32: + case R_WASM_MEMORY_ADDR_I64: // These relocation types are only present in the data section and // will be converted into code by `generateRelocationCode`. This code // requires the symbols to have GOT entires. diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h --- a/lld/wasm/SymbolTable.h +++ b/lld/wasm/SymbolTable.h @@ -53,8 +53,8 @@ Symbol *addDefinedFunction(StringRef name, uint32_t flags, InputFile *file, InputFunction *function); Symbol *addDefinedData(StringRef name, uint32_t flags, InputFile *file, - InputSegment *segment, uint32_t address, - uint32_t size); + InputSegment *segment, uint64_t address, + uint64_t size); Symbol *addDefinedGlobal(StringRef name, uint32_t flags, InputFile *file, InputGlobal *g); Symbol *addDefinedEvent(StringRef name, uint32_t flags, InputFile *file, diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -327,7 +327,7 @@ Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, InputFile *file, InputSegment *segment, - uint32_t address, uint32_t size) { + uint64_t address, uint64_t size) { LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address << "\n"); Symbol *s; diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -264,7 +264,7 @@ public: // Constructor for regular data symbols originating from input files. DefinedData(StringRef name, uint32_t flags, InputFile *f, - InputSegment *segment, uint32_t offset, uint32_t size) + InputSegment *segment, uint64_t offset, uint64_t size) : DataSymbol(name, DefinedDataKind, flags, f), segment(segment), offset(offset), size(size) {} @@ -275,19 +275,19 @@ static bool classof(const Symbol *s) { return s->kind() == DefinedDataKind; } // Returns the output virtual address of a defined data symbol. - uint32_t getVirtualAddress() const; - void setVirtualAddress(uint32_t va); + uint64_t getVirtualAddress() const; + void setVirtualAddress(uint64_t va); // Returns the offset of a defined data symbol within its OutputSegment. - uint32_t getOutputSegmentOffset() const; - uint32_t getOutputSegmentIndex() const; - uint32_t getSize() const { return size; } + uint64_t getOutputSegmentOffset() const; + uint64_t getOutputSegmentIndex() const; + uint64_t getSize() const { return size; } InputSegment *segment = nullptr; protected: - uint32_t offset = 0; - uint32_t size = 0; + uint64_t offset = 0; + uint64_t size = 0; }; class UndefinedData : public DataSymbol { diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -252,7 +252,7 @@ function ? &function->signature : nullptr), function(function) {} -uint32_t DefinedData::getVirtualAddress() const { +uint64_t DefinedData::getVirtualAddress() const { LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); if (segment) { // For thread local data, the symbol location is relative to the start of @@ -265,18 +265,18 @@ return offset; } -void DefinedData::setVirtualAddress(uint32_t value) { +void DefinedData::setVirtualAddress(uint64_t value) { LLVM_DEBUG(dbgs() << "setVirtualAddress " << name << " -> " << value << "\n"); assert(!segment); offset = value; } -uint32_t DefinedData::getOutputSegmentOffset() const { +uint64_t DefinedData::getOutputSegmentOffset() const { LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n"); return segment->outputSegmentOffset + offset; } -uint32_t DefinedData::getOutputSegmentIndex() const { +uint64_t DefinedData::getOutputSegmentIndex() const { LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n"); return segment->outputSeg->index; } diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -292,12 +292,12 @@ global.Type = {WASM_TYPE_I32, false}; global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; if (auto *d = dyn_cast(sym)) - global.InitExpr.Value.Int32 = d->getVirtualAddress(); + global.InitExpr.Value.Int64 = d->getVirtualAddress(); else if (auto *f = dyn_cast(sym)) - global.InitExpr.Value.Int32 = f->getTableIndex(); + global.InitExpr.Value.Int64 = f->getTableIndex(); else { assert(isa(sym)); - global.InitExpr.Value.Int32 = 0; + global.InitExpr.Value.Int64 = 0; } writeGlobal(os, global); } @@ -305,7 +305,7 @@ WasmGlobal global; global.Type = {WASM_TYPE_I32, false}; global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; - global.InitExpr.Value.Int32 = sym->getVirtualAddress(); + global.InitExpr.Value.Int64 = sym->getVirtualAddress(); writeGlobal(os, global); } } @@ -352,7 +352,7 @@ initExpr.Value.Global = WasmSym::tableBase->getGlobalIndex(); } else { initExpr.Opcode = WASM_OPCODE_I32_CONST; - initExpr.Value.Int32 = config->tableBase; + initExpr.Value.Int64 = config->tableBase; } writeInitExpr(os, initExpr); writeUleb128(os, indirectFunctions.size(), "elem count"); diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -224,7 +224,7 @@ log("mem: stack base = " + Twine(memoryPtr)); memoryPtr += config->zStackSize; auto *sp = cast(WasmSym::stackPointer); - sp->global->global.InitExpr.Value.Int32 = memoryPtr; + sp->global->global.InitExpr.Value.Int64 = memoryPtr; log("mem: stack top = " + Twine(memoryPtr)); }; @@ -256,10 +256,10 @@ if (WasmSym::tlsSize && seg->name == ".tdata") { auto *tlsSize = cast(WasmSym::tlsSize); - tlsSize->global->global.InitExpr.Value.Int32 = seg->size; + tlsSize->global->global.InitExpr.Value.Int64 = seg->size; auto *tlsAlign = cast(WasmSym::tlsAlign); - tlsAlign->global->global.InitExpr.Value.Int32 = 1U << seg->alignment; + tlsAlign->global->global.InitExpr.Value.Int64 = int64_t{1} << seg->alignment; } } diff --git a/lld/wasm/WriterUtils.h b/lld/wasm/WriterUtils.h --- a/lld/wasm/WriterUtils.h +++ b/lld/wasm/WriterUtils.h @@ -18,9 +18,9 @@ void debugWrite(uint64_t offset, const Twine &msg); -void writeUleb128(raw_ostream &os, uint32_t number, const Twine &msg); +void writeUleb128(raw_ostream &os, uint64_t number, const Twine &msg); -void writeSleb128(raw_ostream &os, int32_t number, const Twine &msg); +void writeSleb128(raw_ostream &os, int64_t number, const Twine &msg); void writeBytes(raw_ostream &os, const char *bytes, size_t count, const Twine &msg); @@ -38,9 +38,9 @@ void writeI32Const(raw_ostream &os, int32_t number, const Twine &msg); -void writeI64Const(raw_ostream &os, int32_t number, const Twine &msg); +void writeI64Const(raw_ostream &os, int64_t number, const Twine &msg); -void writeMemArg(raw_ostream &os, uint32_t alignment, uint32_t offset); +void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset); void writeInitExpr(raw_ostream &os, const llvm::wasm::WasmInitExpr &initExpr); diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -67,12 +67,12 @@ LLVM_DEBUG(dbgs() << format(" | %08lld: ", offset) << msg << "\n"); } -void writeUleb128(raw_ostream &os, uint32_t number, const Twine &msg) { +void writeUleb128(raw_ostream &os, uint64_t number, const Twine &msg) { debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]"); encodeULEB128(number, os); } -void writeSleb128(raw_ostream &os, int32_t number, const Twine &msg) { +void writeSleb128(raw_ostream &os, int64_t number, const Twine &msg) { debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]"); encodeSLEB128(number, os); } @@ -127,12 +127,12 @@ writeSleb128(os, number, msg); } -void writeI64Const(raw_ostream &os, int32_t number, const Twine &msg) { +void writeI64Const(raw_ostream &os, int64_t number, const Twine &msg) { writeU8(os, WASM_OPCODE_I64_CONST, "i64.const"); writeSleb128(os, number, msg); } -void writeMemArg(raw_ostream &os, uint32_t alignment, uint32_t offset) { +void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset) { writeUleb128(os, alignment, "alignment"); writeUleb128(os, offset, "offset"); } @@ -141,7 +141,7 @@ writeU8(os, initExpr.Opcode, "opcode"); switch (initExpr.Opcode) { case WASM_OPCODE_I32_CONST: - writeSleb128(os, initExpr.Value.Int32, "literal (i32)"); + writeSleb128(os, initExpr.Value.Int64, "literal (i32)"); break; case WASM_OPCODE_I64_CONST: writeSleb128(os, initExpr.Value.Int64, "literal (i64)"); diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -75,7 +75,6 @@ struct WasmInitExpr { uint8_t Opcode; union { - int32_t Int32; int64_t Int64; uint32_t Float32; uint64_t Float64; @@ -159,8 +158,8 @@ // the index of the segment, and the offset and size within the segment. struct WasmDataReference { uint32_t Segment; - uint32_t Offset; - uint32_t Size; + uint64_t Offset; + uint64_t Size; }; struct WasmRelocation { diff --git a/llvm/include/llvm/BinaryFormat/WasmRelocs.def b/llvm/include/llvm/BinaryFormat/WasmRelocs.def --- a/llvm/include/llvm/BinaryFormat/WasmRelocs.def +++ b/llvm/include/llvm/BinaryFormat/WasmRelocs.def @@ -2,17 +2,21 @@ #error "WASM_RELOC must be defined" #endif -WASM_RELOC(R_WASM_FUNCTION_INDEX_LEB, 0) -WASM_RELOC(R_WASM_TABLE_INDEX_SLEB, 1) -WASM_RELOC(R_WASM_TABLE_INDEX_I32, 2) -WASM_RELOC(R_WASM_MEMORY_ADDR_LEB, 3) -WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB, 4) -WASM_RELOC(R_WASM_MEMORY_ADDR_I32, 5) -WASM_RELOC(R_WASM_TYPE_INDEX_LEB, 6) -WASM_RELOC(R_WASM_GLOBAL_INDEX_LEB, 7) -WASM_RELOC(R_WASM_FUNCTION_OFFSET_I32, 8) -WASM_RELOC(R_WASM_SECTION_OFFSET_I32, 9) -WASM_RELOC(R_WASM_EVENT_INDEX_LEB, 10) -WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB, 11) -WASM_RELOC(R_WASM_TABLE_INDEX_REL_SLEB, 12) -WASM_RELOC(R_WASM_GLOBAL_INDEX_I32, 13) +WASM_RELOC(R_WASM_FUNCTION_INDEX_LEB, 0) +WASM_RELOC(R_WASM_TABLE_INDEX_SLEB, 1) +WASM_RELOC(R_WASM_TABLE_INDEX_I32, 2) +WASM_RELOC(R_WASM_MEMORY_ADDR_LEB, 3) +WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB, 4) +WASM_RELOC(R_WASM_MEMORY_ADDR_I32, 5) +WASM_RELOC(R_WASM_TYPE_INDEX_LEB, 6) +WASM_RELOC(R_WASM_GLOBAL_INDEX_LEB, 7) +WASM_RELOC(R_WASM_FUNCTION_OFFSET_I32, 8) +WASM_RELOC(R_WASM_SECTION_OFFSET_I32, 9) +WASM_RELOC(R_WASM_EVENT_INDEX_LEB, 10) +WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB, 11) +WASM_RELOC(R_WASM_TABLE_INDEX_REL_SLEB, 12) +WASM_RELOC(R_WASM_GLOBAL_INDEX_I32, 13) +WASM_RELOC(R_WASM_MEMORY_ADDR_LEB64, 14) +WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB64, 15) +WASM_RELOC(R_WASM_MEMORY_ADDR_I64, 16) +WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB64, 17) diff --git a/llvm/include/llvm/ObjectYAML/WasmYAML.h b/llvm/include/llvm/ObjectYAML/WasmYAML.h --- a/llvm/include/llvm/ObjectYAML/WasmYAML.h +++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h @@ -107,8 +107,10 @@ struct Relocation { RelocType Type; uint32_t Index; + // TODO(wvo): this would strictly be better as Hex64, but that will change + // all existing obj2yaml output. yaml::Hex32 Offset; - int32_t Addend; + int64_t Addend; }; struct DataSegment { diff --git a/llvm/lib/BinaryFormat/Wasm.cpp b/llvm/lib/BinaryFormat/Wasm.cpp --- a/llvm/lib/BinaryFormat/Wasm.cpp +++ b/llvm/lib/BinaryFormat/Wasm.cpp @@ -39,9 +39,13 @@ bool llvm::wasm::relocTypeHasAddend(uint32_t Type) { switch (Type) { case R_WASM_MEMORY_ADDR_LEB: + case R_WASM_MEMORY_ADDR_LEB64: case R_WASM_MEMORY_ADDR_SLEB: + case R_WASM_MEMORY_ADDR_SLEB64: case R_WASM_MEMORY_ADDR_REL_SLEB: + case R_WASM_MEMORY_ADDR_REL_SLEB64: case R_WASM_MEMORY_ADDR_I32: + case R_WASM_MEMORY_ADDR_I64: case R_WASM_FUNCTION_OFFSET_I32: case R_WASM_SECTION_OFFSET_I32: return true; diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -185,21 +185,21 @@ // Write X as an (unsigned) LEB value at offset Offset in Stream, padded // to allow patching. -static void writePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, - uint64_t Offset) { - uint8_t Buffer[5]; - unsigned SizeLen = encodeULEB128(X, Buffer, 5); - assert(SizeLen == 5); +template void writePatchableLEB(raw_pwrite_stream &Stream, uint64_t X, + uint64_t Offset) { + uint8_t Buffer[W]; + unsigned SizeLen = encodeULEB128(X, Buffer, W); + assert(SizeLen == W); Stream.pwrite((char *)Buffer, SizeLen, Offset); } // Write X as an signed LEB value at offset Offset in Stream, padded // to allow patching. -static void writePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, - uint64_t Offset) { - uint8_t Buffer[5]; - unsigned SizeLen = encodeSLEB128(X, Buffer, 5); - assert(SizeLen == 5); +template void writePatchableSLEB(raw_pwrite_stream &Stream, int64_t X, + uint64_t Offset) { + uint8_t Buffer[W]; + unsigned SizeLen = encodeSLEB128(X, Buffer, W); + assert(SizeLen == W); Stream.pwrite((char *)Buffer, SizeLen, Offset); } @@ -210,6 +210,12 @@ Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); } +static void patchI64(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) { + uint8_t Buffer[8]; + support::endian::write64le(Buffer, X); + Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); +} + class WasmObjectWriter : public MCObjectWriter { support::endian::Writer W; @@ -347,7 +353,7 @@ updateCustomSectionRelocations(const SmallVector &Functions, const MCAsmLayout &Layout); - uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); + uint64_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef Relocations, uint64_t ContentsOffset); @@ -410,8 +416,8 @@ // Write the final section size to the payload_len field, which follows // the section id byte. - writePatchableLEB(static_cast(W.OS), Size, - Section.SizeOffset); + writePatchableLEB<5>(static_cast(W.OS), Size, + Section.SizeOffset); } // Emit the Wasm header. @@ -549,7 +555,7 @@ // by RelEntry. This value isn't used by the static linker; it just serves // to make the object format more readable and more likely to be directly // useable. -uint32_t +uint64_t WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { if ((RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB || RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_I32) && @@ -587,9 +593,13 @@ return Section.getSectionOffset() + RelEntry.Addend; } case wasm::R_WASM_MEMORY_ADDR_LEB: - case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_LEB64: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB64: case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: - case wasm::R_WASM_MEMORY_ADDR_SLEB: { + case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_I64: { // Provisional value is address of the global const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol); // For undefined symbols, use zero @@ -666,7 +676,7 @@ RelEntry.Offset; LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); - uint32_t Value = getProvisionalValue(RelEntry); + auto Value = getProvisionalValue(RelEntry); switch (RelEntry.Type) { case wasm::R_WASM_FUNCTION_INDEX_LEB: @@ -674,7 +684,10 @@ case wasm::R_WASM_GLOBAL_INDEX_LEB: case wasm::R_WASM_MEMORY_ADDR_LEB: case wasm::R_WASM_EVENT_INDEX_LEB: - writePatchableLEB(Stream, Value, Offset); + writePatchableLEB<5>(Stream, Value, Offset); + break; + case wasm::R_WASM_MEMORY_ADDR_LEB64: + writePatchableLEB<10>(Stream, Value, Offset); break; case wasm::R_WASM_TABLE_INDEX_I32: case wasm::R_WASM_MEMORY_ADDR_I32: @@ -683,11 +696,18 @@ case wasm::R_WASM_GLOBAL_INDEX_I32: patchI32(Stream, Value, Offset); break; + case wasm::R_WASM_MEMORY_ADDR_I64: + patchI64(Stream, Value, Offset); + break; case wasm::R_WASM_TABLE_INDEX_SLEB: case wasm::R_WASM_TABLE_INDEX_REL_SLEB: case wasm::R_WASM_MEMORY_ADDR_SLEB: case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: - writePatchableSLEB(Stream, Value, Offset); + writePatchableSLEB<5>(Stream, Value, Offset); + break; + case wasm::R_WASM_MEMORY_ADDR_SLEB64: + case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: + writePatchableSLEB<10>(Stream, Value, Offset); break; default: llvm_unreachable("invalid relocation type"); @@ -1420,9 +1440,8 @@ // For each data symbol, export it in the symtab as a reference to the // corresponding Wasm data segment. wasm::WasmDataReference Ref = wasm::WasmDataReference{ - DataSection.getSegmentIndex(), - static_cast(Layout.getSymbolOffset(WS)), - static_cast(Size)}; + DataSection.getSegmentIndex(), Layout.getSymbolOffset(WS), + static_cast(Size)}; DataLocations[&WS] = Ref; LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n"); diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp --- a/llvm/lib/Object/RelocationResolver.cpp +++ b/llvm/lib/Object/RelocationResolver.cpp @@ -485,14 +485,17 @@ llvm_unreachable("Invalid relocation type"); } -static bool supportsWasm32(uint64_t Type) { +static bool supportsWasm(uint64_t Type) { switch (Type) { case wasm::R_WASM_FUNCTION_INDEX_LEB: case wasm::R_WASM_TABLE_INDEX_SLEB: case wasm::R_WASM_TABLE_INDEX_I32: case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_LEB64: case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB64: case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_I64: case wasm::R_WASM_TYPE_INDEX_LEB: case wasm::R_WASM_GLOBAL_INDEX_LEB: case wasm::R_WASM_FUNCTION_OFFSET_I32: @@ -505,14 +508,17 @@ } } -static uint64_t resolveWasm32(RelocationRef R, uint64_t S, uint64_t A) { +static uint64_t resolveWasm(RelocationRef R, uint64_t S, uint64_t A) { switch (R.getType()) { case wasm::R_WASM_FUNCTION_INDEX_LEB: case wasm::R_WASM_TABLE_INDEX_SLEB: case wasm::R_WASM_TABLE_INDEX_I32: case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_LEB64: case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB64: case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_I64: case wasm::R_WASM_TYPE_INDEX_LEB: case wasm::R_WASM_GLOBAL_INDEX_LEB: case wasm::R_WASM_FUNCTION_OFFSET_I32: @@ -605,8 +611,8 @@ return {supportsMachOX86_64, resolveMachOX86_64}; return {nullptr, nullptr}; } else if (Obj.isWasm()) { - if (Obj.getArch() == Triple::wasm32) - return {supportsWasm32, resolveWasm32}; + if (Obj.getArch() == Triple::wasm32 || Obj.getArch() == Triple::wasm64) + return {supportsWasm, resolveWasm}; return {nullptr, nullptr}; } diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -156,6 +156,10 @@ return readLEB128(Ctx); } +static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) { + return readULEB128(Ctx); +} + static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) { return readUint8(Ctx); } @@ -166,8 +170,6 @@ switch (Expr.Opcode) { case wasm::WASM_OPCODE_I32_CONST: - Expr.Value.Int32 = readVarint32(Ctx); - break; case wasm::WASM_OPCODE_I64_CONST: Expr.Value.Int64 = readVarint64(Ctx); break; @@ -558,12 +560,12 @@ case wasm::WASM_SYMBOL_TYPE_DATA: Info.Name = readString(Ctx); if (IsDefined) { - uint32_t Index = readVaruint32(Ctx); + auto Index = readVaruint32(Ctx); if (Index >= DataSegments.size()) return make_error("invalid data symbol index", object_error::parse_failed); - uint32_t Offset = readVaruint32(Ctx); - uint32_t Size = readVaruint32(Ctx); + auto Offset = readVaruint64(Ctx); + auto Size = readVaruint64(Ctx); if (Offset + Size > DataSegments[Index].Data.Content.size()) return make_error("invalid data symbol offset", object_error::parse_failed); @@ -818,6 +820,15 @@ object_error::parse_failed); Reloc.Addend = readVarint32(Ctx); break; + case wasm::R_WASM_MEMORY_ADDR_LEB64: + case wasm::R_WASM_MEMORY_ADDR_SLEB64: + case wasm::R_WASM_MEMORY_ADDR_I64: + case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: + if (!isValidDataSymbol(Reloc.Index)) + return make_error("Bad relocation data index", + object_error::parse_failed); + Reloc.Addend = readVarint64(Ctx); + break; case wasm::R_WASM_FUNCTION_OFFSET_I32: if (!isValidFunctionSymbol(Reloc.Index)) return make_error("Bad relocation function index", @@ -840,12 +851,18 @@ // also shouldn't overlap a function/element boundary, but we don't bother // to check that. uint64_t Size = 5; + if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 || + Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 || + Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64) + Size = 10; if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 || Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 || Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 || Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 || Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32) Size = 4; + if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64) + Size = 8; if (Reloc.Offset + Size > EndOffset) return make_error("Bad relocation offset", object_error::parse_failed); @@ -1234,7 +1251,7 @@ return Err; } else { Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST; - Segment.Data.Offset.Value.Int32 = 0; + Segment.Data.Offset.Value.Int64 = 0; } uint32_t Size = readVaruint32(Ctx); if (Size > (size_t)(Ctx.End - Ctx.Ptr)) @@ -1332,7 +1349,7 @@ uint32_t SegmentIndex = Sym.Info.DataRef.Segment; const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data; assert(Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST); - return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset; + return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset; } case wasm::WASM_SYMBOL_TYPE_SECTION: return 0; diff --git a/llvm/lib/ObjectYAML/WasmEmitter.cpp b/llvm/lib/ObjectYAML/WasmEmitter.cpp --- a/llvm/lib/ObjectYAML/WasmEmitter.cpp +++ b/llvm/lib/ObjectYAML/WasmEmitter.cpp @@ -132,8 +132,6 @@ writeUint8(OS, InitExpr.Opcode); switch (InitExpr.Opcode) { case wasm::WASM_OPCODE_I32_CONST: - encodeSLEB128(InitExpr.Value.Int32, OS); - break; case wasm::WASM_OPCODE_I64_CONST: encodeSLEB128(InitExpr.Value.Int64, OS); break; @@ -532,8 +530,11 @@ encodeULEB128(Reloc.Index, OS); switch (Reloc.Type) { case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_LEB64: case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB64: case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_I64: case wasm::R_WASM_FUNCTION_OFFSET_I32: case wasm::R_WASM_SECTION_OFFSET_I32: encodeULEB128(Reloc.Addend, OS); diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -419,8 +419,6 @@ Expr.Opcode = Op; switch (Expr.Opcode) { case wasm::WASM_OPCODE_I32_CONST: - IO.mapRequired("Value", Expr.Value.Int32); - break; case wasm::WASM_OPCODE_I64_CONST: IO.mapRequired("Value", Expr.Value.Int64); break; @@ -449,7 +447,7 @@ IO.mapRequired("Offset", Segment.Offset); } else { Segment.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST; - Segment.Offset.Value.Int32 = 0; + Segment.Offset.Value.Int64 = 0; } IO.mapRequired("Content", Segment.Content); } 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 @@ -33,6 +33,11 @@ using namespace llvm; +// Defines llvm::WebAssembly::getWasm64Opcode to convert 32-bit instructions to +// 64-bit. +#define GET_INSTRMAP_INFO 1 +#include "WebAssemblyGenInstrInfo.inc" + #define DEBUG_TYPE "wasm-asm-parser" namespace { @@ -846,6 +851,21 @@ if (Op0.getImm() == -1) Op0.setImm(Align); } + if (getSTI().getTargetTriple().getArch() == Triple::ArchType::wasm64) { + // Upgrade 32-bit loads/stores to 64-bit. These mostly differ by having + // an offset64 arg instead of offset32, but to the assembler matcher + // they're both immediates so don't get selected for. + auto Opc64 = WebAssembly::getWasm64Opcode( + static_cast(Inst.getOpcode())); + if (Opc64 >= 0) { + Inst.setOpcode(Opc64); + /* + for (unsigned i = 0; i < Inst.getNumOperands(); i++) { + auto &Op = Inst.getOperand(i); + if (Op.) + }*/ + } + } Out.emitInstruction(Inst, getSTI()); if (CurrentState == EndFunction) { onEndOfFunction(); diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -163,6 +163,7 @@ break; case WebAssembly::OPERAND_OFFSET64: FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i64); + PaddedSize = 10; break; default: llvm_unreachable("unexpected symbolic operand kind"); diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -78,7 +78,8 @@ return wasm::R_WASM_TABLE_INDEX_REL_SLEB; case MCSymbolRefExpr::VK_WASM_MBREL: assert(SymA.isData()); - return wasm::R_WASM_MEMORY_ADDR_REL_SLEB; + return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_REL_SLEB64 + : wasm::R_WASM_MEMORY_ADDR_REL_SLEB; case MCSymbolRefExpr::VK_WASM_TYPEINDEX: return wasm::R_WASM_TYPE_INDEX_LEB; default: @@ -87,12 +88,13 @@ switch (unsigned(Fixup.getKind())) { case WebAssembly::fixup_sleb128_i32: - case WebAssembly::fixup_sleb128_i64: if (SymA.isFunction()) return wasm::R_WASM_TABLE_INDEX_SLEB; return wasm::R_WASM_MEMORY_ADDR_SLEB; + case WebAssembly::fixup_sleb128_i64: + assert(SymA.isData()); + return wasm::R_WASM_MEMORY_ADDR_SLEB64; case WebAssembly::fixup_uleb128_i32: - case WebAssembly::fixup_uleb128_i64: if (SymA.isGlobal()) return wasm::R_WASM_GLOBAL_INDEX_LEB; if (SymA.isFunction()) @@ -100,6 +102,9 @@ if (SymA.isEvent()) return wasm::R_WASM_EVENT_INDEX_LEB; return wasm::R_WASM_MEMORY_ADDR_LEB; + case WebAssembly::fixup_uleb128_i64: + assert(SymA.isData()); + return wasm::R_WASM_MEMORY_ADDR_LEB64; case FK_Data_4: if (SymA.isFunction()) return wasm::R_WASM_TABLE_INDEX_I32; @@ -113,6 +118,9 @@ return wasm::R_WASM_SECTION_OFFSET_I32; } return wasm::R_WASM_MEMORY_ADDR_I32; + case FK_Data_8: + assert(SymA.isData()); + return wasm::R_WASM_MEMORY_ADDR_I64; default: llvm_unreachable("unimplemented fixup kind"); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td @@ -14,9 +14,9 @@ let UseNamedOperandTable = 1 in multiclass ATOMIC_I pattern_r, string asmstr_r = "", - string asmstr_s = "", bits<32> atomic_op = -1> { + string asmstr_s = "", bits<32> atomic_op = -1, string is64 = "false"> { defm "" : I, + !or(0xfe00, !and(0xff, atomic_op)), is64>, Requires<[HasAtomics]>; } @@ -37,13 +37,13 @@ (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count), (outs), (ins P2Align:$p2align, offset32_op:$off), [], "atomic.notify \t$dst, ${off}(${addr})${p2align}, $count", - "atomic.notify \t${off}${p2align}", 0x00>; + "atomic.notify \t${off}${p2align}", 0x00, "false">; defm ATOMIC_NOTIFY_A64 : ATOMIC_I<(outs I32:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$count), (outs), (ins P2Align:$p2align, offset64_op:$off), [], "atomic.notify \t$dst, ${off}(${addr})${p2align}, $count", - "atomic.notify \t${off}${p2align}", 0x00>; + "atomic.notify \t${off}${p2align}", 0x00, "true">; let mayLoad = 1 in { defm ATOMIC_WAIT_I32_A32 : ATOMIC_I<(outs I32:$dst), @@ -51,28 +51,28 @@ I64:$timeout), (outs), (ins P2Align:$p2align, offset32_op:$off), [], "i32.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout", - "i32.atomic.wait \t${off}${p2align}", 0x01>; + "i32.atomic.wait \t${off}${p2align}", 0x01, "false">; defm ATOMIC_WAIT_I32_A64 : ATOMIC_I<(outs I32:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$exp, I64:$timeout), (outs), (ins P2Align:$p2align, offset64_op:$off), [], "i32.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout", - "i32.atomic.wait \t${off}${p2align}", 0x01>; + "i32.atomic.wait \t${off}${p2align}", 0x01, "true">; defm ATOMIC_WAIT_I64_A32 : ATOMIC_I<(outs I32:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp, I64:$timeout), (outs), (ins P2Align:$p2align, offset32_op:$off), [], "i64.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout", - "i64.atomic.wait \t${off}${p2align}", 0x02>; + "i64.atomic.wait \t${off}${p2align}", 0x02, "false">; defm ATOMIC_WAIT_I64_A64 : ATOMIC_I<(outs I32:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I64:$exp, I64:$timeout), (outs), (ins P2Align:$p2align, offset64_op:$off), [], "i64.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout", - "i64.atomic.wait \t${off}${p2align}", 0x02>; + "i64.atomic.wait \t${off}${p2align}", 0x02, "true">; } // mayLoad = 1 } // hasSideEffects = 1 @@ -318,8 +318,8 @@ //===----------------------------------------------------------------------===// multiclass AtomicStore { - defm "" : WebAssemblyStore, - Requires<[HasAtomics]>; + defm "" : WebAssemblyStore; } defm ATOMIC_STORE_I32 : AtomicStore; @@ -460,13 +460,13 @@ (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val), (outs), (ins P2Align:$p2align, offset32_op:$off), [], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"), - !strconcat(name, "\t${off}${p2align}"), atomic_op>; + !strconcat(name, "\t${off}${p2align}"), atomic_op, "false">; defm "_A64" : ATOMIC_I<(outs rc:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val), (outs), (ins P2Align:$p2align, offset64_op:$off), [], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"), - !strconcat(name, "\t${off}${p2align}"), atomic_op>; + !strconcat(name, "\t${off}${p2align}"), atomic_op, "true">; } defm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW; @@ -754,14 +754,14 @@ rc:$new_), (outs), (ins P2Align:$p2align, offset32_op:$off), [], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"), - !strconcat(name, "\t${off}${p2align}"), atomic_op>; + !strconcat(name, "\t${off}${p2align}"), atomic_op, "false">; defm "_A64" : ATOMIC_I<(outs rc:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$exp, rc:$new_), (outs), (ins P2Align:$p2align, offset64_op:$off), [], !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"), - !strconcat(name, "\t${off}${p2align}"), atomic_op>; + !strconcat(name, "\t${off}${p2align}"), atomic_op, "true">; } defm ATOMIC_RMW_CMPXCHG_I32 : diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td @@ -14,11 +14,13 @@ // WebAssembly Instruction Format. // We instantiate 2 of these for every actual instruction (register based // and stack based), see below. -class WebAssemblyInst inst, string asmstr, string stack> : StackRel, - Instruction { +class WebAssemblyInst inst, string asmstr, string stack, string is64> + : StackRel, Wasm64Rel, Instruction { bits<32> Inst = inst; // Instruction encoding. string StackBased = stack; string BaseName = NAME; + string IsWasm64 = is64; + string Wasm32Name = !subst("_A64", "_A32", NAME); let Namespace = "WebAssembly"; let Pattern = []; let AsmString = asmstr; @@ -29,8 +31,8 @@ // Normal instructions. Default instantiation of a WebAssemblyInst. class NI pattern, string stack, - string asmstr = "", bits<32> inst = -1> - : WebAssemblyInst { + string asmstr = "", bits<32> inst = -1, string is64 = "false"> + : WebAssemblyInst { dag OutOperandList = oops; dag InOperandList = iops; let Pattern = pattern; @@ -52,11 +54,11 @@ // there is always an equivalent pair of instructions. multiclass I pattern_r, string asmstr_r = "", string asmstr_s = "", - bits<32> inst = -1> { + bits<32> inst = -1, string is64 = "false"> { let isCodeGenOnly = 1 in - def "" : NI; + def "" : NI; let BaseName = NAME in - def _S : NI; + def _S : NI; } // For instructions that have no register ops, so both sets are the same. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -202,6 +202,19 @@ let ValueCols = [["true"]]; } +//===----------------------------------------------------------------------===// +// WebAssembly 32 to 64-bit instruction mapping +//===----------------------------------------------------------------------===// + +class Wasm64Rel; +def getWasm64Opcode : InstrMapping { + let FilterClass = "Wasm64Rel"; + let RowFields = ["Wasm32Name"]; + let ColFields = ["IsWasm64"]; + let KeyCol = ["false"]; + let ValueCols = [["true"]]; +} + //===----------------------------------------------------------------------===// // WebAssembly Instruction Format Definitions. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td @@ -41,19 +41,19 @@ // Defines atomic and non-atomic loads, regular and extending. multiclass WebAssemblyLoad reqs> { + list reqs = []> { let mayLoad = 1, UseNamedOperandTable = 1 in { defm "_A32": I<(outs rc:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr), (outs), (ins P2Align:$p2align, offset32_op:$off), [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"), - !strconcat(Name, "\t${off}${p2align}"), Opcode>, - Requires; + !strconcat(Name, "\t${off}${p2align}"), Opcode, "false">, + Requires; defm "_A64": I<(outs rc:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr), (outs), (ins P2Align:$p2align, offset64_op:$off), [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"), - !strconcat(Name, "\t${off}${p2align}"), Opcode>, + !strconcat(Name, "\t${off}${p2align}"), Opcode, "true">, Requires; } } @@ -230,21 +230,24 @@ defm : LoadPatGlobalAddrOffOnly; // Defines atomic and non-atomic stores, regular and truncating -multiclass WebAssemblyStore { +multiclass WebAssemblyStore reqs = []> { let mayStore = 1, UseNamedOperandTable = 1 in defm "_A32" : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val), (outs), (ins P2Align:$p2align, offset32_op:$off), [], !strconcat(Name, "\t${off}(${addr})${p2align}, $val"), - !strconcat(Name, "\t${off}${p2align}"), Opcode>; + !strconcat(Name, "\t${off}${p2align}"), Opcode, "false">, + Requires; let mayStore = 1, UseNamedOperandTable = 1 in defm "_A64" : I<(outs), (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val), (outs), (ins P2Align:$p2align, offset64_op:$off), [], !strconcat(Name, "\t${off}(${addr})${p2align}, $val"), - !strconcat(Name, "\t${off}${p2align}"), Opcode>; + !strconcat(Name, "\t${off}${p2align}"), Opcode, "true">, + Requires; } // Basic store. diff --git a/llvm/test/MC/WebAssembly/wasm64.s b/llvm/test/MC/WebAssembly/wasm64.s --- a/llvm/test/MC/WebAssembly/wasm64.s +++ b/llvm/test/MC/WebAssembly/wasm64.s @@ -1,6 +1,5 @@ # RUN: llvm-mc -triple=wasm64-unknown-unknown -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s -# Check that it converts to .o without errors, but don't check any output: -# RUN: llvm-mc -triple=wasm64-unknown-unknown -filetype=obj -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s +# RUN: llvm-mc -triple=wasm64-unknown-unknown -filetype=obj -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling -o - < %s | obj2yaml | FileCheck %s -check-prefix=BIN # Most of our other tests are for wasm32, this one adds some wasm64 specific tests. @@ -18,14 +17,18 @@ f32.load 0 drop -# i64.const .L.str # get i64 relocatable. -# f32.load 0 -# drop + i64.const .L.str # get i64 relocatable. + f32.load 0 + drop global.get myglob64 # get i64 from global f32.load 0 drop + i64.const 0 + f32.load .L.str # relocatable offset! + drop + ### basic stores f32.const 0.0 @@ -36,21 +39,27 @@ local.get 0 # get i64 from local. f32.store 0 -# f32.const 0.0 -# i64.const .L.str # get i64 relocatable. -# f32.store 0 + f32.const 0.0 + i64.const .L.str # get i64 relocatable. + f32.store 0 f32.const 0.0 global.get myglob64 # get i64 from global f32.store 0 + f32.const 0.0 + i64.const 0 + f32.store .L.str # relocatable offset! + end_function .section .rodata..L.str,"",@ .hidden .L.str .type .L.str,@object .L.str: - .asciz "Hello, World!" + .asciz "Hello, World!!!" + .int64 .L.str # relocatable inside data. + .size .L.str, 24 .globaltype myglob64, i64 @@ -68,14 +77,18 @@ # CHECK-NEXT: f32.load 0 # CHECK-NEXT: drop -# NCHECK: i64.const .L.str -# NCHECK-NEXT: f32.load 0 -# NCHECK-NEXT: drop +# CHECK: i64.const .L.str +# CHECK-NEXT: f32.load 0 +# CHECK-NEXT: drop # CHECK: global.get myglob64 # CHECK-NEXT: f32.load 0 # CHECK-NEXT: drop +# CHECK: i64.const 0 +# CHECK-NEXT: f32.load .L.str +# CHECK-NEXT: drop + # CHECK: f32.const 0x0p0 # CHECK-NEXT: i64.const 0 @@ -85,14 +98,18 @@ # CHECK-NEXT: local.get 0 # CHECK-NEXT: f32.store 0 -# NCHECK: f32.const 0x0p0 -# NCHECK-NEXT: i64.const .L.str -# NCHECK-NEXT: f32.store 0 +# CHECK: f32.const 0x0p0 +# CHECK-NEXT: i64.const .L.str +# CHECK-NEXT: f32.store 0 # CHECK: f32.const 0x0p0 # CHECK-NEXT: global.get myglob64 # CHECK-NEXT: f32.store 0 +# CHECK: f32.const 0x0p0 +# CHECK-NEXT: i64.const 0 +# CHECK-NEXT: f32.store .L.str + # CHECK: end_function # CHECK-NEXT: .Ltmp0: @@ -101,6 +118,108 @@ # CHECK: .section .rodata..L.str,"",@ # CHECK-NEXT: .hidden .L.str # CHECK-NEXT: .L.str: -# CHECK-NEXT: .asciz "Hello, World!" +# CHECK-NEXT: .asciz "Hello, World!!!" +# CHECK-NEXT: .int64 .L.str +# CHECK-NEXT: .size .L.str, 24 # CHECK: .globaltype myglob64, i64 + + + +# BIN: --- !WASM +# BIN-NEXT: FileHeader: +# BIN-NEXT: Version: 0x00000001 +# BIN-NEXT: Sections: +# BIN-NEXT: - Type: TYPE +# BIN-NEXT: Signatures: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: ParamTypes: +# BIN-NEXT: - I64 +# BIN-NEXT: ReturnTypes: [] +# BIN-NEXT: - Type: IMPORT +# BIN-NEXT: Imports: +# BIN-NEXT: - Module: env +# BIN-NEXT: Field: __linear_memory +# BIN-NEXT: Kind: MEMORY +# BIN-NEXT: Memory: +# BIN-NEXT: Initial: 0x00000001 +# BIN-NEXT: - Module: env +# BIN-NEXT: Field: __indirect_function_table +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Table: +# BIN-NEXT: ElemType: FUNCREF +# BIN-NEXT: Limits: +# BIN-NEXT: Initial: 0x00000000 +# BIN-NEXT: - Module: env +# BIN-NEXT: Field: myglob64 +# BIN-NEXT: Kind: GLOBAL +# BIN-NEXT: GlobalType: I64 +# BIN-NEXT: GlobalMutable: true +# BIN-NEXT: - Type: FUNCTION +# BIN-NEXT: FunctionTypes: [ 0 ] +# BIN-NEXT: - Type: DATACOUNT +# BIN-NEXT: Count: 1 +# BIN-NEXT: - Type: CODE +# BIN-NEXT: Relocations: +# BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB64 +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x00000013 +# BIN-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB +# BIN-NEXT: Index: 2 +# BIN-NEXT: Offset: 0x00000022 +# BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB64 +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x0000002F +# BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB64 +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x00000054 +# BIN-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB +# BIN-NEXT: Index: 2 +# BIN-NEXT: Offset: 0x00000067 +# BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB64 +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x00000078 +# BIN-NEXT: Functions: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Locals: +# BIN-NEXT: - Type: I64 +# BIN-NEXT: Count: 1 +# BIN-NEXT: Body: 42002A02001A20002A02001A42808080808080808080002A02001A2380808080002A02001A42002A02808080808080808080001A4300000000420038020043000000002000380200430000000042808080808080808080003802004300000000238080808000380200430000000042003802808080808080808080000B +# BIN-NEXT: - Type: DATA +# BIN-NEXT: Relocations: +# BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_I64 +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x00000016 +# BIN-NEXT: Segments: +# BIN-NEXT: - SectionOffset: 6 +# BIN-NEXT: InitFlags: 0 +# BIN-NEXT: Offset: +# BIN-NEXT: Opcode: I32_CONST +# BIN-NEXT: Value: 0 +# BIN-NEXT: Content: 48656C6C6F2C20576F726C64212121000000000000000000 +# BIN-NEXT: - Type: CUSTOM +# BIN-NEXT: Name: linking +# BIN-NEXT: Version: 2 +# BIN-NEXT: SymbolTable: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Kind: FUNCTION +# BIN-NEXT: Name: test +# BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Function: 0 +# BIN-NEXT: - Index: 1 +# BIN-NEXT: Kind: DATA +# BIN-NEXT: Name: .L.str +# BIN-NEXT: Flags: [ BINDING_LOCAL, VISIBILITY_HIDDEN ] +# BIN-NEXT: Segment: 0 +# BIN-NEXT: Size: 24 +# BIN-NEXT: - Index: 2 +# BIN-NEXT: Kind: GLOBAL +# BIN-NEXT: Name: myglob64 +# BIN-NEXT: Flags: [ UNDEFINED ] +# BIN-NEXT: Global: 0 +# BIN-NEXT: SegmentInfo: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Name: .rodata..L.str +# BIN-NEXT: Alignment: 0 +# BIN-NEXT: Flags: [ ] +# BIN-NEXT: ... diff --git a/llvm/tools/llvm-readobj/WasmDumper.cpp b/llvm/tools/llvm-readobj/WasmDumper.cpp --- a/llvm/tools/llvm-readobj/WasmDumper.cpp +++ b/llvm/tools/llvm-readobj/WasmDumper.cpp @@ -181,7 +181,7 @@ W.printString("Name", Seg.Name); W.printNumber("Size", static_cast(Seg.Content.size())); if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) - W.printNumber("Offset", Seg.Offset.Value.Int32); + W.printNumber("Offset", Seg.Offset.Value.Int64); } break; }