Skip to content

Commit

Permalink
[WebAssembly] Use __stack_pointer global when writing wasm binary
Browse files Browse the repository at this point in the history
This ensures that symbolic relocations are generated for stack
pointer manipulations.

These relocations are of type R_WEBASSEMBLY_GLOBAL_INDEX_LEB.
This change also adds support for reading relocations of this
type in WasmObjectFile.cpp.

Since its a globally imported symbol this does mean that
the get_global/set_global instruction won't be valid until
the objects are linked that global used in no longer an
imported global.

Differential Revision: https://reviews.llvm.org/D34172

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305616 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
sbc100 committed Jun 16, 2017
1 parent 2757ca6 commit 46016f2
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 145 deletions.
27 changes: 0 additions & 27 deletions include/llvm/CodeGen/MachineModuleInfoImpls.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,33 +77,6 @@ class MachineModuleInfoELF : public MachineModuleInfoImpl {
SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); }
};

/// MachineModuleInfoWasm - This is a MachineModuleInfoImpl implementation
/// for Wasm targets.
class MachineModuleInfoWasm : public MachineModuleInfoImpl {
/// WebAssembly global variables defined by CodeGen.
std::vector<wasm::Global> Globals;

/// The WebAssembly global variable which is the stack pointer.
unsigned StackPointerGlobal;

virtual void anchor(); // Out of line virtual method.
public:
MachineModuleInfoWasm(const MachineModuleInfo &)
: StackPointerGlobal(-1U) {}

void addGlobal(const wasm::Global &G) { Globals.push_back(G); }
const std::vector<wasm::Global> &getGlobals() const { return Globals; }

bool hasStackPointerGlobal() const {
return StackPointerGlobal != -1U;
}
unsigned getStackPointerGlobal() const {
assert(hasStackPointerGlobal() && "Stack ptr global hasn't been set");
return StackPointerGlobal;
}
void setStackPointerGlobal(unsigned Global) { StackPointerGlobal = Global; }
};

} // end namespace llvm

#endif
1 change: 0 additions & 1 deletion lib/CodeGen/MachineModuleInfoImpls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ using namespace llvm;
// Out of line virtual method.
void MachineModuleInfoMachO::anchor() {}
void MachineModuleInfoELF::anchor() {}
void MachineModuleInfoWasm::anchor() {}

static int SortSymbolPair(const void *LHS, const void *RHS) {
typedef std::pair<MCSymbol*, MachineModuleInfoImpl::StubValueTy> PairTy;
Expand Down
8 changes: 6 additions & 2 deletions lib/MC/WasmObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,8 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
}

assert(!IsPCRel);
assert(SymA);

unsigned Type = getRelocType(Target, Fixup);

WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
Expand Down Expand Up @@ -474,6 +476,7 @@ uint32_t WasmObjectWriter::getRelocationIndexValue(
assert(IndirectSymbolIndices.count(RelEntry.Symbol));
return IndirectSymbolIndices[RelEntry.Symbol];
case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
Expand All @@ -500,7 +503,8 @@ void WasmObjectWriter::applyRelocations(
switch (RelEntry.Type) {
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: {
case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: {
uint32_t Index = getRelocationIndexValue(RelEntry);
WritePatchableSLEB(Stream, Index, Offset);
break;
Expand All @@ -526,7 +530,7 @@ void WasmObjectWriter::applyRelocations(
break;
}
default:
llvm_unreachable("unsupported relocation type");
llvm_unreachable("invalid relocation type");
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion lib/Object/WasmObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,14 +325,16 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr,
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
break;
case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
Reloc.Addend = readVarint32(Ptr);
break;
default:
return make_error<GenericBinaryError>("Bad relocation type",
return make_error<GenericBinaryError>("Bad relocation type: " +
Twine(Reloc.Type),
object_error::parse_failed);
}
Section->Relocations.push_back(Reloc);
Expand Down
18 changes: 7 additions & 11 deletions lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ STATISTIC(MCNumFixups, "Number of MC fixups created.");
namespace {
class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
const MCInstrInfo &MCII;
MCContext &Ctx;

// Implementation generated by tablegen.
uint64_t getBinaryCodeForInstr(const MCInst &MI,
Expand All @@ -48,14 +47,12 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
const MCSubtargetInfo &STI) const override;

public:
WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
: MCII(mcii), Ctx(ctx) {}
WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}
};
} // end anonymous namespace

MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx) {
return new WebAssemblyMCCodeEmitter(MCII, Ctx);
MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) {
return new WebAssemblyMCCodeEmitter(MCII);
}

void WebAssemblyMCCodeEmitter::encodeInstruction(
Expand Down Expand Up @@ -89,11 +86,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
} else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
encodeSLEB128(int64_t(MO.getImm()), OS);
} else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
Fixups.push_back(MCFixup::create(
OS.tell() - Start, MCConstantExpr::create(MO.getImm(), Ctx),
MCFixupKind(WebAssembly::fixup_code_global_index), MI.getLoc()));
++MCNumFixups;
encodeULEB128(uint64_t(MO.getImm()), OS);
llvm_unreachable("wasm globals should only be accessed symbolicly");
} else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
encodeSLEB128(int64_t(MO.getImm()), OS);
} else {
Expand Down Expand Up @@ -135,6 +128,9 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32);
PaddedSize = 5;
} else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
FixupKind = MCFixupKind(WebAssembly::fixup_code_global_index);
PaddedSize = 5;
} else {
llvm_unreachable("unexpected symbolic operand kind");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ static MCInstPrinter *createMCInstPrinter(const Triple & /*T*/,
static MCCodeEmitter *createCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo & /*MRI*/,
MCContext &Ctx) {
return createWebAssemblyMCCodeEmitter(MCII, Ctx);
return createWebAssemblyMCCodeEmitter(MCII);
}

static MCAsmBackend *createAsmBackend(const Target & /*T*/,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ class raw_pwrite_stream;
Target &getTheWebAssemblyTarget32();
Target &getTheWebAssemblyTarget64();

MCCodeEmitter *createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx);
MCCodeEmitter *createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII);

MCAsmBackend *createWebAssemblyAsmBackend(const Triple &TT);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
bool IsFunction = IsFunctionExpr(Fixup.getValue());

switch (unsigned(Fixup.getKind())) {
case WebAssembly::fixup_code_global_index:
return wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB;
case WebAssembly::fixup_code_sleb128_i32:
if (IsFunction)
return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB;
Expand Down
7 changes: 0 additions & 7 deletions lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,6 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
MCConstantExpr::create(Size, OutContext));
}
}

if (!TM.getTargetTriple().isOSBinFormatELF()) {
MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo<MachineModuleInfoWasm>();
getTargetStreamer()->emitGlobal(MMIW.getGlobals());
if (MMIW.hasStackPointerGlobal())
getTargetStreamer()->emitStackPointer(MMIW.getStackPointerGlobal());
}
}

void WebAssemblyAsmPrinter::EmitConstantPool() {
Expand Down
29 changes: 7 additions & 22 deletions lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF,
const DebugLoc &DL) {
const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();

const char *ES = "__stack_pointer";
auto *SPSymbol = MF.createExternalSymbolName(ES);
if (MF.getSubtarget<WebAssemblySubtarget>()
.getTargetTriple().isOSBinFormatELF()) {
const char *ES = "__stack_pointer";
auto *SPSymbol = MF.createExternalSymbolName(ES);
MachineRegisterInfo &MRI = MF.getRegInfo();
const TargetRegisterClass *PtrRC =
MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
Expand All @@ -125,10 +125,8 @@ static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF,
.addReg(SrcReg)
.addMemOperand(MMO);
} else {
MachineModuleInfoWasm &MMIW =
MF.getMMI().getObjFileInfo<MachineModuleInfoWasm>();
BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::SET_GLOBAL_I32))
.addImm(MMIW.getStackPointerGlobal())
.addExternalSymbol(SPSymbol)
.addReg(SrcReg);
}
}
Expand Down Expand Up @@ -171,10 +169,11 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
unsigned SPReg = WebAssembly::SP32;
if (StackSize)
SPReg = MRI.createVirtualRegister(PtrRC);

const char *ES = "__stack_pointer";
auto *SPSymbol = MF.createExternalSymbolName(ES);
if (MF.getSubtarget<WebAssemblySubtarget>()
.getTargetTriple().isOSBinFormatELF()) {
const char *ES = "__stack_pointer";
auto *SPSymbol = MF.createExternalSymbolName(ES);
unsigned Zero = MRI.createVirtualRegister(PtrRC);

BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero)
Expand All @@ -189,22 +188,8 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
.addReg(Zero) // addr
.addMemOperand(LoadMMO);
} else {
auto &MMIW = MF.getMMI().getObjFileInfo<MachineModuleInfoWasm>();
if (!MMIW.hasStackPointerGlobal()) {
MMIW.setStackPointerGlobal(MMIW.getGlobals().size());

// Create the stack-pointer global. For now, just use the
// Emscripten/Binaryen ABI names.
wasm::Global G;
G.Type = wasm::ValType::I32;
G.Mutable = true;
G.InitialValue = 0;
G.InitialModule = "env";
G.InitialName = "STACKTOP";
MMIW.addGlobal(G);
}
BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::GET_GLOBAL_I32), SPReg)
.addImm(MMIW.getStackPointerGlobal());
.addExternalSymbol(SPSymbol);
}

bool HasBP = hasBP(MF);
Expand Down
32 changes: 10 additions & 22 deletions lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,28 +170,16 @@ static void Query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read,
if (MI.mayStore()) {
Write = true;

const MachineFunction &MF = *MI.getParent()->getParent();
if (MF.getSubtarget<WebAssemblySubtarget>()
.getTargetTriple().isOSBinFormatELF()) {
// Check for stores to __stack_pointer.
for (auto MMO : MI.memoperands()) {
const MachinePointerInfo &MPI = MMO->getPointerInfo();
if (MPI.V.is<const PseudoSourceValue *>()) {
auto PSV = MPI.V.get<const PseudoSourceValue *>();
if (const ExternalSymbolPseudoSourceValue *EPSV =
dyn_cast<ExternalSymbolPseudoSourceValue>(PSV))
if (StringRef(EPSV->getSymbol()) == "__stack_pointer")
StackPointer = true;
}
}
} else {
// Check for sets of the stack pointer.
const MachineModuleInfoWasm &MMIW =
MF.getMMI().getObjFileInfo<MachineModuleInfoWasm>();
if ((MI.getOpcode() == WebAssembly::SET_LOCAL_I32 ||
MI.getOpcode() == WebAssembly::SET_LOCAL_I64) &&
MI.getOperand(0).getImm() == MMIW.getStackPointerGlobal()) {
StackPointer = true;
// Check for stores to __stack_pointer.
for (auto MMO : MI.memoperands()) {
const MachinePointerInfo &MPI = MMO->getPointerInfo();
if (MPI.V.is<const PseudoSourceValue *>()) {
auto PSV = MPI.V.get<const PseudoSourceValue *>();
if (const ExternalSymbolPseudoSourceValue *EPSV =
dyn_cast<ExternalSymbolPseudoSourceValue>(PSV))
if (StringRef(EPSV->getSymbol()) == "__stack_pointer") {
StackPointer = true;
}
}
}
} else if (MI.hasOrderedMemoryRef()) {
Expand Down
14 changes: 7 additions & 7 deletions test/CodeGen/WebAssembly/byval.ll
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ declare void @ext_byval_func_empty(%EmptyStruct* byval)
define void @byval_arg(%SmallStruct* %ptr) {
; CHECK: .param i32
; Subtract 16 from SP (SP is 16-byte aligned)
; CHECK-NEXT: get_global $push[[L2:.+]]=, 0
; CHECK-NEXT: get_global $push[[L2:.+]]=, __stack_pointer
; CHECK-NEXT: i32.const $push[[L3:.+]]=, 16
; CHECK-NEXT: i32.sub $push[[L11:.+]]=, $pop[[L2]], $pop[[L3]]
; Ensure SP is stored back before the call
; CHECK-NEXT: tee_local $push[[L10:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}}
; CHECK-NEXT: set_global 0, $pop[[L10]]{{$}}
; CHECK-NEXT: set_global __stack_pointer, $pop[[L10]]{{$}}
; Copy the SmallStruct argument to the stack (SP+12, original SP-4)
; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0)
; CHECK-NEXT: i32.store 12($[[SP]]), $pop[[L0]]
Expand All @@ -41,7 +41,7 @@ define void @byval_arg(%SmallStruct* %ptr) {
; Restore the stack
; CHECK-NEXT: i32.const $push[[L6:.+]]=, 16
; CHECK-NEXT: i32.add $push[[L8:.+]]=, $[[SP]], $pop[[L6]]
; CHECK-NEXT: set_global 0, $pop[[L8]]
; CHECK-NEXT: set_global __stack_pointer, $pop[[L8]]
; CHECK-NEXT: return
ret void
}
Expand All @@ -53,7 +53,7 @@ define void @byval_arg_align8(%SmallStruct* %ptr) {
; CHECK: i32.const $push[[L1:.+]]=, 16
; CHECK-NEXT: i32.sub $push[[L11:.+]]=, {{.+}}, $pop[[L1]]
; CHECK-NEXT: tee_local $push[[L10:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}}
; CHECK-NEXT: set_global 0, $pop[[L10]]{{$}}
; CHECK-NEXT: set_global __stack_pointer, $pop[[L10]]{{$}}
; Copy the SmallStruct argument to the stack (SP+8, original SP-8)
; CHECK-NEXT: i32.load $push[[L0:.+]]=, 0($0){{$}}
; CHECK-NEXT: i32.store 8($[[SP]]), $pop[[L0]]{{$}}
Expand All @@ -72,7 +72,7 @@ define void @byval_arg_double(%AlignedStruct* %ptr) {
; CHECK: i32.const $push[[L1:.+]]=, 16
; CHECK-NEXT: i32.sub $push[[L14:.+]]=, {{.+}}, $pop[[L1]]
; CHECK-NEXT: tee_local $push[[L13:.+]]=, $[[SP:.+]]=, $pop[[L14]]
; CHECK-NEXT: set_global 0, $pop[[L13]]
; CHECK-NEXT: set_global __stack_pointer, $pop[[L13]]
; Copy the AlignedStruct argument to the stack (SP+0, original SP-16)
; Just check the last load/store pair of the memcpy
; CHECK: i64.load $push[[L4:.+]]=, 0($0)
Expand Down Expand Up @@ -110,11 +110,11 @@ define void @byval_empty_callee(%EmptyStruct* byval %ptr) {

; Call memcpy for "big" byvals.
; CHECK-LABEL: big_byval:
; CHECK: get_global $push[[L2:.+]]=, 0{{$}}
; CHECK: get_global $push[[L2:.+]]=, __stack_pointer{{$}}
; CHECK-NEXT: i32.const $push[[L3:.+]]=, 131072
; CHECK-NEXT: i32.sub $push[[L11:.+]]=, $pop[[L2]], $pop[[L3]]
; CHECK-NEXT: tee_local $push[[L10:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}}
; CHECK-NEXT: set_global 0, $pop[[L10]]{{$}}
; CHECK-NEXT: set_global __stack_pointer, $pop[[L10]]{{$}}
; CHECK-NEXT: i32.const $push[[L0:.+]]=, 131072
; CHECK-NEXT: i32.call $push[[L11:.+]]=, memcpy@FUNCTION, $[[SP]], ${{.+}}, $pop{{.+}}
; CHECK-NEXT: tee_local $push[[L9:.+]]=, $[[SP:.+]]=, $pop[[L11]]{{$}}
Expand Down
2 changes: 1 addition & 1 deletion test/CodeGen/WebAssembly/reg-stackify.ll
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ bb10: ; preds = %bb9, %bb

; CHECK-LABEL: stackpointer_dependency:
; CHECK: call {{.+}}, stackpointer_callee@FUNCTION,
; CHECK-NEXT: set_global 0,
; CHECK-NEXT: set_global __stack_pointer,
declare i32 @stackpointer_callee(i8* readnone, i8* readnone)
declare i8* @llvm.frameaddress(i32)
define i32 @stackpointer_dependency(i8* readnone) {
Expand Down
Loading

0 comments on commit 46016f2

Please sign in to comment.