Skip to content

Commit 1cb5f57

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

File tree

1 file changed

+267
-6
lines changed

1 file changed

+267
-6
lines changed

validation-test/SILOptimizer/constant_folded_fp_operations.swift

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

0 commit comments

Comments
 (0)