From: Owen Avery <[email protected]>
More subtle differences between GCC and LLVM inline assembly might be
an issue in the future, but this should handle or safely reject most
usages.
gcc/rust/ChangeLog:
* ast/rust-expr.h (LlvmInlineAsm::LlvmInlineAsm): Initialize
more member variables.
(LlvmInlineAsm::get_dialect): Make function const qualified.
(LlvmInlineAsm::is_stack_aligned): Likewise.
(LlvmInlineAsm::is_volatile): Likewise.
* backend/rust-compile-asm.cc
(CompileLlvmAsm::construct_operands): Handle llvm-specific "=*m"
constraint.
(CompileLlvmAsm::tree_codegen_asm): Handle change from multiple
template strings to a single template string.
* hir/rust-ast-lower-expr.cc (convert_template_str): New
function.
(check_llvm_asm_support): Remove unnecessary parameters and
expand the set of allowed llvm_asm usages.
(ASTLoweringExpr::visit (LlvmInlineAsm)): Adjust lowering.
* hir/tree/rust-hir-expr.h (LlvmInlineAsm::templates): Remove
member variable and replace with...
(LlvmInlineAsm::template_str): ...new member variable.
(LlvmInlineAsm::LlvmInlineAsm): Handle member variable changes.
(LlvmInlineAsm::get_templates): Remove member function and
replace with...
(LlvmInlineAsm::get_template): ...new member function.
* hir/tree/rust-hir-visitor.cc
(DefaultHIRVisitor::walk (LlvmInlineAsm)): Visit outer
attributes.
* typecheck/rust-hir-type-check-expr.cc
(TypeCheckExpr::visit (LlvmInlineAsm)): Adjust comments.
Signed-off-by: Owen Avery <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github: https://github.com/Rust-GCC/gccrs/commit/0029e0e44559501663f95997a892a2a701d95840
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4786
gcc/rust/ast/rust-expr.h | 9 +-
gcc/rust/backend/rust-compile-asm.cc | 27 ++--
gcc/rust/hir/rust-ast-lower-expr.cc | 145 +++++++++++++++---
gcc/rust/hir/tree/rust-hir-expr.h | 8 +-
gcc/rust/hir/tree/rust-hir-visitor.cc | 1 +
.../typecheck/rust-hir-type-check-expr.cc | 4 +-
6 files changed, 157 insertions(+), 37 deletions(-)
diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index 43f5802d3..a30282000 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -5852,10 +5852,11 @@ private:
public:
LlvmInlineAsm (location_t locus)
- : locus (locus), template_str (UNKNOWN_LOCATION, "")
+ : locus (locus), template_str (UNKNOWN_LOCATION, ""), volatility (false),
+ align_stack (false), dialect (Dialect::Att)
{}
- Dialect get_dialect () { return dialect; }
+ Dialect get_dialect () const { return dialect; }
location_t get_locus () const override { return locus; }
@@ -5890,10 +5891,10 @@ public:
}
void set_align_stack (bool align_stack) { this->align_stack = align_stack; }
- bool is_stack_aligned () { return align_stack; }
+ bool is_stack_aligned () const { return align_stack; }
void set_volatile (bool volatility) { this->volatility = volatility; }
- bool is_volatile () { return volatility; }
+ bool is_volatile () const { return volatility; }
void set_dialect (Dialect dialect) { this->dialect = dialect; }
diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc
index 2ac65bd65..73873e440 100644
--- a/gcc/rust/backend/rust-compile-asm.cc
+++ b/gcc/rust/backend/rust-compile-asm.cc
@@ -187,8 +187,22 @@ CompileLlvmAsm::construct_operands (std::vector<HIR::LlvmOperand> operands)
for (auto &operand : operands)
{
tree t = CompileExpr::Compile (*operand.expr, this->ctx);
- auto name = build_string (operand.constraint.size () + 1,
- operand.constraint.c_str ());
+
+ // handle indirect memory operand
+ std::string *constraint;
+ std::string constraint_copy;
+ if (operand.constraint == "=*m")
+ {
+ constraint = &constraint_copy;
+ constraint_copy = "=m";
+ t = indirect_expression (t, operand.expr->get_locus ());
+ }
+ else
+ {
+ constraint = &operand.constraint;
+ }
+
+ auto name = build_string (constraint->size () + 1, constraint->c_str ());
ls.push_back (build_tree_list (build_tree_list (NULL_TREE, name), t));
}
return ls.get_head ();
@@ -215,13 +229,8 @@ CompileLlvmAsm::tree_codegen_asm (HIR::LlvmInlineAsm &expr)
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_STRING (ret)
+ = Backend::string_constant_expression (expr.template_str.symbol);
ASM_INPUTS (ret) = construct_operands (expr.inputs);
ASM_OUTPUTS (ret) = construct_operands (expr.outputs);
ASM_CLOBBERS (ret) = construct_clobbers (expr.get_clobbers ());
diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc
index 8dc2ed04c..77811f2b8 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.cc
+++ b/gcc/rust/hir/rust-ast-lower-expr.cc
@@ -1014,17 +1014,115 @@ ASTLoweringExpr::visit (AST::InlineAsm &expr)
}
namespace {
-// We're not really supporting llvm_asm, only the bare minimum for libcore's
-// blackbox
-// llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
+
+tl::optional<std::string>
+convert_template_str (const std::string &in_template)
+{
+ std::string out_template;
+ auto it = in_template.cbegin ();
+
+ while (it != in_template.cend ())
+ {
+ if (*it == '$')
+ {
+ it++;
+ if (it == in_template.cend ())
+ {
+ return tl::nullopt;
+ }
+ else if (*it >= '0' && *it <= '9')
+ {
+ out_template.push_back ('%');
+ out_template.push_back (*it);
+ it++;
+ }
+ else if (*it == '$')
+ {
+ out_template.push_back ('$');
+ it++;
+ }
+ else if (*it == '{')
+ {
+ it++;
+ // converting
+ // v
+ // ${123:abc}
+ // to
+ // %abc123
+ auto num_it = it;
+ while (true)
+ {
+ if (it == in_template.cend ())
+ return tl::nullopt;
+ if (*it == ':')
+ break;
+ it++;
+ }
+ auto colon_it = it;
+ while (true)
+ {
+ if (it == in_template.cend ())
+ return tl::nullopt;
+ if (*it == '}')
+ break;
+ it++;
+ }
+ // output
+ out_template.push_back ('%');
+ out_template.append (colon_it + 1, it);
+ out_template.append (num_it, colon_it);
+ // increment past '}'
+ it++;
+ }
+ else
+ {
+ return tl::nullopt;
+ }
+ }
+ else if (*it == '%' || *it == '{' || *it == '|' || *it == '}')
+ {
+ out_template.push_back ('%');
+ out_template.push_back (*it);
+ it++;
+ }
+ else
+ {
+ out_template.push_back (*it);
+ it++;
+ }
+ }
+
+ return out_template;
+}
+
+// We're not really supporting llvm_asm, only the bare minimum for libcore
+// ex: llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
bool
-check_llvm_asm_support (const std::vector<LlvmOperand> &inputs,
- const std::vector<LlvmOperand> &outputs,
- const AST::LlvmInlineAsm &expr)
+check_llvm_asm_support (const AST::LlvmInlineAsm &expr)
{
- return outputs.size () == 0 && inputs.size () <= 1
- && expr.get_clobbers ().size () <= 1
- && expr.get_template ().symbol == "";
+ // TODO: more checks/constraint rewriting?
+
+ if (!convert_template_str (expr.get_template ().symbol).has_value ())
+ return false;
+
+ // TODO: check output constraints?
+
+ // prohibit commas
+ // GCC uses them to list multiple options for constraints (?)
+ // while LLVM uses them for inout args (?)
+ for (auto &input : expr.get_inputs ())
+ if (input.constraint.find (',') != std::string::npos)
+ return false;
+
+ // TODO: check clobbers?
+
+ // no alignstack or intel support
+ if (expr.is_stack_aligned ())
+ return false;
+ if (expr.get_dialect () == AST::LlvmInlineAsm::Dialect::Intel)
+ return false;
+
+ return true;
}
} // namespace
@@ -1032,6 +1130,16 @@ check_llvm_asm_support (const std::vector<LlvmOperand> &inputs,
void
ASTLoweringExpr::visit (AST::LlvmInlineAsm &expr)
{
+ if (!check_llvm_asm_support (expr))
+ {
+ rust_error_at (expr.get_locus (), "unsupported %qs construct",
+ "llvm_asm");
+ rust_inform (
+ expr.get_locus (),
+ "%<llvm_asm%> has been replaced with %<asm%>, gccrs only supports a "
+ "subset of %<llvm_asm%> to compile libcore");
+ }
+
auto crate_num = mappings.get_current_crate ();
Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
mappings.get_next_hir_id (crate_num),
@@ -1061,19 +1169,18 @@ ASTLoweringExpr::visit (AST::LlvmInlineAsm &expr)
expr.is_stack_aligned (),
expr.get_dialect ()};
- if (!check_llvm_asm_support (inputs, outputs, expr))
- {
- rust_error_at (expr.get_locus (), "unsupported %qs construct",
- "llvm_asm");
- rust_inform (
- expr.get_locus (),
- "%<llvm_asm%> has been replaced with %<asm%>, gccrs only supports a "
- "subset of %<llvm_asm%> to compile libcore");
- }
+ auto new_template = expr.get_template ();
+ new_template.symbol
+ = convert_template_str (new_template.symbol).value_or (std::string ());
+
+ rust_debug_fmt_at (expr.get_locus (),
+ "converting %<llvm_asm%> template %qs to %qs",
+ expr.get_template ().symbol.c_str (),
+ new_template.symbol.c_str ());
translated
= new HIR::LlvmInlineAsm (expr.get_locus (), inputs, outputs,
- {expr.get_template ()}, expr.get_clobbers (),
+ std::move (new_template), expr.get_clobbers (),
options, expr.get_outer_attrs (), mapping);
}
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index abd5e7d2d..02c6f2538 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -3297,18 +3297,18 @@ public:
AST::AttrVec outer_attrs;
std::vector<LlvmOperand> inputs;
std::vector<LlvmOperand> outputs;
- std::vector<AST::TupleTemplateStr> templates;
+ AST::TupleTemplateStr template_str;
std::vector<AST::TupleClobber> clobbers;
Options options;
LlvmInlineAsm (location_t locus, std::vector<LlvmOperand> inputs,
std::vector<LlvmOperand> outputs,
- std::vector<AST::TupleTemplateStr> templates,
+ AST::TupleTemplateStr template_str,
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)),
+ template_str (std::move (template_str)), clobbers (std::move (clobbers)),
options (options)
{}
@@ -3326,7 +3326,7 @@ public:
return new LlvmInlineAsm (*this);
}
- std::vector<AST::TupleTemplateStr> &get_templates () { return templates; }
+ AST::TupleTemplateStr &get_template () { return template_str; }
Expr::ExprType get_expression_type () const override
{
diff --git a/gcc/rust/hir/tree/rust-hir-visitor.cc b/gcc/rust/hir/tree/rust-hir-visitor.cc
index 544c83db8..cf4650d00 100644
--- a/gcc/rust/hir/tree/rust-hir-visitor.cc
+++ b/gcc/rust/hir/tree/rust-hir-visitor.cc
@@ -595,6 +595,7 @@ DefaultHIRVisitor::walk (InlineAsm &expr)
void
DefaultHIRVisitor::walk (LlvmInlineAsm &expr)
{
+ visit_outer_attrs (expr);
for (auto &output : expr.outputs)
output.expr->accept_vis (*this);
for (auto &input : expr.inputs)
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index fd9d1f953..aff96db1f 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -1021,13 +1021,15 @@ TypeCheckExpr::visit (HIR::InlineAsm &expr)
void
TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr)
{
+ // TODO: verify input/output types?
+
for (auto &i : expr.inputs)
TypeCheckExpr::Resolve (*i.expr);
for (auto &o : expr.outputs)
TypeCheckExpr::Resolve (*o.expr);
- // Black box hint is unit type
+ // always unit type
infered = TyTy::TupleType::get_unit_type ();
}
base-commit: eeec65b7b0154ac5f3337857aca391e3b2a66339
--
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.