Skip to content

Commit 4c39962

Browse files
committed
auto merge of #15005 : dotdash/rust/i1_bool, r=alexcrichton
We currently compiled bools to i8 values, because there was a bug in LLVM that sometimes caused miscompilations when using i1 in, for example, structs. Using i8 means a lot of unnecessary zero-extend and truncate operations though, since we have to convert the value from and to i1 when using for example icmp or br instructions. Besides the unnecessary overhead caused by this, it also sometimes made LLVM miss some optimizations. First, we have to fix some bugs concerning the handling of attributes in foreign function declarations and calls. These are required because the i1 type needs the ZExt attribute when used as a function parameter or return type. Then we have to update LLVM to get a bugfix without which LLVM sometimes generates broken code when using i1. And then, finally, we can switch bools over to i1.
2 parents db9af1d + d747de5 commit 4c39962

19 files changed

+155
-99
lines changed

src/librustc/middle/trans/_match.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -1200,8 +1200,6 @@ fn pick_col(m: &[Match]) -> uint {
12001200
pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len, }
12011201

12021202
// Compiles a comparison between two things.
1203-
//
1204-
// NB: This must produce an i1, not a Rust bool (i8).
12051203
fn compare_values<'a>(
12061204
cx: &'a Block<'a>,
12071205
lhs: ValueRef,
@@ -1218,11 +1216,7 @@ fn compare_values<'a>(
12181216
format!("comparison of `{}`",
12191217
cx.ty_to_str(rhs_t)).as_slice(),
12201218
StrEqFnLangItem);
1221-
let result = callee::trans_lang_call(cx, did, [lhs, rhs], None);
1222-
Result {
1223-
bcx: result.bcx,
1224-
val: bool_to_i1(result.bcx, result.val)
1225-
}
1219+
callee::trans_lang_call(cx, did, [lhs, rhs], None)
12261220
}
12271221

12281222
let _icx = push_ctxt("compare_values");
@@ -1243,11 +1237,7 @@ fn compare_values<'a>(
12431237
format!("comparison of `{}`",
12441238
cx.ty_to_str(rhs_t)).as_slice(),
12451239
UniqStrEqFnLangItem);
1246-
let result = callee::trans_lang_call(cx, did, [scratch_lhs, scratch_rhs], None);
1247-
Result {
1248-
bcx: result.bcx,
1249-
val: bool_to_i1(result.bcx, result.val)
1250-
}
1240+
callee::trans_lang_call(cx, did, [scratch_lhs, scratch_rhs], None)
12511241
}
12521242
_ => cx.sess().bug("only strings supported in compare_values"),
12531243
},

src/librustc/middle/trans/base.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,6 @@ pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
501501
// Used only for creating scalar comparison glue.
502502
pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
503503

504-
// NB: This produces an i1, not a Rust bool (i8).
505504
pub fn compare_scalar_types<'a>(
506505
cx: &'a Block<'a>,
507506
lhs: ValueRef,
@@ -1815,6 +1814,13 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) -> Vec<(uint, u6
18151814
}
18161815
_ => {}
18171816
}
1817+
1818+
match ty::get(ret_ty).sty {
1819+
ty::ty_bool => {
1820+
attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::ZExtAttribute as u64));
1821+
}
1822+
_ => {}
1823+
}
18181824
}
18191825

18201826
for (idx, &t) in fn_sig.inputs.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) {
@@ -1828,6 +1834,9 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) -> Vec<(uint, u6
18281834
attrs.push((idx, lib::llvm::NoCaptureAttribute as u64));
18291835
attrs.push((idx, lib::llvm::NonNullAttribute as u64));
18301836
}
1837+
ty::ty_bool => {
1838+
attrs.push((idx, lib::llvm::ZExtAttribute as u64));
1839+
}
18311840
// `~` pointer parameters never alias because ownership is transferred
18321841
ty::ty_uniq(_) => {
18331842
attrs.push((idx, lib::llvm::NoAliasAttribute as u64));

src/librustc/middle/trans/cabi_arm.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#![allow(non_uppercase_pattern_statics)]
1212

1313
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
14-
use lib::llvm::StructRetAttribute;
14+
use lib::llvm::{StructRetAttribute, ZExtAttribute};
1515
use middle::trans::cabi::{FnType, ArgType};
1616
use middle::trans::context::CrateContext;
1717
use middle::trans::type_::Type;
@@ -85,7 +85,8 @@ fn ty_size(ty: Type) -> uint {
8585

8686
fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
8787
if is_reg_ty(ty) {
88-
return ArgType::direct(ty, None, None, None);
88+
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
89+
return ArgType::direct(ty, None, None, attr);
8990
}
9091
let size = ty_size(ty);
9192
if size <= 4 {
@@ -103,7 +104,8 @@ fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
103104

104105
fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType {
105106
if is_reg_ty(ty) {
106-
return ArgType::direct(ty, None, None, None);
107+
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
108+
return ArgType::direct(ty, None, None, attr);
107109
}
108110
let align = ty_align(ty);
109111
let size = ty_size(ty);

src/librustc/middle/trans/cabi_mips.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use libc::c_uint;
1414
use std::cmp;
1515
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
16-
use lib::llvm::StructRetAttribute;
16+
use lib::llvm::{StructRetAttribute, ZExtAttribute};
1717
use middle::trans::context::CrateContext;
1818
use middle::trans::cabi::*;
1919
use middle::trans::type_::Type;
@@ -83,9 +83,10 @@ fn ty_size(ty: Type) -> uint {
8383
}
8484
}
8585

86-
fn classify_ret_ty(ty: Type) -> ArgType {
86+
fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
8787
if is_reg_ty(ty) {
88-
ArgType::direct(ty, None, None, None)
88+
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
89+
ArgType::direct(ty, None, None, attr)
8990
} else {
9091
ArgType::indirect(ty, Some(StructRetAttribute))
9192
}
@@ -101,7 +102,8 @@ fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut uint) -> ArgType {
101102
*offset += align_up_to(size, align * 8) / 8;
102103

103104
if is_reg_ty(ty) {
104-
ArgType::direct(ty, None, None, None)
105+
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
106+
ArgType::direct(ty, None, None, attr)
105107
} else {
106108
ArgType::direct(
107109
ty,
@@ -160,7 +162,7 @@ pub fn compute_abi_info(ccx: &CrateContext,
160162
rty: Type,
161163
ret_def: bool) -> FnType {
162164
let ret_ty = if ret_def {
163-
classify_ret_ty(rty)
165+
classify_ret_ty(ccx, rty)
164166
} else {
165167
ArgType::direct(Type::void(ccx), None, None, None)
166168
};

src/librustc/middle/trans/cabi_x86.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ pub fn compute_abi_info(ccx: &CrateContext,
5959
}
6060
}
6161
} else {
62-
ret_ty = ArgType::direct(rty, None, None, None);
62+
let attr = if rty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
63+
ret_ty = ArgType::direct(rty, None, None, attr);
6364
}
6465

6566
for &t in atys.iter() {
@@ -72,7 +73,10 @@ pub fn compute_abi_info(ccx: &CrateContext,
7273
ArgType::indirect(t, Some(ByValAttribute))
7374
}
7475
}
75-
_ => ArgType::direct(t, None, None, None),
76+
_ => {
77+
let attr = if t == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
78+
ArgType::direct(t, None, None, attr)
79+
}
7680
};
7781
arg_tys.push(ty);
7882
}

src/librustc/middle/trans/cabi_x86_64.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
use lib::llvm::{llvm, Integer, Pointer, Float, Double};
1717
use lib::llvm::{Struct, Array, Attribute};
18-
use lib::llvm::{StructRetAttribute, ByValAttribute};
18+
use lib::llvm::{StructRetAttribute, ByValAttribute, ZExtAttribute};
1919
use middle::trans::cabi::*;
2020
use middle::trans::context::CrateContext;
2121
use middle::trans::type_::Type;
@@ -337,20 +337,21 @@ pub fn compute_abi_info(ccx: &CrateContext,
337337
fn x86_64_ty(ccx: &CrateContext,
338338
ty: Type,
339339
is_mem_cls: |cls: &[RegClass]| -> bool,
340-
attr: Attribute)
340+
ind_attr: Attribute)
341341
-> ArgType {
342342
if !ty.is_reg_ty() {
343343
let cls = classify_ty(ty);
344344
if is_mem_cls(cls.as_slice()) {
345-
ArgType::indirect(ty, Some(attr))
345+
ArgType::indirect(ty, Some(ind_attr))
346346
} else {
347347
ArgType::direct(ty,
348348
Some(llreg_ty(ccx, cls.as_slice())),
349349
None,
350350
None)
351351
}
352352
} else {
353-
ArgType::direct(ty, None, None, None)
353+
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
354+
ArgType::direct(ty, None, None, attr)
354355
}
355356
}
356357

src/librustc/middle/trans/common.rs

-5
Original file line numberDiff line numberDiff line change
@@ -818,11 +818,6 @@ pub fn find_vtable(tcx: &ty::ctxt,
818818
param_bounds.get(n_bound).clone()
819819
}
820820

821-
// Casts a Rust bool value to an i1.
822-
pub fn bool_to_i1(bcx: &Block, llval: ValueRef) -> ValueRef {
823-
build::ICmp(bcx, lib::llvm::IntNE, llval, C_bool(bcx.ccx(), false))
824-
}
825-
826821
pub fn langcall(bcx: &Block,
827822
span: Option<Span>,
828823
msg: &str,

src/librustc/middle/trans/consts.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -399,18 +399,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
399399
let (dv, _dt) = const_deref(cx, te, ty, true);
400400
dv
401401
}
402-
ast::UnNot => {
403-
match ty::get(ty).sty {
404-
ty::ty_bool => {
405-
// Somewhat questionable, but I believe this is
406-
// correct.
407-
let te = llvm::LLVMConstTrunc(te, Type::i1(cx).to_ref());
408-
let te = llvm::LLVMConstNot(te);
409-
llvm::LLVMConstZExt(te, Type::bool(cx).to_ref())
410-
}
411-
_ => llvm::LLVMConstNot(te),
412-
}
413-
}
402+
ast::UnNot => llvm::LLVMConstNot(te),
414403
ast::UnNeg => {
415404
if is_float { llvm::LLVMConstFNeg(te) }
416405
else { llvm::LLVMConstNeg(te) }

src/librustc/middle/trans/datum.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,6 @@ fn load<'a>(bcx: &'a Block<'a>, llptr: ValueRef, ty: ty::t) -> ValueRef {
525525

526526
if type_is_zero_size(bcx.ccx(), ty) {
527527
C_undef(type_of::type_of(bcx.ccx(), ty))
528-
} else if ty::type_is_bool(ty) {
529-
LoadRangeAssert(bcx, llptr, 0, 2, lib::llvm::False)
530528
} else if ty::type_is_char(ty) {
531529
// a char is a unicode codepoint, and so takes values from 0
532530
// to 0x10FFFF inclusive only.
@@ -652,8 +650,7 @@ impl<K:KindOps> Datum<K> {
652650

653651
pub fn to_llbool<'a>(self, bcx: &'a Block<'a>) -> ValueRef {
654652
assert!(ty::type_is_bool(self.ty) || ty::type_is_bot(self.ty))
655-
let cond_val = self.to_llscalarish(bcx);
656-
bool_to_i1(bcx, cond_val)
653+
self.to_llscalarish(bcx)
657654
}
658655
}
659656

src/librustc/middle/trans/expr.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -1147,11 +1147,7 @@ fn trans_unary<'a>(bcx: &'a Block<'a>,
11471147
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
11481148
let llresult = if ty::type_is_bool(un_ty) {
11491149
let val = datum.to_llscalarish(bcx);
1150-
let llcond = ICmp(bcx,
1151-
lib::llvm::IntEQ,
1152-
val,
1153-
C_bool(ccx, false));
1154-
Select(bcx, llcond, C_bool(ccx, true), C_bool(ccx, false))
1150+
Xor(bcx, val, C_bool(ccx, true))
11551151
} else {
11561152
// Note: `Not` is bitwise, not suitable for logical not.
11571153
Not(bcx, datum.to_llscalarish(bcx))
@@ -1325,9 +1321,7 @@ fn trans_eager_binop<'a>(
13251321
if ty::type_is_bot(rhs_t) {
13261322
C_bool(bcx.ccx(), false)
13271323
} else if ty::type_is_scalar(rhs_t) {
1328-
let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1329-
bcx = cmpr.bcx;
1330-
ZExt(bcx, cmpr.val, Type::i8(bcx.ccx()))
1324+
unpack_result!(bcx, base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op))
13311325
} else if is_simd {
13321326
base::compare_simd_types(bcx, lhs, rhs, intype, ty::simd_size(tcx, lhs_t), op)
13331327
} else {
@@ -1369,10 +1363,9 @@ fn trans_lazy_binop<'a>(
13691363
let join = fcx.new_id_block("join", binop_expr.id);
13701364
let before_rhs = fcx.new_id_block("before_rhs", b.id);
13711365

1372-
let lhs_i1 = bool_to_i1(past_lhs, lhs);
13731366
match op {
1374-
lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1375-
lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1367+
lazy_and => CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb),
1368+
lazy_or => CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb)
13761369
}
13771370

13781371
let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);

src/librustc/middle/trans/foreign.rs

+39-24
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
use back::{link};
1313
use lib::llvm::llvm;
14-
use lib::llvm::{ValueRef, CallConv, StructRetAttribute, Linkage};
14+
use lib::llvm::{ValueRef, CallConv, Linkage};
1515
use lib;
1616
use middle::weak_lang_items;
1717
use middle::trans::base::push_ctxt;
@@ -373,18 +373,41 @@ pub fn trans_native_call<'a>(
373373
};
374374

375375
// A function pointer is called without the declaration available, so we have to apply
376-
// any attributes with ABI implications directly to the call instruction. Right now, the
377-
// only attribute we need to worry about is `sret`.
376+
// any attributes with ABI implications directly to the call instruction.
378377
let mut attrs = Vec::new();
379-
if fn_type.ret_ty.is_indirect() {
380-
attrs.push((1, lib::llvm::StructRetAttribute as u64));
381378

379+
// Add attributes that are always applicable, independent of the concrete foreign ABI
380+
if fn_type.ret_ty.is_indirect() {
382381
// The outptr can be noalias and nocapture because it's entirely
383382
// invisible to the program. We can also mark it as nonnull
384383
attrs.push((1, lib::llvm::NoAliasAttribute as u64));
385384
attrs.push((1, lib::llvm::NoCaptureAttribute as u64));
386385
attrs.push((1, lib::llvm::NonNullAttribute as u64));
387386
};
387+
388+
// Add attributes that depend on the concrete foreign ABI
389+
let mut arg_idx = if fn_type.ret_ty.is_indirect() { 1 } else { 0 };
390+
match fn_type.ret_ty.attr {
391+
Some(attr) => attrs.push((arg_idx, attr as u64)),
392+
_ => ()
393+
}
394+
395+
arg_idx += 1;
396+
for arg_ty in fn_type.arg_tys.iter() {
397+
if arg_ty.is_ignore() {
398+
continue;
399+
}
400+
// skip padding
401+
if arg_ty.pad.is_some() { arg_idx += 1; }
402+
403+
match arg_ty.attr {
404+
Some(attr) => attrs.push((arg_idx, attr as u64)),
405+
_ => {}
406+
}
407+
408+
arg_idx += 1;
409+
}
410+
388411
let llforeign_retval = CallWithConv(bcx,
389412
llfn,
390413
llargs_foreign.as_slice(),
@@ -934,22 +957,17 @@ pub fn lltype_for_foreign_fn(ccx: &CrateContext, ty: ty::t) -> Type {
934957

935958
fn add_argument_attributes(tys: &ForeignTypes,
936959
llfn: ValueRef) {
937-
let mut i = 0;
938-
939-
if tys.fn_ty.ret_ty.is_indirect() {
940-
match tys.fn_ty.ret_ty.attr {
941-
Some(attr) => {
942-
let llarg = get_param(llfn, i);
943-
unsafe {
944-
llvm::LLVMAddAttribute(llarg, attr as c_uint);
945-
}
946-
}
947-
None => {}
948-
}
960+
let mut i = if tys.fn_ty.ret_ty.is_indirect() { 1 } else { 0 };
949961

950-
i += 1;
962+
match tys.fn_ty.ret_ty.attr {
963+
Some(attr) => unsafe {
964+
llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr as u64);
965+
},
966+
None => {}
951967
}
952968

969+
i += 1;
970+
953971
for &arg_ty in tys.fn_ty.arg_tys.iter() {
954972
if arg_ty.is_ignore() {
955973
continue;
@@ -958,12 +976,9 @@ fn add_argument_attributes(tys: &ForeignTypes,
958976
if arg_ty.pad.is_some() { i += 1; }
959977

960978
match arg_ty.attr {
961-
Some(attr) => {
962-
let llarg = get_param(llfn, i);
963-
unsafe {
964-
llvm::LLVMAddAttribute(llarg, attr as c_uint);
965-
}
966-
}
979+
Some(attr) => unsafe {
980+
llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr as u64);
981+
},
967982
None => ()
968983
}
969984

0 commit comments

Comments
 (0)