Skip to content

Commit 7a2dfde

Browse files
committed
[sil-optimizer] Add validation tests for constant folded FP arithmetic
1 parent 371995c commit 7a2dfde

File tree

1 file changed

+270
-20
lines changed

1 file changed

+270
-20
lines changed

validation-test/SILOptimizer/constant_folded_fp_operations.swift

Lines changed: 270 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
// RUN: %target-swift-frontend -emit-sil -O -suppress-warnings -verify %t/constant_folded_fp_operation_validation.swift 2>&1 | %FileCheck --check-prefix=CHECK-SIL %t/constant_folded_fp_operation_validation.swift
55
// RUN: %target-build-swift -O -suppress-warnings %t/constant_folded_fp_operation_validation.swift -o %t/a.out
6-
// RUN: %target-run %t/a.out | %FileCheck --check-prefix=COMPARE-RESULT %t/constant_folded_fp_operation_validation.swift
6+
// RUN: %target-run %t/a.out
77

88
// REQUIRES: executable_test,optimized_stdlib
99
// REQUIRES: swift_in_compiler
@@ -13,11 +13,19 @@
1313
createTestFile()
1414

1515
func createTestFile() {
16-
let validator = FPConstantFoldedComparisonOpsValidator()
17-
validator.generateOptimizedFuncDecls()
18-
validator.generateUnoptimizedFuncDecls()
19-
validator.generateComparisonFuncDecls()
20-
validator.generateComparisonFuncCalls()
16+
generateOperandAccessors()
17+
18+
let cmpOpValidator = FPConstantFoldedComparisonOpsValidator()
19+
cmpOpValidator.generateOptimizedFuncDecls()
20+
cmpOpValidator.generateUnoptimizedFuncDecls()
21+
cmpOpValidator.generateComparisonFuncDecls()
22+
cmpOpValidator.generateComparisonFuncCalls()
23+
24+
let arithOpValidator = FPConstantFoldedArithmeticOpsValidator()
25+
arithOpValidator.generateOptimizedFuncDecls()
26+
arithOpValidator.generateUnoptimizedFuncDecls()
27+
arithOpValidator.generateComparisonFuncDecls()
28+
arithOpValidator.generateComparisonFuncCalls()
2129
}
2230

2331
/////////////////// Protocols ///////////////////
@@ -48,7 +56,7 @@ protocol FPOptimizedOpsValidator {
4856

4957
func optimizedFunDeclCheck(fpType: FPType, op: FPOperation, op1: FPOperand, op2: FPOperand) -> String
5058
func unoptimizedFunDeclCheck(fpType: FPType, op: FPOperation, op1: FPOperand, op2: FPOperand) -> String
51-
func resultComaparisonCheck(fpType: FPType, op: FPOperation, op1: FPOperand, op2: FPOperand) -> String
59+
func resultComparisonCheck(fpType: FPType, op: FPOperation, op1: FPOperand, op2: FPOperand) -> String
5260
}
5361

5462
////////////////// Common ///////////////////
@@ -244,16 +252,16 @@ struct FPConstantFoldedComparisonOpsValidator: FPOptimizedOpsValidator {
244252
"""
245253
}
246254

247-
func resultComaparisonCheck(
255+
func resultComparisonCheck(
248256
fpType: FPType,
249257
op: FPOperation,
250258
op1: FPOperand,
251259
op2: FPOperand
252260
) -> String {
253-
let resultVarName = ["var", fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
261+
let comparisonFuncName = ["comparison", fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
254262

255263
return """
256-
// COMPARE-RESULT: [\(resultVarName)] result equal? true
264+
precondition(\(comparisonFuncName)(), "\(comparisonFuncName) returned false!")
257265
"""
258266
}
259267

@@ -287,15 +295,13 @@ struct FPConstantFoldedComparisonOpsValidator: FPOptimizedOpsValidator {
287295
for op1 in FPOperand.allCases {
288296
for op2 in FPOperand.allCases {
289297
let comparisonFuncName = ["comparison", fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
290-
let resultVarName = ["var", fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
291298
let optFuncName = [optPrefix, fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
292299
let unoptFuncName = [unoptPrefix, fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
293300

294301
print("""
295302
@inline(never) @_silgen_name("\(comparisonFuncName)") @_optimize(none)
296-
func \(comparisonFuncName)() {
297-
let \(resultVarName) = \(optFuncName)() == \(unoptFuncName)()
298-
print("[\(resultVarName)] result equal? \\(\(resultVarName))")
303+
func \(comparisonFuncName)() -> Bool {
304+
return \(optFuncName)() == \(unoptFuncName)()
299305
}
300306
301307
""")
@@ -310,15 +316,12 @@ struct FPConstantFoldedComparisonOpsValidator: FPOptimizedOpsValidator {
310316
for op in FPOperation.allCases {
311317
for op1 in FPOperand.allCases {
312318
for op2 in FPOperand.allCases {
313-
let comparisonFuncName = ["comparison", fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
314-
let checkDirective = resultComaparisonCheck(fpType: fpType, op: op, op1: op1, op2: op2)
319+
let comparison = resultComparisonCheck(fpType: fpType, op: op, op1: op1, op2: op2)
315320

316321
print("""
317-
\(checkDirective)
318-
\(comparisonFuncName)()
322+
\(comparison)
319323
320324
""")
321-
322325
}
323326
}
324327
}
@@ -369,4 +372,251 @@ struct FPConstantFoldedComparisonOpsValidator: FPOptimizedOpsValidator {
369372
370373
""")
371374
}
372-
}
375+
}
376+
377+
////////////////// Arithmetic Operations Validator ///////////////////
378+
379+
struct FPConstantFoldedArithmeticOpsValidator: FPOptimizedOpsValidator {
380+
/// Type of floating points this validator deals with.
381+
enum _FpType : CaseIterable, Representable, Equatable {
382+
case Float
383+
case Double
384+
385+
func math_name() -> String {
386+
switch self {
387+
case .Float:
388+
return "Float"
389+
case .Double:
390+
return "Double"
391+
}
392+
}
393+
394+
func printable_name() -> String {
395+
switch self {
396+
case .Float:
397+
return "float"
398+
case .Double:
399+
return "double"
400+
}
401+
}
402+
}
403+
404+
/// Type of floating point operations this validator deals with.
405+
enum _FPOperation : CaseIterable, Representable, Equatable {
406+
case Add
407+
case Subtract
408+
case Multiply
409+
case Divide
410+
411+
func math_name() -> String {
412+
switch self {
413+
case .Add:
414+
return "+"
415+
case .Subtract:
416+
return "-"
417+
case .Multiply:
418+
return "*"
419+
case .Divide:
420+
return "/"
421+
}
422+
}
423+
424+
func printable_name() -> String {
425+
switch self {
426+
case .Add:
427+
return "add"
428+
case .Subtract:
429+
return "sub"
430+
case .Multiply:
431+
return "mul"
432+
case .Divide:
433+
return "div"
434+
}
435+
}
436+
}
437+
438+
/// Type of floating point operands this validator deals with.
439+
enum _FPOperand : CaseIterable, Representable, Equatable {
440+
case Zero
441+
case One
442+
443+
func math_name() -> String {
444+
switch self {
445+
case .Zero:
446+
return "0.0"
447+
case .One:
448+
return "1.0"
449+
}
450+
}
451+
452+
func printable_name() -> String {
453+
switch self {
454+
case .Zero:
455+
return "zero"
456+
case .One:
457+
return "one"
458+
}
459+
}
460+
}
461+
462+
private let optPrefix = "opt"
463+
private let unoptPrefix = "unopt"
464+
465+
/////////////////////// FPOptimizedOpsValidator Conformances ///////////////////////
466+
typealias FPType = _FpType
467+
typealias FPOperation = _FPOperation
468+
typealias FPOperand = _FPOperand
469+
470+
func optimizedFunDeclCheck(
471+
fpType: FPType,
472+
op: FPOperation,
473+
op1: FPOperand,
474+
op2: FPOperand
475+
) -> String {
476+
let funcName = [optPrefix, fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
477+
478+
return """
479+
// CHECK-SIL-LABEL: sil hidden [noinline] @\(funcName)
480+
// CHECK-SIL-NEXT: [global: ]
481+
// CHECK-SIL-NEXT: bb0:
482+
// CHECK-SIL-NOT: {{.*}}f\(op.printable_name()){{.*}}
483+
// CHECK-SIL: } // end sil function '\(funcName)'
484+
"""
485+
}
486+
487+
func unoptimizedFunDeclCheck(
488+
fpType: FPType,
489+
op: FPOperation,
490+
op1: FPOperand,
491+
op2: FPOperand
492+
) -> String {
493+
let funcName = [unoptPrefix, fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
494+
495+
return """
496+
// CHECK-SIL-LABEL: sil hidden [noinline] [Onone] @\(funcName)
497+
// CHECK-SIL-NEXT: bb0:
498+
// CHECK-SIL: {{.*}}f\(op.printable_name()){{.*}}
499+
// CHECK-SIL: } // end sil function '\(funcName)'
500+
"""
501+
}
502+
503+
func resultComparisonCheck(
504+
fpType: FPType,
505+
op: FPOperation,
506+
op1: FPOperand,
507+
op2: FPOperand
508+
) -> String {
509+
let comparisonFuncName = ["comparison", fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
510+
511+
// 0.0 / 0.0 is NaN and Nan != Nan
512+
if op == .Divide && op1 == .Zero && op2 == .Zero {
513+
return """
514+
precondition(!\(comparisonFuncName)(), "\(comparisonFuncName) returned true. Expected false.")
515+
"""
516+
}
517+
518+
return """
519+
precondition(\(comparisonFuncName)(), "\(comparisonFuncName) returned false. Expected true.")
520+
"""
521+
}
522+
523+
func generateOptimizedFuncDecls() {
524+
for fpType in FPType.allCases {
525+
for op in FPOperation.allCases {
526+
for op1 in FPOperand.allCases {
527+
for op2 in FPOperand.allCases {
528+
generateFuncDeclWithCheckDirectives(fpType: fpType, op: op, op1: op1, op2: op2, isopt: true)
529+
}
530+
}
531+
}
532+
}
533+
}
534+
535+
func generateUnoptimizedFuncDecls() {
536+
for fpType in FPType.allCases {
537+
for op in FPOperation.allCases {
538+
for op1 in FPOperand.allCases {
539+
for op2 in FPOperand.allCases {
540+
generateFuncDeclWithCheckDirectives(fpType: fpType, op: op, op1: op1, op2: op2, isopt: false)
541+
}
542+
}
543+
}
544+
}
545+
}
546+
547+
func generateComparisonFuncDecls() {
548+
for fpType in FPType.allCases {
549+
for op in FPOperation.allCases {
550+
for op1 in FPOperand.allCases {
551+
for op2 in FPOperand.allCases {
552+
let comparisonFuncName = ["comparison", fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
553+
let optFuncName = [optPrefix, fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
554+
let unoptFuncName = [unoptPrefix, fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
555+
556+
print("""
557+
@inline(never) @_silgen_name("\(comparisonFuncName)") @_optimize(none)
558+
func \(comparisonFuncName)() -> Bool {
559+
return \(optFuncName)() == \(unoptFuncName)()
560+
}
561+
562+
""")
563+
}
564+
}
565+
}
566+
}
567+
}
568+
569+
func generateComparisonFuncCalls() {
570+
for fpType in FPType.allCases {
571+
for op in FPOperation.allCases {
572+
for op1 in FPOperand.allCases {
573+
for op2 in FPOperand.allCases {
574+
let comparison = resultComparisonCheck(fpType: fpType, op: op, op1: op1, op2: op2)
575+
print("""
576+
\(comparison)
577+
578+
""")
579+
}
580+
}
581+
}
582+
}
583+
}
584+
585+
/////////////////////// Utilities ///////////////////////
586+
private func generateFuncDeclWithCheckDirectives(
587+
fpType: FPType,
588+
op: FPOperation,
589+
op1: FPOperand,
590+
op2: FPOperand,
591+
isopt: Bool = false
592+
) {
593+
var operand1 = op1.math_name()
594+
var operand2 = op2.math_name()
595+
596+
if !isopt {
597+
if fpType == .Double {
598+
operand1 = op1 == .Zero ? "zero_double()": "one_double()"
599+
operand2 = op2 == .Zero ? "zero_double()": "one_double()"
600+
} else {
601+
operand1 = op1 == .Zero ? "zero_float()": "one_float()"
602+
operand2 = op2 == .Zero ? "zero_float()": "one_float()"
603+
}
604+
}
605+
606+
let optPrefix = isopt ? optPrefix : unoptPrefix
607+
let optAttr = isopt ? "" : "@_optimize(none)"
608+
let funcName = [optPrefix, fpType.printable_name(), op.printable_name(), op1.printable_name(), op2.printable_name()].joined(separator: "_")
609+
let checkDirectives = isopt ?
610+
optimizedFunDeclCheck(fpType: fpType, op: op, op1: op1, op2: op2) :
611+
unoptimizedFunDeclCheck(fpType: fpType, op: op, op1: op1, op2: op2)
612+
613+
print("""
614+
@inline(never) @_silgen_name("\(funcName)") \(optAttr)
615+
func \(funcName)() -> \(fpType.math_name()) {
616+
return \(operand1) \(op.math_name()) \(operand2)
617+
}
618+
\(checkDirectives)
619+
620+
""")
621+
}
622+
}

0 commit comments

Comments
 (0)