Skip to content

Introduce Builtin.bindMemory and SIL bind_memory. #3573

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
Jul 18, 2016
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
14 changes: 14 additions & 0 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2240,6 +2240,20 @@ index_raw_pointer
Given a ``Builtin.RawPointer`` value ``%0``, returns a pointer value at the
byte offset ``%1`` relative to ``%0``.

bind_memory
```````````

::

sil-instruction ::= 'bind_memory' sil-operand ',' sil-operand 'to' sil-type

bind_memory %0 : $Builtin.RawPointer, %1 : $Builtin.Word to $T
// %0 must be of $Builtin.RawPointer type
// %1 must be of $Builtin.Word type

Binds memory at ``Builtin.RawPointer`` value ``%0`` to type ``$T`` with enough
capacity to hold ``%1`` values. See SE-0107: UnsafeRawPointer.

Reference Counting
~~~~~~~~~~~~~~~~~~

Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,9 @@ BUILTIN_SIL_OPERATION(IsUnique_native, "isUnique_native", Special)
BUILTIN_SIL_OPERATION(IsUniqueOrPinned_native, "isUniqueOrPinned_native",
Special)

/// bindMemory : <T> (Builtin.RawPointer, Builtin.Word, T.Type) -> ()
BUILTIN_SIL_OPERATION(BindMemory, "bindMemory", Special)

#undef BUILTIN_SIL_OPERATION

// BUILTIN_RUNTIME_CALL - A call into a runtime function.
Expand Down
6 changes: 6 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,12 @@ class SILBuilder {
getSILDebugLocation(Loc), srcAddr, destAddr, isTake, isInitialize));
}

BindMemoryInst *createBindMemory(SILLocation Loc, SILValue base,
SILValue index, SILType boundType) {
return insert(BindMemoryInst::create(getSILDebugLocation(Loc), base, index,
boundType, F, OpenedArchetypes));
}

ConvertFunctionInst *createConvertFunction(SILLocation Loc, SILValue Op,
SILType Ty) {
return insert(new (F.getModule())
Expand Down
11 changes: 11 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,17 @@ SILCloner<ImplClass>::visitCopyAddrInst(CopyAddrInst *Inst) {
Inst->isInitializationOfDest()));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitBindMemoryInst(BindMemoryInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst,
getBuilder().createBindMemory(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getBase()),
getOpValue(Inst->getIndex()),
Inst->getBoundType()));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitConvertFunctionInst(ConvertFunctionInst *Inst) {
Expand Down
88 changes: 84 additions & 4 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class SILInstruction : public ValueBase,public llvm::ilist_node<SILInstruction>{
/// Return the array of opened archetypes operands for this instruction.
MutableArrayRef<Operand> getOpenedArchetypeOperands();

/// Returns true if a given kind of instruciton may have opened archetype
/// Returns true if a given kind of instruction may have opened archetype
/// operands.
bool mayHaveOpenedArchetypeOperands() const;

Expand Down Expand Up @@ -511,7 +511,6 @@ class UnaryInstructionWithOpenArchetypesBase :
}
};


/// Holds common debug information about local variables and function
/// arguments that are needed by DebugValueInst, DebugValueAddrInst,
/// AllocStackInst, and AllocBoxInst.
Expand Down Expand Up @@ -1573,6 +1572,10 @@ class StringLiteralInst final : public LiteralInst,
}
};

//===----------------------------------------------------------------------===//
// Memory instructions.
//===----------------------------------------------------------------------===//

/// StringLiteralInst::Encoding hashes to its underlying integer representation.
static inline llvm::hash_code hash_value(StringLiteralInst::Encoding E) {
return llvm::hash_value(size_t(E));
Expand Down Expand Up @@ -2047,6 +2050,83 @@ class CopyAddrInst : public SILInstruction {
}
};

/// BindMemoryInst -
/// "bind_memory %0 : $Builtin.RawPointer, %1 : $Builtin.Word to $T"
/// Binds memory at the raw pointer %0 to type $T with enough capacity
/// to hold $1 values.
class BindMemoryInst final :
public SILInstruction,
protected llvm::TrailingObjects<BindMemoryInst, Operand> {

typedef llvm::TrailingObjects<BindMemoryInst, Operand> TrailingBase;
friend TrailingBase;
using TrailingBase::totalSizeToAlloc;

friend class SILBuilder;

enum { BaseOperIdx, IndexOperIdx, NumFixedOpers };

SILType BoundType;

// Fixed operands + opened archetype operands.
unsigned NumOperands;

static BindMemoryInst *create(
SILDebugLocation Loc, SILValue Base, SILValue Index, SILType BoundType,
SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes);

BindMemoryInst(SILDebugLocation Loc, SILValue Base, SILValue Index,
SILType BoundType,
ArrayRef<SILValue> OpenedArchetypeOperands);

public:
// Destruct tail allocated objects.
~BindMemoryInst() {
Operand *Operands = &getAllOperands()[0];
for (unsigned i = 0, end = NumOperands; i < end; ++i) {
Operands[i].~Operand();
}
}

SILValue getBase() const { return getAllOperands()[BaseOperIdx].get(); }

SILValue getIndex() const { return getAllOperands()[IndexOperIdx].get(); }

SILType getBoundType() const { return BoundType ; }

// Implement llvm::TrailingObjects.
size_t numTrailingObjects(
typename TrailingBase::template OverloadToken<Operand>) const {
return NumOperands;
}

ArrayRef<Operand> getAllOperands() const {
return {TrailingBase::template getTrailingObjects<Operand>(),
static_cast<size_t>(NumOperands)};
}

MutableArrayRef<Operand> getAllOperands() {
return {TrailingBase::template getTrailingObjects<Operand>(),
static_cast<size_t>(NumOperands)};
}

ArrayRef<Operand> getOpenedArchetypeOperands() const {
return getAllOperands().slice(2);
}

MutableArrayRef<Operand> getOpenedArchetypeOperands() {
return getAllOperands().slice(2);
}

static bool classof(const ValueBase *V) {
return V->getKind() == ValueKind::BindMemoryInst;
}
};

//===----------------------------------------------------------------------===//
// Conversion instructions.
//===----------------------------------------------------------------------===//

/// ConversionInst - Abstract class representing instructions that convert
/// values.
///
Expand Down Expand Up @@ -4189,7 +4269,7 @@ class IndexingInst : public SILInstruction {
}
};

/// IndexAddrInst - "%2 : $*T = index_addr %0 : $*T, %1 : $Builtin.Int64"
/// IndexAddrInst - "%2 : $*T = index_addr %0 : $*T, %1 : $Builtin.Word"
/// This takes an address and indexes it, striding by the pointed-
/// to type. This is used to index into arrays of uniform elements.
class IndexAddrInst : public IndexingInst {
Expand All @@ -4208,7 +4288,7 @@ class IndexAddrInst : public IndexingInst {

/// IndexRawPointerInst
/// %2 : $Builtin.RawPointer \
/// = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Int64
/// = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Word
/// This takes an address and indexes it, striding by the pointed-
/// to type. This is used to index into arrays of uniform elements.
class IndexRawPointerInst : public IndexingInst {
Expand Down
5 changes: 5 additions & 0 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
INST(IndexRawPointerInst, IndexingInst, None, DoesNotRelease)
VALUE_RANGE(IndexingInst, IndexAddrInst, IndexRawPointerInst)

// BindMemory has no physical side effect. Semantically it writes to
// its affected memory region because any reads or writes accessing
// that memory must be dependent on the bind operation.
INST(BindMemoryInst, SILInstruction, MayWrite, DoesNotRelease)

// Reference Counting
ABSTRACT_VALUE(RefCountingInst, SILInstruction)
INST(StrongRetainInst, RefCountingInst, MayHaveSideEffects, DoesNotRelease)
Expand Down
10 changes: 10 additions & 0 deletions include/swift/SIL/SILValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,16 @@ class TrailingOperandsList {
new (p++) Operand(user, op);
}
}
static void InitOperandsList(Operand *p, SILInstruction *user,
SILValue operand0, SILValue operand1,
ArrayRef<SILValue> operands) {
assert(p && "Trying to initialize operands using a nullptr");
new (p++) Operand(user, operand0);
new (p++) Operand(user, operand1);
for (auto op : operands) {
new (p++) Operand(user, op);
}
}

static void InitOperandsList(Operand *p, SILInstruction *user,
ArrayRef<SILValue> operands) {
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 254; // Last change: remove tuple default args
const uint16_t VERSION_MINOR = 255; // Last change: bind_memory instruction

using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
Expand Down
13 changes: 13 additions & 0 deletions lib/AST/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,15 @@ static ValueDecl *getIsUniqueOperation(ASTContext &Context, Identifier Id) {
return builder.build(Id);
}

static ValueDecl *getBindMemoryOperation(ASTContext &Context, Identifier Id) {
GenericSignatureBuilder builder(Context);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(BuiltinIntegerType::getWordType(Context)));
builder.addParameter(makeMetatype(makeGenericParam()));
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
return builder.build(Id);
}

static ValueDecl *getSizeOrAlignOfOperation(ASTContext &Context,
Identifier Id) {
GenericSignatureBuilder builder(Context);
Expand Down Expand Up @@ -1504,6 +1513,10 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
if (!Types.empty()) return nullptr;
return getIsUniqueOperation(Context, Id);

case BuiltinValueKind::BindMemory:
if (!Types.empty()) return nullptr;
return getBindMemoryOperation(Context, Id);

case BuiltinValueKind::Sizeof:
case BuiltinValueKind::Strideof:
case BuiltinValueKind::Alignof:
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,8 @@ class IRGenSILFunction :
void visitCopyAddrInst(CopyAddrInst *i);
void visitDestroyAddrInst(DestroyAddrInst *i);

void visitBindMemoryInst(BindMemoryInst *i);

void visitCondFailInst(CondFailInst *i);

void visitConvertFunctionInst(ConvertFunctionInst *i);
Expand Down Expand Up @@ -4564,6 +4566,10 @@ void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) {
}
}

// This is a no-op because we do not lower Swift TBAA info to LLVM IR, and it
// does not produce any values.
void IRGenSILFunction::visitBindMemoryInst(swift::BindMemoryInst *) {}

static DeallocStackInst *
findPairedDeallocStackForDestroyAddr(DestroyAddrInst *destroyAddr) {
// This peephole only applies if the address being destroyed is the
Expand Down
22 changes: 22 additions & 0 deletions lib/Parse/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
.Case("alloc_ref", ValueKind::AllocRefInst)
.Case("alloc_ref_dynamic", ValueKind::AllocRefDynamicInst)
.Case("alloc_value_buffer", ValueKind::AllocValueBufferInst)
.Case("bind_memory", ValueKind::BindMemoryInst)
.Case("value_metatype", ValueKind::ValueMetatypeInst)
.Case("witness_method", ValueKind::WitnessMethodInst)
.Case("apply", ValueKind::ApplyInst)
Expand Down Expand Up @@ -2965,6 +2966,27 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
IsInitialization_t(IsInit));
break;
}
case ValueKind::BindMemoryInst: {
SILValue IndexVal;
Identifier ToToken;
SourceLoc ToLoc;
SILType EltTy;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(IndexVal, B) ||
parseSILIdentifier(ToToken, ToLoc,
diag::expected_tok_in_sil_instr, "to") ||
parseSILType(EltTy) ||
parseSILDebugLocation(InstLoc, B))
return true;

if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
ResultVal = B.createBindMemory(InstLoc, Val, IndexVal, EltTy);
break;
}
case ValueKind::StructInst: {
SILType StructTy;
if (parseSILType(StructTy) ||
Expand Down
5 changes: 5 additions & 0 deletions lib/SIL/SILInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ namespace {
return (X->getSrc() == RHS->getSrc() && X->getDest() == RHS->getDest());
}

bool visitBindMemoryInst(const BindMemoryInst *RHS) {
auto *X = cast<BindMemoryInst>(LHS);
return X->getBoundType() == RHS->getBoundType();
}

bool visitFunctionRefInst(const FunctionRefInst *RHS) {
auto *X = cast<FunctionRefInst>(LHS);
return X->getReferencedFunction() == RHS->getReferencedFunction();
Expand Down
27 changes: 27 additions & 0 deletions lib/SIL/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,33 @@ CopyAddrInst::CopyAddrInst(SILDebugLocation Loc, SILValue SrcLValue,
IsInitializationOfDest(isInitializationOfDest),
Operands(this, SrcLValue, DestLValue) {}

BindMemoryInst *
BindMemoryInst::create(SILDebugLocation Loc, SILValue Base, SILValue Index,
SILType BoundType, SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes) {
SmallVector<SILValue, 8> OpenedArchetypeOperands;
collectOpenedArchetypeOperands(BoundType.getSwiftRValueType(),
OpenedArchetypeOperands,
OpenedArchetypes, F.getModule());
void *Buffer = F.getModule().allocateInst(
sizeof(BindMemoryInst) +
sizeof(Operand) * (OpenedArchetypeOperands.size() + NumFixedOpers),
alignof(BindMemoryInst));
return ::new (Buffer)
BindMemoryInst(Loc, Base, Index, BoundType, OpenedArchetypeOperands);
}

BindMemoryInst::BindMemoryInst(SILDebugLocation Loc, SILValue Base,
SILValue Index,
SILType BoundType,
ArrayRef<SILValue> OpenedArchetypeOperands)
: SILInstruction(ValueKind::BindMemoryInst, Loc),
BoundType(BoundType),
NumOperands(NumFixedOpers + OpenedArchetypeOperands.size()) {
TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
Base, Index, OpenedArchetypeOperands);
}

UncheckedRefCastAddrInst::UncheckedRefCastAddrInst(SILDebugLocation Loc,
SILValue src,
CanType srcType,
Expand Down
7 changes: 7 additions & 0 deletions lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,13 @@ class SILPrinter : public SILVisitor<SILPrinter> {
*this << "[initialization] ";
*this << getIDAndType(CI->getDest());
}

void visitBindMemoryInst(BindMemoryInst *BI) {
*this << "bind_memory ";
*this << getIDAndType(BI->getBase()) << ", ";
*this << getIDAndType(BI->getIndex()) << " to ";
*this << BI->getBoundType();
}

void printUncheckedConversionInst(ConversionInst *CI, SILValue operand,
StringRef name) {
Expand Down
10 changes: 10 additions & 0 deletions lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1539,6 +1539,16 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
"Operand of destroy_addr must be address");
}

void checkBindMemoryInst(BindMemoryInst *BI) {
require(!BI->getType(), "BI must not produce a type");
require(BI->getBoundType(), "BI must have a bound type");
require(BI->getBase()->getType().is<BuiltinRawPointerType>(),
"bind_memory base be a RawPointer");
require(BI->getIndex()->getType()
== SILType::getBuiltinWordType(F.getASTContext()),
"bind_memory index must be a Word");
}

void checkIndexAddrInst(IndexAddrInst *IAI) {
require(IAI->getType().isAddress(), "index_addr must produce an address");
require(IAI->getType() == IAI->getBase()->getType(),
Expand Down
Loading