#include "rust-tree.h"
#include "rust-system.h"
+#include <cstddef>
namespace Rust {
namespace Compile {
-tree
-CompileAsm::add_stmt (tree t)
+CompileAsm::CompileAsm (Context *ctx)
+ : HIRCompileBase (ctx), translated (error_mark_node)
+{}
+void
+CompileAsm::visit (HIR::InlineAsm &expr)
{
- enum tree_code code = TREE_CODE (t);
-
- if (EXPR_P (t) && code != LABEL_EXPR)
- {
- if (!EXPR_HAS_LOCATION (t))
- SET_EXPR_LOCATION (t, input_location);
-
- /* When we expand a statement-tree, we must know whether or not the
- statements are full-expressions. We record that fact here. */
- if (STATEMENT_CODE_P (TREE_CODE (t)))
- STMT_IS_FULL_EXPR_P (t) = stmts_are_full_exprs_p ();
- }
-
- if (code == LABEL_EXPR || code == CASE_LABEL_EXPR)
- STATEMENT_LIST_HAS_LABEL (cur_stmt_list) = 1;
-
- /* Add T to the statement-tree. Non-side-effect statements need to be
- recorded during statement expressions. */
- gcc_checking_assert (!stmt_list_stack->is_empty ());
- append_to_statement_list_force (t, &cur_stmt_list);
-
- return t;
+ return ctx->add_statement (asm_build_expr (expr));
}
tree
CompileAsm::asm_build_asm_stmt (HIR::InlineAsm &expr)
// return add_stmt (args);
// }
//
- return add_stmt (asm_build_expr (expr));
+ return NULL_TREE;
}
tree
CompileAsm::asm_build_expr (HIR::InlineAsm &expr)
{
if (expr.template_strs.empty ())
return build_string (1, "");
+ else
+ return build_string (4, "nop");
// Initialize to NULL_TREE
tree string_chain = NULL_TREE;
}
} // namespace Compile
} // namespace Rust
+ //
+ //
+ // The following section serves as documentation for PR revieweres and future
+ // asm developers. It documents the inspriation for the implementation of the
+ // CompileAsm class
+
+// From the implementation of c-typeck.cc
+// tree
+// build_asm_stmt (bool is_volatile, tree args)
+//{
+// if (is_volatile)
+// ASM_VOLATILE_P (args) = 1;
+// return add_stmt (args);
+// }
+//
+///* Build an asm-expr, whose components are a STRING, some OUTPUTS,
+// some INPUTS, and some CLOBBERS. The latter three may be NULL.
+// SIMPLE indicates whether there was anything at all after the
+// string in the asm expression -- asm("blah") and asm("blah" : )
+// are subtly different. We use a ASM_EXPR node to represent this.
+// LOC is the location of the asm, and IS_INLINE says whether this
+// is asm inline. */
+// tree
+// build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
+// tree clobbers, tree labels, bool simple, bool is_inline)
+//{
+// tree tail;
+// tree args;
+// int i;
+// const char *constraint;
+// const char **oconstraints;
+// bool allows_mem, allows_reg, is_inout;
+// int ninputs, noutputs;
+//
+// ninputs = list_length (inputs);
+// noutputs = list_length (outputs);
+// oconstraints = (const char **) alloca (noutputs * sizeof (const char *));
+//
+// string = resolve_asm_operand_names (string, outputs, inputs, labels);
+//
+// /* Remove output conversions that change the type but not the mode. */
+// for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
+// {
+// tree output = TREE_VALUE (tail);
+//
+// output = c_fully_fold (output, false, NULL, true);
+//
+// /* ??? Really, this should not be here. Users should be using a
+// proper lvalue, dammit. But there's a long history of using casts
+// in the output operands. In cases like longlong.h, this becomes a
+// primitive form of typechecking -- if the cast can be removed, then
+// the output operand had a type of the proper width; otherwise we'll
+// get an error. Gross, but ... */
+// STRIP_NOPS (output);
+//
+// if (!lvalue_or_else (loc, output, lv_asm))
+// output = error_mark_node;
+//
+// if (output != error_mark_node
+// && (TREE_READONLY (output)
+// || TYPE_READONLY (TREE_TYPE (output))
+// || (RECORD_OR_UNION_TYPE_P (TREE_TYPE (output))
+// && C_TYPE_FIELDS_READONLY (TREE_TYPE (output)))))
+// readonly_error (loc, output, lv_asm);
+//
+// constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+// oconstraints[i] = constraint;
+//
+// if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+// &allows_mem, &allows_reg, &is_inout))
+// {
+// /* If the operand is going to end up in memory,
+// mark it addressable. */
+// if (!allows_reg && !c_mark_addressable (output))
+// output = error_mark_node;
+// if (!(!allows_reg && allows_mem)
+// && output != error_mark_node
+// && VOID_TYPE_P (TREE_TYPE (output)))
+// {
+// error_at (loc, "invalid use of void expression");
+// output = error_mark_node;
+// }
+// }
+// else
+// output = error_mark_node;
+//
+// TREE_VALUE (tail) = output;
+// }
+//
+// for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail))
+// {
+// tree input;
+//
+// constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+// input = TREE_VALUE (tail);
+//
+// if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+// oconstraints, &allows_mem, &allows_reg))
+// {
+// /* If the operand is going to end up in memory,
+// mark it addressable. */
+// if (!allows_reg && allows_mem)
+// {
+// input = c_fully_fold (input, false, NULL, true);
+//
+// /* Strip the nops as we allow this case. FIXME, this really
+// should be rejected or made deprecated. */
+// STRIP_NOPS (input);
+// if (!c_mark_addressable (input))
+// input = error_mark_node;
+// }
+// else
+// {
+// struct c_expr expr;
+// memset (&expr, 0, sizeof (expr));
+// expr.value = input;
+// expr = convert_lvalue_to_rvalue (loc, expr, true, false);
+// input = c_fully_fold (expr.value, false, NULL);
+//
+// if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input)))
+// {
+// error_at (loc, "invalid use of void expression");
+// input = error_mark_node;
+// }
+// }
+// }
+// else
+// input = error_mark_node;
+//
+// TREE_VALUE (tail) = input;
+// }
+//
+// args = build_stmt (loc, ASM_EXPR, string, outputs, inputs, clobbers,
+// labels);
+//
+// /* asm statements without outputs, including simple ones, are treated
+// as volatile. */
+// ASM_INPUT_P (args) = simple;
+// ASM_VOLATILE_P (args) = (noutputs == 0);
+// ASM_INLINE_P (args) = is_inline;
+//
+// return args;
+//}
namespace Rust {
namespace Compile {
-class CompileAsm
+class CompileAsm : private HIRCompileBase, protected HIR::HIRExpressionVisitor
{
public:
+ // static tree Compile (HIR::Expr *expr, Context *ctx);
+
+ void visit (HIR::InlineAsm &expr) override;
+
+ void visit (HIR::TupleIndexExpr &expr) override {}
+ void visit (HIR::TupleExpr &expr) override {}
+ void visit (HIR::ReturnExpr &expr) override {}
+ void visit (HIR::CallExpr &expr) override {}
+ void visit (HIR::MethodCallExpr &expr) override {}
+ void visit (HIR::LiteralExpr &expr) override {}
+ void visit (HIR::AssignmentExpr &expr) override {}
+ void visit (HIR::CompoundAssignmentExpr &expr) override {}
+ void visit (HIR::ArrayIndexExpr &expr) override {}
+ void visit (HIR::ArrayExpr &expr) override {}
+ void visit (HIR::ArithmeticOrLogicalExpr &expr) override {}
+ void visit (HIR::ComparisonExpr &expr) override {}
+ void visit (HIR::LazyBooleanExpr &expr) override {}
+ void visit (HIR::NegationExpr &expr) override {}
+ void visit (HIR::TypeCastExpr &expr) override {}
+ void visit (HIR::IfExpr &expr) override {}
+ void visit (HIR::IfExprConseqElse &expr) override {}
+ void visit (HIR::BlockExpr &expr) override {}
+ void visit (HIR::UnsafeBlockExpr &expr) override {}
+ void visit (HIR::StructExprStruct &struct_expr) override {}
+ void visit (HIR::StructExprStructFields &struct_expr) override {}
+ void visit (HIR::GroupedExpr &expr) override {}
+ void visit (HIR::FieldAccessExpr &expr) override {}
+ void visit (HIR::QualifiedPathInExpression &expr) override {}
+ void visit (HIR::PathInExpression &expr) override {}
+ void visit (HIR::LoopExpr &expr) override {}
+ void visit (HIR::WhileLoopExpr &expr) override {}
+ void visit (HIR::BreakExpr &expr) override {}
+ void visit (HIR::ContinueExpr &expr) override {}
+ void visit (HIR::BorrowExpr &expr) override {}
+ void visit (HIR::DereferenceExpr &expr) override {}
+ void visit (HIR::MatchExpr &expr) override {}
+ void visit (HIR::RangeFromToExpr &expr) override {}
+ void visit (HIR::RangeFromExpr &expr) override {}
+ void visit (HIR::RangeToExpr &expr) override {}
+ void visit (HIR::RangeFullExpr &expr) override {}
+ void visit (HIR::RangeFromToInclExpr &expr) override {}
+ void visit (HIR::ClosureExpr &expr) override {}
+
+ // TODO
+ void visit (HIR::ErrorPropagationExpr &) override {}
+ void visit (HIR::RangeToInclExpr &) override {}
+
+ // TODO
+ // these need to be sugared in the HIR to if statements and a match
+ void visit (HIR::WhileLetLoopExpr &) override {}
+ void visit (HIR::IfLetExpr &) override {}
+ void visit (HIR::IfLetExprConseqElse &) override {}
+
+ // lets not worry about async yet....
+ void visit (HIR::AwaitExpr &) override {}
+ void visit (HIR::AsyncBlockExpr &) override {}
+
+ // nothing to do for these
+ void visit (HIR::StructExprFieldIdentifier &) override {}
+ void visit (HIR::StructExprFieldIdentifierValue &) override {}
+ void visit (HIR::StructExprFieldIndexValue &) override {}
+
static const int ASM_TREE_ARRAY_LENGTH = 5;
- static tree add_stmt (tree);
static tree asm_build_asm_stmt (HIR::InlineAsm &);
static tree asm_build_expr (HIR::InlineAsm &);
static tree asm_build_stmt (location_t, enum tree_code,
const std::array<tree, ASM_TREE_ARRAY_LENGTH> &);
+
static location_t asm_get_locus (HIR::InlineAsm &);
static tree asm_construct_string_tree (HIR::InlineAsm &);
static tree asm_construct_outputs (HIR::InlineAsm &);
static tree asm_construct_inputs (HIR::InlineAsm &);
static tree asm_construct_clobber_tree (HIR::InlineAsm &);
static tree asm_construct_label_tree (HIR::InlineAsm &);
-
static bool asm_is_simple (HIR::InlineAsm &);
-
static bool asm_is_inline (HIR::InlineAsm &);
+
+ CompileAsm (Context *ctx);
+
+private:
+ tree translated;
};
} // namespace Compile
} // namespace Rust