llvm.org GIT mirror llvm / 53ff96a
[WebAssembly] Basic support for Wasm object file encoding. With the "wasm32-unknown-unknown-wasm" triple, this allows writing out simple wasm object files, and is another step in a larger series toward migrating from ELF to general wasm object support. Note that this code and the binary format itself is still experimental. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296190 91177308-0d34-0410-b5e6-96231b3b80d8 Dan Gohman 3 years ago
64 changed file(s) with 2077 addition(s) and 392 deletion(s). Raw diff Collapse all Expand all
171171 };
172172
173173 class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile {
174 mutable unsigned NextUniqueID = 0;
175
174176 public:
175177 TargetLoweringObjectFileWasm() {}
176178
269269 VK_Hexagon_IE_GOT,
270270
271271 VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr
272 VK_WebAssembly_TYPEINDEX,// Type table index
272273
273274 VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo
274275 VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi
3939
4040 const MCSymbolWasm *Group;
4141
42 // The offset of the MC function section in the wasm code section.
43 uint64_t SectionOffset;
44
4245 private:
4346 friend class MCContext;
4447 MCSectionWasm(StringRef Section, unsigned type, unsigned flags, SectionKind K,
4548 const MCSymbolWasm *group, unsigned UniqueID, MCSymbol *Begin)
4649 : MCSection(SV_Wasm, K, Begin), SectionName(Section), Type(type),
47 Flags(flags), UniqueID(UniqueID), Group(group) {
50 Flags(flags), UniqueID(UniqueID), Group(group), SectionOffset(0) {
4851 }
4952
5053 void setSectionName(StringRef Name) { SectionName = Name; }
7174 bool isUnique() const { return UniqueID != ~0U; }
7275 unsigned getUniqueID() const { return UniqueID; }
7376
77 uint64_t getSectionOffset() const { return SectionOffset; }
78 void setSectionOffset(uint64_t Offset) { SectionOffset = Offset; }
79
7480 static bool classof(const MCSection *S) { return S->getVariant() == SV_Wasm; }
7581 };
7682
1212
1313 namespace llvm {
1414 class MCSymbolWasm : public MCSymbol {
15 private:
16 bool IsFunction = false;
17 std::string ModuleName;
18 SmallVector Returns;
19 SmallVector Params;
20
21 /// An expression describing how to calculate the size of a symbol. If a
22 /// symbol has no size this field will be NULL.
23 const MCExpr *SymbolSize = nullptr;
24
1525 public:
26 // Use a module name of "env" for now, for compatibility with existing tools.
27 // This is temporary, and may change, as the ABI is not yet stable.
1628 MCSymbolWasm(const StringMapEntry *Name, bool isTemporary)
17 : MCSymbol(SymbolKindWasm, Name, isTemporary) {}
29 : MCSymbol(SymbolKindWasm, Name, isTemporary),
30 ModuleName("env") {}
31 static bool classof(const MCSymbol *S) { return S->isWasm(); }
1832
19 static bool classof(const MCSymbol *S) { return S->isWasm(); }
33 const MCExpr *getSize() const { return SymbolSize; }
34 void setSize(const MCExpr *SS) { SymbolSize = SS; }
35
36 bool isFunction() const { return IsFunction; }
37 void setIsFunction(bool isFunc) { IsFunction = isFunc; }
38
39 const StringRef getModuleName() const { return ModuleName; }
40
41 const SmallVector &getReturns() const { return Returns; }
42 void setReturns(SmallVectorImpl &&Rets) {
43 Returns = std::move(Rets);
44 }
45
46 const SmallVector &getParams() const { return Params; }
47 void setParams(SmallVectorImpl &&Pars) {
48 Params = std::move(Pars);
49 }
2050 };
2151 }
2252
2121 class MCFixup;
2222 class MCFragment;
2323 class MCObjectWriter;
24 class MCSectionWasm;
2425 class MCSymbol;
2526 class MCSymbolWasm;
2627 class MCValue;
2728 class raw_pwrite_stream;
2829
30 // Information about a single relocation.
2931 struct WasmRelocationEntry {
3032 uint64_t Offset; // Where is the relocation.
3133 const MCSymbolWasm *Symbol; // The symbol to relocate with.
34 uint64_t Addend; // A value to add to the symbol.
3235 unsigned Type; // The type of the relocation.
36 MCSectionWasm *FixupSection;// The section the relocation is targeting.
3337
3438 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
35 unsigned Type)
36 : Offset(Offset), Symbol(Symbol), Type(Type) {}
39 uint64_t Addend, unsigned Type,
40 MCSectionWasm *FixupSection)
41 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
42 FixupSection(FixupSection) {}
3743
3844 void print(raw_ostream &Out) const {
39 Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type;
45 Out << "Off=" << Offset << ", Sym=" << Symbol << ", Addend=" << Addend
46 << ", Type=" << Type << ", FixupSection=" << FixupSection;
4047 }
4148 void dump() const { print(errs()); }
4249 };
5353 void EmitCOFFSymbolType(int Type) override;
5454 void EndCOFFSymbolDef() override;
5555
56 void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
57
5658 void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
5759 unsigned ByteAlignment) override;
5860
11611161 // Wasm
11621162 //===----------------------------------------------------------------------===//
11631163
1164 static const Comdat *getWasmComdat(const GlobalValue *GV) {
1165 const Comdat *C = GV->getComdat();
1166 if (!C)
1167 return nullptr;
1168
1169 if (C->getSelectionKind() != Comdat::Any)
1170 report_fatal_error("Wasm COMDATs only support SelectionKind::Any, '" +
1171 C->getName() + "' cannot be lowered.");
1172
1173 return C;
1174 }
1175
11641176 MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal(
11651177 const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
11661178 llvm_unreachable("getExplicitSectionGlobal not yet implemented");
11671179 return nullptr;
11681180 }
11691181
1182 static MCSectionWasm *
1183 selectWasmSectionForGlobal(MCContext &Ctx, const GlobalObject *GO,
1184 SectionKind Kind, Mangler &Mang,
1185 const TargetMachine &TM, bool EmitUniqueSection,
1186 unsigned Flags, unsigned *NextUniqueID) {
1187 StringRef Group = "";
1188 if (getWasmComdat(GO))
1189 llvm_unreachable("comdat not yet supported for wasm");
1190
1191 bool UniqueSectionNames = TM.getUniqueSectionNames();
1192 SmallString<128> Name = getSectionPrefixForGlobal(Kind);
1193
1194 if (const auto *F = dyn_cast(GO)) {
1195 const auto &OptionalPrefix = F->getSectionPrefix();
1196 if (OptionalPrefix)
1197 Name += *OptionalPrefix;
1198 }
1199
1200 if (EmitUniqueSection && UniqueSectionNames) {
1201 Name.push_back('.');
1202 TM.getNameWithPrefix(Name, GO, Mang, true);
1203 }
1204 unsigned UniqueID = MCContext::GenericSectionID;
1205 if (EmitUniqueSection && !UniqueSectionNames) {
1206 UniqueID = *NextUniqueID;
1207 (*NextUniqueID)++;
1208 }
1209 return Ctx.getWasmSection(Name, /*Type=*/0, Flags,
1210 Group, UniqueID);
1211 }
1212
11701213 MCSection *TargetLoweringObjectFileWasm::SelectSectionForGlobal(
11711214 const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
1215
1216 if (Kind.isCommon())
1217 report_fatal_error("mergable sections not supported yet on wasm");
1218
1219 // If we have -ffunction-section or -fdata-section then we should emit the
1220 // global value to a uniqued section specifically for it.
1221 bool EmitUniqueSection = false;
11721222 if (Kind.isText())
1173 return TextSection;
1174 assert(!Kind.isMetadata() && "metadata sections not yet implemented");
1175 return DataSection;
1223 EmitUniqueSection = TM.getFunctionSections();
1224 else
1225 EmitUniqueSection = TM.getDataSections();
1226 EmitUniqueSection |= GO->hasComdat();
1227
1228 return selectWasmSectionForGlobal(getContext(), GO, Kind, getMangler(), TM,
1229 EmitUniqueSection, /*Flags=*/0,
1230 &NextUniqueID);
11761231 }
11771232
11781233 bool TargetLoweringObjectFileWasm::shouldPutJumpTableInFunctionSection(
285285 case VK_Hexagon_IE: return "IE";
286286 case VK_Hexagon_IE_GOT: return "IEGOT";
287287 case VK_WebAssembly_FUNCTION: return "FUNCTION";
288 case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX";
288289 case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo";
289290 case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi";
290291 case VK_AMDGPU_REL32_LO: return "rel32@lo";
800800
801801 void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) {
802802 // TODO: Set the section types and flags.
803 TextSection = Ctx->getWasmSection("", 0, 0);
804 DataSection = Ctx->getWasmSection("", 0, 0);
803 TextSection = Ctx->getWasmSection(".text", 0, 0);
804 DataSection = Ctx->getWasmSection(".data", 0, 0);
805805
806806 // TODO: Set the section types and flags.
807807 DwarfLineSection = Ctx->getWasmSection(".debug_line", 0, 0);
8888 // the symbol with the assembler.
8989 getAssembler().registerSymbol(*Symbol);
9090
91 // TODO: Set the symbol binding, type, etc.
91 switch (Attribute) {
92 case MCSA_LazyReference:
93 case MCSA_Reference:
94 case MCSA_SymbolResolver:
95 case MCSA_PrivateExtern:
96 case MCSA_WeakDefinition:
97 case MCSA_WeakDefAutoPrivate:
98 case MCSA_Invalid:
99 case MCSA_IndirectSymbol:
100 return false;
101 case MCSA_Global:
102 Symbol->setExternal(true);
103 break;
104 case MCSA_ELF_TypeFunction:
105 Symbol->setIsFunction(true);
106 break;
107 case MCSA_ELF_TypeObject:
108 Symbol->setIsFunction(false);
109 break;
110 default:
111 // unrecognized directive
112 return false;
113 }
92114
93115 return true;
94116 }
96118 void MCWasmStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size,
97119 unsigned ByteAlignment) {
98120 llvm_unreachable("Common symbols are not yet implemented for Wasm");
121 }
122
123 void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
124 cast(Symbol)->setSize(Value);
99125 }
100126
101127 void MCWasmStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
123149 }
124150
125151 void MCWasmStreamer::EmitIdent(StringRef IdentString) {
126 llvm_unreachable("Ident sections not yet implemented for wasm");
152 MCSection *Comment = getAssembler().getContext().getWasmSection(
153 ".comment", 0, 0);
154 PushSection();
155 SwitchSection(Comment);
156 if (!SeenIdent) {
157 EmitIntValue(0, 1);
158 SeenIdent = true;
159 }
160 EmitBytes(IdentString);
161 EmitIntValue(0, 1);
162 PopSection();
127163 }
128164
129165 void MCWasmStreamer::EmitInstToFragment(const MCInst &Inst,
1212
1313 #include "llvm/ADT/STLExtras.h"
1414 #include "llvm/ADT/SmallPtrSet.h"
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/StringMap.h"
1715 #include "llvm/MC/MCAsmBackend.h"
1816 #include "llvm/MC/MCAsmInfo.h"
1917 #include "llvm/MC/MCAsmLayout.h"
2725 #include "llvm/MC/MCSymbolWasm.h"
2826 #include "llvm/MC/MCValue.h"
2927 #include "llvm/MC/MCWasmObjectWriter.h"
28 #include "llvm/Support/Casting.h"
3029 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/Endian.h"
3230 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/LEB128.h"
3332 #include "llvm/Support/StringSaver.h"
3433 #include "llvm/Support/Wasm.h"
3534 #include
4039 #define DEBUG_TYPE "reloc-info"
4140
4241 namespace {
43 typedef DenseMap SectionIndexMapTy;
42 // For patching purposes, we need to remember where each section starts, both
43 // for patching up the section size field, and for patching up references to
44 // locations within the section.
45 struct SectionBookkeeping {
46 // Where the size of the section is written.
47 uint64_t SizeOffset;
48 // Where the contents of the section starts (after the header).
49 uint64_t ContentsOffset;
50 };
51
52 // This record records information about a call_indirect which needs its
53 // type index fixed up once we've computed type indices.
54 struct TypeIndexFixup {
55 uint64_t Offset;
56 const MCSymbolWasm *Symbol;
57 const MCSectionWasm *FixupSection;
58 TypeIndexFixup(uint64_t O, const MCSymbolWasm *S, MCSectionWasm *F)
59 : Offset(O), Symbol(S), FixupSection(F) {}
60 };
4461
4562 class WasmObjectWriter : public MCObjectWriter {
4663 /// Helper struct for containing some precomputed information on symbols.
5572 /// The target specific Wasm writer instance.
5673 std::unique_ptr TargetObjectWriter;
5774
75 // Relocations for fixing up references in the code section.
76 std::vector CodeRelocations;
77
78 // Relocations for fixing up references in the data section.
79 std::vector DataRelocations;
80
81 // Fixups for call_indirect type indices.
82 std::vector TypeIndexFixups;
83
84 // Index values to use for fixing up call_indirect type indices.
85 std::vector TypeIndexFixupTypes;
86
5887 // TargetObjectWriter wrappers.
5988 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
6089 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
6291 return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel);
6392 }
6493
94 void startSection(SectionBookkeeping &Section, unsigned SectionId,
95 const char *Name = nullptr);
96 void endSection(SectionBookkeeping &Section);
97
6598 public:
6699 WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS)
67100 : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {}
68101
102 private:
69103 void reset() override {
70104 MCObjectWriter::reset();
71105 }
87121 } // end anonymous namespace
88122
89123 WasmObjectWriter::~WasmObjectWriter() {}
124
125 // Return the padding size to write a 32-bit value into a 5-byte ULEB128.
126 static unsigned PaddingFor5ByteULEB128(uint32_t X) {
127 return X == 0 ? 4 : (4u - (31u - countLeadingZeros(X)) / 7u);
128 }
129
130 // Return the padding size to write a 32-bit value into a 5-byte SLEB128.
131 static unsigned PaddingFor5ByteSLEB128(int32_t X) {
132 return 5 - getSLEB128Size(X);
133 }
134
135 // Write out a section header and a patchable section size field.
136 void WasmObjectWriter::startSection(SectionBookkeeping &Section,
137 unsigned SectionId,
138 const char *Name) {
139 assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) &&
140 "Only custom sections can have names");
141
142 write8(SectionId);
143
144 Section.SizeOffset = getStream().tell();
145
146 // The section size. We don't know the size yet, so reserve enough space
147 // for any 32-bit value; we'll patch it later.
148 encodeULEB128(UINT32_MAX, getStream());
149
150 // The position where the section starts, for measuring its size.
151 Section.ContentsOffset = getStream().tell();
152
153 // Custom sections in wasm also have a string identifier.
154 if (SectionId == wasm::WASM_SEC_CUSTOM) {
155 encodeULEB128(strlen(Name), getStream());
156 writeBytes(Name);
157 }
158 }
159
160 // Now that the section is complete and we know how big it is, patch up the
161 // section size field at the start of the section.
162 void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
163 uint64_t Size = getStream().tell() - Section.ContentsOffset;
164 if (uint32_t(Size) != Size)
165 report_fatal_error("section size does not fit in a uint32_t");
166
167 unsigned Padding = PaddingFor5ByteULEB128(Size);
168
169 // Write the final section size to the payload_len field, which follows
170 // the section id byte.
171 uint8_t Buffer[16];
172 unsigned SizeLen = encodeULEB128(Size, Buffer, Padding);
173 assert(SizeLen == 5);
174 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset);
175 }
90176
91177 // Emit the Wasm header.
92178 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
103189 const MCFragment *Fragment,
104190 const MCFixup &Fixup, MCValue Target,
105191 bool &IsPCRel, uint64_t &FixedValue) {
106 // TODO: Implement
192 MCSectionWasm &FixupSection = cast(*Fragment->getParent());
193 uint64_t C = Target.getConstant();
194 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
195 MCContext &Ctx = Asm.getContext();
196
197 if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
198 assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
199 "Should not have constructed this");
200
201 // Let A, B and C being the components of Target and R be the location of
202 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
203 // If it is pcrel, we want to compute (A - B + C - R).
204
205 // In general, Wasm has no relocations for -B. It can only represent (A + C)
206 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
207 // replace B to implement it: (A - R - K + C)
208 if (IsPCRel) {
209 Ctx.reportError(
210 Fixup.getLoc(),
211 "No relocation available to represent this relative expression");
212 return;
213 }
214
215 const auto &SymB = cast(RefB->getSymbol());
216
217 if (SymB.isUndefined()) {
218 Ctx.reportError(Fixup.getLoc(),
219 Twine("symbol '") + SymB.getName() +
220 "' can not be undefined in a subtraction expression");
221 return;
222 }
223
224 assert(!SymB.isAbsolute() && "Should have been folded");
225 const MCSection &SecB = SymB.getSection();
226 if (&SecB != &FixupSection) {
227 Ctx.reportError(Fixup.getLoc(),
228 "Cannot represent a difference across sections");
229 return;
230 }
231
232 uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
233 uint64_t K = SymBOffset - FixupOffset;
234 IsPCRel = true;
235 C -= K;
236 }
237
238 // We either rejected the fixup or folded B into C at this point.
239 const MCSymbolRefExpr *RefA = Target.getSymA();
240 const auto *SymA = RefA ? cast(&RefA->getSymbol()) : nullptr;
241
242 bool ViaWeakRef = false;
243 if (SymA && SymA->isVariable()) {
244 const MCExpr *Expr = SymA->getVariableValue();
245 if (const auto *Inner = dyn_cast(Expr)) {
246 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
247 SymA = cast(&Inner->getSymbol());
248 ViaWeakRef = true;
249 }
250 }
251 }
252
253 // Put any constant offset in an addend. Offsets can be negative, and
254 // LLVM expects wrapping, in contrast to wasm's immediates which can't
255 // be negative and don't wrap.
256 FixedValue = 0;
257
258 if (SymA) {
259 if (ViaWeakRef)
260 llvm_unreachable("weakref used in reloc not yet implemented");
261 else
262 SymA->setUsedInReloc();
263 }
264
265 if (RefA) {
266 if (RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX) {
267 TypeIndexFixups.push_back(TypeIndexFixup(FixupOffset, SymA,
268 &FixupSection));
269 return;
270 }
271 }
272
273 unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel);
274
275 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
276
277 if (FixupSection.hasInstructions())
278 CodeRelocations.push_back(Rec);
279 else
280 DataRelocations.push_back(Rec);
281 }
282
283 namespace {
284
285 //
286 struct WasmFunctionType {
287 // Support empty and tombstone instances, needed by DenseMap.
288 enum { Plain, Empty, Tombstone } State;
289
290 // The return types of the function.
291 SmallVector Returns;
292
293 // The parameter types of the function.
294 SmallVector Params;
295
296 WasmFunctionType() : State(Plain) {}
297
298 bool operator==(const WasmFunctionType &Other) const {
299 return State == Other.State && Returns == Other.Returns &&
300 Params == Other.Params;
301 }
302 };
303
304 // Traits for using WasmFunctionType in a DenseMap.
305 struct WasmFunctionTypeDenseMapInfo {
306 static WasmFunctionType getEmptyKey() {
307 WasmFunctionType FuncTy;
308 FuncTy.State = WasmFunctionType::Empty;
309 return FuncTy;
310 }
311 static WasmFunctionType getTombstoneKey() {
312 WasmFunctionType FuncTy;
313 FuncTy.State = WasmFunctionType::Tombstone;
314 return FuncTy;
315 }
316 static unsigned getHashValue(const WasmFunctionType &FuncTy) {
317 uintptr_t Value = FuncTy.State;
318 for (unsigned Ret : FuncTy.Returns)
319 Value += DenseMapInfo::getHashValue(Ret);
320 for (unsigned Param : FuncTy.Params)
321 Value += DenseMapInfo::getHashValue(Param);
322 return Value;
323 }
324 static bool isEqual(const WasmFunctionType &LHS,
325 const WasmFunctionType &RHS) {
326 return LHS == RHS;
327 }
328 };
329
330 // A wasm import to be written into the import section.
331 struct WasmImport {
332 StringRef ModuleName;
333 StringRef FieldName;
334 unsigned Kind;
335 uint32_t Type;
336 };
337
338 // A wasm function to be written into the function section.
339 struct WasmFunction {
340 unsigned Type;
341 const MCSymbolWasm *Sym;
342 };
343
344 // A wasm export to be written into the export section.
345 struct WasmExport {
346 StringRef FieldName;
347 unsigned Kind;
348 uint32_t Index;
349 };
350
351 // A wasm global to be written into the global section.
352 struct WasmGlobal {
353 unsigned Type;
354 bool IsMutable;
355 uint32_t InitialValue;
356 };
357
358 } // end anonymous namespace
359
360 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
361 // to allow patching.
362 static void
363 WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
364 uint8_t Buffer[5];
365 unsigned Padding = PaddingFor5ByteULEB128(X);
366 unsigned SizeLen = encodeULEB128(X, Buffer, Padding);
367 assert(SizeLen == 5);
368 Stream.pwrite((char *)Buffer, SizeLen, Offset);
369 }
370
371 // Write X as an signed LEB value at offset Offset in Stream, padded
372 // to allow patching.
373 static void
374 WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) {
375 uint8_t Buffer[5];
376 unsigned Padding = PaddingFor5ByteSLEB128(X);
377 unsigned SizeLen = encodeSLEB128(X, Buffer, Padding);
378 assert(SizeLen == 5);
379 Stream.pwrite((char *)Buffer, SizeLen, Offset);
380 }
381
382 // Write X as a plain integer value at offset Offset in Stream.
383 static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
384 uint8_t Buffer[4];
385 support::endian::write32le(Buffer, X);
386 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
387 }
388
389 // Compute a value to write into the code at the location covered
390 // by RelEntry. This value isn't used by the static linker, since
391 // we have addends; it just serves to make the code more readable
392 // and to make standalone wasm modules directly usable.
393 static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) {
394 const MCSymbolWasm *Sym = RelEntry.Symbol;
395
396 // For undefined symbols, use a hopefully invalid value.
397 if (!Sym->isDefined(false))
398 return UINT32_MAX;
399
400 MCSectionWasm &Section =
401 cast(RelEntry.Symbol->getSection(false));
402 uint64_t Address = Section.getSectionOffset() + RelEntry.Addend;
403
404 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
405 uint32_t Value = Address;
406
407 return Value;
408 }
409
410 // Apply the portions of the relocation records that we can handle ourselves
411 // directly.
412 static void ApplyRelocations(
413 ArrayRef Relocations,
414 raw_pwrite_stream &Stream,
415 DenseMap &SymbolIndices,
416 uint64_t ContentsOffset)
417 {
418 for (const WasmRelocationEntry &RelEntry : Relocations) {
419 uint64_t Offset = ContentsOffset +
420 RelEntry.FixupSection->getSectionOffset() +
421 RelEntry.Offset;
422 switch (RelEntry.Type) {
423 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: {
424 uint32_t Index = SymbolIndices[RelEntry.Symbol];
425 assert(RelEntry.Addend == 0);
426
427 WritePatchableLEB(Stream, Index, Offset);
428 break;
429 }
430 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: {
431 uint32_t Index = SymbolIndices[RelEntry.Symbol];
432 assert(RelEntry.Addend == 0);
433
434 WritePatchableSLEB(Stream, Index, Offset);
435 break;
436 }
437 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: {
438 uint32_t Value = ProvisionalValue(RelEntry);
439
440 WritePatchableSLEB(Stream, Value, Offset);
441 break;
442 }
443 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: {
444 uint32_t Value = ProvisionalValue(RelEntry);
445
446 WritePatchableLEB(Stream, Value, Offset);
447 break;
448 }
449 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: {
450 uint32_t Index = SymbolIndices[RelEntry.Symbol];
451 assert(RelEntry.Addend == 0);
452
453 WriteI32(Stream, Index, Offset);
454 break;
455 }
456 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: {
457 uint32_t Value = ProvisionalValue(RelEntry);
458
459 WriteI32(Stream, Value, Offset);
460 break;
461 }
462 default:
463 break;
464 }
465 }
466 }
467
468 // Write out the portions of the relocation records that the linker will
469 // need to handle.
470 static void WriteRelocations(
471 ArrayRef Relocations,
472 raw_pwrite_stream &Stream,
473 DenseMap &SymbolIndices)
474 {
475 for (const WasmRelocationEntry RelEntry : Relocations) {
476 encodeULEB128(RelEntry.Type, Stream);
477
478 uint64_t Offset = RelEntry.Offset +
479 RelEntry.FixupSection->getSectionOffset();
480 uint32_t Index = SymbolIndices[RelEntry.Symbol];
481 int64_t Addend = RelEntry.Addend;
482
483 switch (RelEntry.Type) {
484 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
485 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
486 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
487 encodeULEB128(Offset, Stream);
488 encodeULEB128(Index, Stream);
489 assert(Addend == 0 && "addends not supported for functions");
490 break;
491 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
492 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
493 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
494 encodeULEB128(Offset, Stream);
495 encodeULEB128(Index, Stream);
496 encodeSLEB128(Addend, Stream);
497 break;
498 default:
499 llvm_unreachable("unsupported relocation type");
500 }
501 }
107502 }
108503
109504 void WasmObjectWriter::writeObject(MCAssembler &Asm,
110505 const MCAsmLayout &Layout) {
506 unsigned PtrType = is64Bit() ? wasm::WASM_TYPE_I64 : wasm::WASM_TYPE_I32;
507
508 // Collect information from the available symbols.
509 DenseMap
510 FunctionTypeIndices;
511 SmallVector FunctionTypes;
512 SmallVector Functions;
513 SmallVector TableElems;
514 SmallVector Globals;
515 SmallVector Imports;
516 SmallVector Exports;
517 DenseMap SymbolIndices;
518 SmallPtrSet IsAddressTaken;
519 unsigned NumFuncImports = 0;
520 unsigned NumGlobalImports = 0;
521 SmallVector DataBytes;
522
523 // Populate the IsAddressTaken set.
524 for (WasmRelocationEntry RelEntry : CodeRelocations) {
525 switch (RelEntry.Type) {
526 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
527 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
528 IsAddressTaken.insert(RelEntry.Symbol);
529 break;
530 default:
531 break;
532 }
533 }
534 for (WasmRelocationEntry RelEntry : DataRelocations) {
535 switch (RelEntry.Type) {
536 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
537 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
538 IsAddressTaken.insert(RelEntry.Symbol);
539 break;
540 default:
541 break;
542 }
543 }
544
545 // Populate the Imports set.
546 for (const MCSymbol &S : Asm.symbols()) {
547 const auto &WS = static_cast(S);
548 unsigned Type;
549
550 if (WS.isFunction()) {
551 // Prepare the function's type, if we haven't seen it yet.
552 WasmFunctionType F;
553 F.Returns = WS.getReturns();
554 F.Params = WS.getParams();
555 auto Pair =
556 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
557 if (Pair.second)
558 FunctionTypes.push_back(F);
559
560 Type = Pair.first->second;
561 } else {
562 Type = PtrType;
563 }
564
565 // If the symbol is not defined in this translation unit, import it.
566 if (!WS.isTemporary() && !WS.isDefined(/*SetUsed=*/false)) {
567 WasmImport Import;
568 Import.ModuleName = WS.getModuleName();
569 Import.FieldName = WS.getName();
570
571 if (WS.isFunction()) {
572 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
573 Import.Type = Type;
574 SymbolIndices[&WS] = NumFuncImports;
575 ++NumFuncImports;
576 } else {
577 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
578 Import.Type = Type;
579 SymbolIndices[&WS] = NumGlobalImports;
580 ++NumGlobalImports;
581 }
582
583 Imports.push_back(Import);
584 }
585 }
586
587 // Handle defined symbols.
588 for (const MCSymbol &S : Asm.symbols()) {
589 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
590 // or used in relocations.
591 if (S.isTemporary() && S.getName().empty())
592 continue;
593 const auto &WS = static_cast(S);
594 unsigned Index;
595 if (WS.isFunction()) {
596 // Prepare the function's type, if we haven't seen it yet.
597 WasmFunctionType F;
598 F.Returns = WS.getReturns();
599 F.Params = WS.getParams();
600 auto Pair =
601 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
602 if (Pair.second)
603 FunctionTypes.push_back(F);
604
605 unsigned Type = Pair.first->second;
606
607 if (WS.isDefined(/*SetUsed=*/false)) {
608 // A definition. Take the next available index.
609 Index = NumFuncImports + Functions.size();
610
611 // Prepare the function.
612 WasmFunction Func;
613 Func.Type = Type;
614 Func.Sym = &WS;
615 SymbolIndices[&WS] = Index;
616 Functions.push_back(Func);
617 } else {
618 // An import; the index was assigned above.
619 Index = SymbolIndices.find(&WS)->second;
620 }
621
622 // If needed, prepare the function to be called indirectly.
623 if (IsAddressTaken.count(&WS))
624 TableElems.push_back(Index);
625 } else {
626 // For now, ignore temporary non-function symbols.
627 if (S.isTemporary())
628 continue;
629
630 if (WS.getOffset() != 0)
631 report_fatal_error("data sections must contain one variable each");
632 if (!WS.getSize())
633 report_fatal_error("data symbols must have a size set with .size");
634
635 int64_t Size = 0;
636 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
637 report_fatal_error(".size expression must be evaluatable");
638
639 if (WS.isDefined(false)) {
640 MCSectionWasm &DataSection =
641 static_cast(WS.getSection());
642
643 if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection))
644 report_fatal_error("data sections must contain at most one variable");
645
646 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
647
648 DataSection.setSectionOffset(DataBytes.size());
649
650 for (MCSection::iterator I = DataSection.begin(), E = DataSection.end();
651 I != E; ++I) {
652 const MCFragment &Frag = *I;
653 if (Frag.hasInstructions())
654 report_fatal_error("only data supported in data sections");
655
656 if (const MCAlignFragment *Align = dyn_cast(&Frag)) {
657 if (Align->getValueSize() != 1)
658 report_fatal_error("only byte values supported for alignment");
659 // If nops are requested, use zeros, as this is the data section.
660 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
661 uint64_t Size = std::min(alignTo(DataBytes.size(),
662 Align->getAlignment()),
663 DataBytes.size() +
664 Align->getMaxBytesToEmit());
665 DataBytes.resize(Size, Value);
666 } else if (const MCFillFragment *Fill =
667 dyn_cast(&Frag)) {
668 DataBytes.insert(DataBytes.end(), Size, Fill->getValue());
669 } else {
670 const MCDataFragment &DataFrag = cast(Frag);
671 const SmallVectorImpl &Contents = DataFrag.getContents();
672
673 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
674 }
675 }
676
677 // For each external global, prepare a corresponding wasm global
678 // holding its address.
679 if (WS.isExternal()) {
680 Index = NumGlobalImports + Globals.size();
681
682 WasmGlobal Global;
683 Global.Type = PtrType;
684 Global.IsMutable = false;
685 Global.InitialValue = DataSection.getSectionOffset();
686 SymbolIndices[&WS] = Index;
687 Globals.push_back(Global);
688 }
689 }
690 }
691
692 // If the symbol is visible outside this translation unit, export it.
693 if (WS.isExternal()) {
694 assert(WS.isDefined(false));
695 WasmExport Export;
696 Export.FieldName = WS.getName();
697 Export.Index = Index;
698
699 if (WS.isFunction())
700 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION;
701 else
702 Export.Kind = wasm::WASM_EXTERNAL_GLOBAL;
703
704 Exports.push_back(Export);
705 }
706 }
707
708 // Add types for indirect function calls.
709 for (const TypeIndexFixup &Fixup : TypeIndexFixups) {
710 WasmFunctionType F;
711 F.Returns = Fixup.Symbol->getReturns();
712 F.Params = Fixup.Symbol->getParams();
713 auto Pair =
714 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
715 if (Pair.second)
716 FunctionTypes.push_back(F);
717
718 TypeIndexFixupTypes.push_back(Pair.first->second);
719 }
720
111721 // Write out the Wasm header.
112722 writeHeader(Asm);
113723
114 // TODO: Write the contents.
724 SectionBookkeeping Section;
725
726 // === Type Section =========================================================
727 if (!FunctionTypes.empty()) {
728 startSection(Section, wasm::WASM_SEC_TYPE);
729
730 encodeULEB128(FunctionTypes.size(), getStream());
731
732 for (WasmFunctionType &FuncTy : FunctionTypes) {
733 write8(wasm::WASM_TYPE_FUNC);
734 encodeULEB128(FuncTy.Params.size(), getStream());
735 for (unsigned Ty : FuncTy.Params)
736 write8(Ty);
737 encodeULEB128(FuncTy.Returns.size(), getStream());
738 for (unsigned Ty : FuncTy.Returns)
739 write8(Ty);
740 }
741
742 endSection(Section);
743 }
744
745 // === Import Section ========================================================
746 if (!Imports.empty()) {
747 startSection(Section, wasm::WASM_SEC_IMPORT);
748
749 encodeULEB128(Imports.size(), getStream());
750 for (const WasmImport &Import : Imports) {
751 StringRef ModuleName = Import.ModuleName;
752 encodeULEB128(ModuleName.size(), getStream());
753 writeBytes(ModuleName);
754
755 StringRef FieldName = Import.FieldName;
756 encodeULEB128(FieldName.size(), getStream());
757 writeBytes(FieldName);
758
759 write8(Import.Kind);
760
761 switch (Import.Kind) {
762 case wasm::WASM_EXTERNAL_FUNCTION:
763 encodeULEB128(Import.Type, getStream());
764 break;
765 case wasm::WASM_EXTERNAL_GLOBAL:
766 write8(Import.Type);
767 write8(0); // mutability
768 break;
769 default:
770 llvm_unreachable("unsupported import kind");
771 }
772 }
773
774 endSection(Section);
775 }
776
777 // === Function Section ======================================================
778 if (!Functions.empty()) {
779 startSection(Section, wasm::WASM_SEC_FUNCTION);
780
781 encodeULEB128(Functions.size(), getStream());
782 for (const WasmFunction &Func : Functions)
783 encodeULEB128(Func.Type, getStream());
784
785 endSection(Section);
786 }
787
788 // === Table Section =========================================================
789 // For now, always emit the table section, since indirect calls are not
790 // valid without it. In the future, we could perhaps be more clever and omit
791 // it if there are no indirect calls.
792 startSection(Section, wasm::WASM_SEC_TABLE);
793
794 // The number of tables, fixed to 1 for now.
795 encodeULEB128(1, getStream());
796
797 write8(wasm::WASM_TYPE_ANYFUNC);
798
799 encodeULEB128(0, getStream()); // flags
800 encodeULEB128(TableElems.size(), getStream()); // initial
801
802 endSection(Section);
803
804 // === Memory Section ========================================================
805 // For now, always emit the memory section, since loads and stores are not
806 // valid without it. In the future, we could perhaps be more clever and omit
807 // it if there are no loads or stores.
808 startSection(Section, wasm::WASM_SEC_MEMORY);
809
810 encodeULEB128(1, getStream()); // number of memory spaces
811
812 encodeULEB128(0, getStream()); // flags
813 encodeULEB128(DataBytes.size(), getStream()); // initial
814
815 endSection(Section);
816
817 // === Global Section ========================================================
818 if (!Globals.empty()) {
819 startSection(Section, wasm::WASM_SEC_GLOBAL);
820
821 encodeULEB128(Globals.size(), getStream());
822 for (const WasmGlobal &Global : Globals) {
823 write8(Global.Type);
824 write8(Global.IsMutable);
825
826 write8(wasm::WASM_OPCODE_I32_CONST);
827 encodeSLEB128(Global.InitialValue, getStream()); // offset
828 write8(wasm::WASM_OPCODE_END);
829 }
830
831 endSection(Section);
832 }
833
834 // === Export Section ========================================================
835 if (!Exports.empty()) {
836 startSection(Section, wasm::WASM_SEC_EXPORT);
837
838 encodeULEB128(Exports.size(), getStream());
839 for (const WasmExport &Export : Exports) {
840 encodeULEB128(Export.FieldName.size(), getStream());
841 writeBytes(Export.FieldName);
842
843 write8(Export.Kind);
844
845 encodeULEB128(Export.Index, getStream());
846 }
847
848 endSection(Section);
849 }
850
851 #if 0 // TODO: Start Section
852 if (HaveStartFunction) {
853 // === Start Section =========================================================
854 startSection(Section, wasm::WASM_SEC_START);
855
856 encodeSLEB128(StartFunction, getStream());
857
858 endSection(Section);
859 }
860 #endif
861
862 // === Elem Section ==========================================================
863 if (!TableElems.empty()) {
864 startSection(Section, wasm::WASM_SEC_ELEM);
865
866 encodeULEB128(1, getStream()); // number of "segments"
867 encodeULEB128(0, getStream()); // the table index
868
869 // init expr for starting offset
870 write8(wasm::WASM_OPCODE_I32_CONST);
871 encodeSLEB128(0, getStream());
872 write8(wasm::WASM_OPCODE_END);
873
874 encodeULEB128(TableElems.size(), getStream());
875 for (uint32_t Elem : TableElems)
876 encodeULEB128(Elem, getStream());
877
878 endSection(Section);
879 }
880
881 // === Code Section ==========================================================
882 if (!Functions.empty()) {
883 startSection(Section, wasm::WASM_SEC_CODE);
884
885 encodeULEB128(Functions.size(), getStream());
886
887 for (const WasmFunction &Func : Functions) {
888 MCSectionWasm &FuncSection =
889 static_cast(Func.Sym->getSection());
890
891 if (Func.Sym->isVariable())
892 report_fatal_error("weak symbols not supported yet");
893
894 if (Func.Sym->getOffset() != 0)
895 report_fatal_error("function sections must contain one function each");
896
897 if (!Func.Sym->getSize())
898 report_fatal_error("function symbols must have a size set with .size");
899
900 int64_t Size = 0;
901 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
902 report_fatal_error(".size expression must be evaluatable");
903
904 encodeULEB128(Size, getStream());
905
906 FuncSection.setSectionOffset(getStream().tell() -
907 Section.ContentsOffset);
908
909 Asm.writeSectionData(&FuncSection, Layout);
910 }
911
912 // Apply the type index fixups for call_indirect etc. instructions.
913 for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) {
914 uint32_t Type = TypeIndexFixupTypes[i];
915 unsigned Padding = PaddingFor5ByteULEB128(Type);
916
917 const TypeIndexFixup &Fixup = TypeIndexFixups[i];
918 uint64_t Offset = Fixup.Offset +
919 Fixup.FixupSection->getSectionOffset();
920
921 uint8_t Buffer[16];
922 unsigned SizeLen = encodeULEB128(Type, Buffer, Padding);
923 assert(SizeLen == 5);
924 getStream().pwrite((char *)Buffer, SizeLen,
925 Section.ContentsOffset + Offset);
926 }
927
928 // Apply fixups.
929 ApplyRelocations(CodeRelocations, getStream(), SymbolIndices,
930 Section.ContentsOffset);
931
932 endSection(Section);
933 }
934
935 // === Data Section ==========================================================
936 if (!DataBytes.empty()) {
937 startSection(Section, wasm::WASM_SEC_DATA);
938
939 encodeULEB128(1, getStream()); // count
940 encodeULEB128(0, getStream()); // memory index
941 write8(wasm::WASM_OPCODE_I32_CONST);
942 encodeSLEB128(0, getStream()); // offset
943 write8(wasm::WASM_OPCODE_END);
944 encodeULEB128(DataBytes.size(), getStream()); // size
945 writeBytes(DataBytes); // data
946
947 // Apply fixups.
948 ApplyRelocations(DataRelocations, getStream(), SymbolIndices,
949 Section.ContentsOffset);
950
951 endSection(Section);
952 }
953
954 // === Name Section ==========================================================
955 if (NumFuncImports != 0 || !Functions.empty()) {
956 startSection(Section, wasm::WASM_SEC_CUSTOM, "name");
957
958 encodeULEB128(NumFuncImports + Functions.size(), getStream());
959 for (const WasmImport &Import : Imports) {
960 if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) {
961 encodeULEB128(Import.FieldName.size(), getStream());
962 writeBytes(Import.FieldName);
963 encodeULEB128(0, getStream()); // local count, meaningless for imports
964 }
965 }
966 for (const WasmFunction &Func : Functions) {
967 encodeULEB128(Func.Sym->getName().size(), getStream());
968 writeBytes(Func.Sym->getName());
969
970 // TODO: Local names.
971 encodeULEB128(0, getStream()); // local count
972 }
973
974 endSection(Section);
975 }
976
977 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
978 // for descriptions of the reloc sections.
979
980 // === Code Reloc Section ====================================================
981 if (!CodeRelocations.empty()) {
982 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE");
983
984 write8(wasm::WASM_SEC_CODE);
985
986 encodeULEB128(CodeRelocations.size(), getStream());
987
988 WriteRelocations(CodeRelocations, getStream(), SymbolIndices);
989
990 endSection(Section);
991 }
992
993 // === Data Reloc Section ====================================================
994 if (!DataRelocations.empty()) {
995 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA");
996
997 write8(wasm::WASM_SEC_DATA);
998
999 encodeULEB128(DataRelocations.size(), getStream());
1000
1001 WriteRelocations(DataRelocations, getStream(), SymbolIndices);
1002
1003 endSection(Section);
1004 }
1005
1006 // TODO: Translate the .comment section to the output.
1007
1008 // TODO: Translate debug sections to the output.
1151009 }
1161010
1171011 MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW,
1212 //===----------------------------------------------------------------------===//
1313
1414 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
15 #include "MCTargetDesc/WebAssemblyFixupKinds.h"
1516 #include "llvm/MC/MCAsmBackend.h"
1617 #include "llvm/MC/MCAssembler.h"
1718 #include "llvm/MC/MCDirectives.h"
6970 : MCAsmBackend(), Is64Bit(Is64Bit) {}
7071 ~WebAssemblyAsmBackend() override {}
7172
73 unsigned getNumFixupKinds() const override {
74 return WebAssembly::NumTargetFixupKinds;
75 }
76
77 const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
78
7279 void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
7380 uint64_t Value, bool IsPCRel) const override;
7481
7986 const MCRelaxableFragment *DF,
8087 const MCAsmLayout &Layout) const override {
8188 return false;
82 }
83
84 unsigned getNumFixupKinds() const override {
85 // We currently just use the generic fixups in MCFixup.h and don't have any
86 // target-specific fixups.
87 return 0;
8889 }
8990
9091 bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
128129 MCObjectWriter *
129130 WebAssemblyAsmBackendELF::createObjectWriter(raw_pwrite_stream &OS) const {
130131 return createWebAssemblyELFObjectWriter(OS, Is64Bit, 0);
132 }
133
134 const MCFixupKindInfo &
135 WebAssemblyAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
136 const static MCFixupKindInfo Infos[WebAssembly::NumTargetFixupKinds] = {
137 // This table *must* be in the order that the fixup_* kinds are defined in
138 // WebAssemblyFixupKinds.h.
139 //
140 // Name Offset (bits) Size (bits) Flags
141 { "fixup_code_sleb128_i32", 0, 5*8, 0 },
142 { "fixup_code_sleb128_i64", 0, 10*8, 0 },
143 { "fixup_code_uleb128_i32", 0, 5*8, 0 },
144 };
145
146 if (Kind < FirstTargetFixupKind)
147 return MCAsmBackend::getFixupKindInfo(Kind);
148
149 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
150 "Invalid kind!");
151 return Infos[Kind - FirstTargetFixupKind];
131152 }
132153
133154 bool WebAssemblyAsmBackend::writeNopData(uint64_t Count,
0 //=- WebAssemblyFixupKinds.h - WebAssembly Specific Fixup Entries -*- C++ -*-=//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYFIXUPKINDS_H
10 #define LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYFIXUPKINDS_H
11
12 #include "llvm/MC/MCFixup.h"
13
14 namespace llvm {
15 namespace WebAssembly {
16 enum Fixups {
17 fixup_code_sleb128_i32 = FirstTargetFixupKind, // 32-bit signed
18 fixup_code_sleb128_i64, // 64-bit signed
19 fixup_code_uleb128_i32, // 32-bit unsigned
20
21 fixup_code_global_index, // 32-bit unsigned
22
23 // Marker
24 LastTargetFixupKind,
25 NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
26 };
27 } // end namespace WebAssembly
28 } // end namespace llvm
29
30 #endif
1212 //===----------------------------------------------------------------------===//
1313
1414 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
15 #include "MCTargetDesc/WebAssemblyFixupKinds.h"
1516 #include "llvm/ADT/STLExtras.h"
1617 #include "llvm/ADT/Statistic.h"
1718 #include "llvm/MC/MCCodeEmitter.h"
4748
4849 public:
4950 WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
50 : MCII(mcii), Ctx(ctx) {
51 (void)Ctx;
52 }
51 : MCII(mcii), Ctx(ctx) {}
5352 };
5453 } // end anonymous namespace
5554
6766 assert(Binary < UINT8_MAX && "Multi-byte opcodes not supported yet");
6867 OS << uint8_t(Binary);
6968
69 // For br_table instructions, encode the size of the table. In the MCInst,
70 // there's an index operand, one operand for each table entry, and the
71 // default operand.
72 if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
73 MI.getOpcode() == WebAssembly::BR_TABLE_I64)
74 encodeULEB128(MI.getNumOperands() - 2, OS);
75
7076 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
7177 for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
7278 const MCOperand &MO = MI.getOperand(i);
8187 encodeSLEB128(int32_t(MO.getImm()), OS);
8288 } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
8389 encodeSLEB128(int64_t(MO.getImm()), OS);
90 } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
91 Fixups.push_back(MCFixup::create(
92 OS.tell() - Start, MCConstantExpr::create(MO.getImm(), Ctx),
93 MCFixupKind(WebAssembly::fixup_code_global_index), MI.getLoc()));
94 ++MCNumFixups;
95 encodeULEB128(uint64_t(MO.getImm()), OS);
8496 } else {
8597 encodeULEB128(uint64_t(MO.getImm()), OS);
8698 }
106118 support::endian::Writer(OS).write(d);
107119 }
108120 } else if (MO.isExpr()) {
121 const MCOperandInfo &Info = Desc.OpInfo[i];
122 llvm::MCFixupKind FixupKind;
123 size_t PaddedSize;
124 if (Info.OperandType == WebAssembly::OPERAND_I32IMM) {
125 FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32);
126 PaddedSize = 5;
127 } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
128 FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64);
129 PaddedSize = 10;
130 } else if (Info.OperandType == WebAssembly::OPERAND_FUNCTION32 ||
131 Info.OperandType == WebAssembly::OPERAND_OFFSET32 ||
132 Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
133 FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32);
134 PaddedSize = 5;
135 } else {
136 llvm_unreachable("unexpected symbolic operand kind");
137 }
109138 Fixups.push_back(MCFixup::create(
110139 OS.tell() - Start, MO.getExpr(),
111 STI.getTargetTriple().isArch64Bit() ? FK_Data_8 : FK_Data_4,
112 MI.getLoc()));
140 FixupKind, MI.getLoc()));
113141 ++MCNumFixups;
114 encodeULEB128(STI.getTargetTriple().isArch64Bit() ? UINT64_MAX
115 : uint64_t(UINT32_MAX),
116 OS);
142 encodeULEB128(0, OS, PaddedSize - 1);
117143 } else {
118144 llvm_unreachable("unexpected operand kind");
119145 }
6767 /// p2align immediate for load and store address alignment.
6868 OPERAND_P2ALIGN,
6969 /// signature immediate for block/loop.
70 OPERAND_SIGNATURE
70 OPERAND_SIGNATURE,
71 /// type signature immediate for call_indirect.
72 OPERAND_TYPEINDEX,
7173 };
7274 } // end namespace WebAssembly
7375
2121 #include "llvm/MC/MCSubtargetInfo.h"
2222 #include "llvm/MC/MCSymbolELF.h"
2323 #include "llvm/MC/MCSymbolWasm.h"
24 #include "llvm/Support/Casting.h"
2425 #include "llvm/Support/ErrorHandling.h"
2526 #include "llvm/Support/FormattedStream.h"
27 #include "llvm/Support/Wasm.h"
2628 using namespace llvm;
2729
2830 WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S)
5052 OS << '\n';
5153 }
5254
53 void WebAssemblyTargetAsmStreamer::emitParam(ArrayRef Types) {
54 OS << "\t.param \t";
55 PrintTypes(OS, Types);
56 }
57
58 void WebAssemblyTargetAsmStreamer::emitResult(ArrayRef Types) {
59 OS << "\t.result \t";
60 PrintTypes(OS, Types);
55 void WebAssemblyTargetAsmStreamer::emitParam(MCSymbol *Symbol,
56 ArrayRef Types) {
57 if (!Types.empty()) {
58 OS << "\t.param \t";
59
60 // FIXME: Currently this applies to the "current" function; it may
61 // be cleaner to specify an explicit symbol as part of the directive.
62
63 PrintTypes(OS, Types);
64 }
65 }
66
67 void WebAssemblyTargetAsmStreamer::emitResult(MCSymbol *Symbol,
68 ArrayRef Types) {
69 if (!Types.empty()) {
70 OS << "\t.result \t";
71
72 // FIXME: Currently this applies to the "current" function; it may
73 // be cleaner to specify an explicit symbol as part of the directive.
74
75 PrintTypes(OS, Types);
76 }
6177 }
6278
6379 void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef Types) {
91107 OS << "\t.indidx \t" << *Value << '\n';
92108 }
93109
94 void WebAssemblyTargetELFStreamer::emitParam(ArrayRef Types) {
110 void WebAssemblyTargetELFStreamer::emitParam(MCSymbol *Symbol,
111 ArrayRef Types) {
95112 // Nothing to emit; params are declared as part of the function signature.
96113 }
97114
98 void WebAssemblyTargetELFStreamer::emitResult(ArrayRef Types) {
115 void WebAssemblyTargetELFStreamer::emitResult(MCSymbol *Symbol,
116 ArrayRef Types) {
99117 // Nothing to emit; results are declared as part of the function signature.
100118 }
101119
122140 void WebAssemblyTargetELFStreamer::emitGlobalImport(StringRef name) {
123141 }
124142
125 void WebAssemblyTargetWasmStreamer::emitParam(ArrayRef Types) {
126 // Nothing to emit; params are declared as part of the function signature.
127 }
128
129 void WebAssemblyTargetWasmStreamer::emitResult(ArrayRef Types) {
130 // Nothing to emit; results are declared as part of the function signature.
143 static unsigned MVT2WasmType(MVT Ty) {
144 switch (Ty.SimpleTy) {
145 case MVT::i32: return wasm::WASM_TYPE_I32;
146 case MVT::i64: return wasm::WASM_TYPE_I64;
147 case MVT::f32: return wasm::WASM_TYPE_F32;
148 case MVT::f64: return wasm::WASM_TYPE_F64;
149 default: llvm_unreachable("unsupported type");
150 }
151 }
152
153 void WebAssemblyTargetWasmStreamer::emitParam(MCSymbol *Symbol,
154 ArrayRef Types) {
155 SmallVector Params;
156 for (MVT Ty : Types)
157 Params.push_back(MVT2WasmType(Ty));
158
159 cast(Symbol)->setParams(std::move(Params));
160 }
161
162 void WebAssemblyTargetWasmStreamer::emitResult(MCSymbol *Symbol,
163 ArrayRef Types) {
164 SmallVector Returns;
165 for (MVT Ty : Types)
166 Returns.push_back(MVT2WasmType(Ty));
167
168 cast(Symbol)->setReturns(std::move(Returns));
131169 }
132170
133171 void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef Types) {
134 Streamer.EmitULEB128IntValue(Types.size());
135 for (MVT Type : Types)
136 Streamer.EmitIntValue(int64_t(WebAssembly::toValType(Type)), 1);
172 SmallVector, 4> Grouped;
173 for (MVT Type : Types) {
174 if (Grouped.empty() || Grouped.back().first != Type)
175 Grouped.push_back(std::make_pair(Type, 1));
176 else
177 ++Grouped.back().second;
178 }
179
180 Streamer.EmitULEB128IntValue(Grouped.size());
181 for (auto Pair : Grouped) {
182 Streamer.EmitULEB128IntValue(Pair.second);
183 Streamer.EmitULEB128IntValue(uint64_t(WebAssembly::toValType(Pair.first)));
184 }
137185 }
138186
139187 void WebAssemblyTargetWasmStreamer::emitEndFunc() {
140 Streamer.EmitIntValue(WebAssembly::End, 1);
188 llvm_unreachable(".end_func is not needed for direct wasm output");
141189 }
142190
143191 void WebAssemblyTargetWasmStreamer::emitIndIdx(const MCExpr *Value) {
3030 explicit WebAssemblyTargetStreamer(MCStreamer &S);
3131
3232 /// .param
33 virtual void emitParam(ArrayRef Types) = 0;
33 virtual void emitParam(MCSymbol *Symbol, ArrayRef Types) = 0;
3434 /// .result
35 virtual void emitResult(ArrayRef Types) = 0;
35 virtual void emitResult(MCSymbol *Symbol, ArrayRef Types) = 0;
3636 /// .local
3737 virtual void emitLocal(ArrayRef Types) = 0;
3838 /// .endfunc
5656 public:
5757 WebAssemblyTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
5858
59 void emitParam(ArrayRef Types) override;
60 void emitResult(ArrayRef Types) override;
59 void emitParam(MCSymbol *Symbol, ArrayRef Types) override;
60 void emitResult(MCSymbol *Symbol, ArrayRef Types) override;
6161 void emitLocal(ArrayRef Types) override;
6262 void emitEndFunc() override;
6363 void emitIndirectFunctionType(StringRef name,
7272 public:
7373 explicit WebAssemblyTargetELFStreamer(MCStreamer &S);
7474
75 void emitParam(ArrayRef Types) override;
76 void emitResult(ArrayRef Types) override;
75 void emitParam(MCSymbol *Symbol, ArrayRef Types) override;
76 void emitResult(MCSymbol *Symbol, ArrayRef Types) override;
7777 void emitLocal(ArrayRef Types) override;
7878 void emitEndFunc() override;
7979 void emitIndirectFunctionType(StringRef name,
8888 public:
8989 explicit WebAssemblyTargetWasmStreamer(MCStreamer &S);
9090
91 void emitParam(ArrayRef Types) override;
92 void emitResult(ArrayRef Types) override;
91 void emitParam(MCSymbol *Symbol, ArrayRef Types) override;
92 void emitResult(MCSymbol *Symbol, ArrayRef Types) override;
9393 void emitLocal(ArrayRef Types) override;
9494 void emitEndFunc() override;
9595 void emitIndirectFunctionType(StringRef name,
1313 //===----------------------------------------------------------------------===//
1414
1515 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16 #include "MCTargetDesc/WebAssemblyFixupKinds.h"
1617 #include "llvm/MC/MCFixup.h"
18 #include "llvm/MC/MCSymbolWasm.h"
1719 #include "llvm/MC/MCWasmObjectWriter.h"
20 #include "llvm/Support/Casting.h"
1821 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/Wasm.h"
1923 using namespace llvm;
2024
2125 namespace {
3236 WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit)
3337 : MCWasmObjectTargetWriter(Is64Bit) {}
3438
39 // Test whether the given expression computes a function address.
40 static bool IsFunctionExpr(const MCExpr *Expr) {
41 if (const MCSymbolRefExpr *SyExp =
42 dyn_cast(Expr))
43 return cast(SyExp->getSymbol()).isFunction();
44
45 if (const MCBinaryExpr *BinOp =
46 dyn_cast(Expr))
47 return IsFunctionExpr(BinOp->getLHS()) != IsFunctionExpr(BinOp->getRHS());
48
49 if (const MCUnaryExpr *UnOp =
50 dyn_cast(Expr))
51 return IsFunctionExpr(UnOp->getSubExpr());
52
53 return false;
54 }
55
3556 unsigned WebAssemblyWasmObjectWriter::getRelocType(MCContext &Ctx,
3657 const MCValue &Target,
3758 const MCFixup &Fixup,
3859 bool IsPCRel) const {
39 llvm_unreachable("Relocations not yet implemented");
40 return 0;
60 // WebAssembly functions are not allocated in the data address space. To
61 // resolve a pointer to a function, we must use a special relocation type.
62 bool IsFunction = IsFunctionExpr(Fixup.getValue());
63
64 assert(!IsPCRel);
65 switch (unsigned(Fixup.getKind())) {
66 case WebAssembly::fixup_code_sleb128_i32:
67 if (IsFunction)
68 return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB;
69 return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB;
70 case WebAssembly::fixup_code_sleb128_i64:
71 llvm_unreachable("fixup_sleb128_i64 not implemented yet");
72 case WebAssembly::fixup_code_uleb128_i32:
73 if (IsFunction)
74 return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB;
75 return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB;
76 case FK_Data_4:
77 if (IsFunction)
78 return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32;
79 return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32;
80 case FK_Data_8:
81 llvm_unreachable("FK_Data_8 not implemented yet");
82 default:
83 llvm_unreachable("unimplemented fixup kind");
84 }
4185 }
4286
4387 MCObjectWriter *llvm::createWebAssemblyWasmObjectWriter(raw_pwrite_stream &OS,
1313 ///
1414 //===----------------------------------------------------------------------===//
1515
16 #include "WebAssemblyAsmPrinter.h"
1617 #include "InstPrinter/WebAssemblyInstPrinter.h"
1718 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
1819 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
2021 #include "WebAssemblyMCInstLower.h"
2122 #include "WebAssemblyMachineFunctionInfo.h"
2223 #include "WebAssemblyRegisterInfo.h"
23 #include "WebAssemblySubtarget.h"
2424 #include "llvm/ADT/StringExtras.h"
2525 #include "llvm/CodeGen/Analysis.h"
2626 #include "llvm/CodeGen/AsmPrinter.h"
2727 #include "llvm/CodeGen/MachineConstantPool.h"
2828 #include "llvm/CodeGen/MachineInstr.h"
2929 #include "llvm/IR/DataLayout.h"
30 #include "llvm/IR/GlobalVariable.h"
3031 #include "llvm/MC/MCContext.h"
3132 #include "llvm/MC/MCStreamer.h"
3233 #include "llvm/MC/MCSymbol.h"
3637 using namespace llvm;
3738
3839 #define DEBUG_TYPE "asm-printer"
39
40 namespace {
41
42 class WebAssemblyAsmPrinter final : public AsmPrinter {
43 const MachineRegisterInfo *MRI;
44 WebAssemblyFunctionInfo *MFI;
45
46 public:
47 WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer)
48 : AsmPrinter(TM, std::move(Streamer)), MRI(nullptr), MFI(nullptr) {}
49
50 private:
51 StringRef getPassName() const override {
52 return "WebAssembly Assembly Printer";
53 }
54
55 //===------------------------------------------------------------------===//
56 // MachineFunctionPass Implementation.
57 //===------------------------------------------------------------------===//
58
59 bool runOnMachineFunction(MachineFunction &MF) override {
60 MRI = &MF.getRegInfo();
61 MFI = MF.getInfo();
62 return AsmPrinter::runOnMachineFunction(MF);
63 }
64
65 //===------------------------------------------------------------------===//
66 // AsmPrinter Implementation.
67 //===------------------------------------------------------------------===//
68
69 void EmitEndOfAsmFile(Module &M) override;
70 void EmitJumpTableInfo() override;
71 void EmitConstantPool() override;
72 void EmitFunctionBodyStart() override;
73 void EmitFunctionBodyEnd() override;
74 void EmitInstruction(const MachineInstr *MI) override;
75 const MCExpr *lowerConstant(const Constant *CV) override;
76 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
77 unsigned AsmVariant, const char *ExtraCode,
78 raw_ostream &OS) override;
79 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
80 unsigned AsmVariant, const char *ExtraCode,
81 raw_ostream &OS) override;
82
83 MVT getRegType(unsigned RegNo) const;
84 std::string regToString(const MachineOperand &MO);
85 WebAssemblyTargetStreamer *getTargetStreamer();
86 };
87
88 } // end anonymous namespace
8940
9041 //===----------------------------------------------------------------------===//
9142 // Helpers.
13485 }
13586 for (const auto &G : M.globals()) {
13687 if (!G.hasInitializer() && G.hasExternalLinkage()) {
88 uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
13789 getTargetStreamer()->emitGlobalImport(G.getGlobalIdentifier());
90 OutStreamer->emitELFSize(getSymbol(&G),
91 MCConstantExpr::create(Size, OutContext));
13892 }
13993 }
14094 }
149103 }
150104
151105 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
152 if (!MFI->getParams().empty())
153 getTargetStreamer()->emitParam(MFI->getParams());
106 getTargetStreamer()->emitParam(CurrentFnSym, MFI->getParams());
154107
155108 SmallVector ResultVTs;
156109 const Function &F(*MF->getFunction());
168121 // If the return type needs to be legalized it will get converted into
169122 // passing a pointer.
170123 if (ResultVTs.size() == 1)
171 getTargetStreamer()->emitResult(ResultVTs);
172
173 // FIXME: When ExplicitLocals is enabled by default, we won't need
174 // to define the locals here (and MFI can go back to being pointer-to-const).
175 for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
176 unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
177 unsigned WAReg = MFI->getWAReg(VReg);
178 // Don't declare unused registers.
179 if (WAReg == WebAssemblyFunctionInfo::UnusedReg)
180 continue;
181 // Don't redeclare parameters.
182 if (WAReg < MFI->getParams().size())
183 continue;
184 // Don't declare stackified registers.
185 if (int(WAReg) < 0)
186 continue;
187 MFI->addLocal(getRegType(VReg));
124 getTargetStreamer()->emitResult(CurrentFnSym, ResultVTs);
125 else
126 getTargetStreamer()->emitResult(CurrentFnSym, ArrayRef());
127
128 if (TM.getTargetTriple().isOSBinFormatELF()) {
129 assert(MFI->getLocals().empty());
130 for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
131 unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
132 unsigned WAReg = MFI->getWAReg(VReg);
133 // Don't declare unused registers.
134 if (WAReg == WebAssemblyFunctionInfo::UnusedReg)
135 continue;
136 // Don't redeclare parameters.
137 if (WAReg < MFI->getParams().size())
138 continue;
139 // Don't declare stackified registers.
140 if (int(WAReg) < 0)
141 continue;
142 MFI->addLocal(getRegType(VReg));
143 }
188144 }
189145
190146 getTargetStreamer()->emitLocal(MFI->getLocals());
193149 }
194150
195151 void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() {
196 getTargetStreamer()->emitEndFunc();
152 if (TM.getTargetTriple().isOSBinFormatELF())
153 getTargetStreamer()->emitEndFunc();
197154 }
198155
199156 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
0 // WebAssemblyAsmPrinter.h - WebAssembly implementation of AsmPrinter-*- C++ -*-
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYASMPRINTER_H
10 #define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYASMPRINTER_H
11
12 #include "WebAssemblySubtarget.h"
13 #include "llvm/CodeGen/AsmPrinter.h"
14 #include "llvm/MC/MCStreamer.h"
15 #include "llvm/Target/TargetMachine.h"
16
17 namespace llvm {
18 class MCSymbol;
19 class WebAssemblyFunctionInfo;
20 class WebAssemblyTargetStreamer;
21 class WebAssemblyMCInstLower;
22
23 class LLVM_LIBRARY_VISIBILITY WebAssemblyAsmPrinter final : public AsmPrinter {
24 const WebAssemblySubtarget *Subtarget;
25 const MachineRegisterInfo *MRI;
26 WebAssemblyFunctionInfo *MFI;
27
28 public:
29 explicit WebAssemblyAsmPrinter(TargetMachine &TM,
30 std::unique_ptr Streamer)
31 : AsmPrinter(TM, std::move(Streamer)),
32 Subtarget(nullptr), MRI(nullptr), MFI(nullptr) {}
33
34 StringRef getPassName() const override {
35 return "WebAssembly Assembly Printer";
36 }
37
38 const WebAssemblySubtarget &getSubtarget() const { return *Subtarget; }
39
40 //===------------------------------------------------------------------===//
41 // MachineFunctionPass Implementation.
42 //===------------------------------------------------------------------===//
43
44 bool runOnMachineFunction(MachineFunction &MF) override {
45 Subtarget = &MF.getSubtarget();
46 MRI = &MF.getRegInfo();
47 MFI = MF.getInfo();
48 return AsmPrinter::runOnMachineFunction(MF);
49 }
50
51 //===------------------------------------------------------------------===//
52 // AsmPrinter Implementation.
53 //===------------------------------------------------------------------===//
54
55 void EmitEndOfAsmFile(Module &M) override;
56 void EmitJumpTableInfo() override;
57 void EmitConstantPool() override;
58 void EmitFunctionBodyStart() override;
59 void EmitFunctionBodyEnd() override;
60 void EmitInstruction(const MachineInstr *MI) override;
61 const MCExpr *lowerConstant(const Constant *CV) override;
62 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
63 unsigned AsmVariant, const char *ExtraCode,
64 raw_ostream &OS) override;
65 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
66 unsigned AsmVariant, const char *ExtraCode,
67 raw_ostream &OS) override;
68
69 MVT getRegType(unsigned RegNo) const;
70 std::string regToString(const MachineOperand &MO);
71 WebAssemblyTargetStreamer *getTargetStreamer();
72 };
73
74 } // end namespace llvm
75
76 #endif
487487 }
488488 }
489489
490 // WebAssembly functions end with an end instruction, as if the function body
491 // were a block.
492 static void AppendEndToFunction(
493 MachineFunction &MF,
494 const WebAssemblyInstrInfo &TII) {
495 BuildMI(MF.back(), MF.back().end(), DebugLoc(),
496 TII.get(WebAssembly::END_FUNCTION));
497 }
498
490499 /// Insert LOOP and BLOCK markers at appropriate places.
491500 static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
492501 const WebAssemblyInstrInfo &TII,
554563 // Fix up block/loop signatures at the end of the function to conform to
555564 // WebAssembly's rules.
556565 FixEndsAtEndOfFunction(MF, MFI, BlockTops, LoopTops);
566
567 // Add an end instruction at the end of the function body.
568 if (!MF.getSubtarget()
569 .getTargetTriple().isOSBinFormatELF())
570 AppendEndToFunction(MF, TII);
557571 }
558572
559573 bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
9696 MI.setDesc(Desc);
9797
9898 // Rewrite argument order
99 auto Uses = MI.explicit_uses();
100 MachineInstr::mop_iterator it = Uses.begin();
101 const MachineOperand MO = *it;
99 SmallVector Ops;
100
101 // Set up a placeholder for the type signature immediate.
102 Ops.push_back(MachineOperand::CreateImm(0));
102103
103104 // Set up the flags immediate, which currently has no defined flags
104105 // so it's always zero.
105 it->ChangeToImmediate(0);
106 Ops.push_back(MachineOperand::CreateImm(0));
106107
107 MI.addOperand(MF, MO);
108 for (const MachineOperand &MO :
109 make_range(MI.operands_begin() +
110 MI.getDesc().getNumDefs() + 1,
111 MI.operands_begin() +
112 MI.getNumExplicitOperands()))
113 Ops.push_back(MO);
114 Ops.push_back(MI.getOperand(MI.getDesc().getNumDefs()));
115
116 // Replace the instructions operands.
117 while (MI.getNumOperands() > MI.getDesc().getNumDefs())
118 MI.RemoveOperand(MI.getNumOperands() - 1);
119 for (const MachineOperand &MO : Ops)
120 MI.addOperand(MO);
108121
109122 DEBUG(dbgs() << " After transform: " << MI);
110123 Changed = true;
5959 /// if it doesn't yet have one.
6060 static unsigned getLocalId(DenseMap &Reg2Local,
6161 unsigned &CurLocal, unsigned Reg) {
62 return Reg2Local.insert(std::make_pair(Reg, CurLocal++)).first->second;
62 auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
63 if (P.second)
64 ++CurLocal;
65 return P.first->second;
66 }
67
68 /// Get the appropriate drop opcode for the given register class.
69 static unsigned getDropOpcode(const TargetRegisterClass *RC) {
70 if (RC == &WebAssembly::I32RegClass)
71 return WebAssembly::DROP_I32;
72 if (RC == &WebAssembly::I64RegClass)
73 return WebAssembly::DROP_I64;
74 if (RC == &WebAssembly::F32RegClass)
75 return WebAssembly::DROP_F32;
76 if (RC == &WebAssembly::F64RegClass)
77 return WebAssembly::DROP_F64;
78 if (RC == &WebAssembly::V128RegClass)
79 return WebAssembly::DROP_V128;
80 llvm_unreachable("Unexpected register class");
6381 }
6482
6583 /// Get the appropriate get_local opcode for the given register class.
175193 // Start assigning local numbers after the last parameter.
176194 unsigned CurLocal = MFI.getParams().size();
177195
196 // Precompute the set of registers that are unused, so that we can insert
197 // drops to their defs.
198 BitVector UseEmpty(MRI.getNumVirtRegs());
199 for (unsigned i = 0, e = MRI.getNumVirtRegs(); i < e; ++i)
200 UseEmpty[i] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(i));
201
178202 // Visit each instruction in the function.
179203 for (MachineBasicBlock &MBB : MF) {
180204 for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
223247 assert(MI.getDesc().getNumDefs() <= 1);
224248 if (MI.getDesc().getNumDefs() == 1) {
225249 unsigned OldReg = MI.getOperand(0).getReg();
226 if (!MFI.isVRegStackified(OldReg) && !MRI.use_empty(OldReg)) {
227 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
250 if (!MFI.isVRegStackified(OldReg)) {
228251 const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
229252 unsigned NewReg = MRI.createVirtualRegister(RC);
230253 auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
231 unsigned Opc = getSetLocalOpcode(RC);
232 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
233 .addImm(LocalId)
234 .addReg(NewReg);
254 if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
255 MI.eraseFromParent();
256 Changed = true;
257 continue;
258 }
259 if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) {
260 unsigned Opc = getDropOpcode(RC);
261 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
262 .addReg(NewReg);
263 } else {
264 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
265 unsigned Opc = getSetLocalOpcode(RC);
266 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
267 .addImm(LocalId)
268 .addReg(NewReg);
269 }
235270 MI.getOperand(0).setReg(NewReg);
236271 MFI.stackifyVReg(NewReg);
237272 Changed = true;
277312 }
278313
279314 // Define the locals.
315 // TODO: Sort the locals for better compression.
316 MFI.setNumLocals(CurLocal - MFI.getParams().size());
280317 for (size_t i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) {
281318 unsigned Reg = TargetRegisterInfo::index2VirtReg(i);
282319 auto I = Reg2Local.find(Reg);
283320 if (I == Reg2Local.end() || I->second < MFI.getParams().size())
284321 continue;
285322
286 MFI.addLocal(typeForRegClass(MRI.getRegClass(Reg)));
323 MFI.setLocal(I->second - MFI.getParams().size(),
324 typeForRegClass(MRI.getRegClass(Reg)));
287325 Changed = true;
288326 }
289327
2323 #include "WebAssemblyMachineFunctionInfo.h"
2424 #include "WebAssemblySubtarget.h"
2525 #include "WebAssemblyTargetMachine.h"
26 #include "WebAssemblyUtilities.h"
2627 #include "llvm/CodeGen/MachineFrameInfo.h"
2728 #include "llvm/CodeGen/MachineFunction.h"
2829 #include "llvm/CodeGen/MachineInstrBuilder.h"
150151 auto &MRI = MF.getRegInfo();
151152
152153 auto InsertPt = MBB.begin();
154 while (InsertPt != MBB.end() && WebAssembly::isArgument(*InsertPt))
155 ++InsertPt;
153156 DebugLoc DL;
154157
155158 const TargetRegisterClass *PtrRC =
2929 [(set vt:$dst, (WebAssemblycall1 (i32 imm:$callee)))],
3030 !strconcat(prefix, "call\t$dst, $callee"),
3131 0x10>;
32
3233 let isCodeGenOnly = 1 in {
3334 def PCALL_INDIRECT_#vt : I<(outs vt:$dst), (ins I32:$callee, variable_ops),
3435 [(set vt:$dst, (WebAssemblycall1 I32:$callee))],
3536 "PSEUDO CALL INDIRECT\t$callee">;
3637 } // isCodeGenOnly = 1
3738
38 def CALL_INDIRECT_#vt : I<(outs vt:$dst), (ins i32imm:$flags, variable_ops),
39 def CALL_INDIRECT_#vt : I<(outs vt:$dst),
40 (ins TypeIndex:$type, i32imm:$flags, variable_ops),
3941 [],
4042 !strconcat(prefix, "call_indirect\t$dst"),
4143 0x11>;
4749 (WebAssemblycall1 (i32 imm:$callee)))],
4850 !strconcat(prefix, "call\t$dst, $callee"),
4951 0x10>;
52
5053 let isCodeGenOnly = 1 in {
5154 def PCALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst),
5255 (ins I32:$callee, variable_ops),
5659 } // isCodeGenOnly = 1
5760
5861 def CALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst),
59 (ins i32imm:$flags, variable_ops),
62 (ins TypeIndex:$type, i32imm:$flags,
63 variable_ops),
6064 [],
6165 !strconcat(prefix, "call_indirect\t$dst"),
6266 0x11>;
7579 def CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops),
7680 [(WebAssemblycall0 (i32 imm:$callee))],
7781 "call \t$callee", 0x10>;
82
7883 let isCodeGenOnly = 1 in {
7984 def PCALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops),
8085 [(WebAssemblycall0 I32:$callee)],
8186 "PSEUDO CALL INDIRECT\t$callee">;
8287 } // isCodeGenOnly = 1
8388
84 def CALL_INDIRECT_VOID : I<(outs), (ins i32imm:$flags, variable_ops),
89 def CALL_INDIRECT_VOID : I<(outs),
90 (ins TypeIndex:$type, i32imm:$flags, variable_ops),
8591 [],
8692 "call_indirect\t", 0x11>;
8793 } // Uses = [SP32,SP64], isCall = 1
6363 def BLOCK : I<(outs), (ins Signature:$sig), [], "block \t$sig", 0x02>;
6464 def LOOP : I<(outs), (ins Signature:$sig), [], "loop \t$sig", 0x03>;
6565
66 // END_BLOCK and END_LOOP are represented with the same opcode in wasm.
66 // END_BLOCK, END_LOOP, and END_FUNCTION are represented with the same opcode
67 // in wasm.
6768 def END_BLOCK : I<(outs), (ins), [], "end_block", 0x0b>;
6869 def END_LOOP : I<(outs), (ins), [], "end_loop", 0x0b>;
70 let isTerminator = 1, isBarrier = 1 in
71 def END_FUNCTION : I<(outs), (ins), [], "end_function", 0x0b>;
6972 } // Uses = [VALUE_STACK], Defs = [VALUE_STACK]
7073
7174 multiclass RETURN {
106106 }
107107 } // OperandType = "OPERAND_SIGNATURE"
108108
109 let OperandType = "OPERAND_TYPEINDEX" in
110 def TypeIndex : Operand;
111
109112 } // OperandNamespace = "WebAssembly"
110113
111114 //===----------------------------------------------------------------------===//
1313 //===----------------------------------------------------------------------===//
1414
1515 #include "WebAssemblyMCInstLower.h"
16 #include "WebAssemblyAsmPrinter.h"
1617 #include "WebAssemblyMachineFunctionInfo.h"
18 #include "WebAssemblyRuntimeLibcallSignatures.h"
19 #include "WebAssemblyUtilities.h"
1720 #include "llvm/CodeGen/AsmPrinter.h"
1821 #include "llvm/CodeGen/MachineFunction.h"
1922 #include "llvm/IR/Constants.h"
2124 #include "llvm/MC/MCContext.h"
2225 #include "llvm/MC/MCExpr.h"
2326 #include "llvm/MC/MCInst.h"
27 #include "llvm/MC/MCSymbolELF.h"
28 #include "llvm/MC/MCSymbolWasm.h"
2429 #include "llvm/Support/ErrorHandling.h"
2530 #include "llvm/Support/raw_ostream.h"
2631 using namespace llvm;
2732
2833 MCSymbol *
2934 WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
30 return Printer.getSymbol(MO.getGlobal());
35 const GlobalValue *Global = MO.getGlobal();
36 MCSymbol *Sym = Printer.getSymbol(Global);
37 if (isa(Sym))
38 return Sym;
39
40 MCSymbolWasm *WasmSym = cast(Sym);
41
42 if (const auto *FuncTy = dyn_cast(Global->getValueType())) {
43 const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
44 const TargetMachine &TM = MF.getTarget();
45 const Function &CurrentFunc = *MF.getFunction();
46
47 SmallVector Returns;
48 SmallVector Params;
49
50 WebAssembly::ValType iPTR =
51 MF.getSubtarget().hasAddr64() ?
52 WebAssembly::ValType::I64 :
53 WebAssembly::ValType::I32;
54
55 SmallVector ResultMVTs;
56 ComputeLegalValueVTs(CurrentFunc, TM, FuncTy->getReturnType(), ResultMVTs);
57 // WebAssembly can't currently handle returning tuples.
58 if (ResultMVTs.size() <= 1)
59 for (MVT ResultMVT : ResultMVTs)
60 Returns.push_back(unsigned(WebAssembly::toValType(ResultMVT)));
61 else
62 Params.push_back(unsigned(iPTR));
63
64 for (Type *Ty : FuncTy->params()) {
65 SmallVector ParamMVTs;
66 ComputeLegalValueVTs(CurrentFunc, TM, Ty, ParamMVTs);
67 for (MVT ParamMVT : ParamMVTs)
68 Params.push_back(unsigned(WebAssembly::toValType(ParamMVT)));
69 }
70
71 if (FuncTy->isVarArg())
72 Params.push_back(unsigned(iPTR));
73
74 WasmSym->setReturns(std::move(Returns));
75 WasmSym->setParams(std::move(Params));
76 WasmSym->setIsFunction(true);
77 }
78
79 return WasmSym;
3180 }
3281
3382 MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
3483 const MachineOperand &MO) const {
35 return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
84 const char *Name = MO.getSymbolName();
85 MCSymbol *Sym = Printer.GetExternalSymbolSymbol(Name);
86 if (isa(Sym))
87 return Sym;
88
89 MCSymbolWasm *WasmSym = cast(Sym);
90 const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
91
92 // __stack_pointer is a global variable; all other external symbols used by
93 // CodeGen are functions.
94 if (strcmp(Name, "__stack_pointer") == 0)
95 return WasmSym;
96
97 SmallVector Returns;
98 SmallVector Params;
99 GetSignature(Subtarget, Name, Returns, Params);
100
101 WasmSym->setReturns(std::move(Returns));
102 WasmSym->setParams(std::move(Params));
103 WasmSym->setIsFunction(true);
104
105 return WasmSym;
36106 }
37107
38108 MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
41111 MCSymbolRefExpr::VariantKind VK =
42112 IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
43113 : MCSymbolRefExpr::VK_None;
114 if (!isa(Sym))
115 cast(Sym)->setIsFunction(IsFunc);
116
44117 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
45118
46119 if (Offset != 0) {
53126 return MCOperand::createExpr(Expr);
54127 }
55128
129 // Return the WebAssembly type associated with the given register class.
130 static unsigned getType(const TargetRegisterClass *RC) {
131 if (RC == &WebAssembly::I32RegClass)
132 return unsigned(WebAssembly::ExprType::I32);
133 if (RC == &WebAssembly::I64RegClass)
134 return unsigned(WebAssembly::ExprType::I64);
135 if (RC == &WebAssembly::F32RegClass)
136 return unsigned(WebAssembly::ExprType::F32);
137 if (RC == &WebAssembly::F64RegClass)
138 return unsigned(WebAssembly::ExprType::F64);
139 llvm_unreachable("Unexpected register class");
140 }
141
56142 void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
57143 MCInst &OutMI) const {
58144 OutMI.setOpcode(MI->getOpcode());
59145
146 const MCInstrDesc &Desc = MI->getDesc();
60147 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
61148 const MachineOperand &MO = MI->getOperand(i);
62149
79166 break;
80167 }
81168 case MachineOperand::MO_Immediate:
169 if (i < Desc.NumOperands) {
170 const MCOperandInfo &Info = Desc.OpInfo[i];
171 if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
172 MCSymbol *Sym = Printer.createTempSymbol("typeindex");
173 if (!isa(Sym)) {
174 SmallVector Returns;
175 SmallVector Params;
176
177 const MachineRegisterInfo &MRI =
178 MI->getParent()->getParent()->getRegInfo();
179 for (const MachineOperand &MO : MI->defs())
180 Returns.push_back(getType(MRI.getRegClass(MO.getReg())));
181 for (const MachineOperand &MO : MI->explicit_uses())
182 if (MO.isReg())
183 Params.push_back(getType(MRI.getRegClass(MO.getReg())));
184
185 // call_indirect instructions have a callee operand at the end which
186 // doesn't count as a param.
187 if (WebAssembly::isCallIndirect(*MI))
188 Params.pop_back();
189
190 MCSymbolWasm *WasmSym = cast(Sym);
191 WasmSym->setReturns(std::move(Returns));
192 WasmSym->setParams(std::move(Params));
193 WasmSym->setIsFunction(true);
194
195 const MCExpr *Expr =
196 MCSymbolRefExpr::create(WasmSym,
197 MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX,
198 Ctx);
199 MCOp = MCOperand::createExpr(Expr);
200 break;
201 }
202 }
203 }
82204 MCOp = MCOperand::createImm(MO.getImm());
83205 break;
84206 case MachineOperand::MO_FPImmediate: {
1919 #include "llvm/Support/Compiler.h"
2020
2121 namespace llvm {
22 class AsmPrinter;
22 class WebAssemblyAsmPrinter;
2323 class MCContext;
2424 class MCSymbol;
2525 class MachineInstr;
2828 /// This class is used to lower an MachineInstr into an MCInst.
2929 class LLVM_LIBRARY_VISIBILITY WebAssemblyMCInstLower {
3030 MCContext &Ctx;
31 AsmPrinter &Printer;
31 WebAssemblyAsmPrinter &Printer;
3232
3333 MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const;
3434 MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const;
3636 bool IsFunc) const;
3737
3838 public:
39 WebAssemblyMCInstLower(MCContext &ctx, AsmPrinter &printer)
39 WebAssemblyMCInstLower(MCContext &ctx, WebAssemblyAsmPrinter &printer)
4040 : Ctx(ctx), Printer(printer) {}
4141 void Lower(const MachineInstr *MI, MCInst &OutMI) const;
4242 };
5959 void addResult(MVT VT) { Results.push_back(VT); }
6060 const std::vector &getResults() const { return Results; }
6161
62 void setNumLocals(size_t NumLocals) { Locals.resize(NumLocals, MVT::i32); }
63 void setLocal(size_t i, MVT VT) { Locals[i] = VT; }
6264 void addLocal(MVT VT) { Locals.push_back(VT); }
6365 const std::vector &getLocals() const { return Locals; }
6466
7979 return false;
8080 if (&MBB != &MF.back())
8181 return false;
82 if (&MI != &MBB.back())
83 return false;
82 if (MF.getSubtarget()
83 .getTargetTriple().isOSBinFormatELF()) {
84 if (&MI != &MBB.back())
85 return false;
86 } else {
87 MachineBasicBlock::iterator End = MBB.end();
88 --End;
89 assert(End->getOpcode() == WebAssembly::END_FUNCTION);
90 --End;
91 if (&MI != &*End)
92 return false;
93 }
8494
8595 if (FallthroughOpc != WebAssembly::FALLTHROUGH_RETURN_VOID) {
8696 // If the operand isn't stackified, insert a COPY to read the operand and
8484 // 'unreachable' instructions which is meant for that case.
8585 this->Options.TrapUnreachable = true;
8686
87 // WebAssembly treats each function as an independent unit. Force
88 // -ffunction-sections, effectively, so that we can emit them independently.
89 if (!TT.isOSBinFormatELF()) {
90 this->Options.FunctionSections = true;
91 this->Options.DataSections = true;
92 this->Options.UniqueSectionNames = true;
93 }
94
8795 initAsmInfo();
8896
8997 // Note that we don't use setRequiresStructuredCFG(true). It disables
263271 addPass(createWebAssemblyRegColoring());
264272 }
265273
274 // Eliminate multiple-entry loops. Do this before inserting explicit get_local
275 // and set_local operators because we create a new variable that we want
276 // converted into a local.
277 addPass(createWebAssemblyFixIrreducibleControlFlow());
278
266279 // Insert explicit get_local and set_local operators.
267280 addPass(createWebAssemblyExplicitLocals());
268
269 // Eliminate multiple-entry loops.
270 addPass(createWebAssemblyFixIrreducibleControlFlow());
271281
272282 // Put the CFG in structured form; insert BLOCK and LOOP markers.
273283 addPass(createWebAssemblyCFGStackify());
6868 return TargetRegisterInfo::isVirtualRegister(Reg) &&
6969 MFI.isVRegStackified(Reg);
7070 }
71
72 bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
73 switch (MI.getOpcode()) {
74 case WebAssembly::CALL_INDIRECT_VOID:
75 case WebAssembly::CALL_INDIRECT_I32:
76 case WebAssembly::CALL_INDIRECT_I64:
77 case WebAssembly::CALL_INDIRECT_F32:
78 case WebAssembly::CALL_INDIRECT_F64:
79 case WebAssembly::CALL_INDIRECT_v16i8:
80 case WebAssembly::CALL_INDIRECT_v8i16:
81 case WebAssembly::CALL_INDIRECT_v4i32:
82 case WebAssembly::CALL_INDIRECT_v4f32:
83 return true;
84 default:
85 return false;
86 }
87 }
2626 bool isCopy(const MachineInstr &MI);
2727 bool isTee(const MachineInstr &MI);
2828 bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI);
29 bool isCallIndirect(const MachineInstr &MI);
2930
3031 } // end namespace WebAssembly
3132 } // end namespace llvm
33 ; Test that basic call operations assemble as expected.
44
55 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6 target triple = "wasm32-unknown-unknown"
6 target triple = "wasm32-unknown-unknown-wasm"
77
88 declare i32 @i32_nullary()
99 declare i32 @i32_unary(i32)
6060 ; CHECK-LABEL: call_i32_unary:
6161 ; CHECK-NEXT: .param i32{{$}}
6262 ; CHECK-NEXT: .result i32{{$}}
63 ; CHECK-NEXT: {{^}} i32.call $push[[NUM:[0-9]+]]=, i32_unary@FUNCTION, $0{{$}}
63 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
64 ; CHECK-NEXT: {{^}} i32.call $push[[NUM:[0-9]+]]=, i32_unary@FUNCTION, $pop[[L0]]{{$}}
6465 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
6566 define i32 @call_i32_unary(i32 %a) {
6667 %r = call i32 @i32_unary(i32 %a)
7071 ; CHECK-LABEL: call_i32_binary:
7172 ; CHECK-NEXT: .param i32, i32{{$}}
7273 ; CHECK-NEXT: .result i32{{$}}
73 ; CHECK-NEXT: {{^}} i32.call $push[[NUM:[0-9]+]]=, i32_binary@FUNCTION, $0, $1{{$}}
74 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
75 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
76 ; CHECK-NEXT: {{^}} i32.call $push[[NUM:[0-9]+]]=, i32_binary@FUNCTION, $pop[[L0]], $pop[[L1]]{{$}}
7477 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
7578 define i32 @call_i32_binary(i32 %a, i32 %b) {
7679 %r = call i32 @i32_binary(i32 %a, i32 %b)
7982
8083 ; CHECK-LABEL: call_indirect_void:
8184 ; CHECK-NEXT: .param i32{{$}}
82 ; CHECK-NEXT: {{^}} call_indirect $0{{$}}
85 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
86 ; CHECK-NEXT: {{^}} call_indirect $pop[[L0]]{{$}}
8387 ; CHECK-NEXT: return{{$}}
8488 define void @call_indirect_void(void ()* %callee) {
8589 call void %callee()
8993 ; CHECK-LABEL: call_indirect_i32:
9094 ; CHECK-NEXT: .param i32{{$}}
9195 ; CHECK-NEXT: .result i32{{$}}
92 ; CHECK-NEXT: {{^}} i32.call_indirect $push[[NUM:[0-9]+]]=, $0{{$}}
96 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
97 ; CHECK-NEXT: {{^}} i32.call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
9398 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
9499 define i32 @call_indirect_i32(i32 ()* %callee) {
95100 %t = call i32 %callee()
98103
99104 ; CHECK-LABEL: call_indirect_arg:
100105 ; CHECK-NEXT: .param i32, i32{{$}}
101 ; CHECK-NEXT: {{^}} call_indirect $1, $0{{$}}
106 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 1{{$}}
107 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
108 ; CHECK-NEXT: {{^}} call_indirect $pop[[L0]], $pop[[L1]]{{$}}
102109 ; CHECK-NEXT: return{{$}}
103110 define void @call_indirect_arg(void (i32)* %callee, i32 %arg) {
104111 call void %callee(i32 %arg)
107114
108115 ; CHECK-LABEL: call_indirect_arg_2:
109116 ; CHECK-NEXT: .param i32, i32, i32{{$}}
110 ; CHECK-NEXT: {{^}} i32.call_indirect $drop=, $1, $2, $0{{$}}
117 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 1{{$}}
118 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 2{{$}}
119 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
120 ; CHECK-NEXT: {{^}} i32.call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]], $pop[[L2]]{{$}}
121 ; CHECK-NEXT: drop $pop[[NUM]]{{$}}
111122 ; CHECK-NEXT: return{{$}}
112123 define void @call_indirect_arg_2(i32 (i32, i32)* %callee, i32 %arg, i32 %arg2) {
113124 call i32 %callee(i32 %arg, i32 %arg2)
22 ; Tests that we correctly assign indexes for control flow integrity.
33
44 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
5 target triple = "wasm32-unknown-unknown"
5 target triple = "wasm32-unknown-unknown-wasm"
66
77 @0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16
88
33 ; expected.
44
55 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6 target triple = "wasm32-unknown-unknown"
6 target triple = "wasm32-unknown-unknown-wasm"
77
88 ; CHECK-LABEL: ord_f32:
99 ; CHECK-NEXT: .param f32, f32{{$}}
1010 ; CHECK-NEXT: .result i32{{$}}
11 ; CHECK-NEXT: f32.eq $push[[NUM0:[0-9]+]]=, $0, $0{{$}}
12 ; CHECK-NEXT: f32.eq $push[[NUM1:[0-9]+]]=, $1, $1{{$}}
11 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
12 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
13 ; CHECK-NEXT: f32.eq $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
14 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 1{{$}}
15 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 1{{$}}
16 ; CHECK-NEXT: f32.eq $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
1317 ; CHECK-NEXT: i32.and $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
1418 ; CHECK-NEXT: return $pop[[NUM2]]{{$}}
1519 define i32 @ord_f32(float %x, float %y) {
2125 ; CHECK-LABEL: uno_f32:
2226 ; CHECK-NEXT: .param f32, f32{{$}}
2327 ; CHECK-NEXT: .result i32{{$}}
24 ; CHECK-NEXT: f32.ne $push[[NUM0:[0-9]+]]=, $0, $0{{$}}
25 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $1, $1{{$}}
28 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
29 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
30 ; CHECK-NEXT: f32.ne $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
31 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 1{{$}}
32 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 1{{$}}
33 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
2634 ; CHECK-NEXT: i32.or $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
2735 ; CHECK-NEXT: return $pop[[NUM2]]{{$}}
2836 define i32 @uno_f32(float %x, float %y) {
3442 ; CHECK-LABEL: oeq_f32:
3543 ; CHECK-NEXT: .param f32, f32{{$}}
3644 ; CHECK-NEXT: .result i32{{$}}
37 ; CHECK-NEXT: f32.eq $push[[NUM:[0-9]+]]=, $0, $1{{$}}
45 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
46 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
47 ; CHECK-NEXT: f32.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
3848 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
3949 define i32 @oeq_f32(float %x, float %y) {
4050 %a = fcmp oeq float %x, %y
4353 }
4454
4555 ; CHECK-LABEL: une_f32:
46 ; CHECK: f32.ne $push[[NUM:[0-9]+]]=, $0, $1{{$}}
56 ; CHECK: f32.ne $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
4757 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
4858 define i32 @une_f32(float %x, float %y) {
4959 %a = fcmp une float %x, %y
5262 }
5363
5464 ; CHECK-LABEL: olt_f32:
55 ; CHECK: f32.lt $push[[NUM:[0-9]+]]=, $0, $1{{$}}
65 ; CHECK: f32.lt $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
5666 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
5767 define i32 @olt_f32(float %x, float %y) {
5868 %a = fcmp olt float %x, %y
6171 }
6272
6373 ; CHECK-LABEL: ole_f32:
64 ; CHECK: f32.le $push[[NUM:[0-9]+]]=, $0, $1{{$}}
74 ; CHECK: f32.le $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
6575 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
6676 define i32 @ole_f32(float %x, float %y) {
6777 %a = fcmp ole float %x, %y
7080 }
7181
7282 ; CHECK-LABEL: ogt_f32:
73 ; CHECK: f32.gt $push[[NUM:[0-9]+]]=, $0, $1{{$}}
83 ; CHECK: f32.gt $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
7484 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
7585 define i32 @ogt_f32(float %x, float %y) {
7686 %a = fcmp ogt float %x, %y
7989 }
8090
8191 ; CHECK-LABEL: oge_f32:
82 ; CHECK: f32.ge $push[[NUM:[0-9]+]]=, $0, $1{{$}}
92 ; CHECK: f32.ge $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
8393 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
8494 define i32 @oge_f32(float %x, float %y) {
8595 %a = fcmp oge float %x, %y
92102 ; CHECK-LABEL: ueq_f32:
93103 ; CHECK-NEXT: .param f32, f32{{$}}
94104 ; CHECK-NEXT: .result i32{{$}}
95 ; CHECK-NEXT: f32.eq $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
96 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
97 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
105 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
106 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
107 ; CHECK-NEXT: f32.eq $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
108 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
109 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
110 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
111 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
112 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
113 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
98114 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
99115 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
100116 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
107123 ; CHECK-LABEL: one_f32:
108124 ; CHECK-NEXT: .param f32, f32{{$}}
109125 ; CHECK-NEXT: .result i32{{$}}
110 ; CHECK-NEXT: f32.ne $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
111 ; CHECK-NEXT: f32.eq $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
112 ; CHECK-NEXT: f32.eq $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
126 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
127 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
128 ; CHECK-NEXT: f32.ne $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
129 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
130 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
131 ; CHECK-NEXT: f32.eq $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
132 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
133 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
134 ; CHECK-NEXT: f32.eq $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
113135 ; CHECK-NEXT: i32.and $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
114136 ; CHECK-NEXT: i32.and $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
115137 ; CHECK-NEXT: return $pop[[NUM4]]
122144 ; CHECK-LABEL: ult_f32:
123145 ; CHECK-NEXT: .param f32, f32{{$}}
124146 ; CHECK-NEXT: .result i32{{$}}
125 ; CHECK-NEXT: f32.lt $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
126 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
127 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
147 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
148 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
149 ; CHECK-NEXT: f32.lt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
150 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
151 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
152 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
153 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
154 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
155 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
128156 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
129157 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
130158 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
137165 ; CHECK-LABEL: ule_f32:
138166 ; CHECK-NEXT: .param f32, f32{{$}}
139167 ; CHECK-NEXT: .result i32{{$}}
140 ; CHECK-NEXT: f32.le $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
141 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
142 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
168 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
169 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
170 ; CHECK-NEXT: f32.le $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
171 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
172 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
173 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
174 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
175 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
176 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
143177 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
144178 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
145179 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
152186 ; CHECK-LABEL: ugt_f32:
153187 ; CHECK-NEXT: .param f32, f32{{$}}
154188 ; CHECK-NEXT: .result i32{{$}}
155 ; CHECK-NEXT: f32.gt $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
156 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
157 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
189 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
190 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
191 ; CHECK-NEXT: f32.gt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
192 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
193 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
194 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
195 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
196 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
197 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
158198 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
159199 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
160200 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
167207 ; CHECK-LABEL: uge_f32:
168208 ; CHECK-NEXT: .param f32, f32{{$}}
169209 ; CHECK-NEXT: .result i32{{$}}
170 ; CHECK-NEXT: f32.ge $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
171 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
172 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
210 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
211 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
212 ; CHECK-NEXT: f32.ge $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
213 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
214 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
215 ; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
216 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 1{{$}}
217 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
218 ; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
173219 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
174220 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
175221 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
33 ; expected.
44
55 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6 target triple = "wasm32-unknown-unknown"
6 target triple = "wasm32-unknown-unknown-wasm"
77
88 ; CHECK-LABEL: ord_f64:
99 ; CHECK-NEXT: .param f64, f64{{$}}
1010 ; CHECK-NEXT: .result i32{{$}}
11 ; CHECK-NEXT: f64.eq $push[[NUM0:[0-9]+]]=, $0, $0{{$}}
12 ; CHECK-NEXT: f64.eq $push[[NUM1:[0-9]+]]=, $1, $1{{$}}
11 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
12 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
13 ; CHECK-NEXT: f64.eq $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
14 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 1{{$}}
15 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 1{{$}}
16 ; CHECK-NEXT: f64.eq $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
1317 ; CHECK-NEXT: i32.and $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
1418 ; CHECK-NEXT: return $pop[[NUM2]]{{$}}
1519 define i32 @ord_f64(double %x, double %y) {
2125 ; CHECK-LABEL: uno_f64:
2226 ; CHECK-NEXT: .param f64, f64{{$}}
2327 ; CHECK-NEXT: .result i32{{$}}
24 ; CHECK-NEXT: f64.ne $push[[NUM0:[0-9]+]]=, $0, $0{{$}}
25 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $1, $1{{$}}
28 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
29 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
30 ; CHECK-NEXT: f64.ne $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
31 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 1{{$}}
32 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 1{{$}}
33 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
2634 ; CHECK-NEXT: i32.or $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
2735 ; CHECK-NEXT: return $pop[[NUM2]]{{$}}
2836 define i32 @uno_f64(double %x, double %y) {
3442 ; CHECK-LABEL: oeq_f64:
3543 ; CHECK-NEXT: .param f64, f64{{$}}
3644 ; CHECK-NEXT: .result i32{{$}}
37 ; CHECK-NEXT: f64.eq $push[[NUM:[0-9]+]]=, $0, $1{{$}}
45 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
46 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
47 ; CHECK-NEXT: f64.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
3848 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
3949 define i32 @oeq_f64(double %x, double %y) {
4050 %a = fcmp oeq double %x, %y
4353 }
4454
4555 ; CHECK-LABEL: une_f64:
46 ; CHECK: f64.ne $push[[NUM:[0-9]+]]=, $0, $1{{$}}
56 ; CHECK: f64.ne $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
4757 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
4858 define i32 @une_f64(double %x, double %y) {
4959 %a = fcmp une double %x, %y
5262 }
5363
5464 ; CHECK-LABEL: olt_f64:
55 ; CHECK: f64.lt $push[[NUM:[0-9]+]]=, $0, $1{{$}}
65 ; CHECK: f64.lt $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
5666 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
5767 define i32 @olt_f64(double %x, double %y) {
5868 %a = fcmp olt double %x, %y
6171 }
6272
6373 ; CHECK-LABEL: ole_f64:
64 ; CHECK: f64.le $push[[NUM:[0-9]+]]=, $0, $1{{$}}
74 ; CHECK: f64.le $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
6575 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
6676 define i32 @ole_f64(double %x, double %y) {
6777 %a = fcmp ole double %x, %y
7080 }
7181
7282 ; CHECK-LABEL: ogt_f64:
73 ; CHECK: f64.gt $push[[NUM:[0-9]+]]=, $0, $1{{$}}
83 ; CHECK: f64.gt $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
7484 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
7585 define i32 @ogt_f64(double %x, double %y) {
7686 %a = fcmp ogt double %x, %y
7989 }
8090
8191 ; CHECK-LABEL: oge_f64:
82 ; CHECK: f64.ge $push[[NUM:[0-9]+]]=, $0, $1{{$}}
92 ; CHECK: f64.ge $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
8393 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
8494 define i32 @oge_f64(double %x, double %y) {
8595 %a = fcmp oge double %x, %y
92102 ; CHECK-LABEL: ueq_f64:
93103 ; CHECK-NEXT: .param f64, f64{{$}}
94104 ; CHECK-NEXT: .result i32{{$}}
95 ; CHECK-NEXT: f64.eq $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
96 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
97 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
105 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
106 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
107 ; CHECK-NEXT: f64.eq $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
108 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
109 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
110 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
111 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
112 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
113 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
98114 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
99115 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
100116 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
107123 ; CHECK-LABEL: one_f64:
108124 ; CHECK-NEXT: .param f64, f64{{$}}
109125 ; CHECK-NEXT: .result i32{{$}}
110 ; CHECK-NEXT: f64.ne $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
111 ; CHECK-NEXT: f64.eq $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
112 ; CHECK-NEXT: f64.eq $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
126 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
127 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
128 ; CHECK-NEXT: f64.ne $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
129 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
130 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
131 ; CHECK-NEXT: f64.eq $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
132 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
133 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
134 ; CHECK-NEXT: f64.eq $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
113135 ; CHECK-NEXT: i32.and $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
114136 ; CHECK-NEXT: i32.and $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
115137 ; CHECK-NEXT: return $pop[[NUM4]]
122144 ; CHECK-LABEL: ult_f64:
123145 ; CHECK-NEXT: .param f64, f64{{$}}
124146 ; CHECK-NEXT: .result i32{{$}}
125 ; CHECK-NEXT: f64.lt $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
126 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
127 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
147 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
148 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
149 ; CHECK-NEXT: f64.lt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
150 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
151 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
152 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
153 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
154 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
155 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
128156 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
129157 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
130158 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
137165 ; CHECK-LABEL: ule_f64:
138166 ; CHECK-NEXT: .param f64, f64{{$}}
139167 ; CHECK-NEXT: .result i32{{$}}
140 ; CHECK-NEXT: f64.le $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
141 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
142 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
168 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
169 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
170 ; CHECK-NEXT: f64.le $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
171 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
172 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
173 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
174 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
175 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
176 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
143177 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
144178 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
145179 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
152186 ; CHECK-LABEL: ugt_f64:
153187 ; CHECK-NEXT: .param f64, f64{{$}}
154188 ; CHECK-NEXT: .result i32{{$}}
155 ; CHECK-NEXT: f64.gt $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
156 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
157 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
189 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
190 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
191 ; CHECK-NEXT: f64.gt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
192 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
193 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
194 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
195 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
196 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
197 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
158198 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
159199 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
160200 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
167207 ; CHECK-LABEL: uge_f64:
168208 ; CHECK-NEXT: .param f64, f64{{$}}
169209 ; CHECK-NEXT: .result i32{{$}}
170 ; CHECK-NEXT: f64.ge $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
171 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
172 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
210 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
211 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
212 ; CHECK-NEXT: f64.ge $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
213 ; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
214 ; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
215 ; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
216 ; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
217 ; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
218 ; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
173219 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
174220 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
175221 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
33 ; Test that basic 32-bit integer comparison operations assemble as expected.
44
55 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6 target triple = "wasm32-unknown-unknown"
6 target triple = "wasm32-unknown-unknown-wasm"
77
88 ; CHECK-LABEL: eq_i32:
99 ; CHECK-NEXT: .param i32, i32{{$}}
1010 ; CHECK-NEXT: .result i32{{$}}
11 ; CHECK-NEXT: i32.eq $push[[NUM:[0-9]+]]=, $0, $1{{$}}
11 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
12 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
13 ; CHECK-NEXT: i32.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
1214 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
1315 define i32 @eq_i32(i32 %x, i32 %y) {
1416 %a = icmp eq i32 %x, %y
1719 }
1820
1921 ; CHECK-LABEL: ne_i32:
20 ; CHECK: i32.ne $push[[NUM:[0-9]+]]=, $0, $1{{$}}
22 ; CHECK: i32.ne $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
2123 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
2224 define i32 @ne_i32(i32 %x, i32 %y) {
2325 %a = icmp ne i32 %x, %y
2628 }
2729
2830 ; CHECK-LABEL: slt_i32:
29 ; CHECK: i32.lt_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
31 ; CHECK: i32.lt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
3032 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
3133 define i32 @slt_i32(i32 %x, i32 %y) {
3234 %a = icmp slt i32 %x, %y
3537 }
3638
3739 ; CHECK-LABEL: sle_i32:
38 ; CHECK: i32.le_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
40 ; CHECK: i32.le_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
3941 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
4042 define i32 @sle_i32(i32 %x, i32 %y) {
4143 %a = icmp sle i32 %x, %y
4446 }
4547
4648 ; CHECK-LABEL: ult_i32:
47 ; CHECK: i32.lt_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
49 ; CHECK: i32.lt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
4850 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
4951 define i32 @ult_i32(i32 %x, i32 %y) {
5052 %a = icmp ult i32 %x, %y
5355 }
5456
5557 ; CHECK-LABEL: ule_i32:
56 ; CHECK: i32.le_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
58 ; CHECK: i32.le_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
5759 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
5860 define i32 @ule_i32(i32 %x, i32 %y) {
5961 %a = icmp ule i32 %x, %y
6264 }
6365
6466 ; CHECK-LABEL: sgt_i32:
65 ; CHECK: i32.gt_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
67 ; CHECK: i32.gt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
6668 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
6769 define i32 @sgt_i32(i32 %x, i32 %y) {
6870 %a = icmp sgt i32 %x, %y
7173 }
7274
7375 ; CHECK-LABEL: sge_i32:
74 ; CHECK: i32.ge_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
76 ; CHECK: i32.ge_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
7577 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
7678 define i32 @sge_i32(i32 %x, i32 %y) {
7779 %a = icmp sge i32 %x, %y
8082 }
8183
8284 ; CHECK-LABEL: ugt_i32:
83 ; CHECK: i32.gt_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
85 ; CHECK: i32.gt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
8486 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
8587 define i32 @ugt_i32(i32 %x, i32 %y) {
8688 %a = icmp ugt i32 %x, %y
8991 }
9092
9193 ; CHECK-LABEL: uge_i32:
92 ; CHECK: i32.ge_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
94 ; CHECK: i32.ge_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
9395 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
9496 define i32 @uge_i32(i32 %x, i32 %y) {
9597 %a = icmp uge i32 %x, %y
33 ; Test that basic 64-bit integer comparison operations assemble as expected.
44
55 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6 target triple = "wasm32-unknown-unknown"
6 target triple = "wasm32-unknown-unknown-wasm"
77
88 ; CHECK-LABEL: eq_i64:
99 ; CHECK-NEXT: .param i64, i64{{$}}
1010 ; CHECK-NEXT: .result i32{{$}}
11 ; CHECK-NEXT: i64.eq $push[[NUM:[0-9]+]]=, $0, $1{{$}}
11 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
12 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
13 ; CHECK-NEXT: i64.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
1214 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
1315 define i32 @eq_i64(i64 %x, i64 %y) {
1416 %a = icmp eq i64 %x, %y
1719 }
1820
1921 ; CHECK-LABEL: ne_i64:
20 ; CHECK: i64.ne $push[[NUM:[0-9]+]]=, $0, $1{{$}}
22 ; CHECK: i64.ne $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
2123 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
2224 define i32 @ne_i64(i64 %x, i64 %y) {
2325 %a = icmp ne i64 %x, %y
2628 }
2729
2830 ; CHECK-LABEL: slt_i64:
29 ; CHECK: i64.lt_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
31 ; CHECK: i64.lt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
3032 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
3133 define i32 @slt_i64(i64 %x, i64 %y) {
3234 %a = icmp slt i64 %x, %y
3537 }
3638
3739 ; CHECK-LABEL: sle_i64:
38 ; CHECK: i64.le_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
40 ; CHECK: i64.le_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
3941 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
4042 define i32 @sle_i64(i64 %x, i64 %y) {
4143 %a = icmp sle i64 %x, %y
4446 }
4547
4648 ; CHECK-LABEL: ult_i64:
47 ; CHECK: i64.lt_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
49 ; CHECK: i64.lt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
4850 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
4951 define i32 @ult_i64(i64 %x, i64 %y) {
5052 %a = icmp ult i64 %x, %y
5355 }
5456
5557 ; CHECK-LABEL: ule_i64:
56 ; CHECK: i64.le_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
58 ; CHECK: i64.le_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
5759 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
5860 define i32 @ule_i64(i64 %x, i64 %y) {
5961 %a = icmp ule i64 %x, %y
6264 }
6365
6466 ; CHECK-LABEL: sgt_i64:
65 ; CHECK: i64.gt_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
67 ; CHECK: i64.gt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
6668 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
6769 define i32 @sgt_i64(i64 %x, i64 %y) {
6870 %a = icmp sgt i64 %x, %y
7173 }
7274
7375 ; CHECK-LABEL: sge_i64:
74 ; CHECK: i64.ge_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
76 ; CHECK: i64.ge_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
7577 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
7678 define i32 @sge_i64(i64 %x, i64 %y) {
7779 %a = icmp sge i64 %x, %y
8082 }
8183
8284 ; CHECK-LABEL: ugt_i64:
83 ; CHECK: i64.gt_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
85 ; CHECK: i64.gt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
8486 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
8587 define i32 @ugt_i64(i64 %x, i64 %y) {
8688 %a = icmp ugt i64 %x, %y
8991 }
9092
9193 ; CHECK-LABEL: uge_i64:
92 ; CHECK: i64.ge_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
94 ; CHECK: i64.ge_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
9395 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
9496 define i32 @uge_i64(i64 %x, i64 %y) {
9597 %a = icmp uge i64 %x, %y
33 ; unfolded.
44
55 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6 target triple = "wasm32-unknown-unknown"
6 target triple = "wasm32-unknown-unknown-wasm"
77
88 declare double @copysign(double, double) nounwind readnone
99 declare float @copysignf(float, float) nounwind readnone
1010
1111 ; CHECK-LABEL: fold_promote:
12 ; CHECK: f64.promote/f32 $push0=, $1{{$}}
13 ; CHECK: f64.copysign $push1=, $0, $pop0{{$}}
12 ; CHECK: f64.promote/f32 $push0=, $pop{{[0-9]+}}{{$}}
13 ; CHECK: f64.copysign $push1=, $pop{{[0-9]+}}, $pop0{{$}}
1414 define double @fold_promote(double %a, float %b) {
1515 %c = fpext float %b to double
1616 %t = call double @copysign(double %a, double %c)
1818 }
1919
2020 ; CHECK-LABEL: fold_demote:{{$}}
21 ; CHECK: f32.demote/f64 $push0=, $1{{$}}
22 ; CHECK: f32.copysign $push1=, $0, $pop0{{$}}
21 ; CHECK: f32.demote/f64 $push0=, $pop{{[0-9]+}}{{$}}
22 ; CHECK: f32.copysign $push1=, $pop{{[0-9]+}}, $pop0{{$}}
2323 define float @fold_demote(float %a, double %b) {
2424 %c = fptrunc double %b to float
2525 %t = call float @copysignf(float %a, float %c)
55 ; CHECK: DW_TAG_variable
66 source_filename = "test/CodeGen/WebAssembly/dbgvalue.ll"
77 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
8 target triple = "wasm32-unknown-unknown"
8 target triple = "wasm32-unknown-unknown-wasm"
99
1010 @key = external local_unnamed_addr global [15 x i8], align 1
1111 @.str = external unnamed_addr constant [33 x i8], align 1
22 ; Check that unused vregs aren't assigned registers.
33
44 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
5 target triple = "wasm32-unknown-unknown"
5 target triple = "wasm32-unknown-unknown-wasm"
66
77 define void @foo(i32* nocapture %a, i32 %w, i32 %h) {
88 ; CHECK-LABEL: foo:
22 ; Test that integer div and rem by constant are optimized appropriately.
33
44 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
5 target triple = "wasm32-unknown-unknown"
5 target triple = "wasm32-unknown-unknown-wasm"
66
77 ; CHECK-LABEL: test_udiv_2:
88 ; CHECK: i32.shr_u
22 ; Test that basic 32-bit floating-point operations assemble as expected.
33
44 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
5 target triple = "wasm32-unknown-unknown"
5 target triple = "wasm32-unknown-unknown-wasm"
66
77 declare float @llvm.fabs.f32(float)
88 declare float @llvm.copysign.f32(float, float)
1717 ; CHECK-LABEL: fadd32:
1818 ; CHECK-NEXT: .param f32, f32{{$}}
1919 ; CHECK-NEXT: .result f32{{$}}
20 ; CHECK-NEXT: f32.add $push0=, $0, $1{{$}}
21 ; CHECK-NEXT: return $pop0{{$}}
20 ; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
21 ; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
22 ; CHECK-NEXT: f32.add $push[[LR:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
23 ; CHECK-NEXT: return $pop[[LR]]{{$}}
2224 define float @fadd32(float %x, float %y) {
2325 %a = fadd float %x, %y
2426 ret float %a
2527 }
2628
2729 ; CHECK-LABEL: fsub32:
28 ; CHECK: f32.sub $push0=, $0, $1{{$}}
29 ; CHECK-NEXT: return $pop0{{$}}
30 ; CHECK: f32.sub $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
31 ; CHECK-NEXT: return $pop[[LR]]{{$}}
3032 define float @fsub32(float %x, float %y) {
3133 %a = fsub float %x, %y
3234 ret float %a
3335 }
3436
3537 ; CHECK-LABEL: fmul32:
36 ; CHECK: f32.mul $push0=, $0, $1{{$}}
37 ; CHECK-NEXT: return $pop0{{$}}
38 ; CHECK: f32.mul $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
39 ; CHECK-NEXT: return $pop[[LR]]{{$}}
3840 define float @fmul32(float %x, float %y) {
3941 %a = fmul float %x, %y
4042 ret float %a
4143 }
4244
4345 ; CHECK-LABEL: fdiv32:
44 ; CHECK: f32.div $push0=, $0, $1{{$}}
45 ; CHECK-NEXT: return $pop0{{$}}
46 ; CHECK: f32.div $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
47 ; CHECK-NEXT: return $pop[[LR]]{{$}}
4648 define float @fdiv32(float %x, float %y) {
4749 %a = fdiv float %x, %y
4850 ret float %a
4951 }
5052
5153 ; CHECK-LABEL: fabs32:
52 ; CHECK: f32.abs $push0=, $0{{$}}
53 ; CHECK-NEXT: return $pop0{{$}}
54 ; CHECK: f32.abs $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
55 ; CHECK-NEXT: return $pop[[LR]]{{$}}
5456 define float @fabs32(float %x) {
5557 %a = call float @llvm.fabs.f32(float %x)
5658 ret float %a
5759 }
5860
5961 ; CHECK-LABEL: fneg32:
60 ; CHECK: f32.neg $push0=, $0{{$}}
61 ; CHECK-NEXT: return $pop0{{$}}
62 ; CHECK: f32.neg $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
63 ; CHECK-NEXT: return $pop[[LR]]{{$}}
6264 define float @fneg32(float %x) {
6365 %a = fsub float -0., %x
6466 ret float %a
6567 }
6668
6769 ; CHECK-LABEL: copysign32:
68 ; CHECK: f32.copysign $push0=, $0, $1{{$}}
69 ; CHECK-NEXT: return $pop0{{$}}
70 ; CHECK: f32.copysign $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
71 ; CHECK-NEXT: return $pop[[LR]]{{$}}
7072 define float @copysign32(float %x, float %y) {
7173 %a = call float @llvm.copysign.f32(float %x, float %y)
7274 ret float %a
7375 }
7476
7577 ; CHECK-LABEL: sqrt32:
76 ; CHECK: f32.sqrt $push0=, $0{{$}}
77 ; CHECK-NEXT: return $pop0{{$}}
78 ; CHECK: f32.sqrt $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
79 ; CHECK-NEXT: return $pop[[LR]]{{$}}
7880 define float @sqrt32(float %x) {
7981 %a = call float @llvm.sqrt.f32(float %x)
8082 ret float %a
8183 }
8284
8385 ; CHECK-LABEL: ceil32:
84 ; CHECK: f32.ceil $push0=, $0{{$}}
85 ; CHECK-NEXT: return $pop0{{$}}
86 ; CHECK: f32.ceil $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
87 ; CHECK-NEXT: return $pop[[LR]]{{$}}
8688 define float @ceil32(float %x) {
8789 %a = call float @llvm.ceil.f32(float %x)
8890 ret float %a
8991 }
9092
9193 ; CHECK-LABEL: floor32:
92 ; CHECK: f32.floor $push0=, $0{{$}}
93 ; CHECK-NEXT: return $pop0{{$}}
94 ; CHECK: f32.floor $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
95 ; CHECK-NEXT: return $pop[[LR]]{{$}}
9496 define float @floor32(float %x) {
9597 %a = call float @llvm.floor.f32(float %x)
9698 ret float %a
9799 }
98100
99101 ; CHECK-LABEL: trunc32:
100 ; CHECK: f32.trunc $push0=, $0{{$}}
101 ; CHECK-NEXT: return $pop0{{$}}
102 ; CHECK: f32.trunc $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
103 ; CHECK-NEXT: return $pop[[LR]]{{$}}
102104 define float @trunc32(float %x) {
103105 %a = call float @llvm.trunc.f32(float %x)
104106 ret float %a
105107 }
106108
107109 ; CHECK-LABEL: nearest32:
108 ; CHECK: f32.nearest $push0=, $0{{$}}
109 ; CHECK-NEXT: return $pop0{{$}}
110 ; CHECK: f32.nearest $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
111 ; CHECK-NEXT: return $pop[[LR]]{{$}}
110112 define float @nearest32(float %x) {
111113 %a = call float @llvm.nearbyint.f32(float %x)
112114 ret float %a
113115 }
114116
115117 ; CHECK-LABEL: nearest32_via_rint:
116 ; CHECK: f32.nearest $push0=, $0{{$}}
117 ; CHECK-NEXT: return $pop0{{$}}
118 ; CHECK: f32.nearest $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
119 ; CHECK-NEXT: return $pop[[LR]]{{$}}
118120 define float @nearest32_via_rint(float %x) {
119121 %a = call float @llvm.rint.f32(float %x)
120122 ret float %a
127129 ; tests.
128130
129131 ; CHECK-LABEL: fmin32:
130 ; CHECK: f32.min $push1=, $0, $pop0{{$}}
132 ; CHECK: f32.min $push1=, $pop{{[0-9]+}}, $pop[[LR]]{{$}}
131133 ; CHECK-NEXT: return $pop1{{$}}
132134 define float @fmin32(float %x) {
133135 %a = fcmp ult float %x, 0.0
136138 }
137139
138140 ; CHECK-LABEL: fmax32:
139 ; CHECK: f32.max $push1=, $0, $pop0{{$}}