Function argument attributes

I'm trying to add a new target-specific attribute that goes on function parameters that become an LLVM attribute (will add this to LLVM as well) in the signature.

Something like

#[fn_attr]
fn my_fn(a: u32, #[param_attr] b: u32) {
  // ...
}

Which should emit something like

; Function Attrs: fn_attr uwtable
define void @hello(i32 %a, i32 param_attr %b) unnamed_addr #0 {
start:
; ...
}

attributes #0 = { fn_attr uwtable "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="apple-m1" }


Adding fn_attr was pretty straightforward as there's plenty of precedent for function attributes, but there isn't a clear way to do this for function parameters. I've managed to hack something that passes the attribute through AST -> HIR -> THIR, but I'm a bit lost on how to do this in the MIR. My current guess is to change <TyCtxt as Interner>::Tys to be &'tcx List<(Attr, Ty<'tcx>)> where Attr is a new set of hard-coded attributes. These can then be available when mucking with the ArgAbi objects, which set the existing parameter LLVM attributes (e.g. noalias, nocapture, align etc.). Does this sound right or am I missing something?

2 Likes

You shouldn't have to add it to THIR and MIR, instead you should add a query called by codegen that then looks at the HIR (probably, maybe you want to store them a bit differently than on HIR, compare to the current implementation of otjer attributes).

You were right, I didn't need to mess with THIR. I was trying to cram the attributes on hir::Param rather than hir::FnDef, which meant I couldn't get them onto ty::FnSig so LLVM codegen would see them.

I didn't make a new query, but rather modified the existing fn_abi_of_instance query, which is already choosing what LLVM attributes go on parameters.

I see now that what I was doing is a dirty hack and not the correct way to do this. I should just call a new method in predefine_fn that updates the parameter attributes from the HIR.