pub fn from_fn_attrs(
    cx: &CodegenCx<'ll, 'tcx>,
    llfn: &'ll Value,
    instance: ty::Instance<'tcx>,
    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) {
    let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());

    match codegen_fn_attrs.optimize {
        OptimizeAttr::None => {
            default_optimisation_attrs(cx.tcx.sess, llfn);
        }
        OptimizeAttr::Speed => {
            llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
            llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn);
            llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
        }
        OptimizeAttr::Size => {
            llvm::Attribute::MinSize.apply_llfn(Function, llfn);
            llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
            llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
        }
    }

    // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites).
    if instance.def.is_inline(cx.tcx) {
        inline(cx, llfn, attributes::InlineAttr::Hint);
    }

    inline(cx, llfn, codegen_fn_attrs.inline);

    // The `uwtable` attribute according to LLVM is:
    //
    //     This attribute indicates that the ABI being targeted requires that an
    //     unwind table entry be produced for this function even if we can show
    //     that no exceptions passes by it. This is normally the case for the
    //     ELF x86-64 abi, but it can be disabled for some compilation units.
    //
    // Typically when we're compiling with `-C panic=abort` (which implies this
    // `no_landing_pads` check) we don't need `uwtable` because we can't
    // generate any exceptions! On Windows, however, exceptions include other
    // events such as illegal instructions, segfaults, etc. This means that on
    // Windows we end up still needing the `uwtable` attribute even if the `-C
    // panic=abort` flag is passed.
    //
    // You can also find more info on why Windows is whitelisted here in:
    //      https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
    if !cx.sess().no_landing_pads() ||
       cx.sess().target.target.options.requires_uwtable {
        attributes::emit_uwtable(llfn, true);
    }

    set_frame_pointer_elimination(cx, llfn);
    set_instrument_function(cx, llfn);
    set_probestack(cx, llfn);

    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
        Attribute::Cold.apply_llfn(Function, llfn);
    }
    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
        Attribute::ReturnsTwice.apply_llfn(Function, llfn);
    }
    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
        naked(llfn, true);
    }
    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
        Attribute::NoAlias.apply_llfn(
            llvm::AttributePlace::ReturnValue, llfn);
    }

    unwind(llfn, if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind {
        // In panic=abort mode we assume nothing can unwind anywhere, so
        // optimize based on this!
        false
    } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) {
        // If a specific #[unwind] attribute is present, use that.
        true
    } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
        // Special attribute for allocator functions, which can't unwind.
        false
    } else {
        if fn_abi.conv == Conv::Rust {
            // Any Rust method (or `extern "Rust" fn` or `extern
            // "rust-call" fn`) is explicitly allowed to unwind
            // (unless it has no-unwind attribute, handled above).
            true
        } else {
            // Anything else is either:
            //
            //  1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or
            //
            //  2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`).
            //
            // Foreign items (case 1) are assumed to not unwind; it is
            // UB otherwise. (At least for now; see also
            // rust-lang/rust#63909 and Rust RFC 2753.)
            //
            // Items defined in Rust with non-Rust ABIs (case 2) are also
            // not supposed to unwind. Whether this should be enforced
            // (versus stating it is UB) and *how* it would be enforced
            // is currently under discussion; see rust-lang/rust#58794.
            //
            // In either case, we mark item as explicitly nounwind.
            false
        }
    });

    // Always annotate functions with the target-cpu they are compiled for.
    // Without this, ThinLTO won't inline Rust functions into Clang generated
    // functions (because Clang annotates functions this way too).
    apply_target_cpu_attr(cx, llfn);

    let features = llvm_target_features(cx.tcx.sess)
        .map(|s| s.to_string())
        .chain(
            codegen_fn_attrs.target_features
                .iter()
                .map(|f| {
                    let feature = &f.as_str();
                    format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
                })
        )
        .collect::<Vec<String>>()
        .join(",");

    if !features.is_empty() {
        let val = CString::new(features).unwrap();
        llvm::AddFunctionAttrStringValue(
            llfn, llvm::AttributePlace::Function,
            const_cstr!("target-features"), &val);
    }

    // Note that currently the `wasm-import-module` doesn't do anything, but
    // eventually LLVM 7 should read this and ferry the appropriate import
    // module to the output file.
    if cx.tcx.sess.target.target.arch == "wasm32" {
        if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
            llvm::AddFunctionAttrStringValue(
                llfn,
                llvm::AttributePlace::Function,
                const_cstr!("wasm-import-module"),
                &module,
            );

            let name = codegen_fn_attrs.link_name.unwrap_or_else(|| {
                cx.tcx.item_name(instance.def_id())
            });
            let name = CString::new(&name.as_str()[..]).unwrap();
            llvm::AddFunctionAttrStringValue(
                llfn,
                llvm::AttributePlace::Function,
                const_cstr!("wasm-import-name"),
                &name,
            );
        }
    }
}
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
/// attributes.
Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
attributes.
Composite function which sets LLVM attributes for function depending on its AST ( ` # [ attribute ] ` ) attributes .
pub fn from_fn_attrs(
    cx: &CodegenCx<'ll, 'tcx>,
    llfn: &'ll Value,
    instance: ty::Instance<'tcx>,
    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) {
    let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
    match codegen_fn_attrs.optimize {
        OptimizeAttr::None => {
            default_optimisation_attrs(cx.tcx.sess, llfn);
        }
        OptimizeAttr::Speed => {
            llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
            llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn);
            llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
        }
        OptimizeAttr::Size => {
            llvm::Attribute::MinSize.apply_llfn(Function, llfn);
            llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
            llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn);
        }
    }
    // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites).
    if instance.def.is_inline(cx.tcx) {
        inline(cx, llfn, attributes::InlineAttr::Hint);
    }
    inline(cx, llfn, codegen_fn_attrs.inline);
    // The `uwtable` attribute according to LLVM is:
    //
    //     This attribute indicates that the ABI being targeted requires that an
    //     unwind table entry be produced for this function even if we can show
    //     that no exceptions passes by it. This is normally the case for the
    //     ELF x86-64 abi, but it can be disabled for some compilation units.
    //
    // Typically when we're compiling with `-C panic=abort` (which implies this
    // `no_landing_pads` check) we don't need `uwtable` because we can't
    // generate any exceptions! On Windows, however, exceptions include other
    // events such as illegal instructions, segfaults, etc. This means that on
    // Windows we end up still needing the `uwtable` attribute even if the `-C
    // panic=abort` flag is passed.
    //
    // You can also find more info on why Windows is whitelisted here in:
    //      https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
    if !cx.sess().no_landing_pads() ||
       cx.sess().target.target.options.requires_uwtable {
        attributes::emit_uwtable(llfn, true);
    }
    set_frame_pointer_elimination(cx, llfn);
    set_instrument_function(cx, llfn);
    set_probestack(cx, llfn);
    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
        Attribute::Cold.apply_llfn(Function, llfn);
    }
    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
        Attribute::ReturnsTwice.apply_llfn(Function, llfn);
    }
    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
        naked(llfn, true);
    }
    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
        Attribute::NoAlias.apply_llfn(
            llvm::AttributePlace::ReturnValue, llfn);
    }
    unwind(llfn, if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind {
        // In panic=abort mode we assume nothing can unwind anywhere, so
        // optimize based on this!
        false
    } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) {
        // If a specific #[unwind] attribute is present, use that.
        true
    } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
        // Special attribute for allocator functions, which can't unwind.
        false
    } else {
        if fn_abi.conv == Conv::Rust {
            // Any Rust method (or `extern "Rust" fn` or `extern
            // "rust-call" fn`) is explicitly allowed to unwind
            // (unless it has no-unwind attribute, handled above).
            true
        } else {
            // Anything else is either:
            //
            //  1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or
            //
            //  2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`).
            //
            // Foreign items (case 1) are assumed to not unwind; it is
            // UB otherwise. (At least for now; see also
            // rust-lang/rust#63909 and Rust RFC 2753.)
            //
            // Items defined in Rust with non-Rust ABIs (case 2) are also
            // not supposed to unwind. Whether this should be enforced
            // (versus stating it is UB) and *how* it would be enforced
            // is currently under discussion; see rust-lang/rust#58794.
            //
            // In either case, we mark item as explicitly nounwind.
            false
        }
    });
    // Always annotate functions with the target-cpu they are compiled for.
    // Without this, ThinLTO won't inline Rust functions into Clang generated
    // functions (because Clang annotates functions this way too).
    apply_target_cpu_attr(cx, llfn);
    let features = llvm_target_features(cx.tcx.sess)
        .map(|s| s.to_string())
        .chain(
            codegen_fn_attrs.target_features
                .iter()
                .map(|f| {
                    let feature = &f.as_str();
                    format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
                })
        )
        .collect::<Vec<String>>()
        .join(",");
    if !features.is_empty() {
        let val = CString::new(features).unwrap();
        llvm::AddFunctionAttrStringValue(
            llfn, llvm::AttributePlace::Function,
            const_cstr!("target-features"), &val);
    }
    // Note that currently the `wasm-import-module` doesn't do anything, but
    // eventually LLVM 7 should read this and ferry the appropriate import
    // module to the output file.
    if cx.tcx.sess.target.target.arch == "wasm32" {
        if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
            llvm::AddFunctionAttrStringValue(
                llfn,
                llvm::AttributePlace::Function,
                const_cstr!("wasm-import-module"),
                &module,
            );
            let name = codegen_fn_attrs.link_name.unwrap_or_else(|| {
                cx.tcx.item_name(instance.def_id())
            });
            let name = CString::new(&name.as_str()[..]).unwrap();
            llvm::AddFunctionAttrStringValue(
                llfn,
                llvm::AttributePlace::Function,
                const_cstr!("wasm-import-name"),
                &name,
            );
        }
    }
}
pub fn from_fn_attrs ( cx : & CodegenCx < ' ll , ' tcx > , llfn : & ' ll Value , instance : ty :: Instance < ' tcx > , fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > , ) { let codegen_fn_attrs = cx . tcx . codegen_fn_attrs ( instance . def_id ( ) ) ; match codegen_fn_attrs . optimize { OptimizeAttr :: None => { default_optimisation_attrs ( cx . tcx . sess , llfn ) ; } OptimizeAttr :: Speed => { llvm :: Attribute :: MinSize . unapply_llfn ( Function , llfn ) ; llvm :: Attribute :: OptimizeForSize . unapply_llfn ( Function , llfn ) ; llvm :: Attribute :: OptimizeNone . unapply_llfn ( Function , llfn ) ; } OptimizeAttr :: Size => { llvm :: Attribute :: MinSize . apply_llfn ( Function , llfn ) ; llvm :: Attribute :: OptimizeForSize . apply_llfn ( Function , llfn ) ; llvm :: Attribute :: OptimizeNone . unapply_llfn ( Function , llfn ) ; } } // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites). if instance . def . is_inline ( cx . tcx ) { inline ( cx , llfn , attributes :: InlineAttr :: Hint ) ; } inline ( cx , llfn , codegen_fn_attrs . inline ) ; // The `uwtable` attribute according to LLVM is: // //     This attribute indicates that the ABI being targeted requires that an //     unwind table entry be produced for this function even if we can show //     that no exceptions passes by it. This is normally the case for the //     ELF x86-64 abi, but it can be disabled for some compilation units. // // Typically when we're compiling with `-C panic=abort` (which implies this // `no_landing_pads` check) we don't need `uwtable` because we can't // generate any exceptions! On Windows, however, exceptions include other // events such as illegal instructions, segfaults, etc. This means that on // Windows we end up still needing the `uwtable` attribute even if the `-C // panic=abort` flag is passed. // // You can also find more info on why Windows is whitelisted here in: //      https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if ! cx . sess ( ) . no_landing_pads ( ) || cx . sess ( ) . target . target . options . requires_uwtable { attributes :: emit_uwtable ( llfn , true ) ; } set_frame_pointer_elimination ( cx , llfn ) ; set_instrument_function ( cx , llfn ) ; set_probestack ( cx , llfn ) ; if codegen_fn_attrs . flags . contains ( CodegenFnAttrFlags :: COLD ) { Attribute :: Cold . apply_llfn ( Function , llfn ) ; } if codegen_fn_attrs . flags . contains ( CodegenFnAttrFlags :: FFI_RETURNS_TWICE ) { Attribute :: ReturnsTwice . apply_llfn ( Function , llfn ) ; } if codegen_fn_attrs . flags . contains ( CodegenFnAttrFlags :: NAKED ) { naked ( llfn , true ) ; } if codegen_fn_attrs . flags . contains ( CodegenFnAttrFlags :: ALLOCATOR ) { Attribute :: NoAlias . apply_llfn ( llvm :: AttributePlace :: ReturnValue , llfn ) ; } unwind ( llfn , if cx . tcx . sess . panic_strategy ( ) != PanicStrategy :: Unwind { // In panic=abort mode we assume nothing can unwind anywhere, so // optimize based on this! false } else if codegen_fn_attrs . flags . contains ( CodegenFnAttrFlags :: UNWIND ) { // If a specific #[unwind] attribute is present, use that. true } else if codegen_fn_attrs . flags . contains ( CodegenFnAttrFlags :: RUSTC_ALLOCATOR_NOUNWIND ) { // Special attribute for allocator functions, which can't unwind. false } else { if fn_abi . conv == Conv :: Rust { // Any Rust method (or `extern "Rust" fn` or `extern // "rust-call" fn`) is explicitly allowed to unwind // (unless it has no-unwind attribute, handled above). true } else { // Anything else is either: // //  1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or // //  2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`). // // Foreign items (case 1) are assumed to not unwind; it is // UB otherwise. (At least for now; see also // rust-lang/rust#63909 and Rust RFC 2753.) // // Items defined in Rust with non-Rust ABIs (case 2) are also // not supposed to unwind. Whether this should be enforced // (versus stating it is UB) and *how* it would be enforced // is currently under discussion; see rust-lang/rust#58794. // // In either case, we mark item as explicitly nounwind. false } } ) ; // Always annotate functions with the target-cpu they are compiled for. // Without this, ThinLTO won't inline Rust functions into Clang generated // functions (because Clang annotates functions this way too). apply_target_cpu_attr ( cx , llfn ) ; let features = llvm_target_features ( cx . tcx . sess ) . map ( | s | s . to_string ( ) ) . chain ( codegen_fn_attrs . target_features . iter ( ) . map ( | f | { let feature = & f . as_str ( ) ; format ! ( " " llvm_util to_llvm_feature ( cx tcx sess feature ) ) } ) ) . collect :: < Vec < String > > ( ) . join ( " " ) ; if ! features . is_empty ( ) { let val = CString :: new ( features ) . unwrap ( ) ; llvm :: AddFunctionAttrStringValue ( llfn , llvm :: AttributePlace :: Function , const_cstr ! ( " " ) , & val ) ; } // Note that currently the `wasm-import-module` doesn't do anything, but // eventually LLVM 7 should read this and ferry the appropriate import // module to the output file. if cx . tcx . sess . target . target . arch == " " { if let Some ( module ) = wasm_import_module ( cx . tcx , instance . def_id ( ) ) { llvm :: AddFunctionAttrStringValue ( llfn , llvm :: AttributePlace :: Function , const_cstr ! ( " " ) , & module , ) ; let name = codegen_fn_attrs . link_name . unwrap_or_else ( | | { cx . tcx . item_name ( instance . def_id ( ) ) } ) ; let name = CString :: new ( & name . as_str ( ) [ .. ] ) . unwrap ( ) ; llvm :: AddFunctionAttrStringValue ( llfn , llvm :: AttributePlace :: Function , const_cstr ! ( " " ) , & name , ) ; } } }
Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
attributes.
Composite function which sets LLVM attributes for function depending on its AST ( ` # [ attribute ] ` ) attributes .
cx
&CodegenCx<'ll, 'tcx>
llfn
&'ll Value
instance
ty::Instance<'tcx>
fn_abi
&FnAbi<'tcx, Ty<'tcx>>