[lld] cc1b9b6 - [WebAssembly] 64-bit (function) pointer fixes.
Wouter van Oortmerssen via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 14:10:36 PDT 2020
Author: Wouter van Oortmerssen
Date: 2020-07-16T14:10:22-07:00
New Revision: cc1b9b680f890962cbc3e1eec32a352c3c20849e
URL: https://github.com/llvm/llvm-project/commit/cc1b9b680f890962cbc3e1eec32a352c3c20849e
DIFF: https://github.com/llvm/llvm-project/commit/cc1b9b680f890962cbc3e1eec32a352c3c20849e.diff
LOG: [WebAssembly] 64-bit (function) pointer fixes.
Accounting for the fact that Wasm function indices are 32-bit, but in wasm64 we want uniform 64-bit pointers.
Includes reloc types for 64-bit table indices.
Differential Revision: https://reviews.llvm.org/D83729
Added:
llvm/test/CodeGen/WebAssembly/function-pointer64.ll
Modified:
lld/wasm/InputChunks.cpp
lld/wasm/InputFiles.cpp
lld/wasm/MarkLive.cpp
lld/wasm/Relocations.cpp
llvm/include/llvm/BinaryFormat/WasmRelocs.def
llvm/lib/MC/WasmObjectWriter.cpp
llvm/lib/Object/RelocationResolver.cpp
llvm/lib/Object/WasmObjectFile.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
Removed:
################################################################################
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index e28dc5113410..c7261cf3da2c 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -72,6 +72,7 @@ void InputChunk::verifyRelocTargets() const {
existingValue = decodeULEB128(loc, &bytesRead);
break;
case R_WASM_TABLE_INDEX_SLEB:
+ case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_TABLE_INDEX_REL_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_SLEB64:
@@ -86,6 +87,7 @@ void InputChunk::verifyRelocTargets() const {
case R_WASM_GLOBAL_INDEX_I32:
existingValue = read32le(loc);
break;
+ case R_WASM_TABLE_INDEX_I64:
case R_WASM_MEMORY_ADDR_I64:
existingValue = read64le(loc);
break;
@@ -151,6 +153,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
case R_WASM_MEMORY_ADDR_REL_SLEB:
encodeSLEB128(static_cast<int32_t>(value), loc, 5);
break;
+ case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_MEMORY_ADDR_SLEB64:
case R_WASM_MEMORY_ADDR_REL_SLEB64:
encodeSLEB128(static_cast<int64_t>(value), loc, 10);
@@ -162,6 +165,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
case R_WASM_GLOBAL_INDEX_I32:
write32le(loc, value);
break;
+ case R_WASM_TABLE_INDEX_I64:
case R_WASM_MEMORY_ADDR_I64:
write64le(loc, value);
break;
@@ -219,6 +223,7 @@ static unsigned writeCompressedReloc(uint8_t *buf, const WasmRelocation &rel,
case R_WASM_MEMORY_ADDR_LEB64:
return encodeULEB128(value, buf);
case R_WASM_TABLE_INDEX_SLEB:
+ case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_SLEB64:
return encodeSLEB128(static_cast<int64_t>(value), buf);
@@ -237,6 +242,7 @@ static unsigned getRelocWidthPadded(const WasmRelocation &rel) {
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
return 5;
+ case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_MEMORY_ADDR_LEB64:
case R_WASM_MEMORY_ADDR_SLEB64:
return 10;
@@ -382,7 +388,8 @@ void InputSegment::generateRelocationCode(raw_ostream &os) const {
}
} else {
const GlobalSymbol* baseSymbol = WasmSym::memoryBase;
- if (rel.Type == R_WASM_TABLE_INDEX_I32)
+ if (rel.Type == R_WASM_TABLE_INDEX_I32 ||
+ rel.Type == R_WASM_TABLE_INDEX_I64)
baseSymbol = WasmSym::tableBase;
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 8c2b70fe2849..fbe6888355ea 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -126,7 +126,9 @@ uint64_t ObjFile::calcNewAddend(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: {
+ case R_WASM_TABLE_INDEX_I64:
+ case R_WASM_TABLE_INDEX_SLEB:
+ case R_WASM_TABLE_INDEX_SLEB64: {
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
return tableEntries[sym.Info.ElementIndex];
}
@@ -195,7 +197,9 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc) const {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
+ case R_WASM_TABLE_INDEX_I64:
case R_WASM_TABLE_INDEX_SLEB:
+ case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_TABLE_INDEX_REL_SLEB: {
if (!getFunctionSymbol(reloc.Index)->hasTableIndex())
return 0;
diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp
index 6906f86f7150..2764c88f492c 100644
--- a/lld/wasm/MarkLive.cpp
+++ b/lld/wasm/MarkLive.cpp
@@ -122,7 +122,9 @@ void MarkLive::mark() {
// functions used for weak-undefined symbols have this behaviour (compare
// equal to null pointer, only reachable via direct call).
if (reloc.Type == R_WASM_TABLE_INDEX_SLEB ||
- reloc.Type == R_WASM_TABLE_INDEX_I32) {
+ reloc.Type == R_WASM_TABLE_INDEX_SLEB64 ||
+ reloc.Type == R_WASM_TABLE_INDEX_I32 ||
+ reloc.Type == R_WASM_TABLE_INDEX_I64) {
auto *funcSym = cast<FunctionSymbol>(sym);
if (funcSym->hasTableIndex() && funcSym->getTableIndex() == 0)
continue;
diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp
index 4cc4fff91cd9..2559e0f869cc 100644
--- a/lld/wasm/Relocations.cpp
+++ b/lld/wasm/Relocations.cpp
@@ -70,7 +70,9 @@ void scanRelocations(InputChunk *chunk) {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
+ case R_WASM_TABLE_INDEX_I64:
case R_WASM_TABLE_INDEX_SLEB:
+ case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_TABLE_INDEX_REL_SLEB:
if (requiresGOTAccess(sym))
break;
@@ -86,6 +88,7 @@ void scanRelocations(InputChunk *chunk) {
if (config->isPic) {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_SLEB:
+ case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_SLEB64:
@@ -97,6 +100,7 @@ void scanRelocations(InputChunk *chunk) {
"; recompile with -fPIC");
break;
case R_WASM_TABLE_INDEX_I32:
+ case R_WASM_TABLE_INDEX_I64:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_MEMORY_ADDR_I64:
// These relocation types are only present in the data section and
diff --git a/llvm/include/llvm/BinaryFormat/WasmRelocs.def b/llvm/include/llvm/BinaryFormat/WasmRelocs.def
index 05c5147e6314..b6ea2c59b4bb 100644
--- a/llvm/include/llvm/BinaryFormat/WasmRelocs.def
+++ b/llvm/include/llvm/BinaryFormat/WasmRelocs.def
@@ -20,3 +20,5 @@ 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)
+WASM_RELOC(R_WASM_TABLE_INDEX_SLEB64, 18)
+WASM_RELOC(R_WASM_TABLE_INDEX_I64, 19)
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index f51d908c53e1..af4620361c34 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -556,7 +556,9 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
switch (RelEntry.Type) {
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
case wasm::R_WASM_TABLE_INDEX_SLEB:
- case wasm::R_WASM_TABLE_INDEX_I32: {
+ case wasm::R_WASM_TABLE_INDEX_SLEB64:
+ case wasm::R_WASM_TABLE_INDEX_I32:
+ case wasm::R_WASM_TABLE_INDEX_I64: {
// Provisional value is table address of the resolved symbol itself
const MCSymbolWasm *Base =
cast<MCSymbolWasm>(Layout.getBaseSymbol(*RelEntry.Symbol));
@@ -688,6 +690,7 @@ void WasmObjectWriter::applyRelocations(
case wasm::R_WASM_GLOBAL_INDEX_I32:
patchI32(Stream, Value, Offset);
break;
+ case wasm::R_WASM_TABLE_INDEX_I64:
case wasm::R_WASM_MEMORY_ADDR_I64:
patchI64(Stream, Value, Offset);
break;
@@ -697,6 +700,7 @@ void WasmObjectWriter::applyRelocations(
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
writePatchableSLEB<5>(Stream, Value, Offset);
break;
+ case wasm::R_WASM_TABLE_INDEX_SLEB64:
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
writePatchableSLEB<10>(Stream, Value, Offset);
@@ -1599,7 +1603,9 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
// purely to make the object file's provisional values readable, and is
// ignored by the linker, which re-calculates the relocations itself.
if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 &&
+ Rel.Type != wasm::R_WASM_TABLE_INDEX_I64 &&
Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB &&
+ Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB64 &&
Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB)
return;
assert(Rel.Symbol->isFunction());
diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp
index 3f3f79b0f4ff..93917655073f 100644
--- a/llvm/lib/Object/RelocationResolver.cpp
+++ b/llvm/lib/Object/RelocationResolver.cpp
@@ -531,6 +531,8 @@ static bool supportsWasm64(uint64_t Type) {
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_TABLE_INDEX_SLEB64:
+ case wasm::R_WASM_TABLE_INDEX_I64:
return true;
default:
return supportsWasm32(Type);
@@ -563,6 +565,8 @@ static uint64_t resolveWasm64(RelocationRef R, uint64_t S, uint64_t A) {
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_TABLE_INDEX_SLEB64:
+ case wasm::R_WASM_TABLE_INDEX_I64:
// For wasm section, its offset at 0 -- ignoring Value
return A;
default:
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 47c68ab52883..23418a358fa4 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -791,7 +791,9 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
switch (Reloc.Type) {
case wasm::R_WASM_FUNCTION_INDEX_LEB:
case wasm::R_WASM_TABLE_INDEX_SLEB:
+ case wasm::R_WASM_TABLE_INDEX_SLEB64:
case wasm::R_WASM_TABLE_INDEX_I32:
+ case wasm::R_WASM_TABLE_INDEX_I64:
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
if (!isValidFunctionSymbol(Reloc.Index))
return make_error<GenericBinaryError>("Bad relocation function index",
@@ -871,7 +873,8 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
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)
+ if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
+ Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64)
Size = 8;
if (Reloc.Offset + Size > EndOffset)
return make_error<GenericBinaryError>("Bad relocation offset",
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
index 779e921c1d94..23f8b4f78bbd 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
@@ -92,7 +92,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
return wasm::R_WASM_TABLE_INDEX_SLEB;
return wasm::R_WASM_MEMORY_ADDR_SLEB;
case WebAssembly::fixup_sleb128_i64:
- assert(SymA.isData());
+ if (SymA.isFunction())
+ return wasm::R_WASM_TABLE_INDEX_SLEB64;
return wasm::R_WASM_MEMORY_ADDR_SLEB64;
case WebAssembly::fixup_uleb128_i32:
if (SymA.isGlobal())
@@ -119,6 +120,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
}
return wasm::R_WASM_MEMORY_ADDR_I32;
case FK_Data_8:
+ if (SymA.isFunction())
+ return wasm::R_WASM_TABLE_INDEX_I64;
assert(SymA.isData());
return wasm::R_WASM_MEMORY_ADDR_I64;
default:
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 71b173d76908..c6519fafbc49 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -441,6 +441,19 @@ static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults,
const MCInstrDesc &MCID = TII.get(CallOp);
MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
+ // See if we must truncate the function pointer.
+ // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
+ // as 64-bit for uniformity with other pointer types.
+ if (IsIndirect && MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) {
+ Register Reg32 =
+ MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
+ auto &FnPtr = CallParams.getOperand(0);
+ BuildMI(*BB, CallResults.getIterator(), DL,
+ TII.get(WebAssembly::I32_WRAP_I64), Reg32)
+ .addReg(FnPtr.getReg());
+ FnPtr.setReg(Reg32);
+ }
+
// Move the function pointer to the end of the arguments for indirect calls
if (IsIndirect) {
auto FnPtr = CallParams.getOperand(0);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 5ff0d73534a6..08b964542b5b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -328,19 +328,25 @@ defm CONST_F64 : I<(outs F64:$res), (ins f64imm_op:$imm),
} // isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1
def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
- (CONST_I32 tglobaladdr:$addr)>, Requires<[IsNotPIC]>;
+ (CONST_I32 tglobaladdr:$addr)>, Requires<[IsNotPIC, HasAddr32]>;
+def : Pat<(i64 (WebAssemblywrapper tglobaladdr:$addr)),
+ (CONST_I64 tglobaladdr:$addr)>, Requires<[IsNotPIC, HasAddr64]>;
def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
- (GLOBAL_GET_I32 tglobaladdr:$addr)>, Requires<[IsPIC]>;
+ (GLOBAL_GET_I32 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr32]>;
def : Pat<(i32 (WebAssemblywrapperPIC tglobaladdr:$addr)),
- (CONST_I32 tglobaladdr:$addr)>, Requires<[IsPIC]>;
+ (CONST_I32 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr32]>;
+def : Pat<(i64 (WebAssemblywrapperPIC tglobaladdr:$addr)),
+ (CONST_I64 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr64]>;
def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
- (GLOBAL_GET_I32 texternalsym:$addr)>, Requires<[IsPIC]>;
+ (GLOBAL_GET_I32 texternalsym:$addr)>, Requires<[IsPIC, HasAddr32]>;
def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
- (CONST_I32 texternalsym:$addr)>, Requires<[IsNotPIC]>;
+ (CONST_I32 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr32]>;
+def : Pat<(i64 (WebAssemblywrapper texternalsym:$addr)),
+ (CONST_I64 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr64]>;
def : Pat<(i32 (WebAssemblywrapper mcsym:$sym)), (CONST_I32 mcsym:$sym)>;
def : Pat<(i64 (WebAssemblywrapper mcsym:$sym)), (CONST_I64 mcsym:$sym)>;
diff --git a/llvm/test/CodeGen/WebAssembly/function-pointer64.ll b/llvm/test/CodeGen/WebAssembly/function-pointer64.ll
new file mode 100644
index 000000000000..0bea3930de0a
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/function-pointer64.ll
@@ -0,0 +1,58 @@
+; RUN: llc < %s -asm-verbose=false -O2 | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -O2 --filetype=obj | obj2yaml | FileCheck --check-prefix=YAML %s
+
+; This tests pointer features that may codegen
diff erently in wasm64.
+
+target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
+target triple = "wasm64-unknown-unknown"
+
+define void @bar(i32 %n) {
+entry:
+ ret void
+}
+
+define void @foo(void (i32)* %fp) {
+entry:
+ call void %fp(i32 1)
+ ret void
+}
+
+define void @test() {
+entry:
+ call void @foo(void (i32)* @bar)
+ store void (i32)* @bar, void (i32)** @fptr
+ ret void
+}
+
+ at fptr = global void (i32)* @bar
+
+; For simplicity (and compatibility with UB C/C++ code) we keep all types
+; of pointers the same size, so function pointers (which are 32-bit indices
+; in Wasm) are represented as 64-bit until called.
+
+; CHECK: .functype foo (i64) -> ()
+; CHECK-NEXT: i32.const 1
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: i32.wrap_i64
+; CHECK-NEXT: call_indirect (i32) -> ()
+
+; CHECK: .functype test () -> ()
+; CHECK-NEXT: i64.const bar
+; CHECK-NEXT: call foo
+
+
+; Check we're emitting a 64-bit reloc for `i64.const bar` and the global.
+
+; YAML: Memory:
+; YAML-NEXT: Flags: [ IS_64 ]
+; YAML-NEXT: Initial: 0x00000001
+
+; YAML: - Type: CODE
+; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64
+; YAML-NEXT: Index: 0
+; YAML-NEXT: Offset: 0x00000016
+
+; YAML: - Type: DATA
+; YAML: - Type: R_WASM_TABLE_INDEX_I64
+; YAML-NEXT: Index: 0
+; YAML-NEXT: Offset: 0x00000006
More information about the llvm-commits
mailing list