diff --git a/docs/SIL.rst b/docs/SIL.rst index 766d06a5807..f7b957b1c14 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -341,11 +341,13 @@ Values and Operands sil-identifier ::= [A-Za-z_0-9]+ sil-value-name ::= '%' sil-identifier sil-value ::= sil-value-name ('#' [0-9]+)? + sil-value ::= 'undef' sil-operand ::= sil-value ':' sil-type SIL values are introduced with the ``%`` sigil and named by an alphanumeric identifier, which references the instruction or basic block -argument that produces the value. +argument that produces the value. SIL values may also refer to the keyword +'undef', which is a value of undefined contents. In SIL, a single instruction may produce multiple values. Operands that refer to multiple-value instructions choose the value by following the ``%name`` with ``#`` and the index of the value. For example:: diff --git a/include/swift/Parse/Tokens.def b/include/swift/Parse/Tokens.def index e3b98af30a6..dd22c1886bf 100644 --- a/include/swift/Parse/Tokens.def +++ b/include/swift/Parse/Tokens.def @@ -45,6 +45,7 @@ KEYWORD(subscript) KEYWORD(typealias) KEYWORD(var) +KEYWORD(undef) // This is only enabled when parsing .sil files. KEYWORD(sil) // This is only enabled when parsing .sil files. KEYWORD(sil_stage) // This is only enabled when parsing .sil files. KEYWORD(sil_vtable) // This is only enabled when parsing .sil files. diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index f8e473aa1d8..cf40ddd2854 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -41,6 +41,7 @@ namespace swift { class SILFunction; class SILVTable; class SILTypeList; + class SILUndef; class SourceFile; class TranslationUnit; @@ -78,6 +79,7 @@ private: friend class SILFunction; friend class SILType; friend class SILVTable; + friend class SILUndef; friend class Lowering::SILGenModule; friend class Lowering::TypeConverter; @@ -107,6 +109,9 @@ private: /// This is a cache of builtin Function declarations to numeric ID mappings. llvm::DenseMap BuiltinIDCache; + /// This is the set of undef values we've created, for uniquing purposes. + llvm::DenseMap UndefValues; + /// The stage of processing this module is at. SILStage Stage; diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index b37aee7b5a4..6e7b36d2c28 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -56,6 +56,7 @@ #endif VALUE(SILArgument, ValueBase) +VALUE(SILUndef, ValueBase) // Please keep the order of instructions consistent with the order of their // descriptions in the SIL reference in docs/SIL.rst. diff --git a/include/swift/SIL/SILUndef.h b/include/swift/SIL/SILUndef.h new file mode 100644 index 00000000000..f8dcfe222e9 --- /dev/null +++ b/include/swift/SIL/SILUndef.h @@ -0,0 +1,41 @@ +//===--- SILUndef.h - SIL Undef Value Representation ------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SIL_UNDEF_H +#define SWIFT_SIL_UNDEF_H + +#include "swift/SIL/SILValue.h" + +namespace swift { + class SILModule; + +class SILUndef : public ValueBase { + void operator=(const SILArgument &) = delete; + void operator delete(void *Ptr, size_t) = delete; + + SILUndef(SILType Ty) : ValueBase(ValueKind::SILUndef, Ty) {} +public: + + static SILUndef *get(SILType Ty, SILModule *M); + + /// getType() is ok since this is known to only have one type. + SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } + + static bool classof(const ValueBase *V) { + return V->getKind() == ValueKind::SILUndef; + } +}; + +} // end swift namespace + +#endif + diff --git a/include/swift/SIL/SILVisitor.h b/include/swift/SIL/SILVisitor.h index 001b9642c48..23485ae5498 100644 --- a/include/swift/SIL/SILVisitor.h +++ b/include/swift/SIL/SILVisitor.h @@ -19,6 +19,7 @@ #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILUndef.h" #include "llvm/Support/ErrorHandling.h" namespace swift { @@ -87,6 +88,9 @@ public: ValueRetTy visitSILArgument(SILArgument *A) { llvm_unreachable("should only be visiting instructions"); } + ValueRetTy visitSILUndef(SILUndef *U) { + llvm_unreachable("should only be visiting instructions"); + } ValueRetTy visit(SILInstruction *I) { return SILVisitor::visit(I); diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index 37e47d6da0e..72700beab1f 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -524,9 +524,9 @@ void Lexer::lexIdentifier() { #include "swift/Parse/Tokens.def" .Default(tok::identifier); - // "sil", "sil_stage" and "sil_vtable" are only keywords in SIL mode. + // These keywords are only active in SIL mode. if ((Kind == tok::kw_sil || Kind == tok::kw_sil_stage || - Kind == tok::kw_sil_vtable) && !InSILMode) + Kind == tok::kw_sil_vtable || Kind == tok::kw_undef) && !InSILMode) Kind = tok::identifier; return formToken(Kind, TokStart); diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp index 198f5dbec22..6b001f2a7f5 100644 --- a/lib/Parse/ParseSIL.cpp +++ b/lib/Parse/ParseSIL.cpp @@ -17,6 +17,7 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" +#include "swift/SIL/SILUndef.h" #include "swift/Subsystems.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/ADT/StringSwitch.h" @@ -119,6 +120,7 @@ namespace { SourceLoc NameLoc; unsigned ResultVal; + bool isUndef() const { return Name == "undef"; } bool isMRV() const { return ResultVal != ~0U; } }; @@ -356,6 +358,9 @@ bool SILParser::parseGlobalName(Identifier &Name) { /// and type. SILValue SILParser::getLocalValue(UnresolvedValueName Name, SILType Type, SILLocation Loc) { + if (Name.isUndef()) + return SILUndef::get(Type, &SILMod); + // Check to see if this is already defined. ValueBase *&Entry = LocalValues[Name.Name]; @@ -790,10 +795,17 @@ bool SILParser::parseSILDeclRef(SILDeclRef &Result) { /// /// sil-value-name: /// sil-local-name ('#' integer_literal)? +/// 'undef' /// bool SILParser::parseValueName(UnresolvedValueName &Result) { Result.Name = P.Tok.getText(); + if (P.Tok.is(tok::kw_undef)) { + Result.NameLoc = P.consumeToken(tok::kw_undef); + Result.ResultVal = ~1U; + return false; + } + // Parse the local-name. if (P.parseToken(tok::sil_local_name, Result.NameLoc, diag::expected_sil_value_name)) @@ -1105,6 +1117,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { ValueBase *ResultVal; switch (Opcode) { case ValueKind::SILArgument: + case ValueKind::SILUndef: llvm_unreachable("not an instruction"); case ValueKind::AllocBoxInst: { diff --git a/lib/SIL/SIL.cpp b/lib/SIL/SIL.cpp index 5efd5305505..c3daa6f6d7f 100644 --- a/lib/SIL/SIL.cpp +++ b/lib/SIL/SIL.cpp @@ -14,6 +14,7 @@ #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILType.h" +#include "swift/SIL/SILUndef.h" #include "swift/AST/ASTContext.h" #include "swift/AST/AnyFunctionRef.h" #include "swift/AST/Decl.h" @@ -28,6 +29,16 @@ void SILValue::replaceAllUsesWith(SILValue V) { (**use_begin()).set(V); } +SILUndef *SILUndef::get(SILType Ty, SILModule *M) { + // Unique these. + SILUndef *&Entry = M->UndefValues[Ty]; + if (Entry == nullptr) + Entry = new (*M) SILUndef(Ty); + return Entry; +} + + + static unsigned getFuncNaturalUncurryLevel(AnyFunctionRef AFR) { assert(AFR.getArgParamPatterns().size() >= 1 && "no arguments for func?!"); unsigned Level = AFR.getArgParamPatterns().size() - 1; @@ -270,24 +281,12 @@ SILType SILType::getBuiltinFloatType(BuiltinFloatType::FPKind Kind, const ASTContext &C) { Type ty; switch (Kind) { - case BuiltinFloatType::IEEE16: - ty = C.TheIEEE16Type; - break; - case BuiltinFloatType::IEEE32: - ty = C.TheIEEE32Type; - break; - case BuiltinFloatType::IEEE64: - ty = C.TheIEEE64Type; - break; - case BuiltinFloatType::IEEE80: - ty = C.TheIEEE80Type; - break; - case BuiltinFloatType::IEEE128: - ty = C.TheIEEE128Type; - break; - case BuiltinFloatType::PPC128: - ty = C.ThePPC128Type; - break; + case BuiltinFloatType::IEEE16: ty = C.TheIEEE16Type; break; + case BuiltinFloatType::IEEE32: ty = C.TheIEEE32Type; break; + case BuiltinFloatType::IEEE64: ty = C.TheIEEE64Type; break; + case BuiltinFloatType::IEEE80: ty = C.TheIEEE80Type; break; + case BuiltinFloatType::IEEE128: ty = C.TheIEEE128Type; break; + case BuiltinFloatType::PPC128: ty = C.ThePPC128Type; break; } return getPrimitiveObjectType(CanType(ty)); } diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp index 43a92d76983..a18a6f147e9 100644 --- a/lib/SIL/SILInstruction.cpp +++ b/lib/SIL/SILInstruction.cpp @@ -182,6 +182,7 @@ SILInstructionMemoryBehavior SILInstruction::getMemoryBehavior() const { case ValueKind::CLASS: return SILInstructionMemoryBehavior::MEMBEHAVIOR; #include "swift/SIL/SILNodes.def" case ValueKind::SILArgument: + case ValueKind::SILUndef: llvm_unreachable("Non-instructions are unreachable."); } llvm_unreachable("We've just exhausted the switch."); diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index df0320c7296..26c56ff00db 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -37,7 +37,7 @@ using namespace Demangle; struct ID { enum ID_Kind { - SILBasicBlock, SSAValue + SILBasicBlock, SILUndef, SSAValue } Kind; unsigned Number; int ResultNumber; @@ -69,6 +69,7 @@ public: if (!OS.has_colors()) return; switch (K) { + DEF_COL(ID::SILUndef, RED) DEF_COL(ID::SILBasicBlock, GREEN) DEF_COL(ID::SSAValue, MAGENTA) } @@ -90,6 +91,7 @@ public: static raw_ostream &operator<<(raw_ostream &OS, ID i) { SILColor C(OS, i.Kind); switch (i.Kind) { + case ID::SILUndef: OS << "undef"; return OS; case ID::SILBasicBlock: OS << "bb"; break; case ID::SSAValue: OS << '%'; break; } @@ -477,7 +479,15 @@ public: OS << "argument of " << getID(A->getParent()) << " : "; A->getType().print(OS); } - + + void visitSILUndef(SILUndef *A) { + // This should really only happen during debugging. + OS << "undef<"; + A->getType().print(OS); + OS << ">"; + } + + void visitAllocStackInst(AllocStackInst *AVI) { OS << "alloc_stack " << AVI->getElementType(); if (VarDecl *vd = AVI->getDecl()) @@ -1018,6 +1028,9 @@ ID SILPrinter::getID(const SILBasicBlock *Block) { } ID SILPrinter::getID(SILValue V) { + if (isa(V)) + return { ID::SILUndef }; + // Lazily initialize the instruction -> ID mapping. if (ValueToIDMap.empty()) { const SILBasicBlock *ParentBB; diff --git a/lib/SILPasses/DeadCodeElimination.cpp b/lib/SILPasses/DeadCodeElimination.cpp index 4b00acfed7e..e0962e50365 100644 --- a/lib/SILPasses/DeadCodeElimination.cpp +++ b/lib/SILPasses/DeadCodeElimination.cpp @@ -96,7 +96,7 @@ static bool eraseAndCleanup(const llvm::DenseSet &ToBeDeleted){ for (auto II = ToBeDeleted.begin(), EI = ToBeDeleted.end(); II != EI; ++II) { // Deleting instructions might make their operands dead, let's collect them. - SILInstruction* DI = *II; + SILInstruction *DI = *II; ArrayRef Ops = DI->getAllOperands(); for (auto OpI = Ops.begin(), OpE = Ops.end(); OpI != OpE; ++OpI) { SILInstruction *V = dyn_cast_or_null(OpI->get().getDef()); @@ -105,7 +105,7 @@ static bool eraseAndCleanup(const llvm::DenseSet &ToBeDeleted){ PossiblyDead.insert(V); } - // Drop references for all the instrcutions that will be deleted. + // Drop references for all the instructions that will be deleted. DI->dropAllReferences(); } diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 37620669907..3fdefb9d4e1 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -17,6 +17,7 @@ #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILModule.h" +#include "swift/SIL/SILUndef.h" #include "swift/Serialization/BCReadingExtras.h" // This is a template-only header; eventually it should move to llvm/Support. @@ -168,6 +169,9 @@ void SILDeserializer::setLocalValue(ValueBase *Value, ValueID Id) { SILValue SILDeserializer::getLocalValue(ValueID Id, unsigned ResultNum, SILType Type) { + if (Id == 0) + return SILUndef::get(Type, &SILMod); + // Check to see if this is already defined. ValueBase *&Entry = LocalValues[Id]; if (Entry) { @@ -459,6 +463,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, ValueBase *ResultVal; switch ((ValueKind)OpCode) { case ValueKind::SILArgument: + case ValueKind::SILUndef: llvm_unreachable("not an instruction"); #define ONETYPE_INST(ID) \ diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index e50fe549044..287629f818b 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -15,6 +15,7 @@ #include "swift/AST/Module.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILModule.h" +#include "swift/SIL/SILUndef.h" // This is a template-only header; eventually it should move to llvm/Support. #include "clang/Basic/OnDiskHashTable.h" @@ -149,7 +150,7 @@ SILSerializer::SILSerializer(Serializer &S, ASTContext &Ctx, /// We enumerate all values to update ValueIDs in a separate pass /// to correctly handle forward reference of a value. ValueID SILSerializer::addValueRef(const ValueBase *Val) { - if (!Val) + if (!Val || isa(Val)) return 0; ValueID &id = ValueIDs[Val]; @@ -232,6 +233,7 @@ void SILSerializer::handleMethodInst(const MethodInst *MI, void SILSerializer::writeSILInstruction(const SILInstruction &SI) { switch (SI.getKind()) { case ValueKind::SILArgument: + case ValueKind::SILUndef: llvm_unreachable("not an instruction"); case ValueKind::UnreachableInst: { diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil index 055d4cfd971..4abcf7a1d36 100644 --- a/test/SIL/Parser/basic.sil +++ b/test/SIL/Parser/basic.sil @@ -1037,3 +1037,10 @@ sil_vtable Foo { #Foo.subscript!getter.2: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sig #Foo.subscript!setter.2: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sis } + +sil @undef_value : $() -> () { +bb0: + store undef to undef : $*Builtin.Int1 + unreachable +} +