Skip to content

Commit

Permalink
Give InlineAsmOperand a HIR representation
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Sep 5, 2024
1 parent 304f54e commit f3b6965
Show file tree
Hide file tree
Showing 23 changed files with 409 additions and 217 deletions.
27 changes: 23 additions & 4 deletions src/tools/rust-analyzer/crates/hir-def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,14 @@ pub struct BodySourceMap {
field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,

format_args_template_map: FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
template_map: Option<
Box<(
// format_args!
FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
// asm!
FxHashMap<ExprId, Vec<(syntax::TextRange, usize)>>,
)>,
>,

expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, MacroFileId>,

Expand Down Expand Up @@ -426,7 +433,16 @@ impl BodySourceMap {
node: InFile<&ast::FormatArgsExpr>,
) -> Option<&[(syntax::TextRange, Name)]> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
self.format_args_template_map.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref)
self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref)
}

pub fn asm_template_args(
&self,
node: InFile<&ast::AsmExpr>,
) -> Option<(ExprId, &[(syntax::TextRange, usize)])> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
let expr = self.expr_map.get(&src)?;
Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref))
}

/// Get a reference to the body source map's diagnostics.
Expand All @@ -446,11 +462,14 @@ impl BodySourceMap {
field_map_back,
pat_field_map_back,
expansions,
format_args_template_map,
template_map,
diagnostics,
binding_definitions,
} = self;
format_args_template_map.shrink_to_fit();
if let Some(template_map) = template_map {
template_map.0.shrink_to_fit();
template_map.1.shrink_to_fit();
}
expr_map.shrink_to_fit();
expr_map_back.shrink_to_fit();
pat_map.shrink_to_fit();
Expand Down
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1847,7 +1847,7 @@ impl ExprCollector<'_> {
},
syntax_ptr,
);
self.source_map.format_args_template_map.insert(idx, mappings);
self.source_map.template_map.get_or_insert_with(Default::default).0.insert(idx, mappings);
idx
}

Expand Down
148 changes: 79 additions & 69 deletions src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use hir_expand::name::Name;
use intern::Symbol;
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
Expand All @@ -25,7 +24,7 @@ impl ExprCollector<'_> {
let mut named_pos: FxHashMap<usize, Symbol> = Default::default();
let mut named_args: FxHashMap<Symbol, usize> = Default::default();
let mut reg_args: FxHashSet<usize> = Default::default();
for operand in asm.asm_operands() {
for piece in asm.asm_pieces() {
let slot = operands.len();
let mut lower_reg = |reg: Option<ast::AsmRegSpec>| {
let reg = reg?;
Expand All @@ -39,14 +38,14 @@ impl ExprCollector<'_> {
}
};

let op = match operand {
ast::AsmOperand::AsmClobberAbi(clobber_abi) => {
let op = match piece {
ast::AsmPiece::AsmClobberAbi(clobber_abi) => {
if let Some(abi_name) = clobber_abi.string_token() {
clobber_abis.insert(Symbol::intern(abi_name.text()));
}
continue;
}
ast::AsmOperand::AsmOptions(opt) => {
ast::AsmPiece::AsmOptions(opt) => {
opt.asm_options().for_each(|opt| {
options |= match opt.syntax().first_token().map_or(T![$], |it| it.kind()) {
T![att_syntax] => AsmOptions::ATT_SYNTAX,
Expand All @@ -63,71 +62,82 @@ impl ExprCollector<'_> {
});
continue;
}
ast::AsmOperand::AsmRegOperand(op) => {
let Some(dir_spec) = op.asm_dir_spec() else {
continue;
};
let Some(reg) = lower_reg(op.asm_reg_spec()) else {
continue;
};
ast::AsmPiece::AsmOperandNamed(op) => {
if let Some(name) = op.name() {
let sym = Symbol::intern(&name.text());
named_args.insert(sym.clone(), slot);
named_pos.insert(slot, sym);
}
if dir_spec.in_token().is_some() {
let expr = self
.collect_expr_opt(op.asm_operand_expr().and_then(|it| it.in_expr()));
AsmOperand::In { reg, expr }
} else if dir_spec.out_token().is_some() {
let expr = self
.collect_expr_opt(op.asm_operand_expr().and_then(|it| it.in_expr()));
AsmOperand::Out { reg, expr: Some(expr), late: false }
} else if dir_spec.lateout_token().is_some() {
let expr = self
.collect_expr_opt(op.asm_operand_expr().and_then(|it| it.in_expr()));
AsmOperand::Out { reg, expr: Some(expr), late: true }
} else if dir_spec.inout_token().is_some() {
let Some(op_expr) = op.asm_operand_expr() else { continue };
let in_expr = self.collect_expr_opt(op_expr.in_expr());
let out_expr = op_expr.out_expr().map(|it| self.collect_expr(it));
match out_expr {
Some(out_expr) => AsmOperand::SplitInOut {
reg,
in_expr,
out_expr: Some(out_expr),
late: false,
},
None => AsmOperand::InOut { reg, expr: in_expr, late: false },
let Some(op) = op.asm_operand() else { continue };
match op {
ast::AsmOperand::AsmRegOperand(op) => {
let Some(dir_spec) = op.asm_dir_spec() else {
continue;
};
let Some(reg) = lower_reg(op.asm_reg_spec()) else {
continue;
};
if dir_spec.in_token().is_some() {
let expr = self.collect_expr_opt(
op.asm_operand_expr().and_then(|it| it.in_expr()),
);
AsmOperand::In { reg, expr }
} else if dir_spec.out_token().is_some() {
let expr = self.collect_expr_opt(
op.asm_operand_expr().and_then(|it| it.in_expr()),
);
AsmOperand::Out { reg, expr: Some(expr), late: false }
} else if dir_spec.lateout_token().is_some() {
let expr = self.collect_expr_opt(
op.asm_operand_expr().and_then(|it| it.in_expr()),
);
AsmOperand::Out { reg, expr: Some(expr), late: true }
} else if dir_spec.inout_token().is_some() {
let Some(op_expr) = op.asm_operand_expr() else { continue };
let in_expr = self.collect_expr_opt(op_expr.in_expr());
let out_expr = op_expr.out_expr().map(|it| self.collect_expr(it));
match out_expr {
Some(out_expr) => AsmOperand::SplitInOut {
reg,
in_expr,
out_expr: Some(out_expr),
late: false,
},
None => AsmOperand::InOut { reg, expr: in_expr, late: false },
}
} else if dir_spec.inlateout_token().is_some() {
let Some(op_expr) = op.asm_operand_expr() else { continue };
let in_expr = self.collect_expr_opt(op_expr.in_expr());
let out_expr = op_expr.out_expr().map(|it| self.collect_expr(it));
match out_expr {
Some(out_expr) => AsmOperand::SplitInOut {
reg,
in_expr,
out_expr: Some(out_expr),
late: false,
},
None => AsmOperand::InOut { reg, expr: in_expr, late: false },
}
} else {
continue;
}
}
} else if dir_spec.inlateout_token().is_some() {
let Some(op_expr) = op.asm_operand_expr() else { continue };
let in_expr = self.collect_expr_opt(op_expr.in_expr());
let out_expr = op_expr.out_expr().map(|it| self.collect_expr(it));
match out_expr {
Some(out_expr) => AsmOperand::SplitInOut {
reg,
in_expr,
out_expr: Some(out_expr),
late: false,
},
None => AsmOperand::InOut { reg, expr: in_expr, late: false },
ast::AsmOperand::AsmLabel(l) => {
AsmOperand::Label(self.collect_block_opt(l.block_expr()))
}
ast::AsmOperand::AsmConst(c) => {
AsmOperand::Const(self.collect_expr_opt(c.expr()))
}
ast::AsmOperand::AsmSym(s) => {
let Some(path) =
s.path().and_then(|p| self.expander.parse_path(self.db, p))
else {
continue;
};
AsmOperand::Sym(path)
}
} else {
continue;
}
}
ast::AsmOperand::AsmLabel(l) => {
AsmOperand::Label(self.collect_block_opt(l.block_expr()))
}
ast::AsmOperand::AsmConst(c) => AsmOperand::Const(self.collect_expr_opt(c.expr())),
ast::AsmOperand::AsmSym(s) => {
let Some(path) = s.path().and_then(|p| self.expander.parse_path(self.db, p))
else {
continue;
};
AsmOperand::Sym(path)
}
};
operands.push(op);
}
Expand Down Expand Up @@ -192,7 +202,7 @@ impl ExprCollector<'_> {
rustc_parse_format::Piece::NextArgument(arg) => {
// let span = arg_spans.next();

let _operand_idx = match arg.position {
let operand_idx = match arg.position {
rustc_parse_format::ArgumentIs(idx)
| rustc_parse_format::ArgumentImplicitlyIs(idx) => {
if idx >= operands.len()
Expand All @@ -206,15 +216,15 @@ impl ExprCollector<'_> {
}
rustc_parse_format::ArgumentNamed(name) => {
let name = Symbol::intern(name);
if let Some(position_span) = to_span(arg.position_span) {
mappings.push((
position_span,
Name::new_symbol_root(name.clone()),
));
}
named_args.get(&name).copied()
}
};

if let Some(operand_idx) = operand_idx {
if let Some(position_span) = to_span(arg.position_span) {
mappings.push((position_span, operand_idx));
}
}
}
}
}
Expand All @@ -224,7 +234,7 @@ impl ExprCollector<'_> {
Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options }),
syntax_ptr,
);
self.source_map.format_args_template_map.insert(idx, mappings);
self.source_map.template_map.get_or_insert_with(Default::default).1.insert(idx, mappings);
idx
}
}
9 changes: 8 additions & 1 deletion src/tools/rust-analyzer/crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use hir_def::{
body::{BodyDiagnostic, SyntheticSyntax},
data::adt::VariantData,
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
lang_item::LangItemTarget,
layout::{self, ReprOptions, TargetDataLayout},
Expand Down Expand Up @@ -5246,6 +5246,13 @@ impl Type {
}
}

#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub struct InlineAsmOperand {
owner: DefWithBodyId,
expr: ExprId,
index: usize,
}

// FIXME: Document this
#[derive(Debug)]
pub struct Callable {
Expand Down
Loading

0 comments on commit f3b6965

Please sign in to comment.