llvm.org GIT mirror llvm / 23fe8db
[WebAssembly] Initial implementation of PIC code generation This change implements lowering of references global symbols in PIC mode. This change implements lowering of global references in PIC mode using a new @GOT reference type. @GOT references can be used with function or data symbol names combined with the get_global instruction. In this case the linker will insert the wasm global that stores the address of the symbol (either in memory for data symbols or in the wasm table for function symbols). For now I'm continuing to use the R_WASM_GLOBAL_INDEX_LEB relocation type for this type of reference which means that this relocation type can refer to either a global or a function or data symbol. We could choose to introduce specific relocation types for GOT entries in the future. See the current dynamic linking proposal: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md Differential Revision: https://reviews.llvm.org/D54647 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@357022 91177308-0d34-0410-b5e6-96231b3b80d8 Sam Clegg 1 year, 8 months ago
16 changed file(s) with 634 addition(s) and 201 deletion(s). Raw diff Collapse all Expand all
1717 bool IsWeak = false;
1818 bool IsHidden = false;
1919 bool IsComdat = false;
20 mutable bool IsUsedInGOT = false;
2021 Optional ImportModule;
2122 Optional ImportName;
2223 wasm::WasmSignature *Signature = nullptr;
7778 }
7879 void setImportName(StringRef Name) { ImportName = Name; }
7980
81 void setUsedInGOT() const { IsUsedInGOT = true; }
82 bool isUsedInGOT() const { return IsUsedInGOT; }
83
8084 const wasm::WasmSignature *getSignature() const { return Signature; }
8185 void setSignature(wasm::WasmSignature *Sig) { Signature = Sig; }
8286
242242 // Maps function/global symbols to the function/global/event/section index
243243 // space.
244244 DenseMap WasmIndices;
245 DenseMap GOTIndices;
245246 // Maps data symbols to the Wasm segment and offset/size with the segment.
246247 DenseMap DataLocations;
247248
259260
260261 DenseMap SignatureIndices;
261262 SmallVector Signatures;
262 SmallVector Globals;
263263 SmallVector DataSegments;
264264 unsigned NumFunctionImports = 0;
265265 unsigned NumGlobalImports = 0;
287287 DataRelocations.clear();
288288 TypeIndices.clear();
289289 WasmIndices.clear();
290 GOTIndices.clear();
290291 TableIndices.clear();
291292 DataLocations.clear();
292293 CustomSections.clear();
295296 CustomSectionsRelocations.clear();
296297 SignatureIndices.clear();
297298 Signatures.clear();
298 Globals.clear();
299299 DataSegments.clear();
300300 SectionFunctions.clear();
301301 NumFunctionImports = 0;
325325 void writeImportSection(ArrayRef Imports, uint32_t DataSize,
326326 uint32_t NumElements);
327327 void writeFunctionSection(ArrayRef Functions);
328 void writeGlobalSection();
329328 void writeExportSection(ArrayRef Exports);
330329 void writeElemSection(ArrayRef TableElems);
331330 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
544543 SymA->setUsedInReloc();
545544 }
546545
546 if (RefA->getKind() == MCSymbolRefExpr::VK_GOT)
547 SymA->setUsedInGOT();
548
547549 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
548550 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
549551
574576 // useable.
575577 uint32_t
576578 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
579 if (RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB && !RelEntry.Symbol->isGlobal()) {
580 assert(GOTIndices.count(RelEntry.Symbol) > 0 && "symbol not found in GOT index space");
581 return GOTIndices[RelEntry.Symbol];
582 }
583
577584 switch (RelEntry.Type) {
578585 case wasm::R_WASM_TABLE_INDEX_SLEB:
579586 case wasm::R_WASM_TABLE_INDEX_I32: {
589596 case wasm::R_WASM_GLOBAL_INDEX_LEB:
590597 case wasm::R_WASM_EVENT_INDEX_LEB:
591598 // Provisional value is function/global/event Wasm index
592 if (!WasmIndices.count(RelEntry.Symbol))
593 report_fatal_error("symbol not found in wasm index space: " +
594 RelEntry.Symbol->getName());
599 assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space");
595600 return WasmIndices[RelEntry.Symbol];
596601 case wasm::R_WASM_FUNCTION_OFFSET_I32:
597602 case wasm::R_WASM_SECTION_OFFSET_I32: {
782787 encodeULEB128(Functions.size(), W.OS);
783788 for (const WasmFunction &Func : Functions)
784789 encodeULEB128(Func.SigIndex, W.OS);
785
786 endSection(Section);
787 }
788
789 void WasmObjectWriter::writeGlobalSection() {
790 if (Globals.empty())
791 return;
792
793 SectionBookkeeping Section;
794 startSection(Section, wasm::WASM_SEC_GLOBAL);
795
796 encodeULEB128(Globals.size(), W.OS);
797 for (const WasmGlobal &Global : Globals) {
798 writeValueType(static_cast(Global.Type.Type));
799 W.OS << char(Global.Type.Mutable);
800
801 W.OS << char(wasm::WASM_OPCODE_I32_CONST);
802 encodeSLEB128(Global.InitialValue, W.OS);
803 W.OS << char(wasm::WASM_OPCODE_END);
804 }
805790
806791 endSection(Section);
807792 }
12071192 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
12081193 Import.SigIndex = getFunctionType(WS);
12091194 Imports.push_back(Import);
1195 assert(WasmIndices.count(&WS) == 0);
12101196 WasmIndices[&WS] = NumFunctionImports++;
12111197 } else if (WS.isGlobal()) {
12121198 if (WS.isWeak())
12131199 report_fatal_error("undefined global symbol cannot be weak");
12141200
12151201 wasm::WasmImport Import;
1216 Import.Module = WS.getImportModule();
12171202 Import.Field = WS.getImportName();
12181203 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1204 Import.Module = WS.getImportModule();
12191205 Import.Global = WS.getGlobalType();
12201206 Imports.push_back(Import);
1207 assert(WasmIndices.count(&WS) == 0);
12211208 WasmIndices[&WS] = NumGlobalImports++;
12221209 } else if (WS.isEvent()) {
12231210 if (WS.isWeak())
12301217 Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
12311218 Import.Event.SigIndex = getEventType(WS);
12321219 Imports.push_back(Import);
1220 assert(WasmIndices.count(&WS) == 0);
12331221 WasmIndices[&WS] = NumEventImports++;
12341222 }
1223 }
1224 }
1225
1226 // Add imports for GOT globals
1227 for (const MCSymbol &S : Asm.symbols()) {
1228 const auto &WS = static_cast(S);
1229 if (WS.isUsedInGOT()) {
1230 wasm::WasmImport Import;
1231 if (WS.isFunction())
1232 Import.Module = "GOT.func";
1233 else
1234 Import.Module = "GOT.mem";
1235 Import.Field = WS.getName();
1236 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1237 Import.Global = {wasm::WASM_TYPE_I32, true};
1238 Imports.push_back(Import);
1239 assert(GOTIndices.count(&WS) == 0);
1240 GOTIndices[&WS] = NumGlobalImports++;
12351241 }
12361242 }
12371243
14001406 wasm::WasmEventType Event;
14011407 Event.SigIndex = getEventType(WS);
14021408 Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
1409 assert(WasmIndices.count(&WS) == 0);
14031410 WasmIndices[&WS] = Index;
14041411 Events.push_back(Event);
14051412 } else {
14061413 // An import; the index was assigned above.
1414 assert(WasmIndices.count(&WS) > 0);
14071415 Index = WasmIndices.find(&WS)->second;
14081416 }
14091417 LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second
14331441 if (ResolvedSym->isFunction()) {
14341442 assert(WasmIndices.count(ResolvedSym) > 0);
14351443 uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second;
1444 assert(WasmIndices.count(&WS) == 0);
14361445 WasmIndices[&WS] = WasmIndex;
14371446 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
14381447 } else if (ResolvedSym->isData()) {
15851594 writeFunctionSection(Functions);
15861595 // Skip the "table" section; we import the table instead.
15871596 // Skip the "memory" section; we import the memory instead.
1588 writeGlobalSection();
15891597 writeEventSection(Events);
15901598 writeExportSection(Exports);
15911599 writeElemSection(TableElems);
776776 object_error::parse_failed);
777777 break;
778778 case wasm::R_WASM_GLOBAL_INDEX_LEB:
779 if (!isValidGlobalSymbol(Reloc.Index))
779 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
780 // symbols to refer to thier GOT enties.
781 if (!isValidGlobalSymbol(Reloc.Index) &&
782 !isValidDataSymbol(Reloc.Index) &&
783 !isValidFunctionSymbol(Reloc.Index))
780784 return make_error("Bad relocation global index",
781785 object_error::parse_failed);
782786 break;
9393 MO_SYMBOL_GLOBAL = 0x2,
9494 MO_SYMBOL_EVENT = 0x4,
9595 MO_SYMBOL_MASK = 0x7,
96
97 // Address of data symbol via a wasm global. This adds a level of indirection
98 // similar to the GOT on native platforms.
99 MO_GOT = 0x8,
96100 };
101
97102 } // end namespace WebAssemblyII
98103
99104 } // end namespace llvm
4545 return Ref->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX;
4646 }
4747
48 static bool isGOTRef(const MCSymbolRefExpr *Ref) {
49 return Ref->getKind() == MCSymbolRefExpr::VK_GOT;
50 }
51
4852 static const MCSection *getFixupSection(const MCExpr *Expr) {
4953 if (auto SyExp = dyn_cast(Expr)) {
5054 if (SyExp->getSymbol().isInSection())
7882 case WebAssembly::fixup_code_sleb128_i64:
7983 llvm_unreachable("fixup_sleb128_i64 not implemented yet");
8084 case WebAssembly::fixup_code_uleb128_i32:
85 if (SymA.isGlobal() || isGOTRef(RefA))
86 return wasm::R_WASM_GLOBAL_INDEX_LEB;
8187 if (SymA.isFunction()) {
8288 if (isFunctionSignatureRef(RefA))
8389 return wasm::R_WASM_TYPE_INDEX_LEB;
8490 else
8591 return wasm::R_WASM_FUNCTION_INDEX_LEB;
8692 }
87 if (SymA.isGlobal())
88 return wasm::R_WASM_GLOBAL_INDEX_LEB;
8993 if (SymA.isEvent())
9094 return wasm::R_WASM_EVENT_INDEX_LEB;
9195 return wasm::R_WASM_MEMORY_ADDR_LEB;
150150 return MVT::INVALID_SIMPLE_VALUE_TYPE;
151151 }
152152 bool computeAddress(const Value *Obj, Address &Addr);
153 void materializeLoadStoreOperands(Address &Addr);
153 bool materializeLoadStoreOperands(Address &Addr);
154154 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
155155 MachineMemOperand *MMO);
156156 unsigned maskI1Value(unsigned Reg, const Value *V);
373373 return Addr.getReg() != 0;
374374 }
375375
376 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
376 bool WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
377377 if (Addr.isRegBase()) {
378378 unsigned Reg = Addr.getReg();
379379 if (Reg == 0) {
380 const GlobalValue *GV = Addr.getGlobalValue();
381 if (GV && TLI.isPositionIndependent())
382 return false;
380383 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
381384 : &WebAssembly::I32RegClass);
382385 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
386389 Addr.setReg(Reg);
387390 }
388391 }
392 return true;
389393 }
390394
391395 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
603607 }
604608
605609 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
606 if (const auto *GV = dyn_cast(C)) {
610 if (const GlobalValue *GV = dyn_cast(C)) {
611 if (TLI.isPositionIndependent())
612 return 0;
607613 unsigned ResultReg =
608614 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
609615 : &WebAssembly::I32RegClass);
11801186 return false;
11811187 }
11821188
1183 materializeLoadStoreOperands(Addr);
1189 if (!materializeLoadStoreOperands(Addr))
1190 return false;
11841191
11851192 unsigned ResultReg = createResultReg(RC);
11861193 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
12321239 return false;
12331240 }
12341241
1235 materializeLoadStoreOperands(Addr);
1242 if (!materializeLoadStoreOperands(Addr))
1243 return false;
12361244
12371245 unsigned ValueReg = getRegForValue(Store->getValueOperand());
12381246 if (ValueReg == 0)
1616 HANDLE_NODETYPE(CALL0)
1717 HANDLE_NODETYPE(RETURN)
1818 HANDLE_NODETYPE(ARGUMENT)
19 // A wrapper node for TargetExternalSymbol, TargetGlobalAddress, and MCSymbol
1920 HANDLE_NODETYPE(Wrapper)
21 // A special wapper used in PIC code for __memory_base/__table_base relcative
22 // access.
23 HANDLE_NODETYPE(WrapperPIC)
2024 HANDLE_NODETYPE(BR_IF)
2125 HANDLE_NODETYPE(BR_TABLE)
2226 HANDLE_NODETYPE(SHUFFLE)
726726 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
727727 } else if (IsVarArg) {
728728 FINode = DAG.getIntPtrConstant(0, DL);
729 }
730
731 if (Callee->getOpcode() == ISD::GlobalAddress) {
732 // If the callee is a GlobalAddress node (quite common, every direct call
733 // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
734 // doesn't at MO_GOT which is not needed for direct calls.
735 GlobalAddressSDNode* GA = cast(Callee);
736 Callee = DAG.getTargetGlobalAddress(GA->getGlobal(), DL,
737 getPointerTy(DAG.getDataLayout()),
738 GA->getOffset());
739 Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
740 getPointerTy(DAG.getDataLayout()), Callee);
729741 }
730742
731743 // Compute the operands for the CALLn node.
982994 "Unexpected target flags on generic GlobalAddressSDNode");
983995 if (GA->getAddressSpace() != 0)
984996 fail(DL, DAG, "WebAssembly only expects the 0 address space");
985 return DAG.getNode(
986 WebAssemblyISD::Wrapper, DL, VT,
987 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset()));
997
998 unsigned Flags = 0;
999 if (isPositionIndependent()) {
1000 const GlobalValue *GV = GA->getGlobal();
1001 if (getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) {
1002 MachineFunction &MF = DAG.getMachineFunction();
1003 MVT PtrVT = getPointerTy(MF.getDataLayout());
1004 const char *BaseName;
1005 if (GV->getValueType()->isFunctionTy())
1006 BaseName = MF.createExternalSymbolName("__table_base");
1007 else
1008 BaseName = MF.createExternalSymbolName("__memory_base");
1009 SDValue BaseAddr =
1010 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
1011 DAG.getTargetExternalSymbol(BaseName, PtrVT));
1012
1013 SDValue SymAddr = DAG.getNode(
1014 WebAssemblyISD::WrapperPIC, DL, VT,
1015 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset()));
1016
1017 return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
1018 } else {
1019 Flags |= WebAssemblyII::MO_GOT;
1020 }
1021 }
1022
1023 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
1024 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
1025 GA->getOffset(), Flags));
9881026 }
9891027
9901028 SDValue
1414 // WebAssembly Instruction Predicate Definitions.
1515 //===----------------------------------------------------------------------===//
1616
17 def IsPIC : Predicate<"TM.isPositionIndependent()">;
18 def IsNotPIC : Predicate<"!TM.isPositionIndependent()">;
19
1720 def HasAddr32 : Predicate<"!Subtarget->hasAddr64()">;
1821
1922 def HasAddr64 : Predicate<"Subtarget->hasAddr64()">;
6669 SDTCisVT<1, iPTR>]>;
6770 def SDT_WebAssemblyCallSeqEnd :
6871 SDCallSeqEnd<[SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>;
69 def SDT_WebAssemblyCall0 : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
70 def SDT_WebAssemblyCall1 : SDTypeProfile<1, -1, [SDTCisPtrTy<1>]>;
71 def SDT_WebAssemblyBrTable : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
72 def SDT_WebAssemblyArgument : SDTypeProfile<1, 1, [SDTCisVT<1, i32>]>;
73 def SDT_WebAssemblyReturn : SDTypeProfile<0, -1, []>;
74 def SDT_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
75 SDTCisPtrTy<0>]>;
76 def SDT_WebAssemblyThrow : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
72 def SDT_WebAssemblyCall0 : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
73 def SDT_WebAssemblyCall1 : SDTypeProfile<1, -1, [SDTCisPtrTy<1>]>;
74 def SDT_WebAssemblyBrTable : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
75 def SDT_WebAssemblyArgument : SDTypeProfile<1, 1, [SDTCisVT<1, i32>]>;
76 def SDT_WebAssemblyReturn : SDTypeProfile<0, -1, []>;
77 def SDT_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
78 SDTCisPtrTy<0>]>;
79 def SDT_WebAssemblyWrapperPIC : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
80 SDTCisPtrTy<0>]>;
81 def SDT_WebAssemblyThrow : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
7782
7883 //===----------------------------------------------------------------------===//
7984 // WebAssembly-specific DAG Nodes.
100105 SDT_WebAssemblyReturn, [SDNPHasChain]>;
101106 def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper",
102107 SDT_WebAssemblyWrapper>;
108 def WebAssemblywrapperPIC : SDNode<"WebAssemblyISD::WrapperPIC",
109 SDT_WebAssemblyWrapperPIC>;
103110 def WebAssemblythrow : SDNode<"WebAssemblyISD::THROW", SDT_WebAssemblyThrow,
104111 [SDNPHasChain, SDNPVariadic]>;
105112
294301 } // isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1
295302
296303 def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
297 (CONST_I32 tglobaladdr:$addr)>;
304 (CONST_I32 tglobaladdr:$addr)>, Requires<[IsNotPIC]>;
305
306 def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
307 (GLOBAL_GET_I32 tglobaladdr:$addr)>, Requires<[IsPIC]>;
308
309 def : Pat<(i32 (WebAssemblywrapperPIC tglobaladdr:$addr)),
310 (CONST_I32 tglobaladdr:$addr)>, Requires<[IsPIC]>;
311
298312 def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
299 (CONST_I32 texternalsym:$addr)>;
313 (GLOBAL_GET_I32 texternalsym:$addr)>, Requires<[IsPIC]>;
314
315 def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
316 (CONST_I32 texternalsym:$addr)>, Requires<[IsNotPIC]>;
317
300318 def : Pat<(i32 (WebAssemblywrapper mcsym:$sym)), (CONST_I32 mcsym:$sym)>;
301319 def : Pat<(i64 (WebAssemblywrapper mcsym:$sym)), (CONST_I64 mcsym:$sym)>;
302320
9494
9595 class LoadPatGlobalAddr :
9696 Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))),
97 (inst 0, tglobaladdr:$off, I32:$addr)>;
97 (inst 0, tglobaladdr:$off, I32:$addr)>, Requires<[IsNotPIC]>;
9898
9999 def : LoadPatGlobalAddr;
100100 def : LoadPatGlobalAddr;
112112
113113 class LoadPatGlobalAddrOffOnly :
114114 Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))),
115 (inst 0, tglobaladdr:$off, (CONST_I32 0))>;
115 (inst 0, tglobaladdr:$off, (CONST_I32 0))>, Requires<[IsNotPIC]>;
116116
117117 def : LoadPatGlobalAddrOffOnly;
118118 def : LoadPatGlobalAddrOffOnly;
284284 class StorePatGlobalAddr :
285285 Pat<(kind ty:$val,
286286 (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off))),
287 (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
287 (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>, Requires<[IsNotPIC]>;
288288 def : StorePatGlobalAddr;
289289 def : StorePatGlobalAddr;
290290 def : StorePatGlobalAddr;
300300
301301 class StorePatGlobalAddrOffOnly :
302302 Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)),
303 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
303 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>, Requires<[IsNotPIC]>;
304304 def : StorePatGlobalAddrOffOnly;
305305 def : StorePatGlobalAddrOffOnly;
306306 def : StorePatGlobalAddrOffOnly;
7272 auto *WasmSym = cast(Printer.GetExternalSymbolSymbol(Name));
7373 const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
7474
75 // Except for the two exceptions (__stack_pointer and __cpp_exception), all
76 // other external symbols used by CodeGen are functions. It's OK to hardcode
77 // knowledge of specific symbols here; this method is precisely there for
78 // fetching the signatures of known Clang-provided symbols.
79 if (strcmp(Name, "__stack_pointer") == 0) {
75 // Except for certain known symbols, all symbols used by CodeGen are
76 // functions. It's OK to hardcode knowledge of specific symbols here; this
77 // method is precisely there for fetching the signatures of known
78 // Clang-provided symbols.
79 if (strcmp(Name, "__stack_pointer") == 0 ||
80 strcmp(Name, "__memory_base") == 0 || strcmp(Name, "__table_base") == 0) {
81 bool Mutable = strcmp(Name, "__stack_pointer") == 0;
8082 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
8183 WasmSym->setGlobalType(wasm::WasmGlobalType{
8284 uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
8385 : wasm::WASM_TYPE_I32),
84 true});
86 Mutable});
8587 return WasmSym;
8688 }
8789
117119 return WasmSym;
118120 }
119121
120 MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(MCSymbol *Sym,
121 int64_t Offset,
122 bool IsFunc, bool IsGlob,
123 bool IsEvent) const {
124 const MCExpr *Expr =
125 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
122 MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(
123 MCSymbol *Sym, int64_t Offset, bool IsFunc, unsigned TargetFlags) const {
124 MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None;
125 if (TargetFlags & WebAssemblyII::MO_GOT)
126 Kind = MCSymbolRefExpr::VK_GOT;
127 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
126128
127129 if (Offset != 0) {
128 if (IsFunc)
130 if (TargetFlags & WebAssemblyII::MO_GOT)
131 report_fatal_error("GOT symbol references do not support offsets");
132 unsigned Type = TargetFlags & WebAssemblyII::MO_SYMBOL_MASK;
133 assert((Type == WebAssemblyII::MO_SYMBOL_FUNCTION) == IsFunc);
134 if (Type == WebAssemblyII::MO_SYMBOL_FUNCTION || IsFunc)
129135 report_fatal_error("Function addresses with offsets not supported");
130 if (IsGlob)
136 if (Type == WebAssemblyII::MO_SYMBOL_GLOBAL)
131137 report_fatal_error("Global indexes with offsets not supported");
132 if (IsEvent)
138 if (Type == WebAssemblyII::MO_SYMBOL_EVENT)
133139 report_fatal_error("Event indexes with offsets not supported");
134140 Expr =
135141 MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx);
229235 break;
230236 }
231237 case MachineOperand::MO_GlobalAddress:
232 assert(MO.getTargetFlags() == WebAssemblyII::MO_NO_FLAG &&
233 "WebAssembly does not use target flags on GlobalAddresses");
234238 MCOp = lowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(),
235239 MO.getGlobal()->getValueType()->isFunctionTy(),
236 false, false);
240 MO.getTargetFlags());
237241 break;
238242 case MachineOperand::MO_ExternalSymbol:
239243 // The target flag indicates whether this is a symbol for a
241245 assert((MO.getTargetFlags() & ~WebAssemblyII::MO_SYMBOL_MASK) == 0 &&
242246 "WebAssembly uses only symbol flags on ExternalSymbols");
243247 MCOp = lowerSymbolOperand(
244 GetExternalSymbolSymbol(MO), /*Offset=*/0,
245 (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_FUNCTION) != 0,
246 (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0,
247 (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_EVENT) != 0);
248 GetExternalSymbolSymbol(MO), /*Offset=*/0, false, MO.getTargetFlags());
248249 break;
249250 case MachineOperand::MO_MCSymbol:
250251 // This is currently used only for LSDA symbols (GCC_except_table),
251252 // because global addresses or other external symbols are handled above.
252253 assert(MO.getTargetFlags() == 0 &&
253254 "WebAssembly does not use target flags on MCSymbol");
254 MCOp = lowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, false,
255 false);
255 MCOp = lowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, MO.getTargetFlags());
256256 break;
257257 }
258258
3232 MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const;
3333 MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const;
3434 MCOperand lowerSymbolOperand(MCSymbol *Sym, int64_t Offset, bool IsFunc,
35 bool IsGlob, bool IsEvent) const;
35 unsigned flags) const;
3636
3737 public:
3838 WebAssemblyMCInstLower(MCContext &ctx, WebAssemblyAsmPrinter &printer)
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=CHECK,NON-PIC
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -relocation-model=pic | FileCheck %s -check-prefixes=CHECK,PIC
2
13
24 ; Test folding constant offsets and symbols into load and store addresses under
35 ; a variety of circumstances.
911
1012 ; CHECK-LABEL: load_test0:
1113 ; CHECK-NEXT: .functype load_test0 () -> (i32){{$}}
12 ; CHECK-NEXT: i32.const $push0=, 0{{$}}
13 ; CHECK-NEXT: i32.load $push1=, g+40($pop0){{$}}
14 ; NON-PIC-NEXT: i32.const $push0=, 0{{$}}
15 ; NON-PIC-NEXT: i32.load $push1=, g+40($pop0){{$}}
16 ; PIC-NEXT: global.get $push0=, g@GOT{{$}}
17 ; PIC-NEXT: i32.load $push1=, 40($pop0){{$}}
1418 ; CHECK-NEXT: return $pop1{{$}}
1519 define i32 @load_test0() {
1620 %t = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
1923
2024 ; CHECK-LABEL: load_test0_noinbounds:
2125 ; CHECK-NEXT: .functype load_test0_noinbounds () -> (i32){{$}}
22 ; CHECK-NEXT: i32.const $push0=, 0{{$}}
23 ; CHECK-NEXT: i32.load $push1=, g+40($pop0){{$}}
26 ; NON-PIC-NEXT: i32.const $push0=, 0{{$}}
27 ; NON-PIC-NEXT: i32.load $push1=, g+40($pop0){{$}}
28 ; PIC-NEXT: global.get $push0=, g@GOT{{$}}
29 ; PIC-NEXT: i32.load $push1=, 40($pop0){{$}}
2430 ; CHECK-NEXT: return $pop1{{$}}
2531 define i32 @load_test0_noinbounds() {
2632 %t = load i32, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
3339
3440 ; CHECK-LABEL: load_test1:
3541 ; CHECK-NEXT: .functype load_test1 (i32) -> (i32){{$}}
36 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
42 ; CHECK-NEX T: i32.const $push0=, 2{{$}}
3743 ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
3844 ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
3945 ; CHECK-NEX T: return $pop2{{$}}
4652
4753 ; CHECK-LABEL: load_test2:
4854 ; CHECK-NEXT: .functype load_test2 (i32) -> (i32){{$}}
49 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
55 ; CHECK-NEX T: i32.const $push0=, 2{{$}}
5056 ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
5157 ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
5258 ; CHECK-NEX T: return $pop2{{$}}
5965
6066 ; CHECK-LABEL: load_test3:
6167 ; CHECK-NEXT: .functype load_test3 (i32) -> (i32){{$}}
62 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
68 ; CHECK-NEX T: i32.const $push0=, 2{{$}}
6369 ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
6470 ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
6571 ; CHECK-NEX T: return $pop2{{$}}
7278
7379 ; CHECK-LABEL: load_test4:
7480 ; CHECK-NEXT: .functype load_test4 (i32) -> (i32){{$}}
75 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
81 ; CHECK-NEX T: i32.const $push0=, 2{{$}}
7682 ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
7783 ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
7884 ; CHECK-NEX T: return $pop2{{$}}
8490
8591 ; CHECK-LABEL: load_test5:
8692 ; CHECK-NEXT: .functype load_test5 (i32) -> (i32){{$}}
87 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
93 ; CHECK-NEX T: i32.const $push0=, 2{{$}}
8894 ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
8995 ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
9096 ; CHECK-NEX T: return $pop2{{$}}
96102
97103 ; CHECK-LABEL: load_test6:
98104 ; CHECK-NEXT: .functype load_test6 (i32) -> (i32){{$}}
99 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
105 ; CHECK-NEX T: i32.const $push0=, 2{{$}}
100106 ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
101107 ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
102108 ; CHECK-NEX T: return $pop2{{$}}
109115
110116 ; CHECK-LABEL: load_test7:
111117 ; CHECK-NEXT: .functype load_test7 (i32) -> (i32){{$}}
112 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
118 ; CHECK-NEX T: i32.const $push0=, 2{{$}}
113119 ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
114120 ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
115121 ; CHECK-NEX T: return $pop2{{$}}
122128
123129 ; CHECK-LABEL: load_test8:
124130 ; CHECK-NEXT: .functype load_test8 (i32) -> (i32){{$}}
125 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
131 ; CHECK-NEX T: i32.const $push0=, 2{{$}}
126132 ; CHECK-NEX T: i32.shl $push1=, $0, $pop0{{$}}
127133 ; CHECK-NEX T: i32.load $push2=, g+40($pop1){{$}}
128134 ; CHECK-NEX T: return $pop2{{$}}
134140 }
135141
136142 ; CHECK-LABEL: load_test9:
137 ; CHECK-NEXT: .functype load_test9 () -> (i32){{$}}
138 ; CHECK-NEXT: i32.const $push0=, 0{{$}}
139 ; CHECK-NEXT: i32.load $push1=, g-40($pop0){{$}}
140 ; CHECK-NEXT: return $pop1{{$}}
143 ; CHECK-NEXT: .functype load_test9 () -> (i32){{$}}
144 ; NON-PIC-NEXT: i32.const $push0=, 0{{$}}
145 ; NON-PIC-NEXT: i32.load $push1=, g-40($pop0){{$}}
146 ; NON-PIC_NEXT: return $pop1{{$}}
147
148 ; PIC-NEXT: global.get $push1=, g@GOT{{$}}
149 ; PIC-NEXT: i32.const $push0=, -40{{$}}
150 ; PIC-NEXT: i32.add $push2=, $pop1, $pop0{{$}}
151 ; PIC-NEXT: i32.load $push3=, 0($pop2)
152 ; PIC-NEXT: return $pop3{{$}}
141153 define i32 @load_test9() {
142154 %t = load i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4
143155 ret i32 %t
145157
146158 ; CHECK-LABEL: load_test10:
147159 ; CHECK-NEXT: .functype load_test10 (i32) -> (i32){{$}}
148 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
149 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
150 ; CHECK-NEXT: i32.const $push2=, g-40{{$}}
151 ; CHECK-NEXT: i32.add $push3=, $pop1, $pop2{{$}}
152 ; CHECK-NEXT: i32.load $push4=, 0($pop3){{$}}
153 ; CHECK-NEXT: return $pop4{{$}}
160 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
161 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
162 ; NON-PIC-NEXT: i32.const $push2=, g-40{{$}}
163 ; NON-PIC-NEXT: i32.add $push3=, $pop1, $pop2{{$}}
164 ; NON-PIC-NEXT: i32.load $push4=, 0($pop3){{$}}
165 ; NON-PIC-NEXT: return $pop4{{$}}
166
167 ; PIC-NEXT: global.get $push2=, g@GOT{{$}}
168 ; PIC-NEXT: i32.const $push0=, 2{{$}}
169 ; PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
170 ; PIC-NEXT: i32.add $push3=, $pop2, $pop1{{$}}
171 ; PIC-NEXT: i32.const $push4=, -40{{$}}
172 ; PIC-NEXT: i32.add $push5=, $pop3, $pop4{{$}}
173 ; PIC-NEXT: i32.load $push6=, 0($pop5){{$}}
174 ; PIC-NEXT: return $pop6{{$}}
154175 define i32 @load_test10(i32 %n) {
155176 %add = add nsw i32 %n, -10
156177 %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
334355
335356 ; CHECK-LABEL: store_test0:
336357 ; CHECK-NEXT: .functype store_test0 (i32) -> (){{$}}
337 ; CHECK-NEXT: i32.const $push0=, 0{{$}}
338 ; CHECK-NEXT: i32.store g+40($pop0), $0{{$}}
339 ; CHECK-NEXT: return{{$}}
358 ; NON-PIC-NEXT: i32.const $push0=, 0{{$}}
359 ; NON-PIC-NEXT: i32.store g+40($pop0), $0{{$}}
360 ; PIC-NEXT: global.get $push0=, g@GOT{{$}}
361 ; PIC-NEXT: i32.store 40($pop0), $0
362 ; CHECK-NEXT: return{{$}}
340363 define void @store_test0(i32 %i) {
341364 store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
342365 ret void
344367
345368 ; CHECK-LABEL: store_test0_noinbounds:
346369 ; CHECK-NEXT: .functype store_test0_noinbounds (i32) -> (){{$}}
347 ; CHECK-NEXT: i32.const $push0=, 0{{$}}
348 ; CHECK-NEXT: i32.store g+40($pop0), $0{{$}}
349 ; CHECK-NEXT: return{{$}}
370 ; NON-PIC-NEXT: i32.const $push0=, 0{{$}}
371 ; NON-PIC-NEXT: i32.store g+40($pop0), $0{{$}}
372 ; PIC-NEXT: global.get $push0=, g@GOT{{$}}
373 ; PIC-NEXT: i32.store 40($pop0), $0{{$}}
374 ; CHECK-NEXT: return{{$}}
350375 define void @store_test0_noinbounds(i32 %i) {
351376 store i32 %i, i32* getelementptr ([0 x i32], [0 x i32]* @g, i32 0, i32 10), align 4
352377 ret void
354379
355380 ; CHECK-LABEL: store_test1:
356381 ; CHECK-NEXT: .functype store_test1 (i32, i32) -> (){{$}}
357 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
358 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
382 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
383 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
359384 ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
360385 ; CHECK-NEX T: return{{$}}
361386 define void @store_test1(i32 %n, i32 %i) {
367392
368393 ; CHECK-LABEL: store_test2:
369394 ; CHECK-NEXT: .functype store_test2 (i32, i32) -> (){{$}}
370 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
371 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
395 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
396 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
372397 ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
373398 ; CHECK-NEX T: return{{$}}
374399 define void @store_test2(i32 %n, i32 %i) {
380405
381406 ; CHECK-LABEL: store_test3:
382407 ; CHECK-NEXT: .functype store_test3 (i32, i32) -> (){{$}}
383 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
384 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
408 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
409 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
385410 ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
386411 ; CHECK-NEX T: return{{$}}
387412 define void @store_test3(i32 %n, i32 %i) {
393418
394419 ; CHECK-LABEL: store_test4:
395420 ; CHECK-NEXT: .functype store_test4 (i32, i32) -> (){{$}}
396 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
397 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
421 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
422 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
398423 ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
399424 ; CHECK-NEX T: return{{$}}
400425 define void @store_test4(i32 %n, i32 %i) {
405430
406431 ; CHECK-LABEL: store_test5:
407432 ; CHECK-NEXT: .functype store_test5 (i32, i32) -> (){{$}}
408 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
409 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
433 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
434 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
410435 ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
411436 ; CHECK-NEX T: return{{$}}
412437 define void @store_test5(i32 %n, i32 %i) {
417442
418443 ; CHECK-LABEL: store_test6:
419444 ; CHECK-NEXT: .functype store_test6 (i32, i32) -> (){{$}}
420 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
421 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
445 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
446 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
422447 ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
423448 ; CHECK-NEX T: return{{$}}
424449 define void @store_test6(i32 %n, i32 %i) {
430455
431456 ; CHECK-LABEL: store_test7:
432457 ; CHECK-NEXT: .functype store_test7 (i32, i32) -> (){{$}}
433 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
434 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
458 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
459 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
435460 ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
436461 ; CHECK-NEX T: return{{$}}
437462 define void @store_test7(i32 %n, i32 %i) {
443468
444469 ; CHECK-LABEL: store_test8:
445470 ; CHECK-NEXT: .functype store_test8 (i32, i32) -> (){{$}}
446 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
447 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
471 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
472 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
448473 ; CHECK-NEX T: i32.store g+40($pop1), $1{{$}}
449474 ; CHECK-NEX T: return{{$}}
450475 define void @store_test8(i32 %n, i32 %i) {
456481
457482 ; CHECK-LABEL: store_test9:
458483 ; CHECK-NEXT: .functype store_test9 (i32) -> (){{$}}
459 ; CHECK-NEXT: i32.const $push0=, 0{{$}}
460 ; CHECK-NEXT: i32.store g-40($pop0), $0{{$}}
461 ; CHECK-NEXT: return{{$}}
484 ; NON-PIC-NEXT: i32.const $push0=, 0{{$}}
485 ; NON-PIC-NEXT: i32.store g-40($pop0), $0{{$}}
486 ; PIC-NEXT: global.get $push1=, g@GOT{{$}}
487 ; PIC-NEXT: i32.const $push0=, -40{{$}}
488 ; PIC-NEXT: i32.add $push2=, $pop1, $pop0{{$}}
489 ; PIC-NEXT: i32.store 0($pop2), $0
490 ; CHECK-NEXT: return{{$}}
462491 define void @store_test9(i32 %i) {
463492 store i32 %i, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @g, i32 0, i32 1073741814), align 4
464493 ret void
466495
467496 ; CHECK-LABEL: store_test10:
468497 ; CHECK-NEXT: .functype store_test10 (i32, i32) -> (){{$}}
469 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
470 ; CHECK-NEXT: i32.shl $push1=, $0, $pop0{{$}}
471 ; CHECK-NEXT: i32.const $push2=, g-40{{$}}
472 ; CHECK-NEXT: i32.add $push3=, $pop1, $pop2{{$}}
473 ; CHECK-NEXT: i32.store 0($pop3), $1{{$}}
474 ; CHECK-NEXT: return{{$}}
498 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
499 ; NON-PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
500 ; NON-PIC-NEXT: i32.const $push2=, g-40{{$}}
501 ; NON-PIC-NEXT: i32.add $push3=, $pop1, $pop2{{$}}
502 ; NON-PIC-NEXT: i32.store 0($pop3), $1{{$}}
503 ; PIC-NEXT: global.get $push2=, g@GOT{{$}}
504 ; PIC-NEXT: i32.const $push0=, 2{{$}}
505 ; PIC-NEXT: i32.shl $push1=, $0, $pop0{{$}}
506 ; PIC-NEXT: i32.add $push3=, $pop2, $pop1{{$}}
507 ; PIC-NEXT: i32.const $push4=, -40{{$}}
508 ; PIC-NEXT: i32.add $push5=, $pop3, $pop4{{$}}
509 ; PIC-NEXT: i32.store 0($pop5), $1{{$}}
510 ; CHECK-NEXT: return{{$}}
475511 define void @store_test10(i32 %n, i32 %i) {
476512 %add = add nsw i32 %n, -10
477513 %arrayidx = getelementptr inbounds [0 x i32], [0 x i32]* @g, i32 0, i32 %add
481517
482518 ; CHECK-LABEL: store_test11:
483519 ; CHECK-NEXT: .functype store_test11 (i32, i32) -> (){{$}}
484 ; CHECK-NEXT: i32.store 40($0), $1{{$}}
485 ; CHECK-NEXT: return{{$}}
520 ; CHECK-NEXT: i32.store 40($0), $1{{$}}
521 ; CHECK-NEXT: return{{$}}
486522 define void @store_test11(i32* %p, i32 %i) {
487523 %arrayidx = getelementptr inbounds i32, i32* %p, i32 10
488524 store i32 %i, i32* %arrayidx, align 4
491527
492528 ; CHECK-LABEL: store_test11_noinbounds:
493529 ; CHECK-NEXT: .functype store_test11_noinbounds (i32, i32) -> (){{$}}
494 ; CHECK-NEXT: i32.const $push0=, 40{{$}}
495 ; CHECK-NEXT: i32.add $push1=, $0, $pop0{{$}}
496 ; CHECK-NEXT: i32.store 0($pop1), $1{{$}}
497 ; CHECK-NEXT: return{{$}}
530 ; CHECK-NEXT: i32.const $push0=, 40{{$}}
531 ; CHECK-NEXT: i32.add $push1=, $0, $pop0{{$}}
532 ; CHECK-NEXT: i32.store 0($pop1), $1{{$}}
533 ; CHECK-NEXT: return{{$}}
498534 define void @store_test11_noinbounds(i32* %p, i32 %i) {
499535 %arrayidx = getelementptr i32, i32* %p, i32 10
500536 store i32 %i, i32* %arrayidx, align 4
503539
504540 ; CHECK-LABEL: store_test12:
505541 ; CHECK-NEXT: .functype store_test12 (i32, i32, i32) -> (){{$}}
506 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
507 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
508 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
509 ; CHECK-NEXT: i32.const $push3=, 40{{$}}
510 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
511 ; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
512 ; CHECK-NEXT: return{{$}}
542 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
543 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
544 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
545 ; NON-PIC-NEXT: i32.const $push3=, 40{{$}}
546 ; NON-PIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
547 ; NON-PIC-NEXT: i32.store 0($pop4), $2{{$}}
548 ; NON-PIC-NEXT: return{{$}}
513549 define void @store_test12(i32* %p, i32 %n, i32 %i) {
514550 %add = add nsw i32 %n, 10
515551 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
519555
520556 ; CHECK-LABEL: store_test13:
521557 ; CHECK-NEXT: .functype store_test13 (i32, i32, i32) -> (){{$}}
522 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
523 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
524 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
525 ; CHECK-NEXT: i32.const $push3=, 40{{$}}
526 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
527 ; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
528 ; CHECK-NEXT: return{{$}}
558 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
559 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
560 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
561 ; NON-PIC-NEXT: i32.const $push3=, 40{{$}}
562 ; NON-PIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
563 ; NON-PIC-NEXT: i32.store 0($pop4), $2{{$}}
564 ; NON-PIC-NEXT: return{{$}}
529565 define void @store_test13(i32* %p, i32 %n, i32 %i) {
530566 %add = add nsw i32 10, %n
531567 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
535571
536572 ; CHECK-LABEL: store_test14:
537573 ; CHECK-NEXT: .functype store_test14 (i32, i32, i32) -> (){{$}}
538 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
539 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
540 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
541 ; CHECK-NEXT: i32.store 40($pop2), $2{{$}}
542 ; CHECK-NEXT: return{{$}}
574 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
575 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
576 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
577 ; NON-PIC-NEXT: i32.store 40($pop2), $2{{$}}
578 ; NON-PIC-NEXT: return{{$}}
543579 define void @store_test14(i32* %p, i32 %n, i32 %i) {
544580 %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n
545581 %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
549585
550586 ; CHECK-LABEL: store_test15:
551587 ; CHECK-NEXT: .functype store_test15 (i32, i32, i32) -> (){{$}}
552 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
553 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
554 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
555 ; CHECK-NEXT: i32.const $push3=, 40{{$}}
556 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
557 ; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
558 ; CHECK-NEXT: return{{$}}
588 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
589 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
590 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
591 ; NON-PIC-NEXT: i32.const $push3=, 40{{$}}
592 ; NON-PIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
593 ; NON-PIC-NEXT: i32.store 0($pop4), $2{{$}}
594 ; NON-PIC-NEXT: return{{$}}
559595 define void @store_test15(i32* %p, i32 %n, i32 %i) {
560596 %add.ptr = getelementptr inbounds i32, i32* %p, i32 10
561597 %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n
565601
566602 ; CHECK-LABEL: store_test16:
567603 ; CHECK-NEXT: .functype store_test16 (i32, i32, i32) -> (){{$}}
568 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
569 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
570 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
571 ; CHECK-NEXT: i32.const $push3=, 40{{$}}
572 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
573 ; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
574 ; CHECK-NEXT: return{{$}}
604 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
605 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
606 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
607 ; NON-PIC-NEXT: i32.const $push3=, 40{{$}}
608 ; NON-PIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
609 ; NON-PIC-NEXT: i32.store 0($pop4), $2{{$}}
610 ; NON-PIC-NEXT: return{{$}}
575611 define void @store_test16(i32* %p, i32 %n, i32 %i) {
576612 %add.ptr = getelementptr inbounds i32, i32* %p, i32 10
577613 %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 %n
581617
582618 ; CHECK-LABEL: store_test17:
583619 ; CHECK-NEXT: .functype store_test17 (i32, i32, i32) -> (){{$}}
584 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
585 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
586 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
587 ; CHECK-NEXT: i32.const $push3=, 40{{$}}
588 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
589 ; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
590 ; CHECK-NEXT: return{{$}}
620 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
621 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
622 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
623 ; NON-PIC-NEXT: i32.const $push3=, 40{{$}}
624 ; NON-PIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
625 ; NON-PIC-NEXT: i32.store 0($pop4), $2{{$}}
626 ; NON-PIC-NEXT: return{{$}}
591627 define void @store_test17(i32* %p, i32 %n, i32 %i) {
592628 %add = add nsw i32 %n, 10
593629 %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add
597633
598634 ; CHECK-LABEL: store_test18:
599635 ; CHECK-NEXT: .functype store_test18 (i32, i32, i32) -> (){{$}}
600 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
601 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
602 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
603 ; CHECK-NEXT: i32.store 40($pop2), $2{{$}}
604 ; CHECK-NEXT: return{{$}}
636 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
637 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
638 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
639 ; NON-PIC-NEXT: i32.store 40($pop2), $2{{$}}
640 ; NON-PIC-NEXT: return{{$}}
605641 define void @store_test18(i32* %p, i32 %n, i32 %i) {
606642 %add.ptr = getelementptr inbounds i32, i32* %p, i32 %n
607643 %add.ptr1 = getelementptr inbounds i32, i32* %add.ptr, i32 10
611647
612648 ; CHECK-LABEL: store_test19:
613649 ; CHECK-NEXT: .functype store_test19 (i32, i32, i32) -> (){{$}}
614 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
615 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
616 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
617 ; CHECK-NEXT: i32.const $push3=, 40{{$}}
618 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
619 ; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
620 ; CHECK-NEXT: return{{$}}
650 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
651 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
652 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
653 ; NON-PIC-NEXT: i32.const $push3=, 40{{$}}
654 ; NON-PIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
655 ; NON-PIC-NEXT: i32.store 0($pop4), $2{{$}}
656 ; NON-PIC-NEXT: return{{$}}
621657 define void @store_test19(i32* %p, i32 %n, i32 %i) {
622658 %add = add nsw i32 10, %n
623659 %add.ptr = getelementptr inbounds i32, i32* %p, i32 %add
627663
628664 ; CHECK-LABEL: store_test20:
629665 ; CHECK-NEXT: .functype store_test20 (i32, i32) -> (){{$}}
630 ; CHECK-NEXT: i32.const $push0=, -40{{$}}
631 ; CHECK-NEXT: i32.add $push1=, $0, $pop0{{$}}
632 ; CHECK-NEXT: i32.store 0($pop1), $1{{$}}
633 ; CHECK-NEXT: return{{$}}
666 ; NON-PIC-NEXT: i32.const $push0=, -40{{$}}
667 ; NON-PIC-NEXT: i32.add $push1=, $0, $pop0{{$}}
668 ; NON-PIC-NEXT: i32.store 0($pop1), $1{{$}}
669 ; NON-PIC-NEXT: return{{$}}
634670 define void @store_test20(i32* %p, i32 %i) {
635671 %arrayidx = getelementptr inbounds i32, i32* %p, i32 -10
636672 store i32 %i, i32* %arrayidx, align 4
639675
640676 ; CHECK-LABEL: store_test21:
641677 ; CHECK-NEXT: .functype store_test21 (i32, i32, i32) -> (){{$}}
642 ; CHECK-NEXT: i32.const $push0=, 2{{$}}
643 ; CHECK-NEXT: i32.shl $push1=, $1, $pop0{{$}}
644 ; CHECK-NEXT: i32.add $push2=, $0, $pop1{{$}}
645 ; CHECK-NEXT: i32.const $push3=, -40{{$}}
646 ; CHECK-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
647 ; CHECK-NEXT: i32.store 0($pop4), $2{{$}}
648 ; CHECK-NEXT: return{{$}}
678 ; NON-PIC-NEXT: i32.const $push0=, 2{{$}}
679 ; NON-PIC-NEXT: i32.shl $push1=, $1, $pop0{{$}}
680 ; NON-PIC-NEXT: i32.add $push2=, $0, $pop1{{$}}
681 ; NON-PIC-NEXT: i32.const $push3=, -40{{$}}
682 ; NON-PIC-NEXT: i32.add $push4=, $pop2, $pop3{{$}}
683 ; NON-PIC-NEXT: i32.store 0($pop4), $2{{$}}
684 ; NON-PIC-NEXT: return{{$}}
649685 define void @store_test21(i32* %p, i32 %n, i32 %i) {
650686 %add = add nsw i32 %n, -10
651687 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %add
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -relocation-model=pic -fast-isel=1 | FileCheck %s
1 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -relocation-model=pic -fast-isel=0 | FileCheck %s
2 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
3 target triple = "wasm32-unknown-unknown"
4
5 declare i32 @foo()
6 declare i32 @bar()
7 declare hidden i32 @hidden_function();
8
9 @indirect_func = global i32 ()* @foo
10
11 define void @call_indirect_func() {
12 ; CHECK-LABEL: call_indirect_func:
13 ; CHECK: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
14 ; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, indirect_func{{$}}
15 ; CHECK-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
16 ; CHECK-NEXT: i32.load $push[[L3:[0-9]+]]=, 0($pop[[L2]]){{$}}
17 ; CHECK-NEXT: i32.call_indirect $push[[L4:[0-9]+]]=, $pop[[L3]]{{$}}
18 %1 = load i32 ()*, i32 ()** @indirect_func, align 4
19 %call = call i32 %1()
20 ret void
21 }
22
23 define void @call_direct() {
24 ; CHECK-LABEL: call_direct:
25 ; CHECK: .functype call_direct () -> ()
26 ; CHECK-NEXT: i32.call $push0=, foo{{$}}
27 ; CHECK-NEXT: drop $pop0{{$}}
28 ; CHECK-NEXT: return{{$}}
29 %call = call i32 @foo()
30 ret void
31 }
32
33 define i8* @get_function_address() {
34 ; CHECK-LABEL: get_function_address:
35 ; CHECK: global.get $push[[L0:[0-9]+]]=, bar@GOT{{$}}
36 ; CHECK-NEXT: return $pop[[L0]]{{$}}
37 ; CHECK-NEXT: end_function{{$}}
38
39 ret i8* bitcast (i32 ()* @bar to i8*)
40 }
41
42 define i8* @get_function_address_hidden() {
43 ; CHECK-LABEL: get_function_address_hidden:
44 ; CHECK: global.get $push[[L0:[0-9]+]]=, __table_base{{$}}
45 ; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_function{{$}}
46 ; CHECK-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
47 ; CHECK-NEXT: return $pop[[L2]]{{$}}
48 ; CHECK-NEXT: end_function{{$}}
49
50 ret i8* bitcast (i32 ()* @hidden_function to i8*)
51 }
0 ; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=NON-PIC,CHECK
1 ; RUN: llc < %s -asm-verbose=false -relocation-model=pic -fast-isel -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC,CHECK
2 ; RUN: llc < %s -asm-verbose=false -relocation-model=pic -fast-isel=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s -check-prefixes=PIC,CHECK
3
4 ; Test that globals assemble as expected with -fPIC.
5 ; We test here both with and without fast-isel.
6
7 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
8 target triple = "wasm32-unknown-unknown"
9
10 @hidden_global = external hidden global i32
11 @hidden_global_array = external hidden global [10 x i32]
12 @external_global = external global i32
13 @external_global_array = external global [10 x i32]
14
15 declare i32 @foo();
16
17 ; For hidden symbols PIC code needs to offset all loads and stores
18 ; by the value of the __memory_base global
19
20 define i32 @load_hidden_global() {
21 ; CHECK-LABEL: load_hidden_global:
22 ; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
23 ; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global{{$}}
24 ; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
25 ; PIC-NEXT: i32.load $push[[L3:[0-9]+]]=, 0($pop[[L2]]){{$}}
26
27 ; NON-PIC: i32.const $push0=, 0{{$}}
28 ; NON-PIC-NEXT: i32.load $push1=, hidden_global($pop0){{$}}
29 ; CHECK-NEXT: end_function
30
31 %1 = load i32, i32* @hidden_global
32 ret i32 %1
33 }
34
35 define i32 @load_hidden_global_offset() {
36 ; CHECK-LABEL: load_hidden_global_offset:
37 ; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
38 ; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global_array{{$}}
39 ; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1:[0-9]+]]{{$}}
40 ; PIC-NEXT: i32.const $push[[L3:[0-9]+]]=, 20{{$}}
41 ; PIC-NEXT: i32.add $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
42 ; PIC-NEXT: i32.load $push{{[0-9]+}}=, 0($pop[[L4]]){{$}}
43
44 ; NON-PIC: i32.const $push0=, 0{{$}}
45 ; NON-PIC-NEXT:i32.load $push1=, hidden_global_array+20($pop0){{$}}
46 ; CHECK-NEXT: end_function
47
48 %1 = getelementptr [10 x i32], [10 x i32]* @hidden_global_array, i32 0, i32 5
49 %2 = load i32, i32* %1
50 ret i32 %2
51 }
52
53 ; Store to a hidden global
54
55 define void @store_hidden_global(i32 %n) {
56 ; CHECK-LABEL: store_hidden_global:
57 ; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
58 ; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global{{$}}
59 ; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
60 ; PIC-NEXT: i32.store 0($pop[[L2]]), $0{{$}}
61
62 ; NON-PIC: i32.const $push0=, 0{{$}}
63 ; NON-PIC-NEXT: i32.store hidden_global($pop0), $0{{$}}
64 ; CHECK-NEXT: end_function
65
66 store i32 %n, i32* @hidden_global
67 ret void
68 }
69
70 define void @store_hidden_global_offset(i32 %n) {
71 ; CHECK-LABEL: store_hidden_global_offset:
72 ; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
73 ; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global_array{{$}}
74 ; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
75 ; PIC-NEXT: i32.const $push[[L3:[0-9]+]]=, 20{{$}}
76 ; PIC-NEXT: i32.add $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
77 ; PIC-NEXT: i32.store 0($pop[[L4]]), $0{{$}}
78
79 ; NON-PIC: i32.const $push0=, 0{{$}}
80 ; NON-PIC-NEXT: i32.store hidden_global_array+20($pop0), $0{{$}}
81 ; CHECK-NEXT: end_function
82
83 %1 = getelementptr [10 x i32], [10 x i32]* @hidden_global_array, i32 0, i32 5
84 store i32 %n, i32* %1
85 ret void
86 }
87
88 ; For non-hidden globals PIC code has to load the address from a wasm global
89 ; using the @GOT relocation type.
90
91
92 define i32 @load_external_global() {
93 ; CHECK-LABEL: load_external_global:
94 ; PIC: global.get $push[[L0:[0-9]+]]=, external_global@GOT{{$}}
95 ; PIC-NEXT: i32.load $push{{[0-9]+}}=, 0($pop[[L0]]){{$}}
96
97 ; NON-PIC: i32.const $push0=, 0{{$}}
98 ; NON-PIC-NEXT: i32.load $push1=, external_global($pop0){{$}}
99 ; CHECK-NEXT: end_function
100
101 %1 = load i32, i32* @external_global
102 ret i32 %1
103 }
104
105 define i32 @load_external_global_offset() {
106 ; CHECK-LABEL: load_external_global_offset:
107 ; PIC: global.get $push[[L0:[0-9]+]]=, external_global_array@GOT{{$}}
108 ; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, 20{{$}}
109 ; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
110 ; PIC-NEXT: i32.load $push{{[0-9]+}}=, 0($pop[[L2]]){{$}}
111
112 ; NON-PIC: i32.const $push0=, 0{{$}}
113 ; NON-PIC-NEXT: i32.load $push1=, external_global_array+20($pop0){{$}}
114 ; CHECK-NEXT: end_function
115
116 %1 = getelementptr [10 x i32], [10 x i32]* @external_global_array, i32 0, i32 5
117 %2 = load i32, i32* %1
118 ret i32 %2
119 }
120
121 ; Store to a non-hidden global via the wasm global.
122
123 define void @store_external_global(i32 %n) {
124 ; CHECK-LABEL: store_external_global:
125 ; PIC: global.get $push[[L0:[0-9]+]]=, external_global@GOT{{$}}
126 ; PIC-NEXT: i32.store 0($pop[[L0]]), $0{{$}}
127
128 ; NON-PIC: i32.const $push0=, 0{{$}}
129 ; NON-PIC-NEXT: i32.store external_global($pop0), $0{{$}}
130 ; CHECK-NEXT: end_function
131
132 store i32 %n, i32* @external_global
133 ret void
134 }
135
136 define void @store_external_global_offset(i32 %n) {
137 ; CHECK-LABEL: store_external_global_offset:
138 ; PIC: global.get $push[[L0:[0-9]+]]=, external_global_array@GOT{{$}}
139 ; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, 20{{$}}
140 ; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
141 ; PIC-NEXT: i32.store 0($pop[[L2]]), $0{{$}}
142
143 ; NON-PIC: i32.const $push0=, 0{{$}}
144 ; NON-PIC-NEXT: i32.store external_global_array+20($pop0), $0{{$}}
145 ; CHECK-NEXT: end_function
146
147 %1 = getelementptr [10 x i32], [10 x i32]* @external_global_array, i32 0, i32 5
148 store i32 %n, i32* %1
149 ret void
150 }
151
152 ; PIC: .globaltype __memory_base, i32
0 # RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck %s
1
2 # Verify that @GOT relocation entryes result in R_WASM_GLOBAL_INDEX_LEB against
3 # against the corrsponding function or data symbol and that the corresponding
4 # data symbols are imported as a wasm globals.
5
6 load_default_data:
7 .functype load_default_data () -> (i32)
8 global.get default_data@GOT
9 i32.load 0
10 end_function
11
12 load_default_func:
13 .functype load_default_func () -> (i32)
14 global.get default_func@GOT
15 i32.load 0
16 end_function
17
18 .size default_data, 4
19 .functype default_func () -> (i32)
20
21 # CHECK: --- !WASM
22 # CHECK-NEXT: FileHeader:
23 # CHECK-NEXT: Version: 0x00000001
24 # CHECK-NEXT: Sections:
25 # CHECK-NEXT: - Type: TYPE
26 # CHECK-NEXT: Signatures:
27 # CHECK-NEXT: - Index: 0
28 # CHECK-NEXT: ReturnType: I32
29 # CHECK-NEXT: ParamTypes: []
30 # CHECK-NEXT: - Type: IMPORT
31 # CHECK-NEXT: Imports:
32 # CHECK-NEXT: - Module: env
33 # CHECK-NEXT: Field: __linear_memory
34 # CHECK-NEXT: Kind: MEMORY
35 # CHECK-NEXT: Memory:
36 # CHECK-NEXT: Initial: 0x00000000
37 # CHECK-NEXT: - Module: env
38 # CHECK-NEXT: Field: __indirect_function_table
39 # CHECK-NEXT: Kind: TABLE
40 # CHECK-NEXT: Table:
41 # CHECK-NEXT: ElemType: FUNCREF
42 # CHECK-NEXT: Limits:
43 # CHECK-NEXT: Initial: 0x00000000
44 # CHECK-NEXT: - Module: env
45 # CHECK-NEXT: Field: default_func
46 # CHECK-NEXT: Kind: FUNCTION
47 # CHECK-NEXT: SigIndex: 0
48 # CHECK-NEXT: - Module: GOT.mem
49 # CHECK-NEXT: Field: default_data
50 # CHECK-NEXT: Kind: GLOBAL
51 # CHECK-NEXT: GlobalType: I32
52 # CHECK-NEXT: GlobalMutable: true
53 # CHECK-NEXT: - Module: GOT.func
54 # CHECK-NEXT: Field: default_func
55 # CHECK-NEXT: Kind: GLOBAL
56 # CHECK-NEXT: GlobalType: I32
57 # CHECK-NEXT: GlobalMutable: true
58 # CHECK-NEXT: - Type: FUNCTION
59 # CHECK-NEXT: FunctionTypes: [ 0, 0 ]
60 # CHECK-NEXT: - Type: CODE
61 # CHECK-NEXT: Relocations:
62 # CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB
63 # CHECK-NEXT: Index: 1
64 # CHECK-NEXT: Offset: 0x00000004
65 # CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB
66 # CHECK-NEXT: Index: 3
67 # CHECK-NEXT: Offset: 0x00000010
68 # CHECK-NEXT: Functions:
69 # CHECK-NEXT: - Index: 1
70 # CHECK-NEXT: Locals: []
71 # CHECK-NEXT: Body: 2380808080002800000B
72 # CHECK-NEXT: - Index: 2
73 # CHECK-NEXT: Locals: []
74 # CHECK-NEXT: Body: 2381808080002800000B
75 # CHECK-NEXT: - Type: CUSTOM
76 # CHECK-NEXT: Name: linking
77 # CHECK-NEXT: Version: 2
78 # CHECK-NEXT: SymbolTable:
79 # CHECK-NEXT: - Index: 0
80 # CHECK-NEXT: Kind: FUNCTION
81 # CHECK-NEXT: Name: load_default_data
82 # CHECK-NEXT: Flags: [ BINDING_LOCAL ]
83 # CHECK-NEXT: Function: 1
84 # CHECK-NEXT: - Index: 1
85 # CHECK-NEXT: Kind: DATA
86 # CHECK-NEXT: Name: default_data
87 # CHECK-NEXT: Flags: [ UNDEFINED ]
88 # CHECK-NEXT: - Index: 2
89 # CHECK-NEXT: Kind: FUNCTION
90 # CHECK-NEXT: Name: load_default_func
91 # CHECK-NEXT: Flags: [ BINDING_LOCAL ]
92 # CHECK-NEXT: Function: 2
93 # CHECK-NEXT: - Index: 3
94 # CHECK-NEXT: Kind: FUNCTION
95 # CHECK-NEXT: Name: default_func
96 # CHECK-NEXT: Flags: [ UNDEFINED ]
97 # CHECK-NEXT: Function: 0
98 # CHECK-NEXT: ...