stdlib: remove bitwise operations on Bool

Bitwise operations on Bool are redundant with other logic operations
that stdlib already provides.  The only reason to have them was to avoid
branching in the short-circuiting && and ||.

rdar://19340952

Surprisingly, replacing & and | in the standard library with && and ||
brought performance improvements and no significant performance
regressions:

RecursiveOwnedParameter 1.14
SelectionSort 1.19

Swift SVN r24674
This commit is contained in:
Dmitri Hrybenko
2015-01-23 03:09:55 +00:00
parent b832ef90ab
commit bbf79427ac
10 changed files with 154 additions and 50 deletions

View File

@@ -64,27 +64,6 @@ extension Bool : Printable {
public // COMPILER_INTRINSIC
func _getBool(v: Builtin.Int1) -> Bool { return Bool(v) }
//===----------------------------------------------------------------------===//
// Standard Operators
//===----------------------------------------------------------------------===//
// Unary bitwise complement.
@transparent
public prefix func ~(a: Bool) -> Bool {
return a ^ true
}
// Unary logical complement.
@transparent
public prefix func !(a: Bool) -> Bool {
return ~a
}
@transparent
public func ==(lhs: Bool, rhs: Bool) -> Bool {
return Bool(Builtin.cmp_eq_Int1(lhs.value, rhs.value))
}
@transparent
extension Bool : Equatable, Hashable {
/// The hash value.
@@ -99,36 +78,64 @@ extension Bool : Equatable, Hashable {
}
}
//===----------------------------------------------------------------------===//
// Operators
//===----------------------------------------------------------------------===//
// Unary logical complement.
@transparent
public prefix func !(a: Bool) -> Bool {
return Bool(Builtin.xor_Int1(a.value, true.value))
}
@transparent
public func ==(lhs: Bool, rhs: Bool) -> Bool {
return Bool(Builtin.cmp_eq_Int1(lhs.value, rhs.value))
}
//===----------------------------------------------------------------------===//
// Unavailable Operators
//===----------------------------------------------------------------------===//
// Unary bitwise complement.
@availability(*, unavailable, message="use the '!' operator instead")
public prefix func ~(a: Bool) -> Bool {
_preconditionFailure("unavailable function can not be called")
}
// Bitwise 'and'.
@transparent public func & (lhs: Bool, rhs: Bool) -> Bool {
return Bool(Builtin.and_Int1(lhs.value, rhs.value))
@availability(*, unavailable, message="use the '&&' operator instead")
public func & (lhs: Bool, rhs: Bool) -> Bool {
_preconditionFailure("unavailable function can not be called")
}
// Bitwise 'xor'.
@transparent public func ^ (lhs: Bool, rhs: Bool) -> Bool {
return Bool(Builtin.xor_Int1(lhs.value, rhs.value))
@availability(*, unavailable, message="use the '!=' operator instead")
public func ^ (lhs: Bool, rhs: Bool) -> Bool {
_preconditionFailure("unavailable function can not be called")
}
// Bitwise 'or'.
@transparent public func | (lhs: Bool, rhs: Bool) -> Bool {
return Bool(Builtin.or_Int1(lhs.value, rhs.value))
@availability(*, unavailable, message="use the '||' operator instead")
public func | (lhs: Bool, rhs: Bool) -> Bool {
_preconditionFailure("unavailable function can not be called")
}
// Compound assignment (with bitwise and)
@transparent
@availability(*, unavailable, message="use the '&&' operator instead")
public func &= (inout lhs: Bool, rhs: Bool) {
lhs = lhs & rhs
_preconditionFailure("unavailable function can not be called")
}
// Compound assignment (with bitwise or)
@transparent
@availability(*, unavailable, message="use the '||' operator instead")
public func |= (inout lhs: Bool, rhs: Bool) {
lhs = lhs | rhs
_preconditionFailure("unavailable function can not be called")
}
// Compound assignment (with bitwise xor)
@transparent
@availability(*, unavailable, message="use the '!=' operator instead")
public func ^= (inout lhs: Bool, rhs: Bool) {
lhs = lhs ^ rhs
_preconditionFailure("unavailable function can not be called")
}

View File

@@ -339,7 +339,7 @@ public struct _ContiguousArrayBuffer<T> : _ArrayBufferType {
/// Note that this is better than folding hasStorage in to
/// the return from this function, as this implementation generates
/// no shortcircuiting blocks.
return (index >= 0) & (index < __bufferPointer.value.count)
return (index >= 0) && (index < __bufferPointer.value.count)
}
/// How many elements the buffer can store without reallocation

View File

@@ -534,7 +534,7 @@ public func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
public func ${op}(lhs: ${Self}, rhs: ${Self}) -> ${Self} {
Builtin.condfail((rhs == 0).value)
% if signed:
Builtin.condfail(((lhs == ${Self}.min) & (rhs == -1)).value)
Builtin.condfail(((lhs == ${Self}.min) && (rhs == -1)).value)
% end
// FIXME: currently doesn't detect overflow -- blocked by:
// <rdar://15735295> Need [su]{div,rem}_with_overflow IR

View File

@@ -25,14 +25,14 @@ import SwiftShims
/// index count`
@transparent
internal func _isValidArrayIndex(index: Int, count: Int) -> Bool {
return (index >= 0) & (index <= count)
return (index >= 0) && (index <= count)
}
/// Return true iff the given `index` is valid for subscripting, i.e.
/// `0 index < count`
@transparent
internal func _isValidArraySubscript(index: Int, count: Int) -> Bool {
return (index >= 0) & (index < count)
return (index >= 0) && (index < count)
}
/// An `NSArray` with Swift-native reference counting and contiguous

View File

@@ -185,7 +185,7 @@ public struct _UnitTestArrayBuffer<T> : _ArrayBufferType {
/// the return from this function, as this implementation generates
/// no shortcircuiting blocks.
_precondition(_base.hasStorage, "Cannot index empty buffer")
return (index >= 0) & (index < _base.value.count)
return (index >= 0) && (index < _base.value.count)
}
/// How many elements the buffer can store without reallocation

View File

@@ -225,6 +225,7 @@ public func expectGE(
public func expectType<T>(_: T.Type, inout x: T) {}
public func isSequenceType<X : SequenceType>(x: X) -> X { return x }
public func expectIsBooleanType<X : BooleanType>(inout x: X) -> X { return x }
public struct AssertionResult : Printable, BooleanType {
init(isPass: Bool) {

View File

@@ -991,7 +991,7 @@ Reflection.test("CustomMirror") {
// Check the ObjectIdentifier created is stable
expectTrue(
(ObjectIdentifier(a) < ObjectIdentifier(b))
^ (ObjectIdentifier(a) > ObjectIdentifier(b)))
!= (ObjectIdentifier(a) > ObjectIdentifier(b)))
expectFalse(
ObjectIdentifier(a) >= ObjectIdentifier(b)
&& ObjectIdentifier(a) <= ObjectIdentifier(b))

View File

@@ -445,17 +445,6 @@ func testInOut(inout arg: Int) {
takesExplicitInt(5) // expected-error {{cannot invoke 'takesExplicitInt' with an argument list of type '(Int)'}} expected-note{{expected an argument list of type '(inout Int)'}}
}
//===----------------------------------------------------------------------===//
// Bool operators
//===----------------------------------------------------------------------===//
func boolTest(a: Bool, b: Bool) {
var t1 = a != b
var t2 = a == b
var t3 = !a
var t4 = ~a
}
//===----------------------------------------------------------------------===//
// Conversions
//===----------------------------------------------------------------------===//

View File

@@ -0,0 +1,12 @@
// RUN: %target-parse-verify-swift
func test_removedOperators(a: Bool, b: Bool) {
var t1 = ~a // expected-error {{'~' is unavailable: use the '!' operator instead}}
var t2 = a & b // expected-error {{'&' is unavailable: use the '&&' operator instead}}
var t3 = a | b // expected-error {{'|' is unavailable: use the '||' operator instead}}
var t4 = a ^ b // expected-error {{'^' is unavailable: use the '!=' operator instead}}
t4 &= a // expected-error {{'&=' is unavailable: use the '&&' operator instead}}
t4 |= a // expected-error {{'|=' is unavailable: use the '||' operator instead}}
t4 ^= a // expected-error {{'^=' is unavailable: use the '!=' operator instead}}
}

View File

@@ -267,5 +267,100 @@ _UnimplementedError()
#endif
var BoolTestSuite = TestSuite("Bool")
BoolTestSuite.test("literals") {
if true {
var v = false
expectType(Bool.self, &v)
}
if true {
var v = true
expectType(Bool.self, &v)
}
}
BoolTestSuite.test("init()") {
let v = Bool()
expectFalse(v)
}
struct Booleanish : BooleanType {
let boolValue: Bool
}
BoolTestSuite.test("init<T : BooleanType>(_:)") {
if true {
let v = Bool(Booleanish(boolValue: false))
expectFalse(v)
}
if true {
let v = Bool(Booleanish(boolValue: true))
expectTrue(v)
}
}
BoolTestSuite.test("BooleanType") {
if true {
var v: Bool = false
expectIsBooleanType(&v)
expectFalse(v.boolValue)
}
if true {
var v: Bool = true
expectTrue(v.boolValue)
}
}
BoolTestSuite.test("Printable") {
if true {
let v: Bool = false
expectEqual("false", toString(v))
}
if true {
let v: Bool = true
expectEqual("true", toString(v))
}
}
BoolTestSuite.test("Equatable,Hashable") {
checkHashable(true, false, false)
checkHashable(false, false, true)
checkHashable(true, true, true)
expectNotEqual(false.hashValue, true.hashValue)
}
BoolTestSuite.test("!") {
if true {
let v: Bool = false
var r = !v
expectType(Bool.self, &r)
expectTrue(r)
}
if true {
let v: Bool = true
var r = !v
expectType(Bool.self, &r)
expectFalse(r)
}
}
BoolTestSuite.test("!") {
let v: Bool = false
if true {
var r = (v == v)
expectType(Bool.self, &r)
}
if true {
var r = (v != v)
expectType(Bool.self, &r)
}
if true {
var r = !v
expectType(Bool.self, &r)
}
}
runAllTests()