| // RUN: rm -rf %t |
| // RUN: mkdir -p %t |
| // RUN: %gyb %s -o %t/FixedPointArithmeticTraps.swift |
| // RUN: %line-directive %t/FixedPointArithmeticTraps.swift -- %target-build-swift %t/FixedPointArithmeticTraps.swift -o %t/a.out_Debug |
| // RUN: %line-directive %t/FixedPointArithmeticTraps.swift -- %target-build-swift %t/FixedPointArithmeticTraps.swift -o %t/a.out_Release -O |
| // |
| // RUN: %line-directive %t/FixedPointArithmeticTraps.swift -- %target-run %t/a.out_Debug |
| // RUN: %line-directive %t/FixedPointArithmeticTraps.swift -- %target-run %t/a.out_Release |
| // REQUIRES: executable_test |
| |
| import StdlibUnittest |
| |
| |
| // Note: in this file, we need to go through opaque functions to load |
| // constants. This is to check runtime behaviour and ensure the constant is |
| // not folded. |
| |
| func expectOverflow<T>( |
| _ res: (T, overflow: Bool), |
| //===--- TRACE boilerplate ----------------------------------------------===// |
| _ message: @autoclosure () -> String = "", |
| showFrame: Bool = true, |
| stackTrace: SourceLocStack = SourceLocStack(), |
| file: String = #file, line: UInt = #line |
| ) { |
| expectTrue( |
| res.overflow, "expected overflow", |
| stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) |
| } |
| |
| func expectNoOverflow<T>( |
| _ res: (T, overflow: Bool), |
| //===--- TRACE boilerplate ----------------------------------------------===// |
| _ message: @autoclosure () -> String = "", |
| showFrame: Bool = true, |
| stackTrace: SourceLocStack = SourceLocStack(), |
| file: String = #file, line: UInt = #line |
| ) { |
| expectFalse( |
| res.overflow, "expected no overflow", |
| stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) |
| } |
| |
| %{ |
| |
| from SwiftIntTypes import all_integer_types |
| |
| # Test cases are written in a way that they don't depend on the word size. |
| word_bits = 4 |
| |
| }% |
| |
| var FixedPointArithmeticTraps = TestSuite("FixedPointArithmeticTraps") |
| |
| % for self_ty in all_integer_types(word_bits): |
| % IntTy = self_ty.stdlib_name |
| |
| // |
| // Test pre- and post-increment/decrement for ${IntTy} |
| // |
| |
| FixedPointArithmeticTraps.test("PreDecrement/${IntTy}") { |
| var x = get${IntTy}(${IntTy}.min) |
| x += 1 |
| |
| x = get${IntTy}(${IntTy}.min) |
| expectCrashLater() |
| // IntTy.min -= 1 |
| x -= 1 |
| _blackHole(x) |
| } |
| |
| FixedPointArithmeticTraps.test("PreIncrement/${IntTy}") { |
| var x = get${IntTy}(${IntTy}.max) |
| x -= 1 |
| |
| x = get${IntTy}(${IntTy}.max) |
| expectCrashLater() |
| // IntTy.max += 1 |
| x += 1 |
| _blackHole(x) |
| } |
| |
| FixedPointArithmeticTraps.test("PostDecrement/${IntTy}") { |
| var x = get${IntTy}(${IntTy}.min) |
| x += 1 |
| |
| x = get${IntTy}(${IntTy}.min) |
| expectCrashLater() |
| // IntTy.min -= 1 |
| x -= 1 |
| _blackHole(x) |
| } |
| |
| FixedPointArithmeticTraps.test("PostIncrement/${IntTy}") { |
| var x = get${IntTy}(${IntTy}.max) |
| x -= 1 |
| |
| x = get${IntTy}(${IntTy}.max) |
| expectCrashLater() |
| // IntTy.max += 1 |
| x += 1 |
| _blackHole(x) |
| } |
| |
| // |
| // Test addition for ${IntTy} |
| // |
| |
| FixedPointArithmeticTraps.test("Addition/${IntTy}") { |
| var a = get${IntTy}(${IntTy}.max / 3) |
| |
| expectNoOverflow(${IntTy}.addWithOverflow(a, get${IntTy}(${IntTy}.max / 3))) |
| a = a + get${IntTy}(${IntTy}.max / 3) |
| |
| expectNoOverflow(${IntTy}.addWithOverflow(a, get${IntTy}(${IntTy}.max / 3))) |
| a = a + get${IntTy}(${IntTy}.max / 3) |
| |
| // Overflow in addition. |
| expectOverflow(${IntTy}.addWithOverflow(a, get${IntTy}(${IntTy}.max / 3))) |
| expectCrashLater() |
| a = a + get${IntTy}(${IntTy}.max / 3) |
| _blackHole(a) |
| } |
| |
| // |
| // Test subtraction for ${IntTy} |
| // |
| |
| FixedPointArithmeticTraps.test("Subtraction/${IntTy}") { |
| var a = get${IntTy}(${IntTy}.min + get${IntTy}(${IntTy}.max / 3)) |
| |
| expectNoOverflow(${IntTy}.subtractWithOverflow(a, get${IntTy}(${IntTy}.max / 3))) |
| a = a - get${IntTy}(${IntTy}.max / 3) |
| |
| // Overflow in subtraction. |
| expectOverflow(${IntTy}.subtractWithOverflow(a, get${IntTy}(${IntTy}.max / 3))) |
| expectCrashLater() |
| a = a - get${IntTy}(${IntTy}.max / 3) |
| _blackHole(a) |
| } |
| |
| // |
| // Test multiplication for ${IntTy} |
| // |
| |
| FixedPointArithmeticTraps.test("Multiplication/${IntTy}") { |
| var a = get${IntTy}(${IntTy}.max / 3) |
| |
| expectNoOverflow(${IntTy}.multiplyWithOverflow(a, get${IntTy}(2))) |
| a = a * get${IntTy}(2) |
| |
| // Overflow in multiplication. |
| expectOverflow(${IntTy}.multiplyWithOverflow(a, get${IntTy}(2))) |
| expectCrashLater() |
| a = a * get${IntTy}(2) |
| _blackHole(a) |
| } |
| |
| // |
| // Test division for ${IntTy} |
| // |
| |
| FixedPointArithmeticTraps.test("Division/${IntTy}") { |
| var a = get${IntTy}(${IntTy}.max / 3) |
| |
| // x / 3 |
| expectNoOverflow(${IntTy}.divideWithOverflow(a, get${IntTy}(3))) |
| a = a / get${IntTy}(3) |
| |
| // x / 0 |
| expectOverflow(${IntTy}.divideWithOverflow(a, get${IntTy}(0))) |
| expectCrashLater() |
| a = a / get${IntTy}(0) |
| } |
| |
| % if self_ty.is_signed: |
| |
| FixedPointArithmeticTraps.test("Division/${IntTy}.min-over-minus-one") { |
| var a = get${IntTy}(${IntTy}.min) |
| |
| expectNoOverflow(${IntTy}.divideWithOverflow(a, get${IntTy}(3))) |
| a = a / get${IntTy}(3) |
| |
| a = get${IntTy}(${IntTy}.min) |
| expectOverflow(${IntTy}.divideWithOverflow(a, get${IntTy}(-1))) |
| expectCrashLater() |
| a = a / get${IntTy}(-1) |
| // IntTy.min / -1 |
| _blackHole(a) |
| } |
| |
| % end |
| |
| // |
| // Test remainder computation for ${IntTy} |
| // |
| |
| FixedPointArithmeticTraps.test("Remainder/${IntTy}") { |
| var a = get${IntTy}(${IntTy}.max / 3) |
| |
| // x % 3 |
| expectNoOverflow(${IntTy}.remainderWithOverflow(a, get${IntTy}(3))) |
| a = a % get${IntTy}(3) |
| |
| // x % 0 |
| expectOverflow(${IntTy}.remainderWithOverflow(a, get${IntTy}(0))) |
| expectCrashLater() |
| a = a % get${IntTy}(0) |
| _blackHole(a) |
| } |
| |
| % if self_ty.is_signed: |
| |
| FixedPointArithmeticTraps.test("Remainder/${IntTy}.min-mod-minus-one") { |
| var a = get${IntTy}(${IntTy}.min) |
| |
| // Int.min % 3 |
| expectNoOverflow(${IntTy}.remainderWithOverflow(a, get${IntTy}(3))) |
| a = a % get${IntTy}(3) |
| |
| // Int.min % -1 |
| a = get${IntTy}(${IntTy}.min) |
| expectOverflow(${IntTy}.remainderWithOverflow(a, get${IntTy}(-1))) |
| expectCrashLater() |
| a = a % get${IntTy}(-1) |
| _blackHole(a) |
| } |
| |
| % end |
| |
| % for (description, operation) in [("RightShift", ">>"), ("LeftShift", "<<")]: |
| |
| // |
| // Test ${description} for ${IntTy} |
| // |
| |
| % if self_ty.is_signed: |
| |
| FixedPointArithmeticTraps.test("${description}/${IntTy}/Negative") { |
| var a = get${IntTy}(${IntTy}.max / 3) |
| |
| a = get${IntTy}(a ${operation} get${IntTy}(1)) |
| |
| let shiftAmount: ${IntTy} = -1 |
| |
| // Overflow in ${description}. |
| expectCrashLater() |
| a = a ${operation} get${IntTy}(shiftAmount) |
| _blackHole(a) |
| } |
| |
| % end |
| |
| FixedPointArithmeticTraps.test("${description}/${IntTy}/TypeSize") { |
| var a = get${IntTy}(${IntTy}.max / 3) |
| |
| a = get${IntTy}(a ${operation} get${IntTy}(0)) |
| a = get${IntTy}(a ${operation} get${IntTy}(1)) |
| |
| let shiftAmount = ${IntTy}(MemoryLayout<${IntTy}>.size * 8) |
| |
| // Overflow in ${description}. |
| expectCrashLater() |
| a = a ${operation} get${IntTy}(shiftAmount) |
| _blackHole(a) |
| } |
| |
| FixedPointArithmeticTraps.test("${description}/${IntTy}/TypeSizePlusOne") { |
| var a = get${IntTy}(${IntTy}.max / 3) |
| |
| a = get${IntTy}(a ${operation} get${IntTy}(0)) |
| |
| let shiftAmount = ${IntTy}(MemoryLayout<${IntTy}>.size * 8 + 1) |
| |
| // Overflow in ${description}. |
| expectCrashLater() |
| a = a ${operation} get${IntTy}(shiftAmount) |
| _blackHole(a) |
| } |
| |
| FixedPointArithmeticTraps.test("${description}/${IntTy}/Max") { |
| var a = get${IntTy}(${IntTy}.max / 3) |
| |
| a = get${IntTy}(a ${operation} get${IntTy}(0)) |
| |
| let shiftAmount: ${IntTy} = ${IntTy}.max |
| |
| // Overflow in ${description}. |
| expectCrashLater() |
| a = a ${operation} get${IntTy}(shiftAmount) |
| _blackHole(a) |
| } |
| |
| % end |
| |
| // This comment prevents gyb from miscompiling this file. |
| // <rdar://problem/17548877> gyb miscompiles a certain for loop |
| |
| % end |
| |
| runAllTests() |
| |