[llvm] r252997 - [WebAssembly] Inline asm support.

JF Bastien via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 17 14:56:44 PST 2015


I'm wondering if you see this as a pure LLVM thing that disappears in the
final assembly / binary code, or if tools that consume assembly / binary
code also have to understand this inline assembly. I'm totally fine with
the former, and am slightly concerned by the later (it could work, but we
have to make sure we spec it right). From your description it sounds like
it's only the former you're going for?

On Tue, Nov 17, 2015 at 12:11 PM, Dan Gohman <sunfish at mozilla.com> wrote:

> asm("" : "=r" (x)) is a convenient way to force a use of x in a register
> while introducing minimal disruption, for the purpose of writing a compiler
> test. One can create a variety of contrived constraints this way.
>
> Also, inline asm is convenient for writing tests of WebAssembly engines
> too, where one wants to craft a very specific code sequence in the middle
> of a larger program without having to write the whole function in assembly.
>
> This just adds the "r", " m", and "i" constraints. We won't need a lot
> more because the ISA is very regular. Which other tools are you concerned
> about?
>
> Dan
>
> On Tue, Nov 17, 2015 at 10:46 AM, JF Bastien <jfb at chromium.org> wrote:
>
>> Do you have concrete examples in mind? This was a tad surprising to folks
>> here (self included), and I want to make sure that all our tools support
>> the same feature set (i.e. we don't end up with the slightly mad situation
>> of GCC inline asm).
>>
>> On Tue, Nov 17, 2015 at 7:09 AM, Dan Gohman <sunfish at mozilla.com> wrote:
>>
>>> We do have __builtin functions for all instructions not accessible
>>> through plain C syntax, so inline asm will almost never be needed. However,
>>> inline asm is a useful tool for writing certain kinds of testcases, both
>>> for LLVM itself and for the underlying platform.
>>>
>>> Dan
>>>
>>>
>>> On Mon, Nov 16, 2015 at 4:51 PM, JF Bastien <jfb at chromium.org> wrote:
>>>
>>>> (catching up on email post-vacation)
>>>>
>>>> I'm a bit confused about this: the code looks like what I'd expect, but
>>>> I thought we weren't going to do inline asm. Could you clarify the usecase?
>>>> I thought we'd do calls to the embedders / syscalls through extern C
>>>> functions, so I'm not sure I get the use for inline asm.
>>>>
>>>> On Thu, Nov 12, 2015 at 5:42 PM, Dan Gohman via llvm-commits <
>>>> llvm-commits at lists.llvm.org> wrote:
>>>>
>>>>> Author: djg
>>>>> Date: Thu Nov 12 19:42:29 2015
>>>>> New Revision: 252997
>>>>>
>>>>> URL: http://llvm.org/viewvc/llvm-project?rev=252997&view=rev
>>>>> Log:
>>>>> [WebAssembly] Inline asm support.
>>>>>
>>>>> Added:
>>>>>     llvm/trunk/test/CodeGen/WebAssembly/inline-asm.ll
>>>>> Modified:
>>>>>     llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
>>>>>     llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
>>>>>     llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
>>>>>     llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
>>>>>
>>>>> Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=252997&r1=252996&r2=252997&view=diff
>>>>>
>>>>> ==============================================================================
>>>>> --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
>>>>> (original)
>>>>> +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp Thu
>>>>> Nov 12 19:42:29 2015
>>>>> @@ -77,6 +77,12 @@ private:
>>>>>    void EmitFunctionBodyStart() override;
>>>>>    void EmitInstruction(const MachineInstr *MI) override;
>>>>>    void EmitEndOfAsmFile(Module &M) override;
>>>>> +  bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
>>>>> +                       unsigned AsmVariant, const char *ExtraCode,
>>>>> +                       raw_ostream &OS) override;
>>>>> +  bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
>>>>> +                             unsigned AsmVariant, const char
>>>>> *ExtraCode,
>>>>> +                             raw_ostream &OS) override;
>>>>>
>>>>>    std::string getRegTypeName(unsigned RegNo) const;
>>>>>    const char *toString(MVT VT) const;
>>>>> @@ -275,6 +281,41 @@ void WebAssemblyAsmPrinter::EmitEndOfAsm
>>>>>      OutStreamer->EmitRawText(Text.substr(0, Text.size() - 1));
>>>>>  }
>>>>>
>>>>> +bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
>>>>> +                                            unsigned OpNo, unsigned
>>>>> AsmVariant,
>>>>> +                                            const char *ExtraCode,
>>>>> +                                            raw_ostream &OS) {
>>>>> +  if (AsmVariant != 0)
>>>>> +    report_fatal_error("There are no defined alternate asm variants");
>>>>> +
>>>>> +  if (!ExtraCode) {
>>>>> +    const MachineOperand &MO = MI->getOperand(OpNo);
>>>>> +    if (MO.isImm())
>>>>> +      OS << MO.getImm();
>>>>> +    else
>>>>> +      OS << regToString(MO);
>>>>> +    return false;
>>>>> +  }
>>>>> +
>>>>> +  return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode,
>>>>> OS);
>>>>> +}
>>>>> +
>>>>> +bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
>>>>> *MI,
>>>>> +                                                  unsigned OpNo,
>>>>> +                                                  unsigned AsmVariant,
>>>>> +                                                  const char
>>>>> *ExtraCode,
>>>>> +                                                  raw_ostream &OS) {
>>>>> +  if (AsmVariant != 0)
>>>>> +    report_fatal_error("There are no defined alternate asm variants");
>>>>> +
>>>>> +  if (!ExtraCode) {
>>>>> +    OS << regToString(MI->getOperand(OpNo));
>>>>> +    return false;
>>>>> +  }
>>>>> +
>>>>> +  return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant,
>>>>> ExtraCode, OS);
>>>>> +}
>>>>> +
>>>>>  // Force static initialization.
>>>>>  extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
>>>>>    RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32);
>>>>>
>>>>> Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp?rev=252997&r1=252996&r2=252997&view=diff
>>>>>
>>>>> ==============================================================================
>>>>> --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
>>>>> (original)
>>>>> +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp Thu
>>>>> Nov 12 19:42:29 2015
>>>>> @@ -56,6 +56,9 @@ public:
>>>>>
>>>>>    SDNode *Select(SDNode *Node) override;
>>>>>
>>>>> +  bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned
>>>>> ConstraintID,
>>>>> +                                    std::vector<SDValue> &OutOps)
>>>>> override;
>>>>> +
>>>>>  // Include the pieces autogenerated from the target description.
>>>>>  #include "WebAssemblyGenDAGISel.inc"
>>>>>
>>>>> @@ -101,6 +104,22 @@ SDNode *WebAssemblyDAGToDAGISel::Select(
>>>>>    return ResNode;
>>>>>  }
>>>>>
>>>>> +bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
>>>>> +    const SDValue &Op, unsigned ConstraintID, std::vector<SDValue>
>>>>> &OutOps) {
>>>>> +  switch (ConstraintID) {
>>>>> +  case InlineAsm::Constraint_i:
>>>>> +  case InlineAsm::Constraint_m:
>>>>> +    // We just support simple memory operands that just have a single
>>>>> address
>>>>> +    // operand and need no special handling.
>>>>> +    OutOps.push_back(Op);
>>>>> +    return false;
>>>>> +  default:
>>>>> +    break;
>>>>> +  }
>>>>> +
>>>>> +  return true;
>>>>> +}
>>>>> +
>>>>>  /// This pass converts a legalized DAG into a WebAssembly-specific
>>>>> DAG, ready
>>>>>  /// for instruction scheduling.
>>>>>  FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine
>>>>> &TM,
>>>>>
>>>>> Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp?rev=252997&r1=252996&r2=252997&view=diff
>>>>>
>>>>> ==============================================================================
>>>>> --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
>>>>> (original)
>>>>> +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp Thu
>>>>> Nov 12 19:42:29 2015
>>>>> @@ -211,6 +211,23 @@ WebAssemblyTargetLowering::getTargetNode
>>>>>    return nullptr;
>>>>>  }
>>>>>
>>>>> +std::pair<unsigned, const TargetRegisterClass *>
>>>>> +WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
>>>>> +    const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT)
>>>>> const {
>>>>> +  // First, see if this is a constraint that directly corresponds to a
>>>>> +  // WebAssembly register class.
>>>>> +  if (Constraint.size() == 1) {
>>>>> +    switch (Constraint[0]) {
>>>>> +    case 'r':
>>>>> +      return std::make_pair(0U, &WebAssembly::I32RegClass);
>>>>> +    default:
>>>>> +      break;
>>>>> +    }
>>>>> +  }
>>>>> +
>>>>> +  return TargetLowering::getRegForInlineAsmConstraint(TRI,
>>>>> Constraint, VT);
>>>>> +}
>>>>> +
>>>>>
>>>>>  //===----------------------------------------------------------------------===//
>>>>>  // WebAssembly Lowering private implementation.
>>>>>
>>>>>  //===----------------------------------------------------------------------===//
>>>>>
>>>>> Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h?rev=252997&r1=252996&r2=252997&view=diff
>>>>>
>>>>> ==============================================================================
>>>>> --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
>>>>> (original)
>>>>> +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h Thu
>>>>> Nov 12 19:42:29 2015
>>>>> @@ -49,6 +49,9 @@ private:
>>>>>    bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const
>>>>> override;
>>>>>    MVT getScalarShiftAmountTy(const DataLayout &DL, EVT) const
>>>>> override;
>>>>>    const char *getTargetNodeName(unsigned Opcode) const override;
>>>>> +  std::pair<unsigned, const TargetRegisterClass *>
>>>>> +  getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
>>>>> +                               StringRef Constraint, MVT VT) const
>>>>> override;
>>>>>
>>>>>    SDValue LowerCall(CallLoweringInfo &CLI,
>>>>>                      SmallVectorImpl<SDValue> &InVals) const override;
>>>>>
>>>>> Added: llvm/trunk/test/CodeGen/WebAssembly/inline-asm.ll
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/inline-asm.ll?rev=252997&view=auto
>>>>>
>>>>> ==============================================================================
>>>>> --- llvm/trunk/test/CodeGen/WebAssembly/inline-asm.ll (added)
>>>>> +++ llvm/trunk/test/CodeGen/WebAssembly/inline-asm.ll Thu Nov 12
>>>>> 19:42:29 2015
>>>>> @@ -0,0 +1,53 @@
>>>>> +; RUN: llc < %s -asm-verbose=false | FileCheck %s
>>>>> +
>>>>> +; Test basic inline assembly.
>>>>> +
>>>>> +target datalayout = "e-p:32:32-i64:64-n32:64-S128"
>>>>> +target triple = "wasm32-unknown-unknown"
>>>>> +
>>>>> +; CHECK-LABEL: foo:
>>>>> +; CHECK-NEXT: .param i32{{$}}
>>>>> +; CHECK-NEXT: .result i32{{$}}
>>>>> +; CHECK-NEXT: .local i32, i32{{$}}
>>>>> +; CHECK-NEXT: #APP{{$}}
>>>>> +; CHECK-NEXT: 1 = aaa(0){{$}}
>>>>> +; CHECK-NEXT: #NO_APP{{$}}
>>>>> +; CHECK-NEXT: return (get_local 1){{$}}
>>>>> +define i32 @foo(i32 %r) {
>>>>> +entry:
>>>>> +  %0 = tail call i32 asm sideeffect "$0 = aaa($1)", "=r,r"(i32 %r)
>>>>> #0, !srcloc !0
>>>>> +  ret i32 %0
>>>>> +}
>>>>> +
>>>>> +; CHECK-LABEL: bar:
>>>>> +; CHECK-NEXT: .param i32{{$}}
>>>>> +; CHECK-NEXT: .param i32{{$}}
>>>>> +; CHECK-NEXT: .local i32, i32{{$}}
>>>>> +; CHECK-NEXT: #APP{{$}}
>>>>> +; CHECK-NEXT: 1 = bbb(0){{$}}
>>>>> +; CHECK-NEXT: #NO_APP{{$}}
>>>>> +; CHECK-NEXT: return{{$}}
>>>>> +define void @bar(i32* %r, i32* %s) {
>>>>> +entry:
>>>>> +  tail call void asm sideeffect "$0 = bbb($1)", "=*m,*m"(i32* %s,
>>>>> i32* %r) #0, !srcloc !1
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; CHECK-LABEL: imm:
>>>>> +; CHECK-NEXT: .result i32{{$}}
>>>>> +; CHECK-NEXT: .local i32{{$}}
>>>>> +; CHECK-NEXT: #APP{{$}}
>>>>> +; CHECK-NEXT: 0 = ccc(42){{$}}
>>>>> +; CHECK-NEXT: #NO_APP{{$}}
>>>>> +; CHECK-NEXT: return (get_local 0){{$}}
>>>>> +define i32 @imm() {
>>>>> +entry:
>>>>> +  %0 = tail call i32 asm sideeffect "$0 = ccc($1)", "=r,i"(i32 42)
>>>>> #0, !srcloc !2
>>>>> +  ret i32 %0
>>>>> +}
>>>>> +
>>>>> +attributes #0 = { nounwind }
>>>>> +
>>>>> +!0 = !{i32 47}
>>>>> +!1 = !{i32 145}
>>>>> +!2 = !{i32 231}
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> llvm-commits mailing list
>>>>> llvm-commits at lists.llvm.org
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>>>>
>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20151117/a54896a7/attachment-0001.html>


More information about the llvm-commits mailing list