https://gcc.gnu.org/g:0f347d53597f8c325dcea34ee19749e1ddf429d2
commit r15-8342-g0f347d53597f8c325dcea34ee19749e1ddf429d2 Author: badumbatish <tanghocle...@gmail.com> Date: Sat Jul 6 13:17:00 2024 -0700 gccrs: Successfully produce pseudo-nop gcc/rust/ChangeLog: * backend/rust-compile-asm.cc (CompileAsm::add_stmt): Deleted (CompileAsm::CompileAsm): Successfully produce pseudo-nop (CompileAsm::visit): Likewise (CompileAsm::asm_build_asm_stmt): Likewise (CompileAsm::asm_construct_string_tree): Likewise (CompileAsm::asm_is_inline): Likewise * backend/rust-compile-asm.h (class CompileAsm): Likewise * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise Diff: --- gcc/rust/backend/rust-compile-asm.cc | 178 +++++++++++++++++++++++++++++----- gcc/rust/backend/rust-compile-asm.h | 73 +++++++++++++- gcc/rust/backend/rust-compile-expr.cc | 3 +- 3 files changed, 224 insertions(+), 30 deletions(-) diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc index bc11696ed101..fe080f6aa6b9 100644 --- a/gcc/rust/backend/rust-compile-asm.cc +++ b/gcc/rust/backend/rust-compile-asm.cc @@ -2,34 +2,17 @@ #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) @@ -43,7 +26,7 @@ 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) @@ -116,6 +99,8 @@ CompileAsm::asm_construct_string_tree (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; @@ -168,3 +153,146 @@ CompileAsm::asm_is_inline (HIR::InlineAsm &expr) } } // 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; +//} diff --git a/gcc/rust/backend/rust-compile-asm.h b/gcc/rust/backend/rust-compile-asm.h index fd25090cf982..d7967bc7fdb5 100644 --- a/gcc/rust/backend/rust-compile-asm.h +++ b/gcc/rust/backend/rust-compile-asm.h @@ -26,25 +26,90 @@ 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 diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index b59ed4183e71..31f9809c9227 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -321,7 +321,8 @@ CompileExpr::visit (HIR::IfExpr &expr) void CompileExpr::visit (HIR::InlineAsm &expr) { - translated = CompileAsm::asm_build_expr (expr); + CompileAsm a (ctx); + a.visit (expr); // translated = build_asm_expr (0, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, // NULL_TREE, true, true); // CompileAsm::asm_build_expr (expr);