mirror of
https://github.com/apple/swift.git
synced 2026-10-06 12:37:28 +02:00
Under `-enable-sil-opaque-values`, SILGen copied every builtin argument to +1 and forwarded it into the builtin. Polymorphic builtins such as `Builtin.generic_add` only borrow their operands. Nothing consumed the copy, so the OSSA verifier reported a leaked owned value. SILGen now passes each argument at the ownership its parameter declares in `Builtins.cpp`, instead of special-casing polymorphic builtins. An assertion checks that each declared ownership agrees with the builtin's OperandOwnership classification. AddressLowering now rewrites the value form of a polymorphic builtin into the address form with an indirect result. Adds opaque-values RUN lines to the polymorphic builtin tests in SILGen, IRGen and SILOptimizer, and a SIL test for the AddressLowering rewrite. Removes the opaque-values XFAIL from `test/Interpreter/polymorphic_builtins.swift`. Resolves rdar://180980544
340 lines
18 KiB
Plaintext
340 lines
18 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -address-lowering -enable-sil-opaque-values -module-name Swift -sil-verify-all %s | %FileCheck %s
|
|
|
|
// Polymorphic builtins (e.g. "generic_add") only borrow their operands (they
|
|
// never appear in AddressLowering as a "consuming" def/use), so AddressLowering
|
|
// must materialize an address for each operand and for the result without
|
|
// otherwise touching their ownership. This directly exercises AddressLowering's
|
|
// DefRewriter/UseRewriter handling for every Generic* polymorphic builtin,
|
|
// independently of SILGen and of the unrelated "unspecialized polymorphic
|
|
// builtin" diagnostic that a full -emit-sil run would hit for generic, non-
|
|
// transparent uses of these builtins (see test/SILGen/polymorphic_builtins.swift).
|
|
//
|
|
// The genericXTest functions below cover the builtins one by one in the
|
|
// simplest shape: the result is the caller's @out argument. The shapeX
|
|
// functions at the end instead vary where the result's storage comes from,
|
|
// which is what exercises AddressMaterialization.
|
|
|
|
sil_stage raw
|
|
|
|
import Builtin
|
|
|
|
enum Enum<T> {
|
|
case some(T)
|
|
case none
|
|
}
|
|
|
|
sil @makeT : $@convention(thin) <T> () -> @out T
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericAddTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_add"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericAddTest'
|
|
sil [ossa] @genericAddTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_add"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericAndTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_and"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericAndTest'
|
|
sil [ossa] @genericAndTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_and"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericAshrTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_ashr"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericAshrTest'
|
|
sil [ossa] @genericAshrTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_ashr"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericFaddTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_fadd"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericFaddTest'
|
|
sil [ossa] @genericFaddTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_fadd"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericFdivTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_fdiv"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericFdivTest'
|
|
sil [ossa] @genericFdivTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_fdiv"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericFmulTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_fmul"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericFmulTest'
|
|
sil [ossa] @genericFmulTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_fmul"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericFremTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_frem"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericFremTest'
|
|
sil [ossa] @genericFremTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_frem"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericFsubTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_fsub"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericFsubTest'
|
|
sil [ossa] @genericFsubTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_fsub"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericLshrTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_lshr"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericLshrTest'
|
|
sil [ossa] @genericLshrTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_lshr"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericMulTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_mul"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericMulTest'
|
|
sil [ossa] @genericMulTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_mul"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericOrTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_or"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericOrTest'
|
|
sil [ossa] @genericOrTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_or"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericSdivExactTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_sdiv_exact"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericSdivExactTest'
|
|
sil [ossa] @genericSdivExactTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_sdiv_exact"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericSdivTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_sdiv"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericSdivTest'
|
|
sil [ossa] @genericSdivTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_sdiv"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericShlTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_shl"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericShlTest'
|
|
sil [ossa] @genericShlTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_shl"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericSremTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_srem"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericSremTest'
|
|
sil [ossa] @genericSremTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_srem"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericSubTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_sub"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericSubTest'
|
|
sil [ossa] @genericSubTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_sub"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericUdivExactTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_udiv_exact"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericUdivExactTest'
|
|
sil [ossa] @genericUdivExactTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_udiv_exact"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericUdivTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_udiv"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericUdivTest'
|
|
sil [ossa] @genericUdivTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_udiv"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericUremTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_urem"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericUremTest'
|
|
sil [ossa] @genericUremTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_urem"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @genericXorTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: builtin "generic_xor"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'genericXorTest'
|
|
sil [ossa] @genericXorTest : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_xor"<T>(%0 : $T, %1 : $T) : $T
|
|
return %2 : $T
|
|
}
|
|
|
|
// The result of the inner builtin is not the caller's @out argument, so it
|
|
// needs storage of its own.
|
|
// CHECK-LABEL: sil [ossa] @shapeChained : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: [[TMP:%.*]] = alloc_stack $T
|
|
// CHECK: builtin "generic_mul"<T>([[TMP]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK: builtin "generic_add"<T>([[RESULT]] : $*T, [[TMP]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK: destroy_addr [[TMP]] : $*T
|
|
// CHECK: dealloc_stack [[TMP]] : $*T
|
|
// CHECK-LABEL: } // end sil function 'shapeChained'
|
|
sil [ossa] @shapeChained : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_mul"<T>(%0 : $T, %1 : $T) : $T
|
|
%3 = builtin "generic_add"<T>(%2 : $T, %1 : $T) : $T
|
|
destroy_value %2 : $T
|
|
return %3 : $T
|
|
}
|
|
|
|
// An unused result still needs storage; nothing consumes it, so the storage is
|
|
// destroyed in place.
|
|
// CHECK-LABEL: sil [ossa] @shapeDeadResult : $@convention(thin) <T> (@in_guaranteed T) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : $*T):
|
|
// CHECK: [[TMP:%.*]] = alloc_stack $T
|
|
// CHECK: builtin "generic_xor"<T>([[TMP]] : $*T, [[ARG]] : $*T, [[ARG]] : $*T) : $()
|
|
// CHECK: destroy_addr [[TMP]] : $*T
|
|
// CHECK: dealloc_stack [[TMP]] : $*T
|
|
// CHECK-LABEL: } // end sil function 'shapeDeadResult'
|
|
sil [ossa] @shapeDeadResult : $@convention(thin) <T> (@in_guaranteed T) -> () {
|
|
bb0(%0 : @guaranteed $T):
|
|
%1 = builtin "generic_xor"<T>(%0 : $T, %0 : $T) : $T
|
|
destroy_value %1 : $T
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// The result's storage is a projection out of an enum payload.
|
|
// CHECK-LABEL: sil [ossa] @shapeEnumPayload : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out Enum<T> {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*Enum<T>, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: [[PAYLOAD:%.*]] = init_enum_data_addr [[RESULT]] : $*Enum<T>, #Enum.some!enumelt
|
|
// CHECK: builtin "generic_add"<T>([[PAYLOAD]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK: inject_enum_addr [[RESULT]] : $*Enum<T>, #Enum.some!enumelt
|
|
// CHECK-LABEL: } // end sil function 'shapeEnumPayload'
|
|
sil [ossa] @shapeEnumPayload : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out Enum<T> {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_add"<T>(%0 : $T, %1 : $T) : $T
|
|
%3 = enum $Enum<T>, #Enum.some!enumelt, %2 : $T
|
|
return %3 : $Enum<T>
|
|
}
|
|
|
|
// An owned operand is only borrowed by the builtin: its storage is read in
|
|
// place and destroyed afterwards, not consumed by the builtin.
|
|
// CHECK-LABEL: sil [ossa] @shapeOwnedOperand : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG:%.*]] : $*T):
|
|
// CHECK: [[TMP:%.*]] = alloc_stack $T
|
|
// CHECK: apply {{%.*}}<T>([[TMP]])
|
|
// CHECK: builtin "generic_add"<T>([[RESULT]] : $*T, [[TMP]] : $*T, [[ARG]] : $*T) : $()
|
|
// CHECK: destroy_addr [[TMP]] : $*T
|
|
// CHECK: dealloc_stack [[TMP]] : $*T
|
|
// CHECK-LABEL: } // end sil function 'shapeOwnedOperand'
|
|
sil [ossa] @shapeOwnedOperand : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
|
|
bb0(%0 : @guaranteed $T):
|
|
%1 = function_ref @makeT : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%2 = apply %1<T>() : $@convention(thin) <τ_0_0> () -> @out τ_0_0
|
|
%3 = builtin "generic_add"<T>(%2 : $T, %0 : $T) : $T
|
|
destroy_value %2 : $T
|
|
return %3 : $T
|
|
}
|
|
|
|
// Results flowing into a phi share the phi's storage, so each predecessor
|
|
// writes the caller's @out argument directly and the phi argument goes away.
|
|
// CHECK-LABEL: sil [ossa] @shapePhi : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T, Builtin.Int1) -> @out T {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*T, [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T, {{%.*}} : $Builtin.Int1):
|
|
// CHECK: bb1:
|
|
// CHECK: builtin "generic_add"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK: builtin "generic_sub"<T>([[RESULT]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK: br bb3
|
|
// The merge block prints without an argument list, i.e. the phi is gone.
|
|
// CHECK: bb3:
|
|
// CHECK-LABEL: } // end sil function 'shapePhi'
|
|
sil [ossa] @shapePhi : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T, Builtin.Int1) -> @out T {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T, %2 : $Builtin.Int1):
|
|
cond_br %2, bb1, bb2
|
|
|
|
bb1:
|
|
%3 = builtin "generic_add"<T>(%0 : $T, %1 : $T) : $T
|
|
br bb3(%3 : $T)
|
|
|
|
bb2:
|
|
%4 = builtin "generic_sub"<T>(%0 : $T, %1 : $T) : $T
|
|
br bb3(%4 : $T)
|
|
|
|
bb3(%5 : @owned $T):
|
|
return %5 : $T
|
|
}
|
|
|
|
// Each result's storage is a projection into the caller's @out tuple.
|
|
// CHECK-LABEL: sil [ossa] @shapeTuple : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out (T, T) {
|
|
// CHECK: bb0([[RESULT:%.*]] : $*(T, T), [[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T):
|
|
// CHECK: [[ELT0:%.*]] = tuple_element_addr [[RESULT]] : $*(T, T), 0
|
|
// CHECK: builtin "generic_add"<T>([[ELT0]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK: [[ELT1:%.*]] = tuple_element_addr [[RESULT]] : $*(T, T), 1
|
|
// CHECK: builtin "generic_sub"<T>([[ELT1]] : $*T, [[ARG0]] : $*T, [[ARG1]] : $*T) : $()
|
|
// CHECK-LABEL: } // end sil function 'shapeTuple'
|
|
sil [ossa] @shapeTuple : $@convention(thin) <T> (@in_guaranteed T, @in_guaranteed T) -> @out (T, T) {
|
|
bb0(%0 : @guaranteed $T, %1 : @guaranteed $T):
|
|
%2 = builtin "generic_add"<T>(%0 : $T, %1 : $T) : $T
|
|
%3 = builtin "generic_sub"<T>(%0 : $T, %1 : $T) : $T
|
|
%4 = tuple (%2 : $T, %3 : $T)
|
|
return %4 : $(T, T)
|
|
}
|