]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/cabi_x86_64.rs
New upstream version 1.25.0+dfsg1
[rustc.git] / src / librustc_trans / cabi_x86_64.rs
CommitLineData
970d7e83 1// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
223e47cc
LB
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11// The classification code for the x86_64 ABI is taken from the clay language
12// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
13
ff7c6d11 14use abi::{ArgType, CastTarget, FnType, LayoutExt, Reg, RegKind};
2c00a5a8 15use context::CodegenCx;
223e47cc 16
ff7c6d11 17use rustc::ty::layout::{self, TyLayout, Size};
970d7e83 18
2c00a5a8
XL
19/// Classification of "eightbyte" components.
20// NB: the order of the variants is from general to specific,
21// such that `unify(a, b)` is the "smaller" of `a` and `b`.
22#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
cc61c64b 23enum Class {
cc61c64b
XL
24 Int,
25 Sse,
26 SseUp
970d7e83
LB
27}
28
cc61c64b
XL
29#[derive(Clone, Copy, Debug)]
30struct Memory;
970d7e83 31
abe05a73
XL
32// Currently supported vector size (AVX-512).
33const LARGEST_VECTOR_SIZE: usize = 512;
cc61c64b 34const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
223e47cc 35
2c00a5a8
XL
36fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>)
37 -> Result<[Option<Class>; MAX_EIGHTBYTES], Memory> {
38 fn classify<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
cc61c64b 39 layout: TyLayout<'tcx>,
2c00a5a8 40 cls: &mut [Option<Class>],
ff7c6d11 41 off: Size)
cc61c64b 42 -> Result<(), Memory> {
ff7c6d11
XL
43 if !off.is_abi_aligned(layout.align) {
44 if !layout.is_zst() {
cc61c64b 45 return Err(Memory);
1a4d82fc 46 }
cc61c64b 47 return Ok(());
223e47cc 48 }
223e47cc 49
2c00a5a8
XL
50 let mut c = match layout.abi {
51 layout::Abi::Uninhabited => return Ok(()),
ff7c6d11
XL
52
53 layout::Abi::Scalar(ref scalar) => {
2c00a5a8 54 match scalar.value {
ff7c6d11 55 layout::Int(..) |
cc61c64b
XL
56 layout::Pointer => Class::Int,
57 layout::F32 |
58 layout::F64 => Class::Sse
223e47cc 59 }
970d7e83 60 }
cc61c64b 61
2c00a5a8
XL
62 layout::Abi::Vector { .. } => Class::Sse,
63
ff7c6d11
XL
64 layout::Abi::ScalarPair(..) |
65 layout::Abi::Aggregate { .. } => {
66 match layout.variants {
67 layout::Variants::Single { .. } => {
68 for i in 0..layout.fields.count() {
69 let field_off = off + layout.fields.offset(i);
2c00a5a8 70 classify(cx, layout.field(cx, i), cls, field_off)?;
ff7c6d11 71 }
2c00a5a8 72 return Ok(());
cc61c64b 73 }
ff7c6d11
XL
74 layout::Variants::Tagged { .. } |
75 layout::Variants::NicheFilling { .. } => return Err(Memory),
85aaf69f
SL
76 }
77 }
85aaf69f 78
2c00a5a8
XL
79 };
80
81 // Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
82 let first = (off.bytes() / 8) as usize;
83 let last = ((off.bytes() + layout.size.bytes() - 1) / 8) as usize;
84 for cls in &mut cls[first..=last] {
85 *cls = Some(cls.map_or(c, |old| old.min(c)));
86
87 // Everything after the first Sse "eightbyte"
88 // component is the upper half of a register.
89 if c == Class::Sse {
90 c = Class::SseUp;
91 }
223e47cc 92 }
cc61c64b
XL
93
94 Ok(())
223e47cc
LB
95 }
96
ff7c6d11 97 let n = ((arg.layout.size.bytes() + 7) / 8) as usize;
cc61c64b
XL
98 if n > MAX_EIGHTBYTES {
99 return Err(Memory);
100 }
101
2c00a5a8
XL
102 let mut cls = [None; MAX_EIGHTBYTES];
103 classify(cx, arg.layout, &mut cls, Size::from_bytes(0))?;
cc61c64b 104 if n > 2 {
2c00a5a8 105 if cls[0] != Some(Class::Sse) {
cc61c64b
XL
106 return Err(Memory);
107 }
2c00a5a8 108 if cls[1..n].iter().any(|&c| c != Some(Class::SseUp)) {
cc61c64b
XL
109 return Err(Memory);
110 }
111 } else {
85aaf69f 112 let mut i = 0;
cc61c64b 113 while i < n {
2c00a5a8
XL
114 if cls[i] == Some(Class::SseUp) {
115 cls[i] = Some(Class::Sse);
116 } else if cls[i] == Some(Class::Sse) {
85aaf69f 117 i += 1;
2c00a5a8 118 while i != n && cls[i] == Some(Class::SseUp) { i += 1; }
970d7e83 119 } else {
cc61c64b 120 i += 1;
223e47cc
LB
121 }
122 }
123 }
124
cc61c64b 125 Ok(cls)
223e47cc
LB
126}
127
2c00a5a8 128fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg> {
cc61c64b
XL
129 if *i >= cls.len() {
130 return None;
223e47cc
LB
131 }
132
cc61c64b 133 match cls[*i] {
2c00a5a8
XL
134 None => None,
135 Some(Class::Int) => {
cc61c64b 136 *i += 1;
2c00a5a8
XL
137 Some(if size.bytes() < 8 {
138 Reg {
139 kind: RegKind::Integer,
140 size
141 }
142 } else {
143 Reg::i64()
cc61c64b 144 })
223e47cc 145 }
2c00a5a8
XL
146 Some(Class::Sse) => {
147 let vec_len = 1 + cls[*i+1..].iter()
148 .take_while(|&&c| c == Some(Class::SseUp))
149 .count();
cc61c64b
XL
150 *i += vec_len;
151 Some(if vec_len == 1 {
ff7c6d11 152 match size.bytes() {
cc61c64b
XL
153 4 => Reg::f32(),
154 _ => Reg::f64()
54a0048b 155 }
223e47cc 156 } else {
cc61c64b
XL
157 Reg {
158 kind: RegKind::Vector,
ff7c6d11 159 size: Size::from_bytes(8) * (vec_len as u64)
cc61c64b
XL
160 }
161 })
1a4d82fc 162 }
2c00a5a8 163 Some(c) => bug!("reg_component: unhandled class {:?}", c)
223e47cc 164 }
cc61c64b
XL
165}
166
2c00a5a8 167fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
cc61c64b
XL
168 let mut i = 0;
169 let lo = reg_component(cls, &mut i, size).unwrap();
ff7c6d11 170 let offset = Size::from_bytes(8) * (i as u64);
2c00a5a8
XL
171 let mut target = CastTarget::from(lo);
172 if size > offset {
173 if let Some(hi) = reg_component(cls, &mut i, size - offset) {
174 target = CastTarget::Pair(lo, hi);
175 }
176 }
ff7c6d11 177 assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None);
cc61c64b
XL
178 target
179}
223e47cc 180
2c00a5a8 181pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) {
b039eaaf
SL
182 let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
183 let mut sse_regs = 8; // XMM0-7
1a4d82fc 184
cc61c64b 185 let mut x86_64_ty = |arg: &mut ArgType<'tcx>, is_arg: bool| {
2c00a5a8 186 let mut cls_or_mem = classify_arg(cx, arg);
cc61c64b
XL
187
188 let mut needed_int = 0;
189 let mut needed_sse = 0;
2c00a5a8
XL
190 if is_arg {
191 if let Ok(cls) = cls_or_mem {
192 for &c in &cls {
cc61c64b 193 match c {
2c00a5a8
XL
194 Some(Class::Int) => needed_int += 1,
195 Some(Class::Sse) => needed_sse += 1,
cc61c64b
XL
196 _ => {}
197 }
198 }
2c00a5a8
XL
199 if arg.layout.is_aggregate() {
200 if int_regs < needed_int || sse_regs < needed_sse {
201 cls_or_mem = Err(Memory);
202 }
203 }
cc61c64b 204 }
2c00a5a8 205 }
cc61c64b 206
2c00a5a8
XL
207 match cls_or_mem {
208 Err(Memory) => {
209 if is_arg {
210 arg.make_indirect_byval();
211 } else {
212 // `sret` parameter thus one less integer register available
213 arg.make_indirect();
214 int_regs -= 1;
215 }
cc61c64b 216 }
2c00a5a8
XL
217 Ok(ref cls) => {
218 // split into sized chunks passed individually
219 int_regs -= needed_int;
220 sse_regs -= needed_sse;
221
222 if arg.layout.is_aggregate() {
223 let size = arg.layout.size;
224 arg.cast_to(cast_target(cls, size))
225 } else {
226 arg.extend_integer_width_to(32);
227 }
b039eaaf 228 }
cc61c64b
XL
229 }
230 };
231
232 if !fty.ret.is_ignore() {
233 x86_64_ty(&mut fty.ret, false);
54a0048b 234 }
1a4d82fc 235
54a0048b
SL
236 for arg in &mut fty.args {
237 if arg.is_ignore() { continue; }
cc61c64b 238 x86_64_ty(arg, true);
b039eaaf 239 }
223e47cc 240}