mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[WebAssembly] Adding 64-bit version of R_WASM_MEMORY_ADDR_* relocs
This adds 4 new reloc types. A lot of code that previously assumed any memory or offset values could be contained in a uint32_t (and often truncated results from functions returning 64-bit values) have been upgraded to uint64_t. This is not comprehensive: it is only the values that come in contact with the new relocation values and their dependents. A new tablegen mapping was added to automatically upgrade loads/stores in the assembler, which otherwise has no way to select for these instructions (since they are indentical other than for the offset immediate). It follows a similar technique to https://reviews.llvm.org/D53307 Differential Revision: https://reviews.llvm.org/D81704
This commit is contained in:
parent
0fa32417a7
commit
2eaa4e6cf6
@ -159,8 +159,8 @@ struct WasmElemSegment {
|
||||
// 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 {
|
||||
|
@ -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)
|
||||
|
@ -107,8 +107,10 @@ struct Function {
|
||||
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 {
|
||||
|
@ -39,9 +39,13 @@ std::string llvm::wasm::relocTypetoString(uint32_t Type) {
|
||||
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;
|
||||
|
@ -185,21 +185,21 @@ raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
|
||||
|
||||
// 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 <int W>
|
||||
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 <int W>
|
||||
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 @@ static void patchI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
|
||||
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 @@ private:
|
||||
updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions,
|
||||
const MCAsmLayout &Layout);
|
||||
|
||||
uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
|
||||
uint64_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
|
||||
void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
|
||||
uint64_t ContentsOffset);
|
||||
|
||||
@ -410,8 +416,8 @@ void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
|
||||
|
||||
// Write the final section size to the payload_len field, which follows
|
||||
// the section id byte.
|
||||
writePatchableLEB(static_cast<raw_pwrite_stream &>(W.OS), Size,
|
||||
Section.SizeOffset);
|
||||
writePatchableLEB<5>(static_cast<raw_pwrite_stream &>(W.OS), Size,
|
||||
Section.SizeOffset);
|
||||
}
|
||||
|
||||
// Emit the Wasm header.
|
||||
@ -549,7 +555,7 @@ static const MCSymbolWasm *resolveSymbol(const MCSymbolWasm &Symbol) {
|
||||
// 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 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
|
||||
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 @@ void WasmObjectWriter::applyRelocations(
|
||||
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 @@ void WasmObjectWriter::applyRelocations(
|
||||
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 @@ void WasmObjectWriter::applyRelocations(
|
||||
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 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
// 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<uint32_t>(Layout.getSymbolOffset(WS)),
|
||||
static_cast<uint32_t>(Size)};
|
||||
DataSection.getSegmentIndex(), Layout.getSymbolOffset(WS),
|
||||
static_cast<uint64_t>(Size)};
|
||||
DataLocations[&WS] = Ref;
|
||||
LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n");
|
||||
|
||||
|
@ -505,6 +505,17 @@ static bool supportsWasm32(uint64_t Type) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool supportsWasm64(uint64_t Type) {
|
||||
switch (Type) {
|
||||
case wasm::R_WASM_MEMORY_ADDR_LEB64:
|
||||
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
|
||||
case wasm::R_WASM_MEMORY_ADDR_I64:
|
||||
return true;
|
||||
default:
|
||||
return supportsWasm32(Type);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t resolveWasm32(RelocationRef R, uint64_t S, uint64_t A) {
|
||||
switch (R.getType()) {
|
||||
case wasm::R_WASM_FUNCTION_INDEX_LEB:
|
||||
@ -526,6 +537,18 @@ static uint64_t resolveWasm32(RelocationRef R, uint64_t S, uint64_t A) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t resolveWasm64(RelocationRef R, uint64_t S, uint64_t A) {
|
||||
switch (R.getType()) {
|
||||
case wasm::R_WASM_MEMORY_ADDR_LEB64:
|
||||
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
|
||||
case wasm::R_WASM_MEMORY_ADDR_I64:
|
||||
// For wasm section, its offset at 0 -- ignoring Value
|
||||
return A;
|
||||
default:
|
||||
return resolveWasm32(R, S, A);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool (*)(uint64_t), RelocationResolver>
|
||||
getRelocationResolver(const ObjectFile &Obj) {
|
||||
if (Obj.isCOFF()) {
|
||||
@ -607,6 +630,8 @@ getRelocationResolver(const ObjectFile &Obj) {
|
||||
} else if (Obj.isWasm()) {
|
||||
if (Obj.getArch() == Triple::wasm32)
|
||||
return {supportsWasm32, resolveWasm32};
|
||||
if (Obj.getArch() == Triple::wasm64)
|
||||
return {supportsWasm64, resolveWasm64};
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
|
@ -156,6 +156,10 @@ static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
|
||||
return readLEB128(Ctx);
|
||||
}
|
||||
|
||||
static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
|
||||
return readULEB128(Ctx);
|
||||
}
|
||||
|
||||
static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
|
||||
return readUint8(Ctx);
|
||||
}
|
||||
@ -558,12 +562,12 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
|
||||
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<GenericBinaryError>("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<GenericBinaryError>("invalid data symbol offset",
|
||||
object_error::parse_failed);
|
||||
@ -818,6 +822,15 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
|
||||
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<GenericBinaryError>("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<GenericBinaryError>("Bad relocation function index",
|
||||
@ -840,12 +853,18 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
|
||||
// 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<GenericBinaryError>("Bad relocation offset",
|
||||
object_error::parse_failed);
|
||||
@ -1331,8 +1350,13 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
|
||||
// offset within the segment.
|
||||
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;
|
||||
if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) {
|
||||
return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
|
||||
} else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) {
|
||||
return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset;
|
||||
} else {
|
||||
llvm_unreachable("unknown init expr opcode");
|
||||
}
|
||||
}
|
||||
case wasm::WASM_SYMBOL_TYPE_SECTION:
|
||||
return 0;
|
||||
|
@ -532,8 +532,11 @@ void WasmWriter::writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec,
|
||||
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);
|
||||
|
@ -846,6 +846,16 @@ public:
|
||||
if (Op0.getImm() == -1)
|
||||
Op0.setImm(Align);
|
||||
}
|
||||
if (getSTI().getTargetTriple().isArch64Bit()) {
|
||||
// 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<uint16_t>(Inst.getOpcode()));
|
||||
if (Opc64 >= 0) {
|
||||
Inst.setOpcode(Opc64);
|
||||
}
|
||||
}
|
||||
Out.emitInstruction(Inst, getSTI());
|
||||
if (CurrentState == EndFunction) {
|
||||
onEndOfFunction();
|
||||
|
@ -101,9 +101,6 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
|
||||
case WebAssembly::OPERAND_I64IMM:
|
||||
encodeSLEB128(int64_t(MO.getImm()), OS);
|
||||
break;
|
||||
case WebAssembly::OPERAND_OFFSET64:
|
||||
encodeULEB128(uint64_t(MO.getImm()), OS);
|
||||
break;
|
||||
case WebAssembly::OPERAND_SIGNATURE:
|
||||
OS << uint8_t(MO.getImm());
|
||||
break;
|
||||
@ -163,6 +160,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
|
||||
break;
|
||||
case WebAssembly::OPERAND_OFFSET64:
|
||||
FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i64);
|
||||
PaddedSize = 10;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected symbolic operand kind");
|
||||
|
@ -78,7 +78,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
|
||||
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 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
|
||||
|
||||
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 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
|
||||
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 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
|
||||
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");
|
||||
}
|
||||
|
@ -32,3 +32,9 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTargetInfo() {
|
||||
RegisterTarget<Triple::wasm64> Y(getTheWebAssemblyTarget64(), "wasm64",
|
||||
"WebAssembly 64-bit", "WebAssembly");
|
||||
}
|
||||
|
||||
// Defines llvm::WebAssembly::getWasm64Opcode llvm::WebAssembly::getStackOpcode
|
||||
// which have to be in a shared location between CodeGen and MC.
|
||||
#define GET_INSTRMAP_INFO 1
|
||||
#define GET_INSTRINFO_ENUM 1
|
||||
#include "WebAssemblyGenInstrInfo.inc"
|
||||
|
@ -21,6 +21,13 @@ class Target;
|
||||
Target &getTheWebAssemblyTarget32();
|
||||
Target &getTheWebAssemblyTarget64();
|
||||
|
||||
namespace WebAssembly {
|
||||
|
||||
int getStackOpcode(unsigned short Opcode);
|
||||
int getWasm64Opcode(unsigned short Opcode);
|
||||
|
||||
} // namespace WebAssembly
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_LIB_TARGET_WEBASSEMBLY_TARGETINFO_WEBASSEMBLYTARGETINFO_H
|
||||
|
@ -14,9 +14,10 @@
|
||||
let UseNamedOperandTable = 1 in
|
||||
multiclass ATOMIC_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
|
||||
list<dag> pattern_r, string asmstr_r,
|
||||
string asmstr_s, bits<32> atomic_op> {
|
||||
string asmstr_s, bits<32> atomic_op,
|
||||
string is64 = "false"> {
|
||||
defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s,
|
||||
!or(0xfe00, !and(0xff, atomic_op))>,
|
||||
!or(0xfe00, !and(0xff, atomic_op)), is64>,
|
||||
Requires<[HasAtomics]>;
|
||||
}
|
||||
|
||||
@ -37,13 +38,13 @@ defm ATOMIC_NOTIFY_A32 :
|
||||
(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 +52,28 @@ defm ATOMIC_WAIT_I32_A32 :
|
||||
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
|
||||
|
||||
@ -350,8 +351,8 @@ defm : LoadPatGlobalAddrOffOnly<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
multiclass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
|
||||
defm "" : WebAssemblyStore<rc, name, !or(0xfe00, !and(0xff, atomic_op))>,
|
||||
Requires<[HasAtomics]>;
|
||||
defm "" : WebAssemblyStore<rc, name, !or(0xfe00, !and(0xff, atomic_op)),
|
||||
[HasAtomics]>;
|
||||
}
|
||||
|
||||
defm ATOMIC_STORE_I32 : AtomicStore<I32, "i32.atomic.store", 0x17>;
|
||||
@ -486,13 +487,13 @@ multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
|
||||
(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<I32, "i32.atomic.rmw.add", 0x1e>;
|
||||
@ -797,14 +798,14 @@ multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
|
||||
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 :
|
||||
|
@ -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<bits<32> inst, string asmstr, string stack> : StackRel,
|
||||
Instruction {
|
||||
class WebAssemblyInst<bits<32> 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 @@ class WebAssemblyInst<bits<32> inst, string asmstr, string stack> : StackRel,
|
||||
|
||||
// Normal instructions. Default instantiation of a WebAssemblyInst.
|
||||
class NI<dag oops, dag iops, list<dag> pattern, string stack,
|
||||
string asmstr = "", bits<32> inst = -1>
|
||||
: WebAssemblyInst<inst, asmstr, stack> {
|
||||
string asmstr = "", bits<32> inst = -1, string is64 = "false">
|
||||
: WebAssemblyInst<inst, asmstr, stack, is64> {
|
||||
dag OutOperandList = oops;
|
||||
dag InOperandList = iops;
|
||||
let Pattern = pattern;
|
||||
@ -52,11 +54,11 @@ class NI<dag oops, dag iops, list<dag> pattern, string stack,
|
||||
// there is always an equivalent pair of instructions.
|
||||
multiclass I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
|
||||
list<dag> 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<oops_r, iops_r, pattern_r, "false", asmstr_r, inst>;
|
||||
def "" : NI<oops_r, iops_r, pattern_r, "false", asmstr_r, inst, is64>;
|
||||
let BaseName = NAME in
|
||||
def _S : NI<oops_s, iops_s, [], "true", asmstr_s, inst>;
|
||||
def _S : NI<oops_s, iops_s, [], "true", asmstr_s, inst, is64>;
|
||||
}
|
||||
|
||||
// For instructions that have no register ops, so both sets are the same.
|
||||
|
@ -202,6 +202,19 @@ def getStackOpcode : InstrMapping {
|
||||
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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -41,19 +41,19 @@ def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
|
||||
|
||||
// Defines atomic and non-atomic loads, regular and extending.
|
||||
multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode,
|
||||
list<Predicate> reqs> {
|
||||
list<Predicate> 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>,
|
||||
!strconcat(Name, "\t${off}${p2align}"), Opcode, "false">,
|
||||
Requires<reqs>;
|
||||
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<reqs>;
|
||||
}
|
||||
}
|
||||
@ -236,21 +236,24 @@ defm : LoadPatGlobalAddrOffOnly<i64, extloadi16, "LOAD16_U_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, extloadi32, "LOAD32_U_I64">;
|
||||
|
||||
// Defines atomic and non-atomic stores, regular and truncating
|
||||
multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> {
|
||||
multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode,
|
||||
list<Predicate> 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<reqs>;
|
||||
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<reqs>;
|
||||
}
|
||||
|
||||
// Basic store.
|
||||
|
@ -13,10 +13,11 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "WebAssemblyMCInstLower.h"
|
||||
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
||||
#include "TargetInfo/WebAssemblyTargetInfo.h"
|
||||
#include "WebAssemblyAsmPrinter.h"
|
||||
#include "WebAssemblyMachineFunctionInfo.h"
|
||||
#include "WebAssemblyRuntimeLibcallSignatures.h"
|
||||
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
@ -29,11 +30,6 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
// Defines llvm::WebAssembly::getStackOpcode to convert register instructions to
|
||||
// stack instructions
|
||||
#define GET_INSTRMAP_INFO 1
|
||||
#include "WebAssemblyGenInstrInfo.inc"
|
||||
|
||||
// This disables the removal of registers when lowering into MC, as required
|
||||
// by some current tests.
|
||||
cl::opt<bool>
|
||||
|
@ -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 @@ test:
|
||||
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 @@ test:
|
||||
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 @@ test:
|
||||
# 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 @@ test:
|
||||
# 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 @@ test:
|
||||
# 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: ...
|
||||
|
@ -182,6 +182,10 @@ void WasmDumper::printSectionHeaders() {
|
||||
W.printNumber("Size", static_cast<uint64_t>(Seg.Content.size()));
|
||||
if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST)
|
||||
W.printNumber("Offset", Seg.Offset.Value.Int32);
|
||||
else if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST)
|
||||
W.printNumber("Offset", Seg.Offset.Value.Int64);
|
||||
else
|
||||
llvm_unreachable("unknown init expr opcode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user