Skip to content

Commit b44158c

Browse files
authored
Merge pull request #27284 from gottesmm/pr-492ee9b09850d10ed8d4b8bc54b10acc7c023ada
[polymorphic-builtins] Teach dataflow diagnostics how to emit an erro…
2 parents 43debb4 + e90a68f commit b44158c

File tree

8 files changed

+200
-13
lines changed

8 files changed

+200
-13
lines changed

include/swift/AST/Builtins.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,10 @@ class IntrinsicInfo {
131131

132132
/// Turn a string like "release" into the LLVM enum.
133133
llvm::AtomicOrdering decodeLLVMAtomicOrdering(StringRef O);
134-
134+
135+
/// Returns true if the builtin with ID \p ID has a defined static overload for
136+
/// the type \p Ty.
137+
bool canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty);
135138
}
136139

137140
#endif

include/swift/AST/DiagnosticsSIL.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,16 @@ ERROR(oslog_property_not_constant, none, "'OSLogInterpolation.%0' is not a "
522522
ERROR(global_string_pointer_on_non_constant, none, "globalStringTablePointer "
523523
"builtin must used only on string literals", ())
524524

525+
ERROR(polymorphic_builtin_passed_non_trivial_non_builtin_type, none, "Argument "
526+
"of type %0 can not be passed as an argument to a Polymorphic "
527+
"builtin. Polymorphic builtins can only be passed arguments that are "
528+
"trivial builtin typed", (Type))
529+
530+
ERROR(polymorphic_builtin_passed_type_without_static_overload, none, "Static"
531+
" overload %0 does not exist for polymorphic builtin '%1'. Static "
532+
"overload implied by passing argument of type %2",
533+
(Identifier, StringRef, Type))
534+
525535
#ifndef DIAG_NO_UNDEF
526536
# if defined(DIAG)
527537
# undef DIAG

include/swift/SIL/InstructionUtils.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,23 +149,37 @@ void findClosuresForFunctionValue(SILValue V,
149149
/// NOTE: If we perform this transformation, our builtin will no longer have any
150150
/// substitutions since we only substitute to concrete static overloads.
151151
struct PolymorphicBuiltinSpecializedOverloadInfo {
152+
const BuiltinInfo *builtinInfo;
152153
Identifier staticOverloadIdentifier;
153154
SmallVector<SILType, 8> argTypes;
154155
SILType resultType;
155-
bool hasOutParam = false;
156+
bool hasOutParam;
156157

157158
#ifndef NDEBUG
158159
private:
159-
bool isInitialized = false;
160-
#endif
160+
bool isInitialized;
161161

162162
public:
163-
PolymorphicBuiltinSpecializedOverloadInfo() = default;
163+
#endif
164164

165-
bool init(SILFunction *fn, BuiltinValueKind builtinKind,
166-
ArrayRef<SILType> oldOperandTypes, SILType oldResultType);
165+
PolymorphicBuiltinSpecializedOverloadInfo()
166+
: builtinInfo(nullptr), staticOverloadIdentifier(), argTypes(),
167+
resultType(), hasOutParam(false), isInitialized(false) {}
167168

169+
/// Returns true if we were able to map the polymorphic builtin to a static
170+
/// overload. False otherwise.
171+
///
172+
/// NOTE: This does not mean that the static overload actually exists.
168173
bool init(BuiltinInst *bi);
174+
175+
bool doesOverloadExist() const {
176+
CanBuiltinType builtinType = argTypes.front().getAs<BuiltinType>();
177+
return canBuiltinBeOverloadedForType(builtinInfo->ID, builtinType);
178+
}
179+
180+
private:
181+
bool init(SILFunction *fn, BuiltinValueKind builtinKind,
182+
ArrayRef<SILType> oldOperandTypes, SILType oldResultType);
169183
};
170184

171185
/// Given a polymorphic builtin \p bi, analyze its types and create a builtin

lib/AST/Builtins.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,13 @@ inline bool isBuiltinTypeOverloaded(Type T, OverloadedBuiltinKind OK) {
12561256
llvm_unreachable("bad overloaded builtin kind");
12571257
}
12581258

1259+
bool swift::canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty) {
1260+
if (ID == BuiltinValueKind::None)
1261+
return false;
1262+
1263+
return isBuiltinTypeOverloaded(Ty, OverloadedBuiltinKinds[unsigned(ID)]);
1264+
}
1265+
12591266
/// Table of string intrinsic names indexed by enum value.
12601267
static const char *const IntrinsicNameTable[] = {
12611268
"not_intrinsic",

lib/SIL/InstructionUtils.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,12 @@ bool PolymorphicBuiltinSpecializedOverloadInfo::init(
598598

599599
auto &ctx = fn->getASTContext();
600600
staticOverloadIdentifier = ctx.getIdentifier(staticOverloadName);
601+
602+
// Ok, we have our overload identifier. Grab the builtin info from the
603+
// cache. If we did not actually found a valid builtin value kind for our
604+
// overload, then we do not have a static overload for the passed in types, so
605+
// return false.
606+
builtinInfo = &fn->getModule().getBuiltinInfo(staticOverloadIdentifier);
601607
return true;
602608
}
603609

lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,22 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "swift/SILOptimizer/PassManager/Passes.h"
14-
#include "swift/SILOptimizer/PassManager/Transforms.h"
15-
#include "swift/SILOptimizer/Utils/ConstExpr.h"
1613
#include "swift/AST/ASTContext.h"
1714
#include "swift/AST/DiagnosticEngine.h"
18-
#include "swift/AST/DiagnosticsSema.h"
1915
#include "swift/AST/DiagnosticsSIL.h"
16+
#include "swift/AST/DiagnosticsSema.h"
2017
#include "swift/AST/Expr.h"
2118
#include "swift/AST/Stmt.h"
19+
#include "swift/SIL/InstructionUtils.h"
20+
#include "swift/SIL/SILConstants.h"
2221
#include "swift/SIL/SILFunction.h"
2322
#include "swift/SIL/SILInstruction.h"
2423
#include "swift/SIL/SILLocation.h"
2524
#include "swift/SIL/SILModule.h"
2625
#include "swift/SIL/SILVisitor.h"
27-
#include "swift/SIL/SILConstants.h"
26+
#include "swift/SILOptimizer/PassManager/Passes.h"
27+
#include "swift/SILOptimizer/PassManager/Transforms.h"
28+
#include "swift/SILOptimizer/Utils/ConstExpr.h"
2829

2930
using namespace swift;
3031

@@ -175,6 +176,67 @@ static void diagnosePoundAssert(const SILInstruction *I,
175176
}
176177
}
177178

179+
static void diagnoseUnspecializedPolymorphicBuiltins(SILInstruction *inst) {
180+
// We only validate if we are in a non-transparent function.
181+
if (inst->getFunction()->isTransparent())
182+
return;
183+
184+
auto *bi = dyn_cast<BuiltinInst>(inst);
185+
if (!bi)
186+
return;
187+
188+
auto kind = bi->getBuiltinKind();
189+
if (!kind)
190+
return;
191+
192+
if (!isPolymorphicBuiltin(*kind))
193+
return;
194+
195+
const auto &builtinInfo = bi->getBuiltinInfo();
196+
197+
// First that the parameters were acceptable so we can emit a nice error to
198+
// guide the user.
199+
for (SILValue value : bi->getOperandValues()) {
200+
SILType type = value->getType();
201+
SourceLoc loc;
202+
if (auto *inst = value->getDefiningInstruction()) {
203+
loc = inst->getLoc().getSourceLoc();
204+
} else {
205+
loc = bi->getLoc().getSourceLoc();
206+
}
207+
208+
if (!type.is<BuiltinType>() || !type.isTrivial(*bi->getFunction())) {
209+
diagnose(bi->getModule().getASTContext(), loc,
210+
diag::polymorphic_builtin_passed_non_trivial_non_builtin_type,
211+
type.getASTType());
212+
return;
213+
}
214+
}
215+
216+
// Ok, we have a valid type for a polymorphic builtin. Make sure we actually
217+
// have a static overload for this type.
218+
PolymorphicBuiltinSpecializedOverloadInfo overloadInfo;
219+
bool ableToMapToStaticOverload = overloadInfo.init(bi);
220+
(void)ableToMapToStaticOverload;
221+
assert(ableToMapToStaticOverload);
222+
if (!overloadInfo.doesOverloadExist()) {
223+
diagnose(bi->getModule().getASTContext(), bi->getLoc().getSourceLoc(),
224+
diag::polymorphic_builtin_passed_type_without_static_overload,
225+
overloadInfo.staticOverloadIdentifier,
226+
getBuiltinName(builtinInfo.ID),
227+
overloadInfo.argTypes.front().getASTType());
228+
return;
229+
}
230+
231+
// Otherwise, something happen that we did not understand. This can only
232+
// happen if we specialize the generic type in the builtin /after/ constant
233+
// propagation runs at -Onone but before dataflow diagnostics. This is an
234+
// error in implementation, so we assert.
235+
llvm_unreachable("Found generic builtin with known static overload that it "
236+
"could be transformed to. Did this builtin get its generic "
237+
"type specialized /after/ constant propagation?");
238+
}
239+
178240
namespace {
179241
class EmitDFDiagnostics : public SILFunctionTransform {
180242
~EmitDFDiagnostics() override {}
@@ -186,11 +248,13 @@ class EmitDFDiagnostics : public SILFunctionTransform {
186248
return;
187249

188250
SILModule &M = getFunction()->getModule();
189-
for (auto &BB : *getFunction())
251+
for (auto &BB : *getFunction()) {
190252
for (auto &I : BB) {
191253
diagnoseUnreachable(&I, M.getASTContext());
192254
diagnoseStaticReports(&I, M);
255+
diagnoseUnspecializedPolymorphicBuiltins(&I);
193256
}
257+
}
194258

195259
if (M.getASTContext().LangOpts.EnableExperimentalStaticAssert) {
196260
SymbolicValueBumpAllocator allocator;
@@ -202,6 +266,7 @@ class EmitDFDiagnostics : public SILFunctionTransform {
202266
}
203267
}
204268
};
269+
205270
} // end anonymous namespace
206271

207272

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-sil-opt -module-name Swift -dataflow-diagnostics -verify %s
2+
3+
sil_stage raw
4+
5+
import Builtin
6+
7+
struct MyInt {
8+
var i : Builtin.Int32
9+
}
10+
11+
sil @concrete_type_object_fail : $@convention(thin) (MyInt, MyInt) -> MyInt {
12+
bb0(%0 : $MyInt, %1 : $MyInt):
13+
%2 = builtin "generic_add"<MyInt>(%0 : $MyInt, %1 : $MyInt) : $MyInt // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}}
14+
return %2 : $MyInt
15+
}
16+
17+
sil @concrete_type_address_fail : $@convention(thin) (@in_guaranteed MyInt, @in_guaranteed MyInt) -> @out MyInt {
18+
bb0(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt):
19+
%3 = builtin "generic_add"<MyInt>(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt) : $() // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}}
20+
%9999 = tuple()
21+
return %9999 : $()
22+
}
23+
24+
sil @concrete_type_address_fail_mismatched_trivial_type : $@convention(thin) (@in_guaranteed Builtin.FPIEEE32, @in_guaranteed Builtin.FPIEEE32) -> @out Builtin.FPIEEE32 {
25+
bb0(%0 : $*Builtin.FPIEEE32, %1 : $*Builtin.FPIEEE32, %2 : $*Builtin.FPIEEE32):
26+
%3 = builtin "generic_add"<Builtin.FPIEEE32>(%0 : $*Builtin.FPIEEE32, %1 : $*Builtin.FPIEEE32, %2 : $*Builtin.FPIEEE32) : $() // expected-error {{Static overload 'add_FPIEEE32' does not exist for polymorphic builtin 'generic_add'. Static overload implied by passing argument of type 'Builtin.FPIEEE32'}}
27+
%9999 = tuple()
28+
return %9999 : $()
29+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %target-swift-frontend -parse-stdlib -emit-sil -verify %s
2+
3+
import Swift
4+
5+
struct MyInt {
6+
var i: Builtin.Int64
7+
}
8+
9+
@_transparent
10+
func _isConcrete<T>(type: T.Type) -> Bool {
11+
return Bool(_builtinBooleanLiteral: Builtin.isConcrete(type))
12+
}
13+
14+
func addVectorsNoDiagnostic(lhs: Builtin.Vec4xInt32, rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 {
15+
return Builtin.generic_add(lhs, rhs)
16+
}
17+
18+
func addVectorsEmitDiagnostic(lhs: MyInt, rhs: MyInt) -> MyInt {
19+
return Builtin.generic_add(lhs, rhs) // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}}
20+
}
21+
22+
func addVectorsGeneric<T>(lhs: T, rhs: T) -> T {
23+
return Builtin.generic_add(lhs, rhs) // expected-error {{Argument of type 'T' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}}
24+
}
25+
26+
@_transparent
27+
func calleeAddVectorsGenericTransparentGuarded<T>(_ lhs: T, _ rhs: T) -> T {
28+
// This will be eliminated during constant propagation ensuring that when we
29+
// call in callerAddVectorsGenericTransparent, we do not get an error from our
30+
// underlying call.
31+
if _isConcrete(T.self) {
32+
return Builtin.generic_add(lhs, rhs)
33+
}
34+
return lhs
35+
}
36+
37+
func callerAddVectorsGenericTransparent(_ lhs: Builtin.Vec4xInt32, _ rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 {
38+
// Since after transparent inlining, we have the correct type, we should get an error here.q
39+
return calleeAddVectorsGenericTransparentGuarded(lhs, rhs)
40+
}
41+
42+
@_transparent
43+
func calleeAddVectorsGenericTransparentUnguarded<T>(_ lhs: T, _ rhs: T) -> T {
44+
return Builtin.generic_add(lhs, rhs)
45+
}
46+
47+
func callerAddVectorsGenericTransparentUnguardedNoError(_ lhs: Builtin.Vec4xInt32, _ rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 {
48+
return calleeAddVectorsGenericTransparentUnguarded(lhs, rhs)
49+
}
50+
51+
func callerAddVectorsGenericTransparentUnguardedError(_ lhs: MyInt, _ rhs: MyInt) -> MyInt {
52+
return calleeAddVectorsGenericTransparentUnguarded(lhs, rhs) // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}}
53+
}

0 commit comments

Comments
 (0)