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