Skip to content

Commit b413a0f

Browse files
authored
Add Builtin.ifdef_<FLAGNAME> as a facility to peek at -D flag that client code is building with (swiftlang#39797)
1 parent 223dbd4 commit b413a0f

File tree

13 files changed

+112
-13
lines changed

13 files changed

+112
-13
lines changed

include/swift/AST/Builtins.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,9 @@ BUILTIN_MISC_OPERATION(StaticReport, "staticReport", "", Special)
642642
/// Returns the selected assertion configuration.
643643
BUILTIN_MISC_OPERATION(AssertConf, "assert_configuration", "n", Special)
644644

645+
/// Ifdef has type () -> Bool.
646+
BUILTIN_MISC_OPERATION(Ifdef, "ifdef", "n", Special)
647+
645648
/// StringObjectOr has type (T,T) -> T.
646649
/// Sets bits in a string object. The first operand is bit-cast string literal
647650
/// pointer to an integer. The second operand is the bit mask to be or'd into

include/swift/AST/SILOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ class SILOptions {
192192
/// }
193193
bool EnableDynamicReplacementCanCallPreviousImplementation = true;
194194

195+
/// Are we parsing the stdlib, i.e. -parse-stdlib?
196+
bool ParseStdlib = false;
197+
195198
/// The name of the file to which the backend should save optimization
196199
/// records.
197200
std::string OptRecordFile;

lib/AST/Builtins.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,10 @@ static ValueDecl *getFenceOperation(ASTContext &ctx, Identifier id) {
10281028
return getBuiltinFunction(ctx, id, _thin, _parameters(), _void);
10291029
}
10301030

1031+
static ValueDecl *getIfdefOperation(ASTContext &ctx, Identifier id) {
1032+
return getBuiltinFunction(ctx, id, _thin, _parameters(), _int(1));
1033+
}
1034+
10311035
static ValueDecl *getVoidErrorOperation(ASTContext &ctx, Identifier id) {
10321036
return getBuiltinFunction(ctx, id, _thin, _parameters(_error), _void);
10331037
}
@@ -2280,6 +2284,14 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
22802284
if (getSwiftFunctionTypeForIntrinsic(ID, Types, Context, ArgElts, ResultTy))
22812285
return getBuiltinFunction(Id, ArgElts, ResultTy);
22822286
}
2287+
2288+
// If this starts with fence, we have special suffixes to handle.
2289+
if (OperationName.startswith("ifdef_")) {
2290+
OperationName = OperationName.drop_front(strlen("ifdef_"));
2291+
if (!Types.empty()) return nullptr;
2292+
if (OperationName.empty()) return nullptr;
2293+
return getIfdefOperation(Context, Id);
2294+
}
22832295

22842296
// If this starts with fence, we have special suffixes to handle.
22852297
if (OperationName.startswith("fence_")) {
@@ -2469,6 +2481,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
24692481

24702482
switch (BV) {
24712483
case BuiltinValueKind::Fence:
2484+
case BuiltinValueKind::Ifdef:
24722485
case BuiltinValueKind::CmpXChg:
24732486
case BuiltinValueKind::AtomicRMW:
24742487
case BuiltinValueKind::AtomicLoad:

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,7 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
14331433
Opts.VerifySILOwnership &= !Args.hasArg(OPT_disable_sil_ownership_verifier);
14341434
Opts.EnableDynamicReplacementCanCallPreviousImplementation = !Args.hasArg(
14351435
OPT_disable_previous_implementation_calls_in_dynamic_replacements);
1436+
Opts.ParseStdlib = FEOpts.ParseStdlib;
14361437

14371438
if (const Arg *A = Args.getLastArg(OPT_save_optimization_record_EQ)) {
14381439
llvm::Expected<llvm::remarks::Format> formatOrErr =

lib/IRGen/GenBuiltin.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/ADT/StringSwitch.h"
2323
#include "swift/AST/Builtins.h"
2424
#include "swift/AST/Types.h"
25+
#include "swift/SIL/SILInstruction.h"
2526
#include "swift/SIL/SILModule.h"
2627
#include "clang/AST/ASTContext.h"
2728

@@ -121,10 +122,12 @@ getLoweredTypeAndTypeInfo(IRGenModule &IGM, Type unloweredType) {
121122

122123
/// emitBuiltinCall - Emit a call to a builtin function.
123124
void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
124-
Identifier FnId, SILType resultType,
125-
ArrayRef<SILType> argTypes,
126-
Explosion &args, Explosion &out,
127-
SubstitutionMap substitutions) {
125+
BuiltinInst *Inst, ArrayRef<SILType> argTypes,
126+
Explosion &args, Explosion &out) {
127+
Identifier FnId = Inst->getName();
128+
SILType resultType = Inst->getType();
129+
SubstitutionMap substitutions = Inst->getSubstitutions();
130+
128131
if (Builtin.ID == BuiltinValueKind::COWBufferForReading) {
129132
// Just forward the incoming argument.
130133
assert(args.size() == 1 && "Expecting one incoming argument");
@@ -711,7 +714,15 @@ if (Builtin.ID == BuiltinValueKind::id) { \
711714
return;
712715
}
713716

714-
717+
if (Builtin.ID == BuiltinValueKind::Ifdef) {
718+
// Ifdef not constant folded, which means it was not @_alwaysEmitIntoClient
719+
IGF.IGM.error(
720+
Inst->getLoc().getSourceLoc(),
721+
"Builtin.ifdef can only be used in @_alwaysEmitIntoClient functions");
722+
out.add(IGF.Builder.getInt32(0));
723+
return;
724+
}
725+
715726
if (Builtin.ID == BuiltinValueKind::CmpXChg) {
716727
SmallVector<Type, 4> Types;
717728
StringRef BuiltinName =

lib/IRGen/GenBuiltin.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
namespace swift {
2525
class BuiltinInfo;
26+
class BuiltinInst;
2627
class Identifier;
2728
class SILType;
2829

@@ -32,10 +33,8 @@ namespace irgen {
3233

3334
/// Emit a call to a builtin function.
3435
void emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &builtin,
35-
Identifier fnId, SILType resultType,
36-
ArrayRef<SILType> argTypes,
37-
Explosion &args, Explosion &result,
38-
SubstitutionMap substitutions);
36+
BuiltinInst *Inst, ArrayRef<SILType> argTypes,
37+
Explosion &args, Explosion &result);
3938

4039
} // end namespace irgen
4140
} // end namespace swift

lib/IRGen/IRGenSIL.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2976,8 +2976,7 @@ void IRGenSILFunction::visitBuiltinInst(swift::BuiltinInst *i) {
29762976
}
29772977

29782978
Explosion result;
2979-
emitBuiltinCall(*this, builtin, i->getName(), i->getType(),
2980-
argTypes, args, result, i->getSubstitutions());
2979+
emitBuiltinCall(*this, builtin, i, argTypes, args, result);
29812980

29822981
setLoweredExplosion(i, result);
29832982
}

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFRem)
693693
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FSub)
694694
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFSub)
695695
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Fence)
696+
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Ifdef)
696697
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GetObjCTypeEncoding)
697698
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_EQ)
698699
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_NE)

lib/SIL/IR/SILModule.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ const BuiltinInfo &SILModule::getBuiltinInfo(Identifier ID) {
415415
// Builtins.def, so handle those first.
416416
if (OperationName.startswith("fence_"))
417417
Info.ID = BuiltinValueKind::Fence;
418+
else if (OperationName.startswith("ifdef_"))
419+
Info.ID = BuiltinValueKind::Ifdef;
418420
else if (OperationName.startswith("cmpxchg_"))
419421
Info.ID = BuiltinValueKind::CmpXChg;
420422
else if (OperationName.startswith("atomicrmw_"))

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, UnexpectedError)
520520
CONSTANT_OWNERSHIP_BUILTIN(None, ErrorInMain)
521521
CONSTANT_OWNERSHIP_BUILTIN(None, DeallocRaw)
522522
CONSTANT_OWNERSHIP_BUILTIN(None, Fence)
523+
CONSTANT_OWNERSHIP_BUILTIN(None, Ifdef)
523524
CONSTANT_OWNERSHIP_BUILTIN(None, AtomicStore)
524525
CONSTANT_OWNERSHIP_BUILTIN(None, Once)
525526
CONSTANT_OWNERSHIP_BUILTIN(None, OnceWithContext)

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ static bool isBarrier(SILInstruction *inst) {
155155
case BuiltinValueKind::AllocRaw:
156156
case BuiltinValueKind::DeallocRaw:
157157
case BuiltinValueKind::Fence:
158+
case BuiltinValueKind::Ifdef:
158159
case BuiltinValueKind::AtomicLoad:
159160
case BuiltinValueKind::AtomicStore:
160161
case BuiltinValueKind::AtomicRMW:

lib/SILOptimizer/Utils/ConstantFolding.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,14 @@ void ConstantFolder::initializeWorklist(SILFunction &f) {
15741574
continue;
15751575
}
15761576

1577+
// Builtin.ifdef only replaced when not building the stdlib.
1578+
if (isApplyOfBuiltin(*inst, BuiltinValueKind::Ifdef)) {
1579+
if (!inst->getModule().getASTContext().SILOpts.ParseStdlib) {
1580+
WorkList.insert(inst);
1581+
continue;
1582+
}
1583+
}
1584+
15771585
if (isApplyOfKnownAvailability(*inst)) {
15781586
WorkList.insert(inst);
15791587
continue;
@@ -1779,7 +1787,7 @@ ConstantFolder::processWorkList() {
17791787
if (isApplyOfBuiltin(*I, BuiltinValueKind::GlobalStringTablePointer)) {
17801788
if (constantFoldGlobalStringTablePointerBuiltin(cast<BuiltinInst>(I),
17811789
EnableDiagnostics)) {
1782-
// Here, the bulitin instruction got folded, so clean it up.
1790+
// Here, the builtin instruction got folded, so clean it up.
17831791
eliminateDeadInstruction(I, callbacks);
17841792
}
17851793
continue;
@@ -1804,13 +1812,36 @@ ConstantFolder::processWorkList() {
18041812

18051813
if (isApplyOfBuiltin(*I, BuiltinValueKind::IsConcrete)) {
18061814
if (constantFoldIsConcrete(cast<BuiltinInst>(I))) {
1807-
// Here, the bulitin instruction got folded, so clean it up.
1815+
// Here, the builtin instruction got folded, so clean it up.
18081816
recursivelyDeleteTriviallyDeadInstructions(I, /*force*/ true,
18091817
callbacks);
18101818
}
18111819
continue;
18121820
}
18131821

1822+
// Builtin.ifdef_... is expected to stay unresolved when building the stdlib
1823+
// and must be only used in @_alwaysEmitIntoClient exported functions, which
1824+
// means we never generate IR for it (when building stdlib). Client code is
1825+
// then always constant-folding this builtin based on the compilation flags
1826+
// of the client module.
1827+
if (isApplyOfBuiltin(*I, BuiltinValueKind::Ifdef)) {
1828+
if (!I->getModule().getASTContext().SILOpts.ParseStdlib) {
1829+
auto *BI = cast<BuiltinInst>(I);
1830+
StringRef flagName = BI->getName().str().drop_front(strlen("ifdef_"));
1831+
const LangOptions &langOpts = I->getModule().getASTContext().LangOpts;
1832+
bool val = langOpts.isCustomConditionalCompilationFlagSet(flagName);
1833+
1834+
SILBuilderWithScope builder(BI);
1835+
auto *inst = builder.createIntegerLiteral(
1836+
BI->getLoc(),
1837+
SILType::getBuiltinIntegerType(1, builder.getASTContext()), val);
1838+
BI->replaceAllUsesWith(inst);
1839+
1840+
eliminateDeadInstruction(I, callbacks);
1841+
continue;
1842+
}
1843+
}
1844+
18141845
if (auto *bi = dyn_cast<BuiltinInst>(I)) {
18151846
if (auto kind = bi->getBuiltinKind()) {
18161847
if (SILValue v = specializePolymorphicBuiltin(bi, kind.getValue())) {

test/stdlib/builtin-ifdef.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -parse-stdlib -whole-module-optimization -D LIBRARY -emit-module -o %t/Library.swiftmodule
3+
// RUN: %target-build-swift %s -parse-stdlib -whole-module-optimization -D LIBRARY -emit-bc -o %t/Library.bc
4+
// RUN: %target-build-swift %s -parse-as-library -D CLIENT -I %t -o %t/R1 -O && %target-run %t/R1 | %FileCheck %s
5+
// RUN: %target-build-swift %s -parse-as-library -D CLIENT -I %t -o %t/R2 -O -D FOO_BAR && %target-run %t/R2 | %FileCheck %s --check-prefix CHECK-FOO-BAR
6+
7+
// REQUIRES: executable_test
8+
9+
#if LIBRARY
10+
11+
@_alwaysEmitIntoClient
12+
public func ifdefFooBar() -> Builtin.Int1 {
13+
return Builtin.ifdef_FOO_BAR()
14+
}
15+
16+
#endif
17+
18+
#if CLIENT
19+
20+
import Library
21+
22+
@_cdecl("main")
23+
func main() -> Int32 {
24+
print("Hello")
25+
print(Bool(_builtinBooleanLiteral: ifdefFooBar()))
26+
// CHECK: Hello
27+
// CHECK: false
28+
29+
// CHECK-FOO-BAR: Hello
30+
// CHECK-FOO-BAR: true
31+
return 0
32+
}
33+
34+
#endif

0 commit comments

Comments
 (0)