void
TokenCollector::visit (InlineAsm &expr)
-{
- rust_unreachable ();
-}
+{}
void
TokenCollector::visit (LlvmInlineAsm &expr)
-{
- rust_unreachable ();
-}
+{}
// rust-item.h
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 ¶m)
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:
location_t loc;
std::string symbol;
+ location_t get_locus () { return loc; }
TupleTemplateStr (location_t loc, const std::string &symbol)
: loc (loc), symbol (symbol)
{}
// 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) {}
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
#include "rust-compile-asm.h"
#include "rust-compile-expr.h"
+#include "rust-system.h"
+
namespace Rust {
namespace Compile {
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
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
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)
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)
// 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)
{
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 {}
ExprStmtBuilder::visit (HIR::InlineAsm &expr)
{}
+void
+ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr)
+{}
+
void
ExprStmtBuilder::visit (HIR::MethodCallExpr &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;
}
void visit (HIR::InlineAsm &expr) override {}
+ void visit (HIR::LlvmInlineAsm &expr) override {}
protected: // Illegal at this position.
void visit (HIR::StructExprFieldIdentifier &field) override
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 ¶m) override { rust_unreachable (); }
void visit (HIR::ConstGenericParam ¶m) override { rust_unreachable (); }
void visit (HIR::LifetimeWhereClauseItem &item) override
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 ¶m) override {}
void visit (HIR::ConstGenericParam ¶m) override {}
void visit (HIR::LifetimeWhereClauseItem &item) override {}
PrivacyReporter::visit (HIR::InlineAsm &)
{}
+void
+PrivacyReporter::visit (HIR::LlvmInlineAsm &)
+{}
+
void
PrivacyReporter::visit (HIR::TypePath &path)
{
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 &);
ConstChecker::visit (InlineAsm &)
{}
+void
+ConstChecker::visit (LlvmInlineAsm &)
+{}
+
void
ConstChecker::visit (TypeParam &)
{}
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 ¶m) override;
virtual void visit (ConstGenericParam ¶m) override;
PatternChecker::visit (InlineAsm &expr)
{}
+void
+PatternChecker::visit (LlvmInlineAsm &expr)
+{}
+
void
PatternChecker::visit (TypeParam &)
{}
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 ¶m) override;
virtual void visit (ConstGenericParam ¶m) override;
virtual void visit (LifetimeWhereClauseItem &item) override;
"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 &)
{}
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 ¶m) override;
virtual void visit (ConstGenericParam ¶m) override;
virtual void visit (LifetimeWhereClauseItem &item) override;
#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{
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)
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
// 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);
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)
{
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;
Dump::visit (InlineAsm &e)
{}
+void
+Dump::visit (LlvmInlineAsm &e)
+{}
+
void
Dump::visit (TypeParam &e)
{
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;
AsyncBlock,
Path,
InlineAsm,
+ LlvmInlineAsm,
};
BaseKind get_hir_kind () override final { return Node::BaseKind::EXPR; }
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
struct AnonConst;
class InlineAsmOperand;
class InlineAsm;
+class LlvmInlineAsm;
// rust-stmt.h
class EmptyStmt;
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 ¶m) = 0;
virtual void visit (ConstGenericParam ¶m) = 0;
virtual void visit (LifetimeWhereClauseItem &item) = 0;
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 {}
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;
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)
{
{
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)
{
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;
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)
{
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 {}