Skip to content

Commit 9a65d25

Browse files
committed
gccrs: Handle more llvm_asm usages
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 <powerboat9.gamer@gmail.com>
1 parent 13d344b commit 9a65d25

6 files changed

Lines changed: 157 additions & 37 deletions

File tree

gcc/rust/ast/rust-expr.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5852,10 +5852,11 @@ class LlvmInlineAsm : public ExprWithoutBlock
58525852

58535853
public:
58545854
LlvmInlineAsm (location_t locus)
5855-
: locus (locus), template_str (UNKNOWN_LOCATION, "")
5855+
: locus (locus), template_str (UNKNOWN_LOCATION, ""), volatility (false),
5856+
align_stack (false), dialect (Dialect::Att)
58565857
{}
58575858

5858-
Dialect get_dialect () { return dialect; }
5859+
Dialect get_dialect () const { return dialect; }
58595860

58605861
location_t get_locus () const override { return locus; }
58615862

@@ -5890,10 +5891,10 @@ class LlvmInlineAsm : public ExprWithoutBlock
58905891
}
58915892

58925893
void set_align_stack (bool align_stack) { this->align_stack = align_stack; }
5893-
bool is_stack_aligned () { return align_stack; }
5894+
bool is_stack_aligned () const { return align_stack; }
58945895

58955896
void set_volatile (bool volatility) { this->volatility = volatility; }
5896-
bool is_volatile () { return volatility; }
5897+
bool is_volatile () const { return volatility; }
58975898

58985899
void set_dialect (Dialect dialect) { this->dialect = dialect; }
58995900

gcc/rust/backend/rust-compile-asm.cc

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,22 @@ CompileLlvmAsm::construct_operands (std::vector<HIR::LlvmOperand> operands)
187187
for (auto &operand : operands)
188188
{
189189
tree t = CompileExpr::Compile (*operand.expr, this->ctx);
190-
auto name = build_string (operand.constraint.size () + 1,
191-
operand.constraint.c_str ());
190+
191+
// handle indirect memory operand
192+
std::string *constraint;
193+
std::string constraint_copy;
194+
if (operand.constraint == "=*m")
195+
{
196+
constraint = &constraint_copy;
197+
constraint_copy = "=m";
198+
t = indirect_expression (t, operand.expr->get_locus ());
199+
}
200+
else
201+
{
202+
constraint = &operand.constraint;
203+
}
204+
205+
auto name = build_string (constraint->size () + 1, constraint->c_str ());
192206
ls.push_back (build_tree_list (build_tree_list (NULL_TREE, name), t));
193207
}
194208
return ls.get_head ();
@@ -215,13 +229,8 @@ CompileLlvmAsm::tree_codegen_asm (HIR::LlvmInlineAsm &expr)
215229
SET_EXPR_LOCATION (ret, expr.get_locus ());
216230
ASM_VOLATILE_P (ret) = expr.options.is_volatile;
217231

218-
std::stringstream ss;
219-
for (const auto &template_str : expr.templates)
220-
{
221-
ss << template_str.symbol << "\n";
222-
}
223-
224-
ASM_STRING (ret) = Backend::string_constant_expression (ss.str ());
232+
ASM_STRING (ret)
233+
= Backend::string_constant_expression (expr.template_str.symbol);
225234
ASM_INPUTS (ret) = construct_operands (expr.inputs);
226235
ASM_OUTPUTS (ret) = construct_operands (expr.outputs);
227236
ASM_CLOBBERS (ret) = construct_clobbers (expr.get_clobbers ());

gcc/rust/hir/rust-ast-lower-expr.cc

Lines changed: 126 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,24 +1014,132 @@ ASTLoweringExpr::visit (AST::InlineAsm &expr)
10141014
}
10151015

10161016
namespace {
1017-
// We're not really supporting llvm_asm, only the bare minimum for libcore's
1018-
// blackbox
1019-
// llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
1017+
1018+
tl::optional<std::string>
1019+
convert_template_str (const std::string &in_template)
1020+
{
1021+
std::string out_template;
1022+
auto it = in_template.cbegin ();
1023+
1024+
while (it != in_template.cend ())
1025+
{
1026+
if (*it == '$')
1027+
{
1028+
it++;
1029+
if (it == in_template.cend ())
1030+
{
1031+
return tl::nullopt;
1032+
}
1033+
else if (*it >= '0' && *it <= '9')
1034+
{
1035+
out_template.push_back ('%');
1036+
out_template.push_back (*it);
1037+
it++;
1038+
}
1039+
else if (*it == '$')
1040+
{
1041+
out_template.push_back ('$');
1042+
it++;
1043+
}
1044+
else if (*it == '{')
1045+
{
1046+
it++;
1047+
// converting
1048+
// v
1049+
// ${123:abc}
1050+
// to
1051+
// %abc123
1052+
auto num_it = it;
1053+
while (true)
1054+
{
1055+
if (it == in_template.cend ())
1056+
return tl::nullopt;
1057+
if (*it == ':')
1058+
break;
1059+
it++;
1060+
}
1061+
auto colon_it = it;
1062+
while (true)
1063+
{
1064+
if (it == in_template.cend ())
1065+
return tl::nullopt;
1066+
if (*it == '}')
1067+
break;
1068+
it++;
1069+
}
1070+
// output
1071+
out_template.push_back ('%');
1072+
out_template.append (colon_it + 1, it);
1073+
out_template.append (num_it, colon_it);
1074+
// increment past '}'
1075+
it++;
1076+
}
1077+
else
1078+
{
1079+
return tl::nullopt;
1080+
}
1081+
}
1082+
else if (*it == '%' || *it == '{' || *it == '|' || *it == '}')
1083+
{
1084+
out_template.push_back ('%');
1085+
out_template.push_back (*it);
1086+
it++;
1087+
}
1088+
else
1089+
{
1090+
out_template.push_back (*it);
1091+
it++;
1092+
}
1093+
}
1094+
1095+
return out_template;
1096+
}
1097+
1098+
// We're not really supporting llvm_asm, only the bare minimum for libcore
1099+
// ex: llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
10201100
bool
1021-
check_llvm_asm_support (const std::vector<LlvmOperand> &inputs,
1022-
const std::vector<LlvmOperand> &outputs,
1023-
const AST::LlvmInlineAsm &expr)
1101+
check_llvm_asm_support (const AST::LlvmInlineAsm &expr)
10241102
{
1025-
return outputs.size () == 0 && inputs.size () <= 1
1026-
&& expr.get_clobbers ().size () <= 1
1027-
&& expr.get_template ().symbol == "";
1103+
// TODO: more checks/constraint rewriting?
1104+
1105+
if (!convert_template_str (expr.get_template ().symbol).has_value ())
1106+
return false;
1107+
1108+
// TODO: check output constraints?
1109+
1110+
// prohibit commas
1111+
// GCC uses them to list multiple options for constraints (?)
1112+
// while LLVM uses them for inout args (?)
1113+
for (auto &input : expr.get_inputs ())
1114+
if (input.constraint.find (',') != std::string::npos)
1115+
return false;
1116+
1117+
// TODO: check clobbers?
1118+
1119+
// no alignstack or intel support
1120+
if (expr.is_stack_aligned ())
1121+
return false;
1122+
if (expr.get_dialect () == AST::LlvmInlineAsm::Dialect::Intel)
1123+
return false;
1124+
1125+
return true;
10281126
}
10291127

10301128
} // namespace
10311129

10321130
void
10331131
ASTLoweringExpr::visit (AST::LlvmInlineAsm &expr)
10341132
{
1133+
if (!check_llvm_asm_support (expr))
1134+
{
1135+
rust_error_at (expr.get_locus (), "unsupported %qs construct",
1136+
"llvm_asm");
1137+
rust_inform (
1138+
expr.get_locus (),
1139+
"%<llvm_asm%> has been replaced with %<asm%>, gccrs only supports a "
1140+
"subset of %<llvm_asm%> to compile libcore");
1141+
}
1142+
10351143
auto crate_num = mappings.get_current_crate ();
10361144
Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
10371145
mappings.get_next_hir_id (crate_num),
@@ -1061,19 +1169,18 @@ ASTLoweringExpr::visit (AST::LlvmInlineAsm &expr)
10611169
expr.is_stack_aligned (),
10621170
expr.get_dialect ()};
10631171

1064-
if (!check_llvm_asm_support (inputs, outputs, expr))
1065-
{
1066-
rust_error_at (expr.get_locus (), "unsupported %qs construct",
1067-
"llvm_asm");
1068-
rust_inform (
1069-
expr.get_locus (),
1070-
"%<llvm_asm%> has been replaced with %<asm%>, gccrs only supports a "
1071-
"subset of %<llvm_asm%> to compile libcore");
1072-
}
1172+
auto new_template = expr.get_template ();
1173+
new_template.symbol
1174+
= convert_template_str (new_template.symbol).value_or (std::string ());
1175+
1176+
rust_debug_loc (expr.get_locus (),
1177+
"converting %<llvm_asm%> template %qs to %qs",
1178+
expr.get_template ().symbol.c_str (),
1179+
new_template.symbol.c_str ());
10731180

10741181
translated
10751182
= new HIR::LlvmInlineAsm (expr.get_locus (), inputs, outputs,
1076-
{expr.get_template ()}, expr.get_clobbers (),
1183+
std::move (new_template), expr.get_clobbers (),
10771184
options, expr.get_outer_attrs (), mapping);
10781185
}
10791186

gcc/rust/hir/tree/rust-hir-expr.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3297,18 +3297,18 @@ class LlvmInlineAsm : public ExprWithoutBlock
32973297
AST::AttrVec outer_attrs;
32983298
std::vector<LlvmOperand> inputs;
32993299
std::vector<LlvmOperand> outputs;
3300-
std::vector<AST::TupleTemplateStr> templates;
3300+
AST::TupleTemplateStr template_str;
33013301
std::vector<AST::TupleClobber> clobbers;
33023302
Options options;
33033303

33043304
LlvmInlineAsm (location_t locus, std::vector<LlvmOperand> inputs,
33053305
std::vector<LlvmOperand> outputs,
3306-
std::vector<AST::TupleTemplateStr> templates,
3306+
AST::TupleTemplateStr template_str,
33073307
std::vector<AST::TupleClobber> clobbers, Options options,
33083308
AST::AttrVec outer_attrs, Analysis::NodeMapping mappings)
33093309
: ExprWithoutBlock (mappings, std::move (outer_attrs)), locus (locus),
33103310
inputs (std::move (inputs)), outputs (std::move (outputs)),
3311-
templates (std::move (templates)), clobbers (std::move (clobbers)),
3311+
template_str (std::move (template_str)), clobbers (std::move (clobbers)),
33123312
options (options)
33133313
{}
33143314

@@ -3326,7 +3326,7 @@ class LlvmInlineAsm : public ExprWithoutBlock
33263326
return new LlvmInlineAsm (*this);
33273327
}
33283328

3329-
std::vector<AST::TupleTemplateStr> &get_templates () { return templates; }
3329+
AST::TupleTemplateStr &get_template () { return template_str; }
33303330

33313331
Expr::ExprType get_expression_type () const override
33323332
{

gcc/rust/hir/tree/rust-hir-visitor.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ DefaultHIRVisitor::walk (InlineAsm &expr)
595595
void
596596
DefaultHIRVisitor::walk (LlvmInlineAsm &expr)
597597
{
598+
visit_outer_attrs (expr);
598599
for (auto &output : expr.outputs)
599600
output.expr->accept_vis (*this);
600601
for (auto &input : expr.inputs)

gcc/rust/typecheck/rust-hir-type-check-expr.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1024,13 +1024,15 @@ TypeCheckExpr::visit (HIR::InlineAsm &expr)
10241024
void
10251025
TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr)
10261026
{
1027+
// TODO: verify input/output types?
1028+
10271029
for (auto &i : expr.inputs)
10281030
TypeCheckExpr::Resolve (*i.expr);
10291031

10301032
for (auto &o : expr.outputs)
10311033
TypeCheckExpr::Resolve (*o.expr);
10321034

1033-
// Black box hint is unit type
1035+
// always unit type
10341036
infered = TyTy::TupleType::get_unit_type ();
10351037
}
10361038

0 commit comments

Comments
 (0)