Skip to content

Commit 0511778

Browse files
committed
Add support for setting the inline attribute
1 parent efe476e commit 0511778

File tree

4 files changed

+200
-140
lines changed

4 files changed

+200
-140
lines changed

gcc-test-backend/src/main.rs

Lines changed: 0 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,2 @@
11
fn main() {
2-
let a = [0, 0, 3]; // FIXME: This is casted to 0x7fff00000003. Seems like Rust is generating the code for this (but it could be the memcmp gcc builtin).
3-
let b = [0, 0, 3];
4-
/*let a = [1, 2, 3];
5-
let b = [1, 2, 3];*/
6-
7-
assert_eq!(a, b);
82
}
9-
10-
/*#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
11-
12-
use std::arch::x86_64::*;
13-
14-
fn main() {
15-
unsafe {
16-
test_simd();
17-
}
18-
}
19-
20-
#[target_feature(enable = "sse2")]
21-
unsafe fn test_simd() {
22-
/*let x = _mm_setzero_si128();
23-
let y = _mm_set1_epi16(7);
24-
let or = _mm_or_si128(x, y);
25-
let cmp_eq = _mm_cmpeq_epi8(y, y);
26-
let cmp_lt = _mm_cmplt_epi8(y, y);*/
27-
28-
/*assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
29-
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
30-
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);*/
31-
32-
/*test_mm_slli_si128();
33-
test_mm_movemask_epi8();
34-
test_mm256_movemask_epi8();*/
35-
test_mm_add_epi8();
36-
test_mm_add_pd();
37-
/*test_mm_cvtepi8_epi16();
38-
test_mm_cvtsi128_si64();
39-
40-
// FIXME(#666) implement `#[rustc_arg_required_const(..)]` support
41-
//test_mm_extract_epi8();
42-
43-
let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
44-
assert_eq!(mask1, 1);*/
45-
}
46-
47-
#[target_feature(enable = "sse2")]
48-
unsafe fn test_mm_slli_si128() {
49-
let a = _mm_setr_epi8(
50-
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
51-
);
52-
let r = _mm_slli_si128(a, 1);
53-
let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
54-
assert_eq_m128i(r, e);
55-
56-
let a = _mm_setr_epi8(
57-
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
58-
);
59-
let r = _mm_slli_si128(a, 15);
60-
let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
61-
assert_eq_m128i(r, e);
62-
63-
let a = _mm_setr_epi8(
64-
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
65-
);
66-
let r = _mm_slli_si128(a, 16);
67-
assert_eq_m128i(r, _mm_set1_epi8(0));
68-
69-
let a = _mm_setr_epi8(
70-
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
71-
);
72-
let r = _mm_slli_si128(a, -1);
73-
assert_eq_m128i(_mm_set1_epi8(0), r);
74-
75-
let a = _mm_setr_epi8(
76-
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
77-
);
78-
let r = _mm_slli_si128(a, -0x80000000);
79-
assert_eq_m128i(r, _mm_set1_epi8(0));
80-
}
81-
82-
#[target_feature(enable = "sse2")]
83-
unsafe fn test_mm_movemask_epi8() {
84-
let a = _mm_setr_epi8(
85-
0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01,
86-
0b0101, 0b1111_0000u8 as i8, 0, 0,
87-
0, 0, 0b1111_0000u8 as i8, 0b0101,
88-
0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8,
89-
);
90-
let r = _mm_movemask_epi8(a);
91-
assert_eq!(r, 0b10100100_00100101);
92-
}
93-
94-
#[target_feature(enable = "avx2")]
95-
unsafe fn test_mm256_movemask_epi8() {
96-
let a = _mm256_set1_epi8(-1);
97-
let r = _mm256_movemask_epi8(a);
98-
let e = -1;
99-
assert_eq!(r, e);
100-
}
101-
102-
#[target_feature(enable = "sse2")]
103-
unsafe fn test_mm_add_epi8() {
104-
let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
105-
let b = _mm_setr_epi8(
106-
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
107-
);
108-
let r = _mm_add_epi8(a, b);
109-
let e = _mm_setr_epi8(
110-
16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
111-
);
112-
assert_eq_m128i(r, e);
113-
}
114-
115-
#[target_feature(enable = "sse2")]
116-
unsafe fn test_mm_add_pd() {
117-
let a = _mm_setr_pd(1.0, 2.0);
118-
let b = _mm_setr_pd(5.0, 10.0);
119-
let r = _mm_add_pd(a, b);
120-
assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
121-
}
122-
123-
fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
124-
unsafe {
125-
assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y));
126-
}
127-
}
128-
129-
#[target_feature(enable = "sse2")]
130-
pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
131-
if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
132-
panic!("{:?} != {:?}", a, b);
133-
}
134-
}
135-
136-
#[target_feature(enable = "sse2")]
137-
unsafe fn test_mm_cvtsi128_si64() {
138-
let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0]));
139-
assert_eq!(r, 5);
140-
}
141-
*/

src/attributes.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
use gccjit::{Function, InlineMode};
2+
use rustc_attr::InlineAttr;
3+
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
4+
use rustc_middle::ty::{self, layout::HasTyCtxt};
5+
6+
use crate::context::CodegenCx;
7+
8+
/// Mark GCC function to use provided inline heuristic.
9+
#[inline]
10+
fn inline<'gcc>(cx: &CodegenCx<'gcc, '_>, function: Function<'gcc>, inline: InlineAttr) {
11+
use self::InlineAttr::*;
12+
match inline {
13+
Hint => function.set_inline_mode(InlineMode::Inline),
14+
Always => function.set_inline_mode(InlineMode::AlwaysInline),
15+
Never => {
16+
if cx.tcx().sess.target.arch != "amdgpu" {
17+
function.set_inline_mode(InlineMode::NoInline);
18+
}
19+
}
20+
None => {}
21+
};
22+
}
23+
24+
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
25+
/// attributes.
26+
pub fn from_fn_attrs<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, func: Function<'gcc>, instance: ty::Instance<'tcx>) {
27+
let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
28+
29+
/*match codegen_fn_attrs.optimize {
30+
OptimizeAttr::None => {
31+
default_optimisation_attrs(cx.tcx.sess, func);
32+
}
33+
OptimizeAttr::Speed => {
34+
llvm::Attribute::MinSize.unapply_llfn(Function, func);
35+
llvm::Attribute::OptimizeForSize.unapply_llfn(Function, func);
36+
llvm::Attribute::OptimizeNone.unapply_llfn(Function, func);
37+
}
38+
OptimizeAttr::Size => {
39+
llvm::Attribute::MinSize.apply_llfn(Function, func);
40+
llvm::Attribute::OptimizeForSize.apply_llfn(Function, func);
41+
llvm::Attribute::OptimizeNone.unapply_llfn(Function, func);
42+
}
43+
}*/
44+
45+
let inline_attr =
46+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
47+
InlineAttr::Never
48+
}
49+
else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
50+
InlineAttr::Hint
51+
}
52+
else {
53+
codegen_fn_attrs.inline
54+
};
55+
inline(cx, func, inline_attr);
56+
57+
// The `uwtable` attribute according to LLVM is:
58+
//
59+
// This attribute indicates that the ABI being targeted requires that an
60+
// unwind table entry be produced for this function even if we can show
61+
// that no exceptions passes by it. This is normally the case for the
62+
// ELF x86-64 abi, but it can be disabled for some compilation units.
63+
//
64+
// Typically when we're compiling with `-C panic=abort` (which implies this
65+
// `no_landing_pads` check) we don't need `uwtable` because we can't
66+
// generate any exceptions! On Windows, however, exceptions include other
67+
// events such as illegal instructions, segfaults, etc. This means that on
68+
// Windows we end up still needing the `uwtable` attribute even if the `-C
69+
// panic=abort` flag is passed.
70+
//
71+
// You can also find more info on why Windows always requires uwtables here:
72+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
73+
/*if cx.sess().must_emit_unwind_tables() {
74+
attributes::emit_uwtable(func, true);
75+
}
76+
77+
// FIXME: none of these three functions interact with source level attributes.
78+
set_frame_pointer_elimination(cx, func);
79+
set_instrument_function(cx, func);
80+
set_probestack(cx, func);
81+
82+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
83+
Attribute::Cold.apply_llfn(Function, func);
84+
}
85+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
86+
Attribute::ReturnsTwice.apply_llfn(Function, func);
87+
}
88+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
89+
Attribute::ReadOnly.apply_llfn(Function, func);
90+
}
91+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
92+
Attribute::ReadNone.apply_llfn(Function, func);
93+
}
94+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
95+
naked(func, true);
96+
}
97+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
98+
Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, func);
99+
}
100+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
101+
llvm::AddFunctionAttrString(func, Function, cstr!("cmse_nonsecure_entry"));
102+
}
103+
if let Some(align) = codegen_fn_attrs.alignment {
104+
llvm::set_alignment(func, align as usize);
105+
}
106+
sanitize(cx, codegen_fn_attrs.no_sanitize, func);
107+
108+
// Always annotate functions with the target-cpu they are compiled for.
109+
// Without this, ThinLTO won't inline Rust functions into Clang generated
110+
// functions (because Clang annotates functions this way too).
111+
apply_target_cpu_attr(cx, func);
112+
// tune-cpu is only conveyed through the attribute for our purpose.
113+
// The target doesn't care; the subtarget reads our attribute.
114+
apply_tune_cpu_attr(cx, func);
115+
116+
let mut function_features = codegen_fn_attrs
117+
.target_features
118+
.iter()
119+
.map(|f| {
120+
let feature = &f.as_str();
121+
format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
122+
})
123+
.chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
124+
InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
125+
InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
126+
}))
127+
.collect::<Vec<String>>();
128+
129+
if cx.tcx.sess.target.is_like_wasm {
130+
// If this function is an import from the environment but the wasm
131+
// import has a specific module/name, apply them here.
132+
if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
133+
llvm::AddFunctionAttrStringValue(
134+
func,
135+
llvm::AttributePlace::Function,
136+
cstr!("wasm-import-module"),
137+
&module,
138+
);
139+
140+
let name =
141+
codegen_fn_attrs.link_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id()));
142+
let name = CString::new(&name.as_str()[..]).unwrap();
143+
llvm::AddFunctionAttrStringValue(
144+
func,
145+
llvm::AttributePlace::Function,
146+
cstr!("wasm-import-name"),
147+
&name,
148+
);
149+
}
150+
151+
// The `"wasm"` abi on wasm targets automatically enables the
152+
// `+multivalue` feature because the purpose of the wasm abi is to match
153+
// the WebAssembly specification, which has this feature. This won't be
154+
// needed when LLVM enables this `multivalue` feature by default.
155+
if !cx.tcx.is_closure(instance.def_id()) {
156+
let abi = cx.tcx.fn_sig(instance.def_id()).abi();
157+
if abi == Abi::Wasm {
158+
function_features.push("+multivalue".to_string());
159+
}
160+
}
161+
}
162+
163+
if !function_features.is_empty() {
164+
let mut global_features = llvm_util::llvm_global_features(cx.tcx.sess);
165+
global_features.extend(function_features.into_iter());
166+
let features = global_features.join(",");
167+
let val = CString::new(features).unwrap();
168+
llvm::AddFunctionAttrStringValue(
169+
func,
170+
llvm::AttributePlace::Function,
171+
cstr!("target-features"),
172+
&val,
173+
);
174+
}*/
175+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
/*extern crate flate2;
1717
extern crate libc;*/
1818
extern crate rustc_ast;
19+
extern crate rustc_attr;
1920
extern crate rustc_codegen_ssa;
2021
extern crate rustc_data_structures;
2122
extern crate rustc_errors;
@@ -35,6 +36,7 @@ extern crate rustc_driver;
3536
mod abi;
3637
mod allocator;
3738
mod archive;
39+
mod attributes;
3840
mod asm;
3941
mod back;
4042
mod base;

src/mono_item.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use gccjit::{Function, ToRValue};
2+
use rustc_attr::InlineAttr;
13
use rustc_codegen_ssa::traits::PreDefineMethods;
24
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
35
use rustc_middle::mir::mono::{Linkage, Visibility};
@@ -7,7 +9,9 @@ use rustc_span::def_id::DefId;
79
use rustc_target::abi::LayoutOf;
810
use rustc_target::abi::call::FnAbi;
911

12+
use crate::attributes;
1013
use crate::base;
14+
use crate::common::TypeReflection;
1115
use crate::context::CodegenCx;
1216
use crate::type_of::LayoutGccExt;
1317

@@ -51,8 +55,26 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
5155

5256
//debug!("predefine_fn: instance = {:?}", instance);
5357

58+
let func: Function = unsafe { std::mem::transmute(decl) };
59+
60+
let mut set_attributes = true;
61+
for i in 0..func.get_param_count() {
62+
let param = func.get_param(i as i32);
63+
// FIXME: 128-bit integers seem to break inlining in libgccjit.
64+
// Here's an example function that causes the ICE:
65+
// #[inline(always)]
66+
// pub fn overflowing_add(a: i128, b: i128) -> (i128, bool) {
67+
// (a + b, false)
68+
// }
69+
if param.to_rvalue().get_type().is_u128(self) || param.to_rvalue().get_type().is_i128(self) {
70+
set_attributes = false;
71+
}
72+
}
73+
5474
// TODO: use inline attribute from there in linkage.set() above:
55-
//attributes::from_fn_attrs(self, decl, instance);
75+
if set_attributes {
76+
attributes::from_fn_attrs(self, func, instance);
77+
}
5678

5779
//self.instances.borrow_mut().insert(instance, decl);
5880
}

0 commit comments

Comments
 (0)