[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
This commit is contained in:
parent
b636e7d1fc
commit
cc1b9b680f
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)>;
|
||||
|
|
58
llvm/test/CodeGen/WebAssembly/function-pointer64.ll
Normal file
58
llvm/test/CodeGen/WebAssembly/function-pointer64.ll
Normal file
|
@ -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 differently 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
|
||||
}
|
||||
|
||||
@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
|
Loading…
Reference in a new issue