Skip to content

Add Builtin.ifdef_<FLAGNAME> as a facility to peek at -D flag that client code is building with #39797

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,9 @@ BUILTIN_MISC_OPERATION(StaticReport, "staticReport", "", Special)
/// Returns the selected assertion configuration.
BUILTIN_MISC_OPERATION(AssertConf, "assert_configuration", "n", Special)

/// Ifdef has type () -> Bool.
BUILTIN_MISC_OPERATION(Ifdef, "ifdef", "n", Special)

/// StringObjectOr has type (T,T) -> T.
/// Sets bits in a string object. The first operand is bit-cast string literal
/// pointer to an integer. The second operand is the bit mask to be or'd into
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/SILOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ class SILOptions {
/// }
bool EnableDynamicReplacementCanCallPreviousImplementation = true;

/// Are we parsing the stdlib, i.e. -parse-stdlib?
bool ParseStdlib = false;

/// The name of the file to which the backend should save optimization
/// records.
std::string OptRecordFile;
Expand Down
13 changes: 13 additions & 0 deletions lib/AST/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,10 @@ static ValueDecl *getFenceOperation(ASTContext &ctx, Identifier id) {
return getBuiltinFunction(ctx, id, _thin, _parameters(), _void);
}

static ValueDecl *getIfdefOperation(ASTContext &ctx, Identifier id) {
return getBuiltinFunction(ctx, id, _thin, _parameters(), _int(1));
}

static ValueDecl *getVoidErrorOperation(ASTContext &ctx, Identifier id) {
return getBuiltinFunction(ctx, id, _thin, _parameters(_error), _void);
}
Expand Down Expand Up @@ -2280,6 +2284,14 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
if (getSwiftFunctionTypeForIntrinsic(ID, Types, Context, ArgElts, ResultTy))
return getBuiltinFunction(Id, ArgElts, ResultTy);
}

// If this starts with fence, we have special suffixes to handle.
if (OperationName.startswith("ifdef_")) {
OperationName = OperationName.drop_front(strlen("ifdef_"));
if (!Types.empty()) return nullptr;
if (OperationName.empty()) return nullptr;
return getIfdefOperation(Context, Id);
}

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

switch (BV) {
case BuiltinValueKind::Fence:
case BuiltinValueKind::Ifdef:
case BuiltinValueKind::CmpXChg:
case BuiltinValueKind::AtomicRMW:
case BuiltinValueKind::AtomicLoad:
Expand Down
1 change: 1 addition & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,7 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
Opts.VerifySILOwnership &= !Args.hasArg(OPT_disable_sil_ownership_verifier);
Opts.EnableDynamicReplacementCanCallPreviousImplementation = !Args.hasArg(
OPT_disable_previous_implementation_calls_in_dynamic_replacements);
Opts.ParseStdlib = FEOpts.ParseStdlib;

if (const Arg *A = Args.getLastArg(OPT_save_optimization_record_EQ)) {
llvm::Expected<llvm::remarks::Format> formatOrErr =
Expand Down
21 changes: 16 additions & 5 deletions lib/IRGen/GenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "swift/AST/Builtins.h"
#include "swift/AST/Types.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "clang/AST/ASTContext.h"

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

/// emitBuiltinCall - Emit a call to a builtin function.
void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
Identifier FnId, SILType resultType,
ArrayRef<SILType> argTypes,
Explosion &args, Explosion &out,
SubstitutionMap substitutions) {
BuiltinInst *Inst, ArrayRef<SILType> argTypes,
Explosion &args, Explosion &out) {
Identifier FnId = Inst->getName();
SILType resultType = Inst->getType();
SubstitutionMap substitutions = Inst->getSubstitutions();

if (Builtin.ID == BuiltinValueKind::COWBufferForReading) {
// Just forward the incoming argument.
assert(args.size() == 1 && "Expecting one incoming argument");
Expand Down Expand Up @@ -711,7 +714,15 @@ if (Builtin.ID == BuiltinValueKind::id) { \
return;
}


if (Builtin.ID == BuiltinValueKind::Ifdef) {
// Ifdef not constant folded, which means it was not @_alwaysEmitIntoClient
IGF.IGM.error(
Inst->getLoc().getSourceLoc(),
"Builtin.ifdef can only be used in @_alwaysEmitIntoClient functions");
out.add(IGF.Builder.getInt32(0));
return;
}

if (Builtin.ID == BuiltinValueKind::CmpXChg) {
SmallVector<Type, 4> Types;
StringRef BuiltinName =
Expand Down
7 changes: 3 additions & 4 deletions lib/IRGen/GenBuiltin.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

namespace swift {
class BuiltinInfo;
class BuiltinInst;
class Identifier;
class SILType;

Expand All @@ -32,10 +33,8 @@ namespace irgen {

/// Emit a call to a builtin function.
void emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &builtin,
Identifier fnId, SILType resultType,
ArrayRef<SILType> argTypes,
Explosion &args, Explosion &result,
SubstitutionMap substitutions);
BuiltinInst *Inst, ArrayRef<SILType> argTypes,
Explosion &args, Explosion &result);

} // end namespace irgen
} // end namespace swift
Expand Down
3 changes: 1 addition & 2 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2976,8 +2976,7 @@ void IRGenSILFunction::visitBuiltinInst(swift::BuiltinInst *i) {
}

Explosion result;
emitBuiltinCall(*this, builtin, i->getName(), i->getType(),
argTypes, args, result, i->getSubstitutions());
emitBuiltinCall(*this, builtin, i, argTypes, args, result);

setLoweredExplosion(i, result);
}
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/IR/OperandOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFRem)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FSub)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFSub)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Fence)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Ifdef)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GetObjCTypeEncoding)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_EQ)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_NE)
Expand Down
2 changes: 2 additions & 0 deletions lib/SIL/IR/SILModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ const BuiltinInfo &SILModule::getBuiltinInfo(Identifier ID) {
// Builtins.def, so handle those first.
if (OperationName.startswith("fence_"))
Info.ID = BuiltinValueKind::Fence;
else if (OperationName.startswith("ifdef_"))
Info.ID = BuiltinValueKind::Ifdef;
else if (OperationName.startswith("cmpxchg_"))
Info.ID = BuiltinValueKind::CmpXChg;
else if (OperationName.startswith("atomicrmw_"))
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/IR/ValueOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, UnexpectedError)
CONSTANT_OWNERSHIP_BUILTIN(None, ErrorInMain)
CONSTANT_OWNERSHIP_BUILTIN(None, DeallocRaw)
CONSTANT_OWNERSHIP_BUILTIN(None, Fence)
CONSTANT_OWNERSHIP_BUILTIN(None, Ifdef)
CONSTANT_OWNERSHIP_BUILTIN(None, AtomicStore)
CONSTANT_OWNERSHIP_BUILTIN(None, Once)
CONSTANT_OWNERSHIP_BUILTIN(None, OnceWithContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ static bool isBarrier(SILInstruction *inst) {
case BuiltinValueKind::AllocRaw:
case BuiltinValueKind::DeallocRaw:
case BuiltinValueKind::Fence:
case BuiltinValueKind::Ifdef:
case BuiltinValueKind::AtomicLoad:
case BuiltinValueKind::AtomicStore:
case BuiltinValueKind::AtomicRMW:
Expand Down
35 changes: 33 additions & 2 deletions lib/SILOptimizer/Utils/ConstantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,14 @@ void ConstantFolder::initializeWorklist(SILFunction &f) {
continue;
}

// Builtin.ifdef only replaced when not building the stdlib.
if (isApplyOfBuiltin(*inst, BuiltinValueKind::Ifdef)) {
if (!inst->getModule().getASTContext().SILOpts.ParseStdlib) {
WorkList.insert(inst);
continue;
}
}

if (isApplyOfKnownAvailability(*inst)) {
WorkList.insert(inst);
continue;
Expand Down Expand Up @@ -1779,7 +1787,7 @@ ConstantFolder::processWorkList() {
if (isApplyOfBuiltin(*I, BuiltinValueKind::GlobalStringTablePointer)) {
if (constantFoldGlobalStringTablePointerBuiltin(cast<BuiltinInst>(I),
EnableDiagnostics)) {
// Here, the bulitin instruction got folded, so clean it up.
// Here, the builtin instruction got folded, so clean it up.
eliminateDeadInstruction(I, callbacks);
}
continue;
Expand All @@ -1804,13 +1812,36 @@ ConstantFolder::processWorkList() {

if (isApplyOfBuiltin(*I, BuiltinValueKind::IsConcrete)) {
if (constantFoldIsConcrete(cast<BuiltinInst>(I))) {
// Here, the bulitin instruction got folded, so clean it up.
// Here, the builtin instruction got folded, so clean it up.
recursivelyDeleteTriviallyDeadInstructions(I, /*force*/ true,
callbacks);
}
continue;
}

// Builtin.ifdef_... is expected to stay unresolved when building the stdlib
// and must be only used in @_alwaysEmitIntoClient exported functions, which
// means we never generate IR for it (when building stdlib). Client code is
// then always constant-folding this builtin based on the compilation flags
// of the client module.
if (isApplyOfBuiltin(*I, BuiltinValueKind::Ifdef)) {
if (!I->getModule().getASTContext().SILOpts.ParseStdlib) {
auto *BI = cast<BuiltinInst>(I);
StringRef flagName = BI->getName().str().drop_front(strlen("ifdef_"));
const LangOptions &langOpts = I->getModule().getASTContext().LangOpts;
bool val = langOpts.isCustomConditionalCompilationFlagSet(flagName);

SILBuilderWithScope builder(BI);
auto *inst = builder.createIntegerLiteral(
BI->getLoc(),
SILType::getBuiltinIntegerType(1, builder.getASTContext()), val);
BI->replaceAllUsesWith(inst);

eliminateDeadInstruction(I, callbacks);
continue;
}
}

if (auto *bi = dyn_cast<BuiltinInst>(I)) {
if (auto kind = bi->getBuiltinKind()) {
if (SILValue v = specializePolymorphicBuiltin(bi, kind.getValue())) {
Expand Down
34 changes: 34 additions & 0 deletions test/stdlib/builtin-ifdef.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift %s -parse-stdlib -whole-module-optimization -D LIBRARY -emit-module -o %t/Library.swiftmodule
// RUN: %target-build-swift %s -parse-stdlib -whole-module-optimization -D LIBRARY -emit-bc -o %t/Library.bc
// RUN: %target-build-swift %s -parse-as-library -D CLIENT -I %t -o %t/R1 -O && %target-run %t/R1 | %FileCheck %s
// 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

// REQUIRES: executable_test

#if LIBRARY

@_alwaysEmitIntoClient
public func ifdefFooBar() -> Builtin.Int1 {
return Builtin.ifdef_FOO_BAR()
}

#endif

#if CLIENT

import Library

@_cdecl("main")
func main() -> Int32 {
print("Hello")
print(Bool(_builtinBooleanLiteral: ifdefFooBar()))
// CHECK: Hello
// CHECK: false

// CHECK-FOO-BAR: Hello
// CHECK-FOO-BAR: true
return 0
}

#endif