diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -82,37 +82,24 @@ //===----------------------------------------------------------------------===// void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { - for (auto &It : OutContext.getSymbols()) { - // Emit a .globaltype and .eventtype declaration. - auto Sym = cast(It.getValue()); - if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) - getTargetStreamer()->emitGlobalType(Sym); - else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT) - getTargetStreamer()->emitEventType(Sym); - } - for (const auto &F : M) { - // Emit function type info for all undefined functions if (F.isDeclarationForLinker() && !F.isIntrinsic()) { SmallVector Results; SmallVector Params; computeSignatureVTs(F.getFunctionType(), F, TM, Params, Results); auto *Sym = cast(getSymbol(&F)); - Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); - if (!Sym->getSignature()) { + + if (Sym->getType() != wasm::WASM_SYMBOL_TYPE_FUNCTION) { + //dbgs() << "Missing Sig: " << *Sym << "\n"; auto Signature = signatureFromMVTs(Results, Params); + Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); Sym->setSignature(Signature.get()); addSignature(std::move(Signature)); + //assert(false); } - // FIXME: this was originally intended for post-linking and was only used - // for imports that were only called indirectly (i.e. s2wasm could not - // infer the type from a call). With object files it applies to all - // imports. so fix the names and the tests, or rethink how import - // delcarations work in asm files. - getTargetStreamer()->emitFunctionType(Sym); - if (TM.getTargetTriple().isOSBinFormatWasm() && - F.hasFnAttribute("wasm-import-module")) { + if (F.hasFnAttribute("wasm-import-module")) { + auto *Sym = cast(getSymbol(&F)); StringRef Name = F.getFnAttribute("wasm-import-module").getValueAsString(); Sym->setImportModule(Name); @@ -128,6 +115,32 @@ } } + for (auto &It : OutContext.getSymbols()) { + // Emit a .globaltype/.eventtype/.functype declaration. + auto* Sym = cast(It.getValue()); + //dbgs() << "sym: " << *Sym << "\n"; + if (Sym->isVariable()) + continue; + switch (Sym->getType()) { + case wasm::WASM_SYMBOL_TYPE_GLOBAL: + getTargetStreamer()->emitGlobalType(Sym); + break; + case wasm::WASM_SYMBOL_TYPE_EVENT: + getTargetStreamer()->emitEventType(Sym); + break; + case wasm::WASM_SYMBOL_TYPE_FUNCTION: + // Defined symbols have this function type set at the declartion site + if (Sym->isDefined()) + continue; + assert(Sym->getSignature()); + getTargetStreamer()->emitFunctionType(Sym); + break; + case wasm::WASM_SYMBOL_TYPE_DATA: + case wasm::WASM_SYMBOL_TYPE_SECTION: + break; + } + } + for (const auto &G : M.globals()) { if (!G.hasInitializer() && G.hasExternalLinkage()) { if (G.getValueType()->isSized()) { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -152,6 +152,8 @@ } bool computeAddress(const Value *Obj, Address &Addr); void materializeLoadStoreOperands(Address &Addr); + unsigned materializeDataAddrPIC(const GlobalValue *GV); + unsigned materializeFunctionAddrPIC(const GlobalValue *GV); void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB, MachineMemOperand *MMO); unsigned maskI1Value(unsigned Reg, const Value *V); @@ -374,16 +376,93 @@ return Addr.getReg() != 0; } +unsigned WebAssemblyFastISel::materializeFunctionAddrPIC(const GlobalValue *GV) { + // For PIC code, function addresses need to be offset by to __table_base + // wasm global. + LLVM_DEBUG(dbgs() << "materializeFunctionAddrPIC\n"); + unsigned BaseReg = createResultReg(&WebAssembly::I32RegClass); + auto *Base = FuncInfo.MF->createExternalSymbolName("__table_base"); + unsigned Opc = WebAssembly::GET_GLOBAL_I32; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), BaseReg) + .addExternalSymbol(Base, WebAssemblyII::MO_SYMBOL_GLOBAL); + + unsigned OpcConst = WebAssembly::CONST_I32; + unsigned ConstReg = createResultReg(&WebAssembly::I32RegClass); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(OpcConst), + ConstReg) + .addGlobalAddress(GV); + + unsigned OpcAdd = WebAssembly::ADD_I32; + unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(OpcAdd), + ResultReg) + .addReg(BaseReg) + .addReg(ConstReg); + return ResultReg; +} + +unsigned WebAssemblyFastISel::materializeDataAddrPIC(const GlobalValue *GV) { + + unsigned Reg = + createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass + : &WebAssembly::I32RegClass); + assert(TLI.isPositionIndependent()); + dbgs() << "materializeDataAddrPIC\n"; + // For PIC code, data address need to be offset by to __memory_base wasm + // global. External data address are accessed by special functions starting + // with `g$`. + if (GV->isDeclaration()) { + std::string getterName("g$"); + getterName += GV->getName(); + auto *getterSymName = + FuncInfo.MF->createExternalSymbolName(getterName); + unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CALL_I64 + : WebAssembly::CALL_I32; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg) + .addExternalSymbol(getterSymName, + WebAssemblyII::MO_SYMBOL_FUNCTION); + } else { + unsigned BaseReg = createResultReg(&WebAssembly::I32RegClass); + auto *Base = FuncInfo.MF->createExternalSymbolName("__memory_base"); + unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::GET_GLOBAL_I64 + : WebAssembly::GET_GLOBAL_I32; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), BaseReg) + .addExternalSymbol(Base, WebAssemblyII::MO_SYMBOL_GLOBAL); + + unsigned OpcConst = WebAssembly::CONST_I32; + unsigned ConstReg = createResultReg(&WebAssembly::I32RegClass); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(OpcConst), + ConstReg) + .addGlobalAddress(GV); + + unsigned OpcAdd = WebAssembly::ADD_I32; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(OpcAdd), Reg) + .addReg(BaseReg) + .addReg(ConstReg); + } + + return Reg; +} + void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) { if (Addr.isRegBase()) { unsigned Reg = Addr.getReg(); if (Reg == 0) { - Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass + const GlobalValue *GV = Addr.getGlobalValue(); + if (GV && TLI.isPositionIndependent()) { + if (GV->getValueType()->isFunctionTy()) + Reg = materializeFunctionAddrPIC(GV); + else + Reg = materializeDataAddrPIC(GV); + } else { + Reg = + createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass : &WebAssembly::I32RegClass); - unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64 - : WebAssembly::CONST_I32; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg) - .addImm(0); + unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64 + : WebAssembly::CONST_I32; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg) + .addImm(0); + } Addr.setReg(Reg); } } @@ -396,7 +475,14 @@ // TODO: Disable SetP2AlignOperands for FastISel and just do it here. MIB.addImm(0); - if (const GlobalValue *GV = Addr.getGlobalValue()) + const GlobalValue *GV = Addr.getGlobalValue(); + bool IncludeGlobalAddr = GV != nullptr; + + // Fir PIC code the global address in the stack already + if (GV && TLI.isPositionIndependent() && !GV->hasHiddenVisibility()) + IncludeGlobalAddr = false; + + if (IncludeGlobalAddr) MIB.addGlobalAddress(GV, Addr.getOffset()); else MIB.addImm(Addr.getOffset()); @@ -604,15 +690,23 @@ } unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) { - if (const auto *GV = dyn_cast(C)) { - unsigned ResultReg = - createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass - : &WebAssembly::I32RegClass); - unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64 - : WebAssembly::CONST_I32; - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) - .addGlobalAddress(GV); - return ResultReg; + if (const GlobalValue *GV = dyn_cast(C)) { + LLVM_DEBUG(dbgs() << "fastMaterializeConstant " << *GV << "\n"); + if (TLI.isPositionIndependent()) { + if (GV->getValueType()->isFunctionTy()) + return materializeFunctionAddrPIC(GV); + else + return materializeDataAddrPIC(GV); + } else { + unsigned ResultReg = + createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass + : &WebAssembly::I32RegClass); + unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64 + : WebAssembly::CONST_I32; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + .addGlobalAddress(GV); + return ResultReg; + } } // Let target-independent code handle it. @@ -741,9 +835,17 @@ return false; bool IsDirect = Func != nullptr; + if (!IsDirect && isa(Call->getCalledValue())) return false; + if (IsDirect && TLI.isPositionIndependent() && !Func->hasHiddenVisibility()) { + LLVM_DEBUG(dbgs() << "call to external function\n"); + LLVM_DEBUG(dbgs() << *Func << "\n"); + LLVM_DEBUG(dbgs() << "YYY\n"); + IsDirect = false; + } + FunctionType *FuncTy = Call->getFunctionType(); unsigned Opc; bool IsVoid = FuncTy->getReturnType()->isVoidTy(); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -759,9 +759,10 @@ } InTys.push_back(MVT::Other); SDVTList InTyList = DAG.getVTList(InTys); - SDValue Res = - DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1, - DL, InTyList, Ops); + unsigned Opcode = Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1; + //if (isPositionIndependent() ) + //Opcode = Ins.empty() ? WebAssemblyISD::CALL_INDIRECT1 : WebAssemblyISD::CALL_INDIRECT1; + SDValue Res = DAG.getNode(Opcode, DL, InTyList, Ops); if (Ins.empty()) { Chain = Res; } else { @@ -996,11 +997,10 @@ EVT VT = Op.getValueType(); assert(ES->getTargetFlags() == 0 && "Unexpected target flags on generic ExternalSymbolSDNode"); - // Set the TargetFlags to 0x1 which indicates that this is a "function" - // symbol rather than a data symbol. We do this unconditionally even though - // we don't know anything about the symbol other than its name, because all - // external symbols used in target-independent SelectionDAG code are for - // functions. + // Set TargetFlags to WebAssemblyII::MO_SYMBOL_FUNCTION. We do this + // unconditionally even though we don't know anything about the symbol other + // than its name, because all external symbols used in target-independent + // SelectionDAG code are for functions. return DAG.getNode( WebAssemblyISD::Wrapper, DL, VT, DAG.getTargetExternalSymbol(ES->getSymbol(), VT, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -73,11 +73,12 @@ auto *WasmSym = cast(Printer.GetExternalSymbolSymbol(Name)); const WebAssemblySubtarget &Subtarget = Printer.getSubtarget(); - // Except for the two exceptions (__stack_pointer and __cpp_exception), all - // other external symbols used by CodeGen are functions. It's OK to hardcode - // knowledge of specific symbols here; this method is precisely there for - // fetching the signatures of known Clang-provided symbols. - if (strcmp(Name, "__stack_pointer") == 0) { + // Except for certain known symbols, all symbols used by CodeGen are + // functions. It's OK to hardcode knowledge of specific symbols here; this + // method is precisely there for fetching the signatures of known + // Clang-provided symbols. + if (strcmp(Name, "__stack_pointer") == 0 || + strcmp(Name, "__memory_base") == 0 || strcmp(Name, "__table_base") == 0) { WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); WasmSym->setGlobalType(wasm::WasmGlobalType{ uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64 @@ -106,6 +107,10 @@ // functions, exceptions are assumed to have void return type. Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64 : wasm::ValType::I32); + } else if (strncmp(Name, "g$", 2) == 0) { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + Returns.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64 + : wasm::ValType::I32); } else { // Function symbols WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); getLibcallSignature(Subtarget, Name, Returns, Params); diff --git a/llvm/test/CodeGen/WebAssembly/address-offsets.ll b/llvm/test/CodeGen/WebAssembly/address-offsets.ll --- a/llvm/test/CodeGen/WebAssembly/address-offsets.ll +++ b/llvm/test/CodeGen/WebAssembly/address-offsets.ll @@ -1,4 +1,6 @@ -; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s +; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=CHECK,NPIC +; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -relocation-model=pic -fast-isel | FileCheck %s -check-prefixes=CHECK,PIC + ; Test folding constant offsets and symbols into load and store addresses under ; a variety of circumstances. @@ -10,8 +12,10 @@ ; CHECK-LABEL: load_test0: ; CHECK-NEXT: .functype load_test0 () -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 0{{$}} -; CHECK-NEXT: i32.load $push1=, g+40($pop0){{$}} +; NPIC-NEXT: i32.const $push0=, 0{{$}} +; NPIC-NEXT: i32.load $push1=, g+40($pop0){{$}} +; PIC-NEXT: i32.call $push0=, g$g@FUNCTION +; PIC-NEXT: i32.load $push1=, 40($pop0) ; CHECK-NEXT: return $pop1{{$}} define i32 @load_test0() { %t = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4 @@ -20,8 +24,10 @@ ; CHECK-LABEL: load_test0_noinbounds: ; CHECK-NEXT: .functype load_test0_noinbounds () -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 0{{$}} -; CHECK-NEXT: i32.load $push1=, g+40($pop0){{$}} +; NPIC-NEXT: i32.const $push0=, 0{{$}} +; NPIC-NEXT: i32.load $push1=, g+40($pop0){{$}} +; PIC-NEXT: i32.call $push0=, g$g@FUNCTION{{$}} +; PIC-NEXT: i32.load $push1=, 40($pop0){{$}} ; CHECK-NEXT: return $pop1{{$}} define i32 @load_test0_noinbounds() { %t = load i32, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4 @@ -34,7 +40,7 @@ ; CHECK-LABEL: load_test1: ; CHECK-NEXT: .functype load_test1 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}} ; CHECK-NEX T: return $pop2{{$}} @@ -47,7 +53,7 @@ ; CHECK-LABEL: load_test2: ; CHECK-NEXT: .functype load_test2 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}} ; CHECK-NEX T: return $pop2{{$}} @@ -60,7 +66,7 @@ ; CHECK-LABEL: load_test3: ; CHECK-NEXT: .functype load_test3 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}} ; CHECK-NEX T: return $pop2{{$}} @@ -73,7 +79,7 @@ ; CHECK-LABEL: load_test4: ; CHECK-NEXT: .functype load_test4 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}} ; CHECK-NEX T: return $pop2{{$}} @@ -85,7 +91,7 @@ ; CHECK-LABEL: load_test5: ; CHECK-NEXT: .functype load_test5 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}} ; CHECK-NEX T: return $pop2{{$}} @@ -97,7 +103,7 @@ ; CHECK-LABEL: load_test6: ; CHECK-NEXT: .functype load_test6 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}} ; CHECK-NEX T: return $pop2{{$}} @@ -110,7 +116,7 @@ ; CHECK-LABEL: load_test7: ; CHECK-NEXT: .functype load_test7 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}} ; CHECK-NEX T: return $pop2{{$}} @@ -123,7 +129,7 @@ ; CHECK-LABEL: load_test8: ; CHECK-NEXT: .functype load_test8 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}} ; CHECK-NEX T: return $pop2{{$}} @@ -136,8 +142,10 @@ ; CHECK-LABEL: load_test9: ; CHECK-NEXT: .functype load_test9 () -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 0{{$}} -; CHECK-NEXT: i32.load $push1=, g-40($pop0){{$}} +; PIC-NEXT: i32.call $push0=, g$g@FUNCTION +; PIC-NEXT: i32.load $push1=, 4294967256($pop0) +; NPIC-NEXT: i32.const $push0=, 0{{$}} +; NPIC-NEXT: i32.load $push1=, g-40($pop0){{$}} ; CHECK-NEXT: return $pop1{{$}} define i32 @load_test9() { %t = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4 @@ -146,12 +154,20 @@ ; CHECK-LABEL: load_test10: ; CHECK-NEXT: .functype load_test10 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} -; CHECK-NEXT: i32.const $push2=, g-40{{$}} -; CHECK-NEXT: i32.add $push3=, $pop1, $pop2{{$}} -; CHECK-NEXT: i32.load $push4=, 0($pop3){{$}} -; CHECK-NEXT: return $pop4{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push2=, g-40{{$}} +; NPIC-NEXT: i32.add $push3=, $pop1, $pop2{{$}} +; NPIC-NEXT: i32.load $push4=, 0($pop3){{$}} +; NPIC-NEXT: return $pop4{{$}} +; PIC-NEXT: i32.call $push1=, g$g@FUNCTION +; PIC-NEXT: i32.const $push5=, -10 +; PIC-NEXT: i32.add $push6=, $0, $pop5 +; PIC-NEXT: i32.const $push2=, 2 +; PIC-NEXT: i32.shl $push3=, $pop6, $pop2 +; PIC-NEXT: i32.add $push4=, $pop1, $pop3 +; PIC-NEXT: i32.load $push0=, 0($pop4) +; PIC-NEXT: return $pop0{{$}} define i32 @load_test10(i32 %n) { %add = add nsw i32 %n, -10 %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add @@ -183,13 +199,13 @@ ; CHECK-LABEL: load_test12: ; CHECK-NEXT: .functype load_test12 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.load $push5=, 0($pop4){{$}} -; CHECK-NEXT: return $pop5{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.load $push5=, 0($pop4){{$}} +; NPIC-NEXT: return $pop5{{$}} define i32 @load_test12(i32* %p, i32 %n) { %add = add nsw i32 %n, 10 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add @@ -199,13 +215,13 @@ ; CHECK-LABEL: load_test13: ; CHECK-NEXT: .functype load_test13 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.load $push5=, 0($pop4){{$}} -; CHECK-NEXT: return $pop5{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.load $push5=, 0($pop4){{$}} +; NPIC-NEXT: return $pop5{{$}} define i32 @load_test13(i32* %p, i32 %n) { %add = add nsw i32 10, %n %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add @@ -215,11 +231,11 @@ ; CHECK-LABEL: load_test14: ; CHECK-NEXT: .functype load_test14 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.load $push3=, 40($pop2){{$}} -; CHECK-NEXT: return $pop3{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.load $push3=, 40($pop2){{$}} +; NPIC-NEXT: return $pop3{{$}} define i32 @load_test14(i32* %p, i32 %n) { %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10 @@ -229,13 +245,13 @@ ; CHECK-LABEL: load_test15: ; CHECK-NEXT: .functype load_test15 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.load $push5=, 0($pop4){{$}} -; CHECK-NEXT: return $pop5{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.load $push5=, 0($pop4){{$}} +; NPIC-NEXT: return $pop5{{$}} define i32 @load_test15(i32* %p, i32 %n) { %add.ptr = getelementptr inbounds i32, i32* %p, i32 10 %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n @@ -245,13 +261,13 @@ ; CHECK-LABEL: load_test16: ; CHECK-NEXT: .functype load_test16 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.load $push5=, 0($pop4){{$}} -; CHECK-NEXT: return $pop5{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.load $push5=, 0($pop4){{$}} +; NPIC-NEXT: return $pop5{{$}} define i32 @load_test16(i32* %p, i32 %n) { %add.ptr = getelementptr inbounds i32, i32* %p, i32 10 %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n @@ -261,13 +277,13 @@ ; CHECK-LABEL: load_test17: ; CHECK-NEXT: .functype load_test17 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.load $push5=, 0($pop4){{$}} -; CHECK-NEXT: return $pop5{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.load $push5=, 0($pop4){{$}} +; NPIC-NEXT: return $pop5{{$}} define i32 @load_test17(i32* %p, i32 %n) { %add = add nsw i32 %n, 10 %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add @@ -277,11 +293,11 @@ ; CHECK-LABEL: load_test18: ; CHECK-NEXT: .functype load_test18 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.load $push3=, 40($pop2){{$}} -; CHECK-NEXT: return $pop3{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.load $push3=, 40($pop2){{$}} +; NPIC-NEXT: return $pop3{{$}} define i32 @load_test18(i32* %p, i32 %n) { %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10 @@ -291,13 +307,13 @@ ; CHECK-LABEL: load_test19: ; CHECK-NEXT: .functype load_test19 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.load $push5=, 0($pop4){{$}} -; CHECK-NEXT: return $pop5{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.load $push5=, 0($pop4){{$}} +; NPIC-NEXT: return $pop5{{$}} define i32 @load_test19(i32* %p, i32 %n) { %add = add nsw i32 10, %n %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add @@ -307,10 +323,10 @@ ; CHECK-LABEL: load_test20: ; CHECK-NEXT: .functype load_test20 (i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, -40{{$}} -; CHECK-NEXT: i32.add $push1=, $0, $pop0{{$}} -; CHECK-NEXT: i32.load $push2=, 0($pop1){{$}} -; CHECK-NEXT: return $pop2{{$}} +; NPIC-NEXT: i32.const $push0=, -40{{$}} +; NPIC-NEXT: i32.add $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.load $push2=, 0($pop1){{$}} +; NPIC-NEXT: return $pop2{{$}} define i32 @load_test20(i32* %p) { %arrayidx = getelementptr inbounds i32, i32* %p, i32 -10 %t = load i32, i32* %arrayidx, align 4 @@ -319,13 +335,13 @@ ; CHECK-LABEL: load_test21: ; CHECK-NEXT: .functype load_test21 (i32, i32) -> (i32){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, -40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.load $push5=, 0($pop4){{$}} -; CHECK-NEXT: return $pop5{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, -40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.load $push5=, 0($pop4){{$}} +; NPIC-NEXT: return $pop5{{$}} define i32 @load_test21(i32* %p, i32 %n) { %add = add nsw i32 %n, -10 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add @@ -335,9 +351,9 @@ ; CHECK-LABEL: store_test0: ; CHECK-NEXT: .functype store_test0 (i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 0{{$}} -; CHECK-NEXT: i32.store g+40($pop0), $0{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 0{{$}} +; NPIC-NEXT: i32.store g+40($pop0), $0{{$}} +; NPIC-NEXT: return{{$}} define void @store_test0(i32 %i) { store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4 ret void @@ -345,9 +361,9 @@ ; CHECK-LABEL: store_test0_noinbounds: ; CHECK-NEXT: .functype store_test0_noinbounds (i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 0{{$}} -; CHECK-NEXT: i32.store g+40($pop0), $0{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 0{{$}} +; NPIC-NEXT: i32.store g+40($pop0), $0{{$}} +; NPIC-NEXT: return{{$}} define void @store_test0_noinbounds(i32 %i) { store i32 %i, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4 ret void @@ -355,8 +371,8 @@ ; CHECK-LABEL: store_test1: ; CHECK-NEXT: .functype store_test1 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}} ; CHECK-NEX T: return{{$}} define void @store_test1(i32 %n, i32 %i) { @@ -368,8 +384,8 @@ ; CHECK-LABEL: store_test2: ; CHECK-NEXT: .functype store_test2 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}} ; CHECK-NEX T: return{{$}} define void @store_test2(i32 %n, i32 %i) { @@ -381,8 +397,8 @@ ; CHECK-LABEL: store_test3: ; CHECK-NEXT: .functype store_test3 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}} ; CHECK-NEX T: return{{$}} define void @store_test3(i32 %n, i32 %i) { @@ -394,8 +410,8 @@ ; CHECK-LABEL: store_test4: ; CHECK-NEXT: .functype store_test4 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}} ; CHECK-NEX T: return{{$}} define void @store_test4(i32 %n, i32 %i) { @@ -406,8 +422,8 @@ ; CHECK-LABEL: store_test5: ; CHECK-NEXT: .functype store_test5 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}} ; CHECK-NEX T: return{{$}} define void @store_test5(i32 %n, i32 %i) { @@ -418,8 +434,8 @@ ; CHECK-LABEL: store_test6: ; CHECK-NEXT: .functype store_test6 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}} ; CHECK-NEX T: return{{$}} define void @store_test6(i32 %n, i32 %i) { @@ -431,8 +447,8 @@ ; CHECK-LABEL: store_test7: ; CHECK-NEXT: .functype store_test7 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}} ; CHECK-NEX T: return{{$}} define void @store_test7(i32 %n, i32 %i) { @@ -444,8 +460,8 @@ ; CHECK-LABEL: store_test8: ; CHECK-NEXT: .functype store_test8 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}} ; CHECK-NEX T: return{{$}} define void @store_test8(i32 %n, i32 %i) { @@ -457,9 +473,9 @@ ; CHECK-LABEL: store_test9: ; CHECK-NEXT: .functype store_test9 (i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 0{{$}} -; CHECK-NEXT: i32.store g-40($pop0), $0{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 0{{$}} +; NPIC-NEXT: i32.store g-40($pop0), $0{{$}} +; NPIC-NEXT: return{{$}} define void @store_test9(i32 %i) { store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4 ret void @@ -467,12 +483,12 @@ ; CHECK-LABEL: store_test10: ; CHECK-NEXT: .functype store_test10 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}} -; CHECK-NEXT: i32.const $push2=, g-40{{$}} -; CHECK-NEXT: i32.add $push3=, $pop1, $pop2{{$}} -; CHECK-NEXT: i32.store 0($pop3), $1{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.const $push2=, g-40{{$}} +; NPIC-NEXT: i32.add $push3=, $pop1, $pop2{{$}} +; NPIC-NEXT: i32.store 0($pop3), $1{{$}} +; NPIC-NEXT: return{{$}} define void @store_test10(i32 %n, i32 %i) { %add = add nsw i32 %n, -10 %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add @@ -482,8 +498,8 @@ ; CHECK-LABEL: store_test11: ; CHECK-NEXT: .functype store_test11 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.store 40($0), $1{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.store 40($0), $1{{$}} +; NPIC-NEXT: return{{$}} define void @store_test11(i32* %p, i32 %i) { %arrayidx = getelementptr inbounds i32, i32* %p, i32 10 store i32 %i, i32* %arrayidx, align 4 @@ -492,10 +508,10 @@ ; CHECK-LABEL: store_test11_noinbounds: ; CHECK-NEXT: .functype store_test11_noinbounds (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 40{{$}} -; CHECK-NEXT: i32.add $push1=, $0, $pop0{{$}} -; CHECK-NEXT: i32.store 0($pop1), $1{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 40{{$}} +; NPIC-NEXT: i32.add $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.store 0($pop1), $1{{$}} +; NPIC-NEXT: return{{$}} define void @store_test11_noinbounds(i32* %p, i32 %i) { %arrayidx = getelementptr i32, i32* %p, i32 10 store i32 %i, i32* %arrayidx, align 4 @@ -504,13 +520,13 @@ ; CHECK-LABEL: store_test12: ; CHECK-NEXT: .functype store_test12 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.store 0($pop4), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.store 0($pop4), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test12(i32* %p, i32 %n, i32 %i) { %add = add nsw i32 %n, 10 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add @@ -520,13 +536,13 @@ ; CHECK-LABEL: store_test13: ; CHECK-NEXT: .functype store_test13 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.store 0($pop4), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.store 0($pop4), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test13(i32* %p, i32 %n, i32 %i) { %add = add nsw i32 10, %n %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add @@ -536,11 +552,11 @@ ; CHECK-LABEL: store_test14: ; CHECK-NEXT: .functype store_test14 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.store 40($pop2), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.store 40($pop2), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test14(i32* %p, i32 %n, i32 %i) { %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10 @@ -550,13 +566,13 @@ ; CHECK-LABEL: store_test15: ; CHECK-NEXT: .functype store_test15 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.store 0($pop4), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.store 0($pop4), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test15(i32* %p, i32 %n, i32 %i) { %add.ptr = getelementptr inbounds i32, i32* %p, i32 10 %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n @@ -566,13 +582,13 @@ ; CHECK-LABEL: store_test16: ; CHECK-NEXT: .functype store_test16 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.store 0($pop4), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.store 0($pop4), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test16(i32* %p, i32 %n, i32 %i) { %add.ptr = getelementptr inbounds i32, i32* %p, i32 10 %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n @@ -582,13 +598,13 @@ ; CHECK-LABEL: store_test17: ; CHECK-NEXT: .functype store_test17 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.store 0($pop4), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.store 0($pop4), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test17(i32* %p, i32 %n, i32 %i) { %add = add nsw i32 %n, 10 %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add @@ -598,11 +614,11 @@ ; CHECK-LABEL: store_test18: ; CHECK-NEXT: .functype store_test18 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.store 40($pop2), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.store 40($pop2), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test18(i32* %p, i32 %n, i32 %i) { %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10 @@ -612,13 +628,13 @@ ; CHECK-LABEL: store_test19: ; CHECK-NEXT: .functype store_test19 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, 40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.store 0($pop4), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, 40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.store 0($pop4), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test19(i32* %p, i32 %n, i32 %i) { %add = add nsw i32 10, %n %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add @@ -628,10 +644,10 @@ ; CHECK-LABEL: store_test20: ; CHECK-NEXT: .functype store_test20 (i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, -40{{$}} -; CHECK-NEXT: i32.add $push1=, $0, $pop0{{$}} -; CHECK-NEXT: i32.store 0($pop1), $1{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, -40{{$}} +; NPIC-NEXT: i32.add $push1=, $0, $pop0{{$}} +; NPIC-NEXT: i32.store 0($pop1), $1{{$}} +; NPIC-NEXT: return{{$}} define void @store_test20(i32* %p, i32 %i) { %arrayidx = getelementptr inbounds i32, i32* %p, i32 -10 store i32 %i, i32* %arrayidx, align 4 @@ -640,13 +656,13 @@ ; CHECK-LABEL: store_test21: ; CHECK-NEXT: .functype store_test21 (i32, i32, i32) -> (){{$}} -; CHECK-NEXT: i32.const $push0=, 2{{$}} -; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}} -; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}} -; CHECK-NEXT: i32.const $push3=, -40{{$}} -; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}} -; CHECK-NEXT: i32.store 0($pop4), $2{{$}} -; CHECK-NEXT: return{{$}} +; NPIC-NEXT: i32.const $push0=, 2{{$}} +; NPIC-NEXT: i32.shl $push1=, $1, $pop0{{$}} +; NPIC-NEXT: i32.add $push2=, $0, $pop1{{$}} +; NPIC-NEXT: i32.const $push3=, -40{{$}} +; NPIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}} +; NPIC-NEXT: i32.store 0($pop4), $2{{$}} +; NPIC-NEXT: return{{$}} define void @store_test21(i32* %p, i32 %n, i32 %i) { %add = add nsw i32 %n, -10 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add diff --git a/llvm/test/CodeGen/WebAssembly/global-pic.ll b/llvm/test/CodeGen/WebAssembly/global-pic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/global-pic.ll @@ -0,0 +1,86 @@ +; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=NON-PIC +; RUN: llc < %s -asm-verbose=false -relocation-model=pic -fast-isel -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC +; RUN: llc < %s -asm-verbose=false -relocation-model=pic -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC + +; Test that globals assemble as expected with -fPIC + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +@hidden_global = external hidden global i32 + +declare i32 @foo(); + +; For hidden symbols PIC code needs to offset all loads and stores +; by the value of the __memory_base global + +define i32 @load_hidden_global() { +; PIC-LABEL: load_hidden_global: +; PIC: get_global $push0=, __memory_base@GLOBAL +; PIC-NEXT: i32.load $push1=, hidden_global($pop0) +; PIC-NEXT: end_function + +; NON-PIC-LABEL: load_hidden_global: +; NON-PIC: i32.const $push0=, 0 +; NON-PIC-NEXT: i32.load $push1=, hidden_global($pop0) +; NON-PIC-NEXT: end_function + + %1 = load i32, i32* @hidden_global + ret i32 %1 +} + +; Store to a hidden global + +define void @store_hidden_global(i32 %n) { +; PIC-LABEL: store_hidden_global: +; PIC: get_global $push0=, __memory_base@GLOBAL +; PIC-NEXT: i32.store hidden_global($pop0), $0 +; PIC-NEXT: end_function + +; NON-PIC-LABEL: store_hidden_global: +; NON-PIC: i32.const $push0=, 0 +; NON-PIC-NEXT: i32.store hidden_global($pop0), $0 +; NON-PIC-NEXT: end_function + + store i32 %n, i32* @hidden_global + ret void +} + +; For non-hidden globals PIC code needs to call special rtld-created 'g$' +; functions to find the runtime offset. + +@external_global = external global i32 + +define i32 @load_external_global() { +; PIC-LABEL: load_external_global: +; PIC: i32.call $push0=, g$external_global@FUNCTION +; PIC-NEXT: i32.load $push1=, 0($pop0) +; PIC-NEXT: end_function + +; NON-PIC-LABEL: load_external_global: +; NON-PIC: i32.const $push0=, 0 +; NON-PIC-NEXT: i32.load $push1=, external_global($pop0) +; NON-PIC-NEXT: end_function + + %1 = load i32, i32* @external_global + ret i32 %1 +} + +; Store to a non-hidden global + +define void @store_external_global(i32 %n) { +; PIC-LABEL: store_external_global: +; PIC: i32.call $push0=, g$external_global@FUNCTION +; PIC-NEXT: i32.store 0($pop0), $0 +; PIC-NEXT: end_function + +; NON-PIC-LABEL: store_external_global: +; NON-PIC: i32.const $push0=, 0 +; NON-PIC-NEXT: i32.store external_global($pop0), $0 +; NON-PIC-NEXT: end_function + + store i32 %n, i32* @external_global + ret void +} + +; CHECK-PIC: .globaltype __memory_base, i32 diff --git a/llvm/test/CodeGen/WebAssembly/indirect-import.ll b/llvm/test/CodeGen/WebAssembly/indirect-import.ll --- a/llvm/test/CodeGen/WebAssembly/indirect-import.ll +++ b/llvm/test/CodeGen/WebAssembly/indirect-import.ll @@ -70,10 +70,10 @@ attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } -; CHECK: .functype extern_fd (f64) -> (f32) +; CHECK: .functype extern_sret (i32) -> () ; CHECK: .functype extern_vj (i64) -> () +; CHECK: .functype extern_i128ret (i32, i64) -> () +; CHECK: .functype extern_struct (i32) -> () ; CHECK: .functype extern_v () -> () ; CHECK: .functype extern_ijidf (i64, i32, f64, f32) -> (i32) -; CHECK: .functype extern_struct (i32) -> () -; CHECK: .functype extern_sret (i32) -> () -; CHECK: .functype extern_i128ret (i32, i64) -> () +; CHECK: .functype extern_fd (f64) -> (f32)