What are the various causes of "shift amount is greater than or equal to type size in bits"

I have code that is giving the "shift amount is greater than or equal to type size in bits” error when built in release mode but doesn’t in debug mode. I’m trying to understand all of the various causes of this error in order to better understand what’s happening.

Here’s a dumbed down version of the code that illustrates the issue:

/// Skeleton for actual UInt128 structure.
struct UInt128 {
  let value: (upperBits: UInt64, lowerBits: UInt64) = (0, 0)
}
/// Shifts `lhs`' bits left by `rhs` bits and returns the result.
public func <<(lhs: UInt128, rhs: UInt128) -> UInt128 {
    if rhs.value.upperBits > 0 || rhs.value.lowerBits > 128 {
        return UInt128(0)
    }
    switch rhs {
    case 0: return lhs // Do nothing shift.
    case 1...63:
        let upperBits = (lhs.value.upperBits << rhs.value.lowerBits) + (lhs.value.lowerBits >> (64 - rhs.value.lowerBits))
        let lowerBits = lhs.value.lowerBits << rhs.value.lowerBits
        return UInt128(upperBits: upperBits, lowerBits: lowerBits)
    case 64:
        // Shift 64 means move lower bits to upper bits.
        return UInt128(upperBits: lhs.value.lowerBits, lowerBits: 0)
    case 65...127:
        // This causes a "shift amount is greater than or equal to type size in bits" error
        // on release build but not debug build.
        let upperBits = lhs.value.lowerBits << (rhs.value.lowerBits - 64)
        return UInt128(upperBits: upperBits, lowerBits: 0)
    default: return UInt128(0)
    }
}

I’ve walked through the Swift code, and while I see some things that might be flagging this error, I’m having a hard time understanding what the underlying causes are.

Joel Gerber
joel@grrbrr.ca

   switch rhs {

   case 65...127:
       // This causes a "shift amount is greater than or equal to type size in bits" error
       // on release build but not debug build.
       let upperBits = lhs.value.lowerBits << (rhs.value.lowerBits - 64)

I suspect the problem is that you’re switching on `rhs` instead of `rhs.value.lowerBits`. You haven’t shown the conversion method that lets your struct be compared with an integer literal, but I’m guessing that the compiler isn’t smart enough to deduce that when rhs<127, then rhs.value.lowerBits must also be <127.

As for why this only happens in release builds, it’s probably because only release builds perform the control-flow analysis that’s necessary for detecting these types of errors when the RHS of `<<` isn’t a constant.

—Jens

···

On Feb 13, 2016, at 11:11 AM, Joel Gerber via swift-users <swift-users@swift.org> wrote:

This whole library is at https://github.com/Jitsusama/UInt128\. I tried simplifying the library down to the bare necessities and I couldn’t replicate the issue, so I’m guessing that it does have to do with integer literals somehow now that you mention it.

Here is my integerLiteralConvertible implementation:

extension UInt128: IntegerLiteralConvertible {
    public init(integerLiteral value: IntegerLiteralType) {
        self.init()
        self.value.lowerBits = UInt64(value)
    }
    public init(_builtinIntegerLiteral value: _MaxBuiltinIntegerType) {
        self.init()
        self.value.lowerBits = UInt64(_builtinIntegerLiteral: value)
    }
}

Joel Gerber
joel@grrbrr.ca

···

On Feb 13, 2016, at 2:47 PM, Jens Alfke <jens@mooseyard.com> wrote:

On Feb 13, 2016, at 11:11 AM, Joel Gerber via swift-users <swift-users@swift.org> wrote:

  switch rhs {

  case 65...127:
      // This causes a "shift amount is greater than or equal to type size in bits" error
      // on release build but not debug build.
      let upperBits = lhs.value.lowerBits << (rhs.value.lowerBits - 64)

I suspect the problem is that you’re switching on `rhs` instead of `rhs.value.lowerBits`. You haven’t shown the conversion method that lets your struct be compared with an integer literal, but I’m guessing that the compiler isn’t smart enough to deduce that when rhs<127, then rhs.value.lowerBits must also be <127.

As for why this only happens in release builds, it’s probably because only release builds perform the control-flow analysis that’s necessary for detecting these types of errors when the RHS of `<<` isn’t a constant.

—Jens

Taking what you said in mind, I switched “let upperBits = lhs.value.lowerBits << (rhs.value.lowerBits - 64)” to "let upperBits = lhs.value.lowerBits << UInt64(rhs - 64)” and that compile error goes away. I wonder if Swift is just having an issue with dealing with the conversion when it involves a tuple.

Speaking of which, there is one other circumstance where a release build gives the same error, in my IntegerLiteralConvertible initializer!:

extension UInt128: IntegerLiteralConvertible {
    public init(integerLiteral value: IntegerLiteralType) {
        self.init()
        self.value.lowerBits = UInt64(value)
    }
    public init(_builtinIntegerLiteral value: _MaxBuiltinIntegerType) {
        self.init()
        // Gives “Shift amount is greater than or equal to type size in bits” error.
        self.value.lowerBits = UInt64(_builtinIntegerLiteral: value)
    }
}

I broke down my init(_bulterinIntegerLiteral:) function like so and it gave the same error:

extension UInt128: IntegerLiteralConvertible {
    public init(integerLiteral value: IntegerLiteralType) {
        self.init()
        self.value.lowerBits = UInt64(value)
    }
    public init(_builtinIntegerLiteral value: _MaxBuiltinIntegerType) {
        self.init()
        // Error happens on the below line.
        let temporaryHolder = UInt64(_builtinIntegerLiteral: value)
        self.value.lowerBits = temporaryHolder
    }
}

In this case, temporaryHolder seems to be resolving to a UInt64 type, so I have no clue why the compiler would have a problem with it.

Joel Gerber
joel@grrbrr.ca

···

On Feb 13, 2016, at 2:47 PM, Jens Alfke <jens@mooseyard.com> wrote:

On Feb 13, 2016, at 11:11 AM, Joel Gerber via swift-users <swift-users@swift.org> wrote:

  switch rhs {

  case 65...127:
      // This causes a "shift amount is greater than or equal to type size in bits" error
      // on release build but not debug build.
      let upperBits = lhs.value.lowerBits << (rhs.value.lowerBits - 64)

I suspect the problem is that you’re switching on `rhs` instead of `rhs.value.lowerBits`. You haven’t shown the conversion method that lets your struct be compared with an integer literal, but I’m guessing that the compiler isn’t smart enough to deduce that when rhs<127, then rhs.value.lowerBits must also be <127.

As for why this only happens in release builds, it’s probably because only release builds perform the control-flow analysis that’s necessary for detecting these types of errors when the RHS of `<<` isn’t a constant.

—Jens

If you're seeing different diagnostic behavior in debug and release modes, that's a bug. If you have time, please file this on bugs.swift.org for us to take a look. Thanks!

-Joe

···

On Feb 13, 2016, at 11:11 AM, Joel Gerber via swift-users <swift-users@swift.org> wrote:

I have code that is giving the "shift amount is greater than or equal to type size in bits” error when built in release mode but doesn’t in debug mode. I’m trying to understand all of the various causes of this error in order to better understand what’s happening.

Here’s a dumbed down version of the code that illustrates the issue:

/// Skeleton for actual UInt128 structure.
struct UInt128 {
let value: (upperBits: UInt64, lowerBits: UInt64) = (0, 0)
}
/// Shifts `lhs`' bits left by `rhs` bits and returns the result.
public func <<(lhs: UInt128, rhs: UInt128) -> UInt128 {
   if rhs.value.upperBits > 0 || rhs.value.lowerBits > 128 {
       return UInt128(0)
   }
   switch rhs {
   case 0: return lhs // Do nothing shift.
   case 1...63:
       let upperBits = (lhs.value.upperBits << rhs.value.lowerBits) + (lhs.value.lowerBits >> (64 - rhs.value.lowerBits))
       let lowerBits = lhs.value.lowerBits << rhs.value.lowerBits
       return UInt128(upperBits: upperBits, lowerBits: lowerBits)
   case 64:
       // Shift 64 means move lower bits to upper bits.
       return UInt128(upperBits: lhs.value.lowerBits, lowerBits: 0)
   case 65...127:
       // This causes a "shift amount is greater than or equal to type size in bits" error
       // on release build but not debug build.
       let upperBits = lhs.value.lowerBits << (rhs.value.lowerBits - 64)
       return UInt128(upperBits: upperBits, lowerBits: 0)
   default: return UInt128(0)
   }
}

I’ve walked through the Swift code, and while I see some things that might be flagging this error, I’m having a hard time understanding what the underlying causes are.

Joel Gerber
joel@grrbrr.ca
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

I did a bugreport.apple.com one (26448395). I just created another on bugs.swift.org (SR-743). And yes, in debug mode, no error at all, release mode, error.

Joel Gerber
joel@grrbrr.ca

···

On Feb 15, 2016, at 1:17 PM, Joe Groff <jgroff@apple.com> wrote:

If you're seeing different diagnostic behavior in debug and release modes, that's a bug. If you have time, please file this on bugs.swift.org for us to take a look. Thanks!

-Joe

On Feb 13, 2016, at 11:11 AM, Joel Gerber via swift-users <swift-users@swift.org> wrote:

I have code that is giving the "shift amount is greater than or equal to type size in bits” error when built in release mode but doesn’t in debug mode. I’m trying to understand all of the various causes of this error in order to better understand what’s happening.

Here’s a dumbed down version of the code that illustrates the issue:

/// Skeleton for actual UInt128 structure.
struct UInt128 {
let value: (upperBits: UInt64, lowerBits: UInt64) = (0, 0)
}
/// Shifts `lhs`' bits left by `rhs` bits and returns the result.
public func <<(lhs: UInt128, rhs: UInt128) -> UInt128 {
  if rhs.value.upperBits > 0 || rhs.value.lowerBits > 128 {
      return UInt128(0)
  }
  switch rhs {
  case 0: return lhs // Do nothing shift.
  case 1...63:
      let upperBits = (lhs.value.upperBits << rhs.value.lowerBits) + (lhs.value.lowerBits >> (64 - rhs.value.lowerBits))
      let lowerBits = lhs.value.lowerBits << rhs.value.lowerBits
      return UInt128(upperBits: upperBits, lowerBits: lowerBits)
  case 64:
      // Shift 64 means move lower bits to upper bits.
      return UInt128(upperBits: lhs.value.lowerBits, lowerBits: 0)
  case 65...127:
      // This causes a "shift amount is greater than or equal to type size in bits" error
      // on release build but not debug build.
      let upperBits = lhs.value.lowerBits << (rhs.value.lowerBits - 64)
      return UInt128(upperBits: upperBits, lowerBits: 0)
  default: return UInt128(0)
  }
}

I’ve walked through the Swift code, and while I see some things that might be flagging this error, I’m having a hard time understanding what the underlying causes are.

Joel Gerber
joel@grrbrr.ca
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Thank you!
-Joe

···

On Feb 15, 2016, at 12:04 PM, Joel Gerber <joel@grrbrr.ca> wrote:

I did a bugreport.apple.com <Feedback Assistant; one (26448395). I just created another on bugs.swift.org <Issues · apple/swift · GitHub; (SR-743). And yes, in debug mode, no error at all, release mode, error.

Joel Gerber
joel@grrbrr.ca <mailto:joel@grrbrr.ca>

On Feb 15, 2016, at 1:17 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

If you're seeing different diagnostic behavior in debug and release modes, that's a bug. If you have time, please file this on bugs.swift.org <Issues · apple/swift · GitHub; for us to take a look. Thanks!

-Joe

On Feb 13, 2016, at 11:11 AM, Joel Gerber via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I have code that is giving the "shift amount is greater than or equal to type size in bits” error when built in release mode but doesn’t in debug mode. I’m trying to understand all of the various causes of this error in order to better understand what’s happening.

Here’s a dumbed down version of the code that illustrates the issue:

/// Skeleton for actual UInt128 structure.
struct UInt128 {
let value: (upperBits: UInt64, lowerBits: UInt64) = (0, 0)
}
/// Shifts `lhs`' bits left by `rhs` bits and returns the result.
public func <<(lhs: UInt128, rhs: UInt128) -> UInt128 {
  if rhs.value.upperBits > 0 || rhs.value.lowerBits > 128 {
      return UInt128(0)
  }
  switch rhs {
  case 0: return lhs // Do nothing shift.
  case 1...63:
      let upperBits = (lhs.value.upperBits << rhs.value.lowerBits) + (lhs.value.lowerBits >> (64 - rhs.value.lowerBits))
      let lowerBits = lhs.value.lowerBits << rhs.value.lowerBits
      return UInt128(upperBits: upperBits, lowerBits: lowerBits)
  case 64:
      // Shift 64 means move lower bits to upper bits.
      return UInt128(upperBits: lhs.value.lowerBits, lowerBits: 0)
  case 65...127:
      // This causes a "shift amount is greater than or equal to type size in bits" error
      // on release build but not debug build.
      let upperBits = lhs.value.lowerBits << (rhs.value.lowerBits - 64)
      return UInt128(upperBits: upperBits, lowerBits: 0)
  default: return UInt128(0)
  }
}

I’ve walked through the Swift code, and while I see some things that might be flagging this error, I’m having a hard time understanding what the underlying causes are.

Joel Gerber
joel@grrbrr.ca <mailto:joel@grrbrr.ca>
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users