From: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>

Add a new HIR LlvmInlineAsm HIR node as well as some structures to
represent it's options and operands. Lower AST::LlvmInlineAsm node to it
and then create a tree from that node.

gcc/rust/ChangeLog:

        * ast/rust-ast-collector.cc (TokenCollector::visit): Remove unreachable
        code.
        * ast/rust-expr.h (struct LlvmOperand): Add LlvmOperand struct to
        represent input and outputs.
        (class LlvmInlineAsm): Add input, output and clobber operands.
        (struct TupleTemplateStr): Add locus getter.
        * backend/rust-compile-block.h: Add visit for LlvmInlineAsm.
        * backend/rust-compile-expr.cc (CompileExpr::visit): Add llvm inline
        asm stmt compilation.
        * backend/rust-compile-expr.h: Add function prototype.
        * backend/rust-compile-asm.h (class CompileLlvmAsm): Add llvm asm hir
        not to gimple.
        * backend/rust-compile-asm.cc (CompileLlvmAsm::CompileLlvmAsm): Add
        constructor.
        (CompileLlvmAsm::construct_operands): Add function to construct operand
        tree.
        (CompileLlvmAsm::construct_clobbers): Add function to construct clobber
        tree.
        (CompileLlvmAsm::tree_codegen_asm): Generate the whole tree for a given
        llvm inline assembly node.
        * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc 
(ExprStmtBuilder::visit):
        Add visit function.
        * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Add function
        prototype.
        * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Add visit
        function.
        * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise.
        * checks/errors/borrowck/rust-function-collector.h: Likewise.
        * checks/errors/privacy/rust-privacy-reporter.cc 
(PrivacyReporter::visit):
        Likewise.
        * checks/errors/privacy/rust-privacy-reporter.h: Add visit function
        prototype.
        * checks/errors/rust-const-checker.cc (ConstChecker::visit): Add visit
        function.
        * checks/errors/rust-const-checker.h: Add visit function prototype.
        * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit):
        Add visit function.
        * checks/errors/rust-hir-pattern-analysis.h: Add visit function
        prototype.
        * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Add
        visit function.
        * checks/errors/rust-unsafe-checker.h: Add function prototype.
        * expand/rust-macro-builtins-asm.cc (parse_llvm_templates): Parse
        templates.
        (parse_llvm_arguments): Add function to parse non template tokens.
        (parse_llvm_operands): Add function to parse operands, either input or
        output.
        (parse_llvm_outputs): Add function to parse and collect llvm asm
        outputs.
        (parse_llvm_inputs): Likewise with inputs.
        (parse_llvm_clobbers): Add function to parse llvm asm clobbers.
        (parse_llvm_options): Add function to parse llvm asm options.
        (parse_llvm_asm): Add function to parse llvm asm.
        * expand/rust-macro-builtins-asm.h (class LlvmAsmContext): Add context
        for llvm asm parser.
        (parse_llvm_outputs): Add function prototype.
        (parse_llvm_inputs): Likewise.
        (parse_llvm_clobbers): Likewise.
        (parse_llvm_options): Likewise.
        * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Lower AST llvm
        asm node to HIR.
        * hir/rust-ast-lower-expr.h: Add function prototype.
        * hir/rust-hir-dump.cc (Dump::visit): Add visit function.
        * hir/rust-hir-dump.h: Add function prototype.
        * hir/tree/rust-hir-expr-abstract.h: Add HIR llvm asm node kind.
        * hir/tree/rust-hir-expr.h (struct LlvmOperand): Add LlvmOperand type
        to represent input and outputs.
        (class LlvmInlineAsm): Add LlvmInlineAsm hir node.
        * hir/tree/rust-hir-full-decls.h (class LlvmInlineAsm): Add
        LlvmInlineAsm hir node forward declaration.
        * hir/tree/rust-hir-visitor.h: Add visit functions for LlvmInlineAsm
        hir node.
        * hir/tree/rust-hir.cc (LlvmInlineAsm::accept_vis): Add hir node
        visitor related functions.
        * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit):
        Type check input and output operands.
        * typecheck/rust-hir-type-check-expr.h: Add function prototype.
        * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit input and
        output operand expressions.
        * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Resolve input
        and output expressions.
        * resolve/rust-ast-resolve-expr.h: Add function prototypes.

Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>
---
 gcc/rust/ast/rust-ast-collector.cc            |   8 +-
 gcc/rust/ast/rust-ast-visitor.cc              |   8 +-
 gcc/rust/ast/rust-expr.h                      |  61 ++++-
 gcc/rust/backend/rust-compile-asm.cc          |  54 +++++
 gcc/rust/backend/rust-compile-asm.h           |  14 ++
 gcc/rust/backend/rust-compile-block.h         |   2 +
 gcc/rust/backend/rust-compile-expr.cc         |   7 +
 gcc/rust/backend/rust-compile-expr.h          |   1 +
 .../borrowck/rust-bir-builder-expr-stmt.cc    |   4 +
 .../borrowck/rust-bir-builder-expr-stmt.h     |   1 +
 .../borrowck/rust-bir-builder-lazyboolexpr.h  |   1 +
 .../errors/borrowck/rust-bir-builder-struct.h |   1 +
 .../errors/borrowck/rust-function-collector.h |   1 +
 .../errors/privacy/rust-privacy-reporter.cc   |   4 +
 .../errors/privacy/rust-privacy-reporter.h    |   1 +
 gcc/rust/checks/errors/rust-const-checker.cc  |   4 +
 gcc/rust/checks/errors/rust-const-checker.h   |   1 +
 .../errors/rust-hir-pattern-analysis.cc       |   4 +
 .../checks/errors/rust-hir-pattern-analysis.h |   1 +
 gcc/rust/checks/errors/rust-unsafe-checker.cc |  11 +
 gcc/rust/checks/errors/rust-unsafe-checker.h  |   1 +
 gcc/rust/expand/rust-macro-builtins-asm.cc    | 208 ++++++++++++++++++
 gcc/rust/expand/rust-macro-builtins-asm.h     |  29 ++-
 gcc/rust/hir/rust-ast-lower-expr.cc           |  44 ++++
 gcc/rust/hir/rust-ast-lower-expr.h            |   1 +
 gcc/rust/hir/rust-hir-dump.cc                 |   4 +
 gcc/rust/hir/rust-hir-dump.h                  |   1 +
 gcc/rust/hir/tree/rust-hir-expr-abstract.h    |   1 +
 gcc/rust/hir/tree/rust-hir-expr.h             |  74 +++++++
 gcc/rust/hir/tree/rust-hir-full-decls.h       |   1 +
 gcc/rust/hir/tree/rust-hir-visitor.h          |   3 +
 gcc/rust/hir/tree/rust-hir.cc                 |  11 +
 gcc/rust/resolve/rust-ast-resolve-expr.cc     |  11 +
 gcc/rust/resolve/rust-ast-resolve-expr.h      |   1 +
 .../typecheck/rust-hir-type-check-expr.cc     |  13 ++
 gcc/rust/typecheck/rust-hir-type-check-expr.h |   1 +
 36 files changed, 576 insertions(+), 17 deletions(-)

diff --git a/gcc/rust/ast/rust-ast-collector.cc 
b/gcc/rust/ast/rust-ast-collector.cc
index 90ff2e36251..4148644324a 100644
--- a/gcc/rust/ast/rust-ast-collector.cc
+++ b/gcc/rust/ast/rust-ast-collector.cc
@@ -1520,15 +1520,11 @@ TokenCollector::visit (AsyncBlockExpr &expr)
 
 void
 TokenCollector::visit (InlineAsm &expr)
-{
-  rust_unreachable ();
-}
+{}
 
 void
 TokenCollector::visit (LlvmInlineAsm &expr)
-{
-  rust_unreachable ();
-}
+{}
 
 // rust-item.h
 
diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc
index beb3360c4e1..de01a6d3531 100644
--- a/gcc/rust/ast/rust-ast-visitor.cc
+++ b/gcc/rust/ast/rust-ast-visitor.cc
@@ -715,7 +715,13 @@ DefaultASTVisitor::visit (AST::InlineAsm &expr)
 
 void
 DefaultASTVisitor::visit (AST::LlvmInlineAsm &expr)
-{}
+{
+  for (auto &output : expr.get_outputs ())
+    visit (output.expr);
+
+  for (auto &input : expr.get_inputs ())
+    visit (input.expr);
+}
 
 void
 DefaultASTVisitor::visit (AST::TypeParam &param)
diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index 0dfb4e5fd60..fdb6360eb3b 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -4885,6 +4885,27 @@ struct InlineAsmRegOrRegClass
   location_t locus;
 };
 
+struct LlvmOperand
+{
+  std::string constraint;
+  std::unique_ptr<Expr> expr;
+
+  LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr)
+    : constraint (constraint), expr (std::move (expr))
+  {}
+
+  LlvmOperand (const LlvmOperand &other)
+    : constraint (other.constraint), expr (other.expr->clone_expr ())
+  {}
+  LlvmOperand &operator= (const LlvmOperand &other)
+  {
+    constraint = other.constraint;
+    expr = other.expr->clone_expr ();
+
+    return *this;
+  }
+};
+
 class InlineAsmOperand
 {
 public:
@@ -5258,6 +5279,7 @@ struct TupleTemplateStr
   location_t loc;
   std::string symbol;
 
+  location_t get_locus () { return loc; }
   TupleTemplateStr (location_t loc, const std::string &symbol)
     : loc (loc), symbol (symbol)
   {}
@@ -5335,18 +5357,23 @@ class LlvmInlineAsm : public ExprWithoutBlock
   // llvm_asm!("" :         : "r"(&mut dummy) : "memory" : "volatile");
   //           Asm, Outputs, Inputs,            Clobbers, Options,
 
-private:
-  location_t locus;
-  std::vector<Attribute> outer_attrs;
-
-  std::vector<TupleClobber> clobber_abi;
-  bool is_volatile;
-  bool align_stack;
+public:
   enum class Dialect
   {
     Att,
     Intel,
-  } dialect;
+  };
+
+private:
+  location_t locus;
+  std::vector<Attribute> outer_attrs;
+  std::vector<LlvmOperand> inputs;
+  std::vector<LlvmOperand> outputs;
+  std::vector<TupleTemplateStr> templates;
+  std::vector<TupleClobber> clobbers;
+  bool volatility;
+  bool align_stack;
+  Dialect dialect;
 
 public:
   LlvmInlineAsm (location_t locus) : locus (locus) {}
@@ -5372,10 +5399,28 @@ public:
     return new LlvmInlineAsm (*this);
   }
 
+  std::vector<TupleTemplateStr> &get_templates () { return templates; }
+
   Expr::Kind get_expr_kind () const override
   {
     return Expr::Kind::LlvmInlineAsm;
   }
+
+  void set_align_stack (bool align_stack) { this->align_stack = align_stack; }
+  bool is_stack_aligned () { return align_stack; }
+
+  void set_volatile (bool volatility) { this->volatility = volatility; }
+  bool is_volatile () { return volatility; }
+
+  void set_dialect (Dialect dialect) { this->dialect = dialect; }
+
+  void set_inputs (std::vector<LlvmOperand> operands) { inputs = operands; }
+  void set_outputs (std::vector<LlvmOperand> operands) { outputs = operands; }
+
+  std::vector<LlvmOperand> &get_inputs () { return inputs; }
+  std::vector<LlvmOperand> &get_outputs () { return outputs; }
+
+  std::vector<TupleClobber> &get_clobbers () { return clobbers; }
 };
 
 } // namespace AST
diff --git a/gcc/rust/backend/rust-compile-asm.cc 
b/gcc/rust/backend/rust-compile-asm.cc
index 22498bc4ea0..7351cf0c567 100644
--- a/gcc/rust/backend/rust-compile-asm.cc
+++ b/gcc/rust/backend/rust-compile-asm.cc
@@ -1,5 +1,7 @@
 #include "rust-compile-asm.h"
 #include "rust-compile-expr.h"
+#include "rust-system.h"
+
 namespace Rust {
 namespace Compile {
 
@@ -141,5 +143,57 @@ CompileAsm::asm_construct_label_tree (HIR::InlineAsm &expr)
   return NULL_TREE;
 }
 
+CompileLlvmAsm::CompileLlvmAsm (Context *ctx) : HIRCompileBase (ctx) {}
+
+tree
+CompileLlvmAsm::construct_operands (std::vector<HIR::LlvmOperand> operands)
+{
+  tree head = NULL_TREE;
+  for (auto &operand : operands)
+    {
+      tree t = CompileExpr::Compile (*operand.expr, this->ctx);
+      auto name = build_string (operand.constraint.size () + 1,
+                               operand.constraint.c_str ());
+      head = chainon (head,
+                     build_tree_list (build_tree_list (NULL_TREE, name), t));
+    }
+  return head;
+}
+
+tree
+CompileLlvmAsm::construct_clobbers (std::vector<AST::TupleClobber> clobbers)
+{
+  tree head = NULL_TREE;
+  for (auto &clobber : clobbers)
+    {
+      auto name
+       = build_string (clobber.symbol.size () + 1, clobber.symbol.c_str ());
+      head = chainon (head, build_tree_list (NULL_TREE, name));
+    }
+  return head;
+}
+
+tree
+CompileLlvmAsm::tree_codegen_asm (HIR::LlvmInlineAsm &expr)
+{
+  tree ret = make_node (ASM_EXPR);
+  TREE_TYPE (ret) = void_type_node;
+  SET_EXPR_LOCATION (ret, expr.get_locus ());
+  ASM_VOLATILE_P (ret) = expr.options.is_volatile;
+
+  std::stringstream ss;
+  for (const auto &template_str : expr.templates)
+    {
+      ss << template_str.symbol << "\n";
+    }
+
+  ASM_STRING (ret) = Backend::string_constant_expression (ss.str ());
+  ASM_INPUTS (ret) = construct_operands (expr.inputs);
+  ASM_OUTPUTS (ret) = construct_operands (expr.outputs);
+  ASM_CLOBBERS (ret) = construct_clobbers (expr.get_clobbers ());
+
+  return ret;
+}
+
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-asm.h 
b/gcc/rust/backend/rust-compile-asm.h
index 4abd24eded4..22be94a8833 100644
--- a/gcc/rust/backend/rust-compile-asm.h
+++ b/gcc/rust/backend/rust-compile-asm.h
@@ -56,6 +56,20 @@ public:
 
   tree tree_codegen_asm (HIR::InlineAsm &);
 };
+
+class CompileLlvmAsm : private HIRCompileBase
+{
+private:
+  tree construct_operands (std::vector<HIR::LlvmOperand> operands);
+
+  tree construct_clobbers (std::vector<AST::TupleClobber>);
+
+public:
+  CompileLlvmAsm (Context *ctx);
+
+  tree tree_codegen_asm (HIR::LlvmInlineAsm &);
+};
+
 } // namespace Compile
 } // namespace Rust
 #endif // RUST_COMPILE_ASM
diff --git a/gcc/rust/backend/rust-compile-block.h 
b/gcc/rust/backend/rust-compile-block.h
index 37e3980bd6c..3f38d087859 100644
--- a/gcc/rust/backend/rust-compile-block.h
+++ b/gcc/rust/backend/rust-compile-block.h
@@ -100,6 +100,7 @@ public:
   void visit (HIR::AwaitExpr &) override {}
   void visit (HIR::AsyncBlockExpr &) override {}
   void visit (HIR::InlineAsm &) override {}
+  void visit (HIR::LlvmInlineAsm &) override {}
 
 private:
   CompileConditionalBlocks (Context *ctx, Bvariable *result)
@@ -182,6 +183,7 @@ public:
   void visit (HIR::AwaitExpr &) override {}
   void visit (HIR::AsyncBlockExpr &) override {}
   void visit (HIR::InlineAsm &) override {}
+  void visit (HIR::LlvmInlineAsm &) override {}
 
 private:
   CompileExprWithBlock (Context *ctx, Bvariable *result)
diff --git a/gcc/rust/backend/rust-compile-expr.cc 
b/gcc/rust/backend/rust-compile-expr.cc
index 37856a77f2c..141086fc084 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -367,6 +367,13 @@ CompileExpr::visit (HIR::InlineAsm &expr)
   // CompileAsm::asm_build_expr (expr);
 }
 
+void
+CompileExpr::visit (HIR::LlvmInlineAsm &expr)
+{
+  CompileLlvmAsm asm_codegen (ctx);
+  ctx->add_statement (asm_codegen.tree_codegen_asm (expr));
+}
+
 void
 CompileExpr::visit (HIR::IfExprConseqElse &expr)
 {
diff --git a/gcc/rust/backend/rust-compile-expr.h 
b/gcc/rust/backend/rust-compile-expr.h
index dc78dee3c8f..65ed4b39e2d 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -69,6 +69,7 @@ public:
   void visit (HIR::RangeFromToInclExpr &expr) override;
   void visit (HIR::ClosureExpr &expr) override;
   void visit (HIR::InlineAsm &expr) override;
+  void visit (HIR::LlvmInlineAsm &expr) override;
 
   // TODO
   void visit (HIR::ErrorPropagationExpr &) override {}
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
index d6acc6abcef..6b8b2e97ba7 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
@@ -324,6 +324,10 @@ void
 ExprStmtBuilder::visit (HIR::InlineAsm &expr)
 {}
 
+void
+ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr)
+{}
+
 void
 ExprStmtBuilder::visit (HIR::MethodCallExpr &expr)
 {}
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
index daedb680744..5cab3c495fd 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
@@ -100,6 +100,7 @@ protected: // Expr
   void visit (HIR::IfExpr &expr) override;
   void visit (HIR::IfExprConseqElse &expr) override;
   void visit (HIR::InlineAsm &expr) override;
+  void visit (HIR::LlvmInlineAsm &expr) override;
 
   void visit (HIR::MatchExpr &expr) override;
   void visit (HIR::AwaitExpr &expr) override;
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
index 3bc622cda72..b7a1555b392 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
@@ -207,6 +207,7 @@ public:
   }
 
   void visit (HIR::InlineAsm &expr) override {}
+  void visit (HIR::LlvmInlineAsm &expr) override {}
 
 protected: // Illegal at this position.
   void visit (HIR::StructExprFieldIdentifier &field) override
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h 
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
index 94fcecd40ed..84311cc7a2a 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
@@ -153,6 +153,7 @@ protected:
   void visit (HIR::AwaitExpr &expr) override { rust_unreachable (); }
   void visit (HIR::AsyncBlockExpr &expr) override { rust_unreachable (); }
   void visit (HIR::InlineAsm &expr) override { rust_unreachable (); }
+  void visit (HIR::LlvmInlineAsm &expr) override { rust_unreachable (); }
   void visit (HIR::TypeParam &param) override { rust_unreachable (); }
   void visit (HIR::ConstGenericParam &param) override { rust_unreachable (); }
   void visit (HIR::LifetimeWhereClauseItem &item) override
diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h 
b/gcc/rust/checks/errors/borrowck/rust-function-collector.h
index cdb20e8504a..7cf09524007 100644
--- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h
+++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h
@@ -123,6 +123,7 @@ public:
   void visit (HIR::AwaitExpr &expr) override {}
   void visit (HIR::AsyncBlockExpr &expr) override {}
   void visit (HIR::InlineAsm &expr) override {}
+  void visit (HIR::LlvmInlineAsm &expr) override {}
   void visit (HIR::TypeParam &param) override {}
   void visit (HIR::ConstGenericParam &param) override {}
   void visit (HIR::LifetimeWhereClauseItem &item) override {}
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc 
b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
index a537c4276a8..2a1005343a1 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
@@ -305,6 +305,10 @@ void
 PrivacyReporter::visit (HIR::InlineAsm &)
 {}
 
+void
+PrivacyReporter::visit (HIR::LlvmInlineAsm &)
+{}
+
 void
 PrivacyReporter::visit (HIR::TypePath &path)
 {
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h 
b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
index 5111a3e656d..7df2cf488b6 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
@@ -125,6 +125,7 @@ types
   virtual void visit (HIR::AwaitExpr &expr);
   virtual void visit (HIR::AsyncBlockExpr &expr);
   virtual void visit (HIR::InlineAsm &expr);
+  virtual void visit (HIR::LlvmInlineAsm &expr);
 
   virtual void visit (HIR::EnumItemTuple &);
   virtual void visit (HIR::EnumItemStruct &);
diff --git a/gcc/rust/checks/errors/rust-const-checker.cc 
b/gcc/rust/checks/errors/rust-const-checker.cc
index 4c2257a2455..3716ea53174 100644
--- a/gcc/rust/checks/errors/rust-const-checker.cc
+++ b/gcc/rust/checks/errors/rust-const-checker.cc
@@ -536,6 +536,10 @@ void
 ConstChecker::visit (InlineAsm &)
 {}
 
+void
+ConstChecker::visit (LlvmInlineAsm &)
+{}
+
 void
 ConstChecker::visit (TypeParam &)
 {}
diff --git a/gcc/rust/checks/errors/rust-const-checker.h 
b/gcc/rust/checks/errors/rust-const-checker.h
index 00f5798865a..b954330df4c 100644
--- a/gcc/rust/checks/errors/rust-const-checker.h
+++ b/gcc/rust/checks/errors/rust-const-checker.h
@@ -132,6 +132,7 @@ private:
   virtual void visit (AwaitExpr &expr) override;
   virtual void visit (AsyncBlockExpr &expr) override;
   virtual void visit (InlineAsm &expr) override;
+  virtual void visit (LlvmInlineAsm &expr) override;
 
   virtual void visit (TypeParam &param) override;
   virtual void visit (ConstGenericParam &param) override;
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc 
b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
index 257f4cd0c08..648bc07762d 100644
--- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
@@ -422,6 +422,10 @@ void
 PatternChecker::visit (InlineAsm &expr)
 {}
 
+void
+PatternChecker::visit (LlvmInlineAsm &expr)
+{}
+
 void
 PatternChecker::visit (TypeParam &)
 {}
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h 
b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
index 2171340d4ad..6d60ceda538 100644
--- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
@@ -106,6 +106,7 @@ private:
   virtual void visit (AwaitExpr &expr) override;
   virtual void visit (AsyncBlockExpr &expr) override;
   virtual void visit (InlineAsm &expr) override;
+  virtual void visit (LlvmInlineAsm &expr) override;
   virtual void visit (TypeParam &param) override;
   virtual void visit (ConstGenericParam &param) override;
   virtual void visit (LifetimeWhereClauseItem &item) override;
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc 
b/gcc/rust/checks/errors/rust-unsafe-checker.cc
index bb887a99117..46eef115877 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.cc
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc
@@ -670,6 +670,17 @@ UnsafeChecker::visit (InlineAsm &expr)
     "use of inline assembly is unsafe and requires unsafe function or block");
 }
 
+void
+UnsafeChecker::visit (LlvmInlineAsm &expr)
+{
+  if (unsafe_context.is_in_context ())
+    return;
+
+  rust_error_at (
+    expr.get_locus (), ErrorCode::E0133,
+    "use of inline assembly is unsafe and requires unsafe function or block");
+}
+
 void
 UnsafeChecker::visit (TypeParam &)
 {}
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h 
b/gcc/rust/checks/errors/rust-unsafe-checker.h
index 63098fe5a7d..9a8fb7cdb0a 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.h
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.h
@@ -114,6 +114,7 @@ private:
   virtual void visit (AwaitExpr &expr) override;
   virtual void visit (AsyncBlockExpr &expr) override;
   virtual void visit (InlineAsm &expr) override;
+  virtual void visit (LlvmInlineAsm &expr) override;
   virtual void visit (TypeParam &param) override;
   virtual void visit (ConstGenericParam &param) override;
   virtual void visit (LifetimeWhereClauseItem &item) override;
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc 
b/gcc/rust/expand/rust-macro-builtins-asm.cc
index 8bee4524d49..e255729885b 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.cc
+++ b/gcc/rust/expand/rust-macro-builtins-asm.cc
@@ -22,6 +22,7 @@
 #include "rust-ast.h"
 #include "rust-fmt.h"
 #include "rust-stmt.h"
+#include "rust-parse.h"
 
 namespace Rust {
 std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{
@@ -980,6 +981,184 @@ validate (InlineAsmContext inline_asm_ctx)
   return tl::expected<InlineAsmContext, InlineAsmParseError> (inline_asm_ctx);
 }
 
+tl::optional<LlvmAsmContext>
+parse_llvm_templates (LlvmAsmContext ctx)
+{
+  auto &parser = ctx.parser;
+
+  auto token = parser.peek_current_token ();
+
+  if (token->get_id () == ctx.last_token_id
+      || token->get_id () != STRING_LITERAL)
+    {
+      return tl::nullopt;
+    }
+
+  ctx.llvm_asm.get_templates ().emplace_back (token->get_locus (),
+                                             strip_double_quotes (
+                                               token->as_string ()));
+  ctx.parser.skip_token ();
+
+  token = parser.peek_current_token ();
+  if (token->get_id () != ctx.last_token_id && token->get_id () != COLON
+      && token->get_id () != SCOPE_RESOLUTION)
+    {
+      // We do not handle multiple template string, we provide minimal support
+      // for the black_box intrinsics.
+      rust_unreachable ();
+    }
+
+  return ctx;
+}
+
+tl::optional<LlvmAsmContext>
+parse_llvm_arguments (LlvmAsmContext ctx)
+{
+  auto &parser = ctx.parser;
+  enum State
+  {
+    Templates = 0,
+    Output,
+    Input,
+    Clobbers,
+    Options
+  } current_state
+    = State::Templates;
+
+  while (parser.peek_current_token ()->get_id () != ctx.last_token_id
+        && parser.peek_current_token ()->get_id () != END_OF_FILE)
+    {
+      if (parser.peek_current_token ()->get_id () == SCOPE_RESOLUTION)
+       {
+         parser.skip_token (SCOPE_RESOLUTION);
+         current_state = static_cast<State> (current_state + 2);
+       }
+      else
+       {
+         parser.skip_token (COLON);
+         current_state = static_cast<State> (current_state + 1);
+       }
+
+      switch (current_state)
+       {
+       case State::Output:
+         parse_llvm_outputs (ctx);
+         break;
+       case State::Input:
+         parse_llvm_inputs (ctx);
+         break;
+       case State::Clobbers:
+         parse_llvm_clobbers (ctx);
+         break;
+       case State::Options:
+         parse_llvm_options (ctx);
+         break;
+       case State::Templates:
+       default:
+         rust_unreachable ();
+       }
+    }
+
+  return ctx;
+}
+
+void
+parse_llvm_operands (LlvmAsmContext &ctx, std::vector<AST::LlvmOperand> 
&result)
+{
+  auto &parser = ctx.parser;
+  auto token = parser.peek_current_token ();
+  while (token->get_id () != COLON && token->get_id () != SCOPE_RESOLUTION
+        && token->get_id () != ctx.last_token_id)
+    {
+      std::string constraint;
+      if (token->get_id () == STRING_LITERAL)
+       {
+         constraint = strip_double_quotes (token->as_string ());
+       }
+      parser.skip_token (STRING_LITERAL);
+      parser.skip_token (LEFT_PAREN);
+
+      token = parser.peek_current_token ();
+
+      ParseRestrictions restrictions;
+      restrictions.expr_can_be_null = true;
+      auto expr = parser.parse_expr ();
+
+      parser.skip_token (RIGHT_PAREN);
+
+      result.emplace_back (constraint, std::move (expr));
+
+      if (parser.peek_current_token ()->get_id () == COMMA)
+       parser.skip_token (COMMA);
+
+      token = parser.peek_current_token ();
+    }
+}
+
+void
+parse_llvm_outputs (LlvmAsmContext &ctx)
+{
+  parse_llvm_operands (ctx, ctx.llvm_asm.get_outputs ());
+}
+
+void
+parse_llvm_inputs (LlvmAsmContext &ctx)
+{
+  parse_llvm_operands (ctx, ctx.llvm_asm.get_inputs ());
+}
+
+void
+parse_llvm_clobbers (LlvmAsmContext &ctx)
+{
+  auto &parser = ctx.parser;
+  auto token = parser.peek_current_token ();
+  while (token->get_id () != COLON && token->get_id () != ctx.last_token_id)
+    {
+      if (token->get_id () == STRING_LITERAL)
+       {
+         ctx.llvm_asm.get_clobbers ().push_back (
+           {strip_double_quotes (token->as_string ()), token->get_locus ()});
+       }
+      parser.skip_token (STRING_LITERAL);
+      token = parser.peek_current_token ();
+    }
+}
+
+void
+parse_llvm_options (LlvmAsmContext &ctx)
+{
+  auto &parser = ctx.parser;
+  auto token = parser.peek_current_token ();
+
+  while (token->get_id () != ctx.last_token_id)
+    {
+      if (token->get_id () == STRING_LITERAL)
+       {
+         auto token_str = strip_double_quotes (token->as_string ());
+
+         if (token_str == "volatile")
+           ctx.llvm_asm.set_volatile (true);
+         else if (token_str == "alignstack")
+           ctx.llvm_asm.set_align_stack (true);
+         else if (token_str == "intel")
+           ctx.llvm_asm.set_dialect (AST::LlvmInlineAsm::Dialect::Intel);
+         else
+           rust_error_at (token->get_locus (),
+                          "Unknown llvm assembly option %qs",
+                          token_str.c_str ());
+       }
+      parser.skip_token (STRING_LITERAL);
+
+      token = parser.peek_current_token ();
+
+      if (token->get_id () == ctx.last_token_id)
+       continue;
+      parser.skip_token (COMMA);
+    }
+
+  parser.skip_token ();
+}
+
 tl::optional<AST::Fragment>
 parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
                AST::InvocKind semicolon, AST::AsmKind is_global_asm)
@@ -989,6 +1168,35 @@ parse_llvm_asm (location_t invoc_locus, 
AST::MacroInvocData &invoc,
   auto last_token_id = macro_end_token (invoc.get_delim_tok_tree (), parser);
 
   AST::LlvmInlineAsm llvm_asm{invoc_locus};
+
+  auto asm_ctx = LlvmAsmContext (llvm_asm, parser, last_token_id);
+
+  auto resulting_context
+    = parse_llvm_templates (asm_ctx).and_then (parse_llvm_arguments);
+
+  if (resulting_context)
+    {
+      auto node = (*resulting_context).llvm_asm.clone_expr_without_block ();
+
+      std::vector<AST::SingleASTNode> single_vec = {};
+
+      // If the macro invocation has a semicolon (`asm!("...");`), then we
+      // need to make it a statement. This way, it will be expanded
+      // properly.
+      if (semicolon == AST::InvocKind::Semicoloned)
+       single_vec.emplace_back (AST::SingleASTNode (
+         std::make_unique<AST::ExprStmt> (std::move (node), invoc_locus,
+                                          semicolon
+                                            == AST::InvocKind::Semicoloned)));
+      else
+       single_vec.emplace_back (AST::SingleASTNode (std::move (node)));
+
+      AST::Fragment fragment_ast
+       = AST::Fragment (single_vec,
+                        std::vector<std::unique_ptr<AST::Token>> ());
+      return fragment_ast;
+    }
+  return tl::nullopt;
 }
 
 } // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.h 
b/gcc/rust/expand/rust-macro-builtins-asm.h
index e13ee25a935..bd64a7f4dd6 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.h
+++ b/gcc/rust/expand/rust-macro-builtins-asm.h
@@ -174,8 +174,33 @@ parse_label (Parser<MacroInvocLexer> &parser, TokenId 
last_token_id,
 
 // LLVM ASM bits
 
-WARN_UNUSED_RESULT
-tl::optional<AST::Fragment>
+class LlvmAsmContext
+{
+public:
+  AST::LlvmInlineAsm &llvm_asm;
+  Parser<MacroInvocLexer> &parser;
+  int last_token_id;
+
+public:
+  LlvmAsmContext (AST::LlvmInlineAsm &llvm_asm, Parser<MacroInvocLexer> 
&parser,
+                 int last_token_id)
+    : llvm_asm (llvm_asm), parser (parser), last_token_id (last_token_id)
+  {}
+};
+
+void
+parse_llvm_outputs (LlvmAsmContext &ctx);
+
+void
+parse_llvm_inputs (LlvmAsmContext &ctx);
+
+void
+parse_llvm_clobbers (LlvmAsmContext &ctx);
+
+void
+parse_llvm_options (LlvmAsmContext &ctx);
+
+WARN_UNUSED_RESULT tl::optional<AST::Fragment>
 parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
                AST::InvocKind semicolon, AST::AsmKind is_global_asm);
 
diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc 
b/gcc/rust/hir/rust-ast-lower-expr.cc
index 3784e744f65..07d0c835e56 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.cc
+++ b/gcc/rust/hir/rust-ast-lower-expr.cc
@@ -955,6 +955,50 @@ ASTLoweringExpr::visit (AST::InlineAsm &expr)
                          hir_operands, expr.get_clobber_abi (),
                          expr.get_options (), mapping);
 }
+
+void
+ASTLoweringExpr::visit (AST::LlvmInlineAsm &expr)
+{
+  auto crate_num = mappings.get_current_crate ();
+  Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+                                mappings.get_next_hir_id (crate_num),
+                                mappings.get_next_localdef_id (crate_num));
+
+  std::vector<LlvmOperand> inputs;
+  std::vector<LlvmOperand> outputs;
+
+  for (auto i : expr.get_inputs ())
+    {
+      std::unique_ptr<Expr> inner_expr
+       = std::unique_ptr<Expr> (translate (*i.expr.get ()));
+      inputs.emplace_back (i.constraint, std::move (inner_expr));
+    }
+
+  for (auto o : expr.get_outputs ())
+    {
+      std::unique_ptr<Expr> inner_expr
+       = std::unique_ptr<Expr> (translate (*o.expr.get ()));
+      outputs.emplace_back (o.constraint, std::move (inner_expr));
+    }
+
+  HIR::LlvmInlineAsm::Options options{expr.is_volatile (),
+                                     expr.is_stack_aligned (),
+                                     expr.get_dialect ()};
+
+  // We're not really supporting llvm_asm, only the bare minimum
+  // we're quite conservative here as the current code support more usecase.
+  rust_assert (outputs.size () == 0);
+  rust_assert (inputs.size () <= 1);
+  rust_assert (expr.get_clobbers ().size () <= 1);
+  rust_assert (expr.get_templates ().size () == 1);
+  rust_assert (expr.get_templates ()[0].symbol == "");
+
+  translated
+    = new HIR::LlvmInlineAsm (expr.get_locus (), inputs, outputs,
+                             expr.get_templates (), expr.get_clobbers (),
+                             options, expr.get_outer_attrs (), mapping);
+}
+
 void
 ASTLoweringExpr::visit (AST::FormatArgs &fmt)
 {
diff --git a/gcc/rust/hir/rust-ast-lower-expr.h 
b/gcc/rust/hir/rust-ast-lower-expr.h
index af60e017af4..adedeb3cfcb 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.h
+++ b/gcc/rust/hir/rust-ast-lower-expr.h
@@ -122,6 +122,7 @@ public:
   void visit (AST::ClosureExprInner &expr) override;
   void visit (AST::ClosureExprInnerTyped &expr) override;
   void visit (AST::InlineAsm &expr) override;
+  void visit (AST::LlvmInlineAsm &expr) override;
 
   // Extra visitor for FormatArgs nodes
   void visit (AST::FormatArgs &fmt) override;
diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc
index 16fce6be28e..cb32f68ab96 100644
--- a/gcc/rust/hir/rust-hir-dump.cc
+++ b/gcc/rust/hir/rust-hir-dump.cc
@@ -1509,6 +1509,10 @@ void
 Dump::visit (InlineAsm &e)
 {}
 
+void
+Dump::visit (LlvmInlineAsm &e)
+{}
+
 void
 Dump::visit (TypeParam &e)
 {
diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h
index afcd6683728..45b17080e69 100644
--- a/gcc/rust/hir/rust-hir-dump.h
+++ b/gcc/rust/hir/rust-hir-dump.h
@@ -166,6 +166,7 @@ private:
   virtual void visit (AwaitExpr &) override;
   virtual void visit (AsyncBlockExpr &) override;
   virtual void visit (InlineAsm &) override;
+  virtual void visit (LlvmInlineAsm &) override;
 
   virtual void visit (TypeParam &) override;
   virtual void visit (ConstGenericParam &) override;
diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h 
b/gcc/rust/hir/tree/rust-hir-expr-abstract.h
index ecf9bd1af5d..5bc5d890309 100644
--- a/gcc/rust/hir/tree/rust-hir-expr-abstract.h
+++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h
@@ -71,6 +71,7 @@ public:
     AsyncBlock,
     Path,
     InlineAsm,
+    LlvmInlineAsm,
   };
 
   BaseKind get_hir_kind () override final { return Node::BaseKind::EXPR; }
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h 
b/gcc/rust/hir/tree/rust-hir-expr.h
index 96f0cf68ba0..375f47402f0 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -3118,6 +3118,80 @@ public:
             AST::AttrVec outer_attribs = AST::AttrVec ());
 };
 
+struct LlvmOperand
+{
+  std::string constraint;
+  std::unique_ptr<Expr> expr;
+
+  LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr)
+    : constraint (constraint), expr (std::move (expr))
+  {}
+
+  LlvmOperand (const LlvmOperand &other)
+    : constraint (other.constraint), expr (other.expr->clone_expr ())
+  {}
+  LlvmOperand &operator= (const LlvmOperand &other)
+  {
+    constraint = other.constraint;
+    expr = other.expr->clone_expr ();
+
+    return *this;
+  }
+};
+
+class LlvmInlineAsm : public ExprWithoutBlock
+{
+public:
+  struct Options
+  {
+    bool is_volatile;
+    bool align_stack;
+    AST::LlvmInlineAsm::Dialect dialect;
+  };
+
+  location_t locus;
+  AST::AttrVec outer_attrs;
+  std::vector<LlvmOperand> inputs;
+  std::vector<LlvmOperand> outputs;
+  std::vector<AST::TupleTemplateStr> templates;
+  std::vector<AST::TupleClobber> clobbers;
+  Options options;
+
+  LlvmInlineAsm (location_t locus, std::vector<LlvmOperand> inputs,
+                std::vector<LlvmOperand> outputs,
+                std::vector<AST::TupleTemplateStr> templates,
+                std::vector<AST::TupleClobber> clobbers, Options options,
+                AST::AttrVec outer_attrs, Analysis::NodeMapping mappings)
+    : ExprWithoutBlock (mappings, std::move (outer_attrs)), locus (locus),
+      inputs (std::move (inputs)), outputs (std::move (outputs)),
+      templates (std::move (templates)), clobbers (std::move (clobbers)),
+      options (options)
+  {}
+
+  AST::LlvmInlineAsm::Dialect get_dialect () { return options.dialect; }
+
+  location_t get_locus () const override { return locus; }
+
+  std::vector<AST::Attribute> &get_outer_attrs () { return outer_attrs; }
+
+  void accept_vis (HIRFullVisitor &vis) override;
+  void accept_vis (HIRExpressionVisitor &vis) override;
+
+  LlvmInlineAsm *clone_expr_without_block_impl () const override
+  {
+    return new LlvmInlineAsm (*this);
+  }
+
+  std::vector<AST::TupleTemplateStr> &get_templates () { return templates; }
+
+  Expr::ExprType get_expression_type () const override
+  {
+    return Expr::ExprType::LlvmInlineAsm;
+  }
+
+  std::vector<AST::TupleClobber> get_clobbers () { return clobbers; }
+};
+
 } // namespace HIR
 } // namespace Rust
 
diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h 
b/gcc/rust/hir/tree/rust-hir-full-decls.h
index 6c19f24e0ad..1e313ec1c7b 100644
--- a/gcc/rust/hir/tree/rust-hir-full-decls.h
+++ b/gcc/rust/hir/tree/rust-hir-full-decls.h
@@ -126,6 +126,7 @@ class InlineAsmRegClass;
 struct AnonConst;
 class InlineAsmOperand;
 class InlineAsm;
+class LlvmInlineAsm;
 
 // rust-stmt.h
 class EmptyStmt;
diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h 
b/gcc/rust/hir/tree/rust-hir-visitor.h
index 800e64767a4..283cc346e1e 100644
--- a/gcc/rust/hir/tree/rust-hir-visitor.h
+++ b/gcc/rust/hir/tree/rust-hir-visitor.h
@@ -84,6 +84,7 @@ public:
   virtual void visit (AwaitExpr &expr) = 0;
   virtual void visit (AsyncBlockExpr &expr) = 0;
   virtual void visit (InlineAsm &expr) = 0;
+  virtual void visit (LlvmInlineAsm &expr) = 0;
   virtual void visit (TypeParam &param) = 0;
   virtual void visit (ConstGenericParam &param) = 0;
   virtual void visit (LifetimeWhereClauseItem &item) = 0;
@@ -220,6 +221,7 @@ public:
   virtual void visit (AwaitExpr &) override {}
   virtual void visit (AsyncBlockExpr &) override {}
   virtual void visit (InlineAsm &) override {}
+  virtual void visit (LlvmInlineAsm &) override {}
 
   virtual void visit (TypeParam &) override {}
   virtual void visit (ConstGenericParam &) override {}
@@ -441,6 +443,7 @@ public:
   virtual void visit (IfExpr &expr) = 0;
   virtual void visit (IfExprConseqElse &expr) = 0;
   virtual void visit (InlineAsm &expr) = 0;
+  virtual void visit (LlvmInlineAsm &expr) = 0;
   virtual void visit (MatchExpr &expr) = 0;
   virtual void visit (AwaitExpr &expr) = 0;
   virtual void visit (AsyncBlockExpr &expr) = 0;
diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc
index c8bf9da58e7..093d8d50146 100644
--- a/gcc/rust/hir/tree/rust-hir.cc
+++ b/gcc/rust/hir/tree/rust-hir.cc
@@ -3821,6 +3821,17 @@ InlineAsm::accept_vis (HIRFullVisitor &vis)
   vis.visit (*this);
 }
 
+void
+LlvmInlineAsm::accept_vis (HIRFullVisitor &vis)
+{
+  vis.visit (*this);
+}
+void
+LlvmInlineAsm::accept_vis (HIRExpressionVisitor &vis)
+{
+  vis.visit (*this);
+}
+
 void
 BorrowExpr::accept_vis (HIRExpressionVisitor &vis)
 {
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc 
b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 8070fc1b07c..6242235a1bb 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -368,6 +368,17 @@ ResolveExpr::visit (AST::InlineAsm &expr)
 {
   translate_operand (expr, prefix, canonical_prefix);
 }
+
+void
+ResolveExpr::visit (AST::LlvmInlineAsm &expr)
+{
+  for (auto &output : expr.get_outputs ())
+    ResolveExpr::go (*output.expr, prefix, canonical_prefix);
+
+  for (auto &input : expr.get_inputs ())
+    ResolveExpr::go (*input.expr, prefix, canonical_prefix);
+}
+
 void
 ResolveExpr::visit (AST::UnsafeBlockExpr &expr)
 {
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h 
b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 562a3bd0272..b296d669cb7 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -57,6 +57,7 @@ public:
   void visit (AST::IfLetExprConseqElse &expr) override;
   void visit (AST::BlockExpr &expr) override;
   void visit (AST::InlineAsm &expr) override;
+  void visit (AST::LlvmInlineAsm &expr) override;
   void visit (AST::UnsafeBlockExpr &expr) override;
   void visit (AST::ArrayElemsValues &elems) override;
   void visit (AST::ArrayExpr &expr) override;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc 
b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index b2bcac065eb..7ddcebc731d 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -843,6 +843,19 @@ TypeCheckExpr::visit (HIR::InlineAsm &expr)
     infered = TyTy::TupleType::get_unit_type ();
 }
 
+void
+TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr)
+{
+  for (auto &i : expr.inputs)
+    TypeCheckExpr::Resolve (*i.expr);
+
+  for (auto &o : expr.outputs)
+    TypeCheckExpr::Resolve (*o.expr);
+
+  // Black box hint is unit type
+  infered = TyTy::TupleType::get_unit_type ();
+}
+
 void
 TypeCheckExpr::visit (HIR::RangeFullExpr &expr)
 {
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h 
b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 2a0022ce701..79121b36b43 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -70,6 +70,7 @@ public:
   void visit (HIR::WhileLoopExpr &expr) override;
   void visit (HIR::ClosureExpr &expr) override;
   void visit (HIR::InlineAsm &expr) override;
+  void visit (HIR::LlvmInlineAsm &expr) override;
 
   // TODO
   void visit (HIR::ErrorPropagationExpr &) override {}
-- 
2.49.0

Reply via email to