diff options
| author | JF Bastien <jfb@google.com> | 2015-08-31 22:24:11 +0000 |
|---|---|---|
| committer | JF Bastien <jfb@google.com> | 2015-08-31 22:24:11 +0000 |
| commit | 73ff6afa87f0e5b162af37edd60b8f76035e72be (patch) | |
| tree | 11e069866ab7d236f2ccf79318b09009f8001103 /llvm/lib/Target/WebAssembly | |
| parent | 3b0b43c8c6fefdac69d51279d63d106f296a7c7a (diff) | |
| download | bcm5719-llvm-73ff6afa87f0e5b162af37edd60b8f76035e72be.tar.gz bcm5719-llvm-73ff6afa87f0e5b162af37edd60b8f76035e72be.zip | |
WebAssembly: generate load/store
Summary: This handles all load/store operations that WebAssembly defines, and handles those necessary for C++ such as i1. I left a FIXME for outstanding features which aren't required for now.
Reviewers: sunfish
Subscribers: jfb, llvm-commits, dschuff
llvm-svn: 246500
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
| -rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp | 51 | ||||
| -rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp | 12 | ||||
| -rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td | 99 |
3 files changed, 113 insertions, 49 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 12811b096eb..eb1343292d3 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -40,6 +40,7 @@ using namespace llvm; namespace { class WebAssemblyAsmPrinter final : public AsmPrinter { + bool hasAddr64; const WebAssemblyInstrInfo *TII; public: @@ -60,7 +61,9 @@ private: } bool runOnMachineFunction(MachineFunction &MF) override { - TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); + const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>(); + hasAddr64 = Subtarget.hasAddr64(); + TII = Subtarget.getInstrInfo(); return AsmPrinter::runOnMachineFunction(MF); } @@ -97,23 +100,6 @@ static SmallString<32> OpcodeName(const WebAssemblyInstrInfo *TII, static std::string toSymbol(StringRef S) { return ("$" + S).str(); } -static const char *toString(const Type *Ty) { - switch (Ty->getTypeID()) { - default: break; - case Type::FloatTyID: return "f32"; - case Type::DoubleTyID: return "f64"; - case Type::IntegerTyID: - switch (Ty->getIntegerBitWidth()) { - case 32: return "i32"; - case 64: return "i64"; - default: break; - } - } - DEBUG(dbgs() << "Invalid type "; Ty->print(dbgs()); dbgs() << '\n'); - llvm_unreachable("invalid type"); - return "<invalid>"; -} - static std::string toString(const APFloat &FP) { static const size_t BufBytes = 128; char buf[BufBytes]; @@ -131,6 +117,28 @@ static std::string toString(const APFloat &FP) { return buf; } +static const char *toString(const Type *Ty, bool hasAddr64) { + switch (Ty->getTypeID()) { + default: break; + // Treat all pointers as the underlying integer into linear memory. + case Type::PointerTyID: return hasAddr64 ? "i64" : "i32"; + case Type::FloatTyID: return "f32"; + case Type::DoubleTyID: return "f64"; + case Type::IntegerTyID: + switch (Ty->getIntegerBitWidth()) { + case 8: return "i8"; + case 16: return "i16"; + case 32: return "i32"; + case 64: return "i64"; + default: break; + } + } + DEBUG(dbgs() << "Invalid type "; Ty->print(dbgs()); dbgs() << '\n'); + llvm_unreachable("invalid type"); + return "<invalid>"; +} + + //===----------------------------------------------------------------------===// // WebAssemblyAsmPrinter Implementation. //===----------------------------------------------------------------------===// @@ -186,7 +194,8 @@ void WebAssemblyAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { return; } - OS << "(global " << toSymbol(Name) << ' ' << toString(Init->getType()) << ' '; + OS << "(global " << toSymbol(Name) << ' ' + << toString(Init->getType(), hasAddr64) << ' '; if (const auto *C = dyn_cast<ConstantInt>(Init)) { assert(C->getBitWidth() <= 64 && "Printing wider types unimplemented"); OS << C->getZExtValue(); @@ -228,10 +237,10 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { raw_svector_ostream OS(Str); const Function *F = MF->getFunction(); for (const Argument &A : F->args()) - OS << " (param " << toString(A.getType()) << ')'; + OS << " (param " << toString(A.getType(), hasAddr64) << ')'; const Type *Rt = F->getReturnType(); if (!Rt->isVoidTy()) - OS << " (result " << toString(Rt) << ')'; + OS << " (result " << toString(Rt, hasAddr64) << ')'; OS << '\n'; OutStreamer->EmitRawText(OS.str()); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index d3ab439b523..f4c2e5bce0d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -113,8 +113,6 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( // Compute derived properties from the register classes. computeRegisterProperties(Subtarget->getRegisterInfo()); - // FIXME: many setOperationAction are missing... - setOperationAction(ISD::GlobalAddress, MVTPtr, Custom); for (auto T : {MVT::f32, MVT::f64}) { @@ -154,6 +152,16 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand); + + // WebAssembly doesn't have: + // - Floating-point extending loads. + // - Floating-point truncating stores. + // - i1 extending loads. + setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f64, Expand); + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + for (auto T : MVT::integer_valuetypes()) + for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD}) + setLoadExtAction(Ext, T, MVT::i1, Promote); } FastISel *WebAssemblyTargetLowering::createFastISel( diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td index 8457dc89c4d..dd4c2451622 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td @@ -14,37 +14,84 @@ /* * TODO(jfb): Add the following. - * Each has optional alignment and immediate byte offset. - * - * int32.load_sx[int8]: sign-extend to int32 - * int32.load_sx[int16]: sign-extend to int32 - * int32.load_zx[int8]: zero-extend to int32 - * int32.load_zx[int16]: zero-extend to int32 - * int32.load[int32]: (no conversion) - * int64.load_sx[int8]: sign-extend to int64 - * int64.load_sx[int16]: sign-extend to int64 - * int64.load_sx[int32]: sign-extend to int64 - * int64.load_zx[int8]: zero-extend to int64 - * int64.load_zx[int16]: zero-extend to int64 - * int64.load_zx[int32]: zero-extend to int64 - * int64.load[int64]: (no conversion) - * float32.load[float32]: (no conversion) - * float64.load[float64]: (no conversion) - * - * int32.store[int8]: wrap int32 to int8 - * int32.store[int16]: wrap int32 to int16 - * int32.store[int32]: (no conversion) - * int64.store[int8]: wrap int64 to int8 - * int64.store[int16]: wrap int64 to int16 - * int64.store[int32]: wrap int64 to int32 - * int64.store[int64]: (no conversion) - * float32.store[float32]: (no conversion) - * float64.store[float64]: (no conversion) * * load_global: load the value of a given global variable * store_global: store a given value to a given global variable */ +// FIXME: +// - HasAddr64 +// - WebAssemblyTargetLowering::isLegalAddressingMode +// - WebAssemblyTargetLowering having to do with atomics +// - Each has optional alignment and immediate byte offset. + +// WebAssembly has i8/i16/i32/i64/f32/f64 memory types, but doesn't have i8/i16 +// local types. These memory-only types instead zero- or sign-extend into local +// types when loading, and truncate when storing. + +// Basic load. +def LOAD_I32_ : I<(outs Int32:$dst), (ins Int32:$addr), + [(set Int32:$dst, (load Int32:$addr))]>; +def LOAD_I64_ : I<(outs Int64:$dst), (ins Int32:$addr), + [(set Int64:$dst, (load Int32:$addr))]>; +def LOAD_F32_ : I<(outs Float32:$dst), (ins Int32:$addr), + [(set Float32:$dst, (load Int32:$addr))]>; +def LOAD_F64_ : I<(outs Float64:$dst), (ins Int32:$addr), + [(set Float64:$dst, (load Int32:$addr))]>; + +// Extending load. +def LOAD_SX_I8_I32_ : I<(outs Int32:$dst), (ins Int32:$addr), + [(set Int32:$dst, (sextloadi8 Int32:$addr))]>; +def LOAD_ZX_I8_I32_ : I<(outs Int32:$dst), (ins Int32:$addr), + [(set Int32:$dst, (zextloadi8 Int32:$addr))]>; +def LOAD_SX_I16_I32_ : I<(outs Int32:$dst), (ins Int32:$addr), + [(set Int32:$dst, (sextloadi16 Int32:$addr))]>; +def LOAD_ZX_I16_I32_ : I<(outs Int32:$dst), (ins Int32:$addr), + [(set Int32:$dst, (zextloadi16 Int32:$addr))]>; +def LOAD_SX_I8_I64_ : I<(outs Int64:$dst), (ins Int32:$addr), + [(set Int64:$dst, (sextloadi8 Int32:$addr))]>; +def LOAD_ZX_I8_I64_ : I<(outs Int64:$dst), (ins Int32:$addr), + [(set Int64:$dst, (zextloadi8 Int32:$addr))]>; +def LOAD_SX_I16_I64_ : I<(outs Int64:$dst), (ins Int32:$addr), + [(set Int64:$dst, (sextloadi16 Int32:$addr))]>; +def LOAD_ZX_I16_I64_ : I<(outs Int64:$dst), (ins Int32:$addr), + [(set Int64:$dst, (zextloadi16 Int32:$addr))]>; +def LOAD_SX_I32_I64_ : I<(outs Int64:$dst), (ins Int32:$addr), + [(set Int64:$dst, (sextloadi32 Int32:$addr))]>; +def LOAD_ZX_I32_I64_ : I<(outs Int64:$dst), (ins Int32:$addr), + [(set Int64:$dst, (zextloadi32 Int32:$addr))]>; + +// "Don't care" extending load become zero-extending load. +def : Pat<(i32 (extloadi8 Int32:$addr)), (LOAD_ZX_I8_I32_ $addr)>; +def : Pat<(i32 (extloadi16 Int32:$addr)), (LOAD_ZX_I16_I32_ $addr)>; +def : Pat<(i64 (extloadi8 Int32:$addr)), (LOAD_ZX_I8_I64_ $addr)>; +def : Pat<(i64 (extloadi16 Int32:$addr)), (LOAD_ZX_I16_I64_ $addr)>; +def : Pat<(i64 (extloadi32 Int32:$addr)), (LOAD_ZX_I32_I64_ $addr)>; + +// Basic store. +// Note: WebAssembly inverts SelectionDAG's usual operand order. +def STORE_I32_ : I<(outs), (ins Int32:$addr, Int32:$val), + [(store Int32:$val, Int32:$addr)]>; +def STORE_I64_ : I<(outs), (ins Int32:$addr, Int64:$val), + [(store Int64:$val, Int32:$addr)]>; +def STORE_F32_ : I<(outs), (ins Int32:$addr, Float32:$val), + [(store Float32:$val, Int32:$addr)]>; +def STORE_F64_ : I<(outs), (ins Int32:$addr, Float64:$val), + [(store Float64:$val, Int32:$addr)]>; + +// Truncating store. +def STORE_I8_I32 : I<(outs), (ins Int32:$addr, Int32:$val), + [(truncstorei8 Int32:$val, Int32:$addr)]>; +def STORE_I16_I32 : I<(outs), (ins Int32:$addr, Int32:$val), + [(truncstorei16 Int32:$val, Int32:$addr)]>; +def STORE_I8_I64 : I<(outs), (ins Int32:$addr, Int64:$val), + [(truncstorei8 Int64:$val, Int32:$addr)]>; +def STORE_I16_I64 : I<(outs), (ins Int32:$addr, Int64:$val), + [(truncstorei16 Int64:$val, Int32:$addr)]>; +def STORE_I32_I64 : I<(outs), (ins Int32:$addr, Int64:$val), + [(truncstorei32 Int64:$val, Int32:$addr)]>; + +// Page size. def page_size_I32 : I<(outs Int32:$dst), (ins), [(set Int32:$dst, (int_wasm_page_size))]>, Requires<[HasAddr32]>; |

