(index<- )        ./librustc/middle/trans/cabi_x86_64.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Wed Apr  9 17:27:02 2014
   1  // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
   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  
  14  #![allow(non_uppercase_pattern_statics)]
  15  
  16  use lib::llvm::{llvm, Integer, Pointer, Float, Double};
  17  use lib::llvm::{Struct, Array, Attribute};
  18  use lib::llvm::{StructRetAttribute, ByValAttribute};
  19  use middle::trans::cabi::*;
  20  use middle::trans::context::CrateContext;
  21  use middle::trans::type_::Type;
  22  
  23  use std::cmp;
  24  
  25  #[deriving(Clone, Eq)]
  26  enum RegClass {
  27      NoClass,
  28      Int,
  29      SSEFs,
  30      SSEFv,
  31      SSEDs,
  32      SSEDv,
  33      SSEInt,
  34      SSEUp,
  35      X87,
  36      X87Up,
  37      ComplexX87,
  38      Memory
  39  }
  40  
  41  trait TypeMethods {
  42      fn is_reg_ty(&self) -> bool;
  43  }
  44  
  45  impl TypeMethods for Type {
  46      fn is_reg_ty(&self) -> bool {
  47          match self.kind() {
  48              Integer | Pointer | Float | Double => true,
  49              _ => false
  50          }
  51      }
  52  }
  53  
  54  impl RegClass {
  55      fn is_sse(&self) -> bool {
  56          match *self {
  57              SSEFs | SSEFv | SSEDs | SSEDv => true,
  58              _ => false
  59          }
  60      }
  61  }
  62  
  63  trait ClassList {
  64      fn is_pass_byval(&self) -> bool;
  65      fn is_ret_bysret(&self) -> bool;
  66  }
  67  
  68  impl<'a> ClassList for &'a [RegClass{
  69      fn is_pass_byval(&self) -> bool {
  70          if self.len() == 0 { return false; }
  71  
  72          let class = self[0];
  73             class == Memory
  74          || class == X87
  75          || class == ComplexX87
  76      }
  77  
  78      fn is_ret_bysret(&self) -> bool {
  79          if self.len() == 0 { return false; }
  80  
  81          self[0] == Memory
  82      }
  83  }
  84  
  85  fn classify_ty(tyType) -> Vec<RegClass> {
  86      fn align(offuint, tyType) -> uint {
  87          let a = ty_align(ty);
  88          return (off + a - 1u) / a * a;
  89      }
  90  
  91      fn ty_align(tyType) -> uint {
  92          match ty.kind() {
  93              Integer => {
  94                  unsafe {
  95                      ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
  96                  }
  97              }
  98              Pointer => 8,
  99              Float => 4,
 100              Double => 8,
 101              Struct => {
 102                if ty.is_packed() {
 103                  1
 104                } else {
 105                  let str_tys = ty.field_types();
 106                  str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
 107                }
 108              }
 109              Array => {
 110                  let elt = ty.element_type();
 111                  ty_align(elt)
 112              }
 113              _ => fail!("ty_size: unhandled type")
 114          }
 115      }
 116  
 117      fn ty_size(tyType) -> uint {
 118          match ty.kind() {
 119              Integer => {
 120                  unsafe {
 121                      ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
 122                  }
 123              }
 124              Pointer => 8,
 125              Float => 4,
 126              Double => 8,
 127              Struct => {
 128                  let str_tys = ty.field_types();
 129                  if ty.is_packed() {
 130                      str_tys.iter().fold(0, |s, t| s + ty_size(*t))
 131                  } else {
 132                      let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
 133                      align(size, ty)
 134                  }
 135              }
 136              Array => {
 137                  let len = ty.array_length();
 138                  let elt = ty.element_type();
 139                  let eltsz = ty_size(elt);
 140                  len * eltsz
 141              }
 142              _ => fail!("ty_size: unhandled type")
 143          }
 144      }
 145  
 146      fn all_mem(cls&mut [RegClass]) {
 147          for elt in cls.mut_iter() {
 148              *elt = Memory;
 149          }
 150      }
 151  
 152      fn unify(cls&mut [RegClass],
 153               iuint,
 154               newvRegClass) {
 155          if cls[i] == newv {
 156              return;
 157          } else if cls[i] == NoClass {
 158              cls[i] = newv;
 159          } else if newv == NoClass {
 160              return;
 161          } else if cls[i] == Memory || newv == Memory {
 162              cls[i] = Memory;
 163          } else if cls[i] == Int || newv == Int {
 164              cls[i] = Int;
 165          } else if cls[i] == X87 ||
 166                    cls[i] == X87Up ||
 167                    cls[i] == ComplexX87 ||
 168                    newv == X87 ||
 169                    newv == X87Up ||
 170                    newv == ComplexX87 {
 171              cls[i] = Memory;
 172          } else {
 173              cls[i] = newv;
 174          }
 175      }
 176  
 177      fn classify_struct(tys&[Type],
 178                         cls&mut [RegClass], iuint,
 179                         offuint) {
 180          let mut field_off = off;
 181          for ty in tys.iter() {
 182              field_off = align(field_off, *ty);
 183              classify(*ty, cls, i, field_off);
 184              field_off += ty_size(*ty);
 185          }
 186      }
 187  
 188      fn classify(tyType,
 189                  cls&mut [RegClass], ixuint,
 190                  offuint) {
 191          let t_align = ty_align(ty);
 192          let t_size = ty_size(ty);
 193  
 194          let misalign = off % t_align;
 195          if misalign != 0u {
 196              let mut i = off / 8u;
 197              let e = (off + t_size + 7u) / 8u;
 198              while i < e {
 199                  unify(cls, ix + i, Memory);
 200                  i += 1u;
 201              }
 202              return;
 203          }
 204  
 205          match ty.kind() {
 206              Integer |
 207              Pointer => {
 208                  unify(cls, ix + off / 8u, Int);
 209              }
 210              Float => {
 211                  if off % 8u == 4u {
 212                      unify(cls, ix + off / 8u, SSEFv);
 213                  } else {
 214                      unify(cls, ix + off / 8u, SSEFs);
 215                  }
 216              }
 217              Double => {
 218                  unify(cls, ix + off / 8u, SSEDs);
 219              }
 220              Struct => {
 221                  classify_struct(ty.field_types().as_slice(), cls, ix, off);
 222              }
 223              Array => {
 224                  let len = ty.array_length();
 225                  let elt = ty.element_type();
 226                  let eltsz = ty_size(elt);
 227                  let mut i = 0u;
 228                  while i < len {
 229                      classify(elt, cls, ix, off + i * eltsz);
 230                      i += 1u;
 231                  }
 232              }
 233              _ => fail!("classify: unhandled type")
 234          }
 235      }
 236  
 237      fn fixup(tyType, cls&mut [RegClass]) {
 238          let mut i = 0u;
 239          let ty_kind = ty.kind();
 240          let e = cls.len();
 241          if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array) {
 242              if cls[i].is_sse() {
 243                  i += 1u;
 244                  while i < e {
 245                      if cls[i] != SSEUp {
 246                          all_mem(cls);
 247                          return;
 248                      }
 249                      i += 1u;
 250                  }
 251              } else {
 252                  all_mem(cls);
 253                  return
 254              }
 255          } else {
 256              while i < e {
 257                  if cls[i] == Memory {
 258                      all_mem(cls);
 259                      return;
 260                  }
 261                  if cls[i] == X87Up {
 262                      // for darwin
 263                      // cls[i] = SSEDs;
 264                      all_mem(cls);
 265                      return;
 266                  }
 267                  if cls[i] == SSEUp {
 268                      cls[i] = SSEDv;
 269                  } else if cls[i].is_sse() {
 270                      i += 1;
 271                      while i != e && cls[i] == SSEUp { i += 1u; }
 272                  } else if cls[i] == X87 {
 273                      i += 1;
 274                      while i != e && cls[i] == X87Up { i += 1u; }
 275                  } else {
 276                      i += 1;
 277                  }
 278              }
 279          }
 280      }
 281  
 282      let words = (ty_size(ty) + 7) / 8;
 283      let mut cls = Vec::from_elem(words, NoClass);
 284      if words > 4 {
 285          all_mem(cls.as_mut_slice());
 286          return cls;
 287      }
 288      classify(ty, cls.as_mut_slice(), 0, 0);
 289      fixup(ty, cls.as_mut_slice());
 290      return cls;
 291  }
 292  
 293  fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
 294      fn llvec_len(cls&[RegClass]) -> uint {
 295          let mut len = 1u;
 296          for c in cls.iter() {
 297              if *c != SSEUp {
 298                  break;
 299              }
 300              len += 1u;
 301          }
 302          return len;
 303      }
 304  
 305      let mut tys = Vec::new();
 306      let mut i = 0u;
 307      let e = cls.len();
 308      while i < e {
 309          match cls[i] {
 310              Int => {
 311                  tys.push(Type::i64(ccx));
 312              }
 313              SSEFv => {
 314                  let vec_len = llvec_len(cls.tailn(i + 1u));
 315                  let vec_ty = Type::vector(&Type::f32(ccx), (vec_len * 2u) as u64);
 316                  tys.push(vec_ty);
 317                  i += vec_len;
 318                  continue;
 319              }
 320              SSEFs => {
 321                  tys.push(Type::f32(ccx));
 322              }
 323              SSEDs => {
 324                  tys.push(Type::f64(ccx));
 325              }
 326              _ => fail!("llregtype: unhandled class")
 327          }
 328          i += 1u;
 329      }
 330      return Type::struct_(ccx, tys.as_slice(), false);
 331  }
 332  
 333  pub fn compute_abi_info(ccx: &CrateContext,
 334                          atys: &[Type],
 335                          rtyType,
 336                          ret_def: bool) -> FnType {
 337      fn x86_64_ty(ccx&CrateContext,
 338                   tyType,
 339                   is_mem_cls|cls: &[RegClass]-> bool,
 340                   attrAttribute)
 341                   -> ArgType {
 342          if !ty.is_reg_ty() {
 343              let cls = classify_ty(ty);
 344              if is_mem_cls(cls.as_slice()) {
 345                  ArgType::indirect(ty, Some(attr))
 346              } else {
 347                  ArgType::direct(ty,
 348                                  Some(llreg_ty(ccx, cls.as_slice())),
 349                                  None,
 350                                  None)
 351              }
 352          } else {
 353              ArgType::direct(ty, None, None, None)
 354          }
 355      }
 356  
 357      let mut arg_tys = Vec::new();
 358      for t in atys.iter() {
 359          let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), ByValAttribute);
 360          arg_tys.push(ty);
 361      }
 362  
 363      let ret_ty = if ret_def {
 364          x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), StructRetAttribute)
 365      } else {
 366          ArgType::direct(Type::void(ccx), None, None, None)
 367      };
 368  
 369      return FnType {
 370          arg_tys: arg_tys,
 371          ret_ty: ret_ty,
 372      };
 373  }


librustc/middle/trans/cabi_x86_64.rs:117:4-117:4 -fn- definition:
    fn ty_size(ty: Type) -> uint {
        match ty.kind() {
            Integer => {
references:- 7
131:                 } else {
132:                     let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
133:                     align(size, ty)
--
138:                 let elt = ty.element_type();
139:                 let eltsz = ty_size(elt);
140:                 len * eltsz
--
191:         let t_align = ty_align(ty);
192:         let t_size = ty_size(ty);
--
225:                 let elt = ty.element_type();
226:                 let eltsz = ty_size(elt);
227:                 let mut i = 0u;
--
282:     let words = (ty_size(ty) + 7) / 8;
283:     let mut cls = Vec::from_elem(words, NoClass);


librustc/middle/trans/cabi_x86_64.rs:86:4-86:4 -fn- definition:
    fn align(off: uint, ty: Type) -> uint {
        let a = ty_align(ty);
        return (off + a - 1u) / a * a;
references:- 3
181:         for ty in tys.iter() {
182:             field_off = align(field_off, *ty);
183:             classify(*ty, cls, i, field_off);


librustc/middle/trans/cabi_x86_64.rs:152:4-152:4 -fn- definition:
    fn unify(cls: &mut [RegClass],
             i: uint,
             newv: RegClass) {
references:- 5
217:             Double => {
218:                 unify(cls, ix + off / 8u, SSEDs);
219:             }


librustc/middle/trans/cabi_x86_64.rs:91:4-91:4 -fn- definition:
    fn ty_align(ty: Type) -> uint {
        match ty.kind() {
            Integer => {
references:- 4
190:                 off: uint) {
191:         let t_align = ty_align(ty);
192:         let t_size = ty_size(ty);


librustc/middle/trans/cabi_x86_64.rs:337:4-337:4 -fn- definition:
    fn x86_64_ty(ccx: &CrateContext,
                 ty: Type,
                 is_mem_cls: |cls: &[RegClass]| -> bool,
references:- 2
358:     for t in atys.iter() {
359:         let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), ByValAttribute);
360:         arg_tys.push(ty);
--
363:     let ret_ty = if ret_def {
364:         x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), StructRetAttribute)
365:     } else {


librustc/middle/trans/cabi_x86_64.rs:25:23-25:23 -enum- definition:
enum RegClass {
    NoClass,
    Int,
references:- 17
153:              i: uint,
154:              newv: RegClass) {
155:         if cls[i] == newv {
--
188:     fn classify(ty: Type,
189:                 cls: &mut [RegClass], ix: uint,
190:                 off: uint) {
--
293: fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
294:     fn llvec_len(cls: &[RegClass]) -> uint {
--
338:                  ty: Type,
339:                  is_mem_cls: |cls: &[RegClass]| -> bool,
340:                  attr: Attribute)


librustc/middle/trans/cabi_x86_64.rs:188:4-188:4 -fn- definition:
    fn classify(ty: Type,
                cls: &mut [RegClass], ix: uint,
                off: uint) {
references:- 3
182:             field_off = align(field_off, *ty);
183:             classify(*ty, cls, i, field_off);
184:             field_off += ty_size(*ty);
--
228:                 while i < len {
229:                     classify(elt, cls, ix, off + i * eltsz);
230:                     i += 1u;
--
287:     }
288:     classify(ty, cls.as_mut_slice(), 0, 0);
289:     fixup(ty, cls.as_mut_slice());


librustc/middle/trans/cabi_x86_64.rs:146:4-146:4 -fn- definition:
    fn all_mem(cls: &mut [RegClass]) {
        for elt in cls.mut_iter() {
            *elt = Memory;
references:- 5
284:     if words > 4 {
285:         all_mem(cls.as_mut_slice());
286:         return cls;