Skip to content

Commit 2b732d0

Browse files
authored
Introduce Builtin.bindMemory and SIL bind_memory. (#3573)
Required for SE-0107: UnsafeRawPointer.
1 parent ebbc643 commit 2b732d0

File tree

25 files changed

+317
-8
lines changed

25 files changed

+317
-8
lines changed

docs/SIL.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,6 +2240,20 @@ index_raw_pointer
22402240
Given a ``Builtin.RawPointer`` value ``%0``, returns a pointer value at the
22412241
byte offset ``%1`` relative to ``%0``.
22422242

2243+
bind_memory
2244+
```````````
2245+
2246+
::
2247+
2248+
sil-instruction ::= 'bind_memory' sil-operand ',' sil-operand 'to' sil-type
2249+
2250+
bind_memory %0 : $Builtin.RawPointer, %1 : $Builtin.Word to $T
2251+
// %0 must be of $Builtin.RawPointer type
2252+
// %1 must be of $Builtin.Word type
2253+
2254+
Binds memory at ``Builtin.RawPointer`` value ``%0`` to type ``$T`` with enough
2255+
capacity to hold ``%1`` values. See SE-0107: UnsafeRawPointer.
2256+
22432257
Reference Counting
22442258
~~~~~~~~~~~~~~~~~~
22452259

include/swift/AST/Builtins.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ BUILTIN_SIL_OPERATION(IsUnique_native, "isUnique_native", Special)
311311
BUILTIN_SIL_OPERATION(IsUniqueOrPinned_native, "isUniqueOrPinned_native",
312312
Special)
313313

314+
/// bindMemory : <T> (Builtin.RawPointer, Builtin.Word, T.Type) -> ()
315+
BUILTIN_SIL_OPERATION(BindMemory, "bindMemory", Special)
316+
314317
#undef BUILTIN_SIL_OPERATION
315318

316319
// BUILTIN_RUNTIME_CALL - A call into a runtime function.

include/swift/SIL/SILBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,12 @@ class SILBuilder {
518518
getSILDebugLocation(Loc), srcAddr, destAddr, isTake, isInitialize));
519519
}
520520

521+
BindMemoryInst *createBindMemory(SILLocation Loc, SILValue base,
522+
SILValue index, SILType boundType) {
523+
return insert(BindMemoryInst::create(getSILDebugLocation(Loc), base, index,
524+
boundType, F, OpenedArchetypes));
525+
}
526+
521527
ConvertFunctionInst *createConvertFunction(SILLocation Loc, SILValue Op,
522528
SILType Ty) {
523529
return insert(new (F.getModule())

include/swift/SIL/SILCloner.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,17 @@ SILCloner<ImplClass>::visitCopyAddrInst(CopyAddrInst *Inst) {
788788
Inst->isInitializationOfDest()));
789789
}
790790

791+
template<typename ImplClass>
792+
void
793+
SILCloner<ImplClass>::visitBindMemoryInst(BindMemoryInst *Inst) {
794+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
795+
doPostProcess(Inst,
796+
getBuilder().createBindMemory(getOpLocation(Inst->getLoc()),
797+
getOpValue(Inst->getBase()),
798+
getOpValue(Inst->getIndex()),
799+
Inst->getBoundType()));
800+
}
801+
791802
template<typename ImplClass>
792803
void
793804
SILCloner<ImplClass>::visitConvertFunctionInst(ConvertFunctionInst *Inst) {

include/swift/SIL/SILInstruction.h

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ class SILInstruction : public ValueBase,public llvm::ilist_node<SILInstruction>{
178178
/// Return the array of opened archetypes operands for this instruction.
179179
MutableArrayRef<Operand> getOpenedArchetypeOperands();
180180

181-
/// Returns true if a given kind of instruciton may have opened archetype
181+
/// Returns true if a given kind of instruction may have opened archetype
182182
/// operands.
183183
bool mayHaveOpenedArchetypeOperands() const;
184184

@@ -511,7 +511,6 @@ class UnaryInstructionWithOpenArchetypesBase :
511511
}
512512
};
513513

514-
515514
/// Holds common debug information about local variables and function
516515
/// arguments that are needed by DebugValueInst, DebugValueAddrInst,
517516
/// AllocStackInst, and AllocBoxInst.
@@ -1573,6 +1572,10 @@ class StringLiteralInst final : public LiteralInst,
15731572
}
15741573
};
15751574

1575+
//===----------------------------------------------------------------------===//
1576+
// Memory instructions.
1577+
//===----------------------------------------------------------------------===//
1578+
15761579
/// StringLiteralInst::Encoding hashes to its underlying integer representation.
15771580
static inline llvm::hash_code hash_value(StringLiteralInst::Encoding E) {
15781581
return llvm::hash_value(size_t(E));
@@ -2047,6 +2050,83 @@ class CopyAddrInst : public SILInstruction {
20472050
}
20482051
};
20492052

2053+
/// BindMemoryInst -
2054+
/// "bind_memory %0 : $Builtin.RawPointer, %1 : $Builtin.Word to $T"
2055+
/// Binds memory at the raw pointer %0 to type $T with enough capacity
2056+
/// to hold $1 values.
2057+
class BindMemoryInst final :
2058+
public SILInstruction,
2059+
protected llvm::TrailingObjects<BindMemoryInst, Operand> {
2060+
2061+
typedef llvm::TrailingObjects<BindMemoryInst, Operand> TrailingBase;
2062+
friend TrailingBase;
2063+
using TrailingBase::totalSizeToAlloc;
2064+
2065+
friend class SILBuilder;
2066+
2067+
enum { BaseOperIdx, IndexOperIdx, NumFixedOpers };
2068+
2069+
SILType BoundType;
2070+
2071+
// Fixed operands + opened archetype operands.
2072+
unsigned NumOperands;
2073+
2074+
static BindMemoryInst *create(
2075+
SILDebugLocation Loc, SILValue Base, SILValue Index, SILType BoundType,
2076+
SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes);
2077+
2078+
BindMemoryInst(SILDebugLocation Loc, SILValue Base, SILValue Index,
2079+
SILType BoundType,
2080+
ArrayRef<SILValue> OpenedArchetypeOperands);
2081+
2082+
public:
2083+
// Destruct tail allocated objects.
2084+
~BindMemoryInst() {
2085+
Operand *Operands = &getAllOperands()[0];
2086+
for (unsigned i = 0, end = NumOperands; i < end; ++i) {
2087+
Operands[i].~Operand();
2088+
}
2089+
}
2090+
2091+
SILValue getBase() const { return getAllOperands()[BaseOperIdx].get(); }
2092+
2093+
SILValue getIndex() const { return getAllOperands()[IndexOperIdx].get(); }
2094+
2095+
SILType getBoundType() const { return BoundType ; }
2096+
2097+
// Implement llvm::TrailingObjects.
2098+
size_t numTrailingObjects(
2099+
typename TrailingBase::template OverloadToken<Operand>) const {
2100+
return NumOperands;
2101+
}
2102+
2103+
ArrayRef<Operand> getAllOperands() const {
2104+
return {TrailingBase::template getTrailingObjects<Operand>(),
2105+
static_cast<size_t>(NumOperands)};
2106+
}
2107+
2108+
MutableArrayRef<Operand> getAllOperands() {
2109+
return {TrailingBase::template getTrailingObjects<Operand>(),
2110+
static_cast<size_t>(NumOperands)};
2111+
}
2112+
2113+
ArrayRef<Operand> getOpenedArchetypeOperands() const {
2114+
return getAllOperands().slice(2);
2115+
}
2116+
2117+
MutableArrayRef<Operand> getOpenedArchetypeOperands() {
2118+
return getAllOperands().slice(2);
2119+
}
2120+
2121+
static bool classof(const ValueBase *V) {
2122+
return V->getKind() == ValueKind::BindMemoryInst;
2123+
}
2124+
};
2125+
2126+
//===----------------------------------------------------------------------===//
2127+
// Conversion instructions.
2128+
//===----------------------------------------------------------------------===//
2129+
20502130
/// ConversionInst - Abstract class representing instructions that convert
20512131
/// values.
20522132
///
@@ -4189,7 +4269,7 @@ class IndexingInst : public SILInstruction {
41894269
}
41904270
};
41914271

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

42094289
/// IndexRawPointerInst
42104290
/// %2 : $Builtin.RawPointer \
4211-
/// = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Int64
4291+
/// = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Word
42124292
/// This takes an address and indexes it, striding by the pointed-
42134293
/// to type. This is used to index into arrays of uniform elements.
42144294
class IndexRawPointerInst : public IndexingInst {

include/swift/SIL/SILNodes.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
112112
INST(IndexRawPointerInst, IndexingInst, None, DoesNotRelease)
113113
VALUE_RANGE(IndexingInst, IndexAddrInst, IndexRawPointerInst)
114114

115+
// BindMemory has no physical side effect. Semantically it writes to
116+
// its affected memory region because any reads or writes accessing
117+
// that memory must be dependent on the bind operation.
118+
INST(BindMemoryInst, SILInstruction, MayWrite, DoesNotRelease)
119+
115120
// Reference Counting
116121
ABSTRACT_VALUE(RefCountingInst, SILInstruction)
117122
INST(StrongRetainInst, RefCountingInst, MayHaveSideEffects, DoesNotRelease)

include/swift/SIL/SILValue.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,16 @@ class TrailingOperandsList {
603603
new (p++) Operand(user, op);
604604
}
605605
}
606+
static void InitOperandsList(Operand *p, SILInstruction *user,
607+
SILValue operand0, SILValue operand1,
608+
ArrayRef<SILValue> operands) {
609+
assert(p && "Trying to initialize operands using a nullptr");
610+
new (p++) Operand(user, operand0);
611+
new (p++) Operand(user, operand1);
612+
for (auto op : operands) {
613+
new (p++) Operand(user, op);
614+
}
615+
}
606616

607617
static void InitOperandsList(Operand *p, SILInstruction *user,
608618
ArrayRef<SILValue> operands) {

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const uint16_t VERSION_MAJOR = 0;
5353
/// in source control, you should also update the comment to briefly
5454
/// describe what change you made. The content of this comment isn't important;
5555
/// it just ensures a conflict if two people change the module format.
56-
const uint16_t VERSION_MINOR = 254; // Last change: remove tuple default args
56+
const uint16_t VERSION_MINOR = 255; // Last change: bind_memory instruction
5757

5858
using DeclID = PointerEmbeddedInt<unsigned, 31>;
5959
using DeclIDField = BCFixed<31>;

lib/AST/Builtins.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,15 @@ static ValueDecl *getIsUniqueOperation(ASTContext &Context, Identifier Id) {
657657
return builder.build(Id);
658658
}
659659

660+
static ValueDecl *getBindMemoryOperation(ASTContext &Context, Identifier Id) {
661+
GenericSignatureBuilder builder(Context);
662+
builder.addParameter(makeConcrete(Context.TheRawPointerType));
663+
builder.addParameter(makeConcrete(BuiltinIntegerType::getWordType(Context)));
664+
builder.addParameter(makeMetatype(makeGenericParam()));
665+
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
666+
return builder.build(Id);
667+
}
668+
660669
static ValueDecl *getSizeOrAlignOfOperation(ASTContext &Context,
661670
Identifier Id) {
662671
GenericSignatureBuilder builder(Context);
@@ -1504,6 +1513,10 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
15041513
if (!Types.empty()) return nullptr;
15051514
return getIsUniqueOperation(Context, Id);
15061515

1516+
case BuiltinValueKind::BindMemory:
1517+
if (!Types.empty()) return nullptr;
1518+
return getBindMemoryOperation(Context, Id);
1519+
15071520
case BuiltinValueKind::Sizeof:
15081521
case BuiltinValueKind::Strideof:
15091522
case BuiltinValueKind::Alignof:

lib/IRGen/IRGenSIL.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,8 @@ class IRGenSILFunction :
872872
void visitCopyAddrInst(CopyAddrInst *i);
873873
void visitDestroyAddrInst(DestroyAddrInst *i);
874874

875+
void visitBindMemoryInst(BindMemoryInst *i);
876+
875877
void visitCondFailInst(CondFailInst *i);
876878

877879
void visitConvertFunctionInst(ConvertFunctionInst *i);
@@ -4564,6 +4566,10 @@ void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) {
45644566
}
45654567
}
45664568

4569+
// This is a no-op because we do not lower Swift TBAA info to LLVM IR, and it
4570+
// does not produce any values.
4571+
void IRGenSILFunction::visitBindMemoryInst(swift::BindMemoryInst *) {}
4572+
45674573
static DeallocStackInst *
45684574
findPairedDeallocStackForDestroyAddr(DestroyAddrInst *destroyAddr) {
45694575
// This peephole only applies if the address being destroyed is the

lib/Parse/ParseSIL.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
11141114
.Case("alloc_ref", ValueKind::AllocRefInst)
11151115
.Case("alloc_ref_dynamic", ValueKind::AllocRefDynamicInst)
11161116
.Case("alloc_value_buffer", ValueKind::AllocValueBufferInst)
1117+
.Case("bind_memory", ValueKind::BindMemoryInst)
11171118
.Case("value_metatype", ValueKind::ValueMetatypeInst)
11181119
.Case("witness_method", ValueKind::WitnessMethodInst)
11191120
.Case("apply", ValueKind::ApplyInst)
@@ -2965,6 +2966,27 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
29652966
IsInitialization_t(IsInit));
29662967
break;
29672968
}
2969+
case ValueKind::BindMemoryInst: {
2970+
SILValue IndexVal;
2971+
Identifier ToToken;
2972+
SourceLoc ToLoc;
2973+
SILType EltTy;
2974+
if (parseTypedValueRef(Val, B) ||
2975+
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
2976+
parseTypedValueRef(IndexVal, B) ||
2977+
parseSILIdentifier(ToToken, ToLoc,
2978+
diag::expected_tok_in_sil_instr, "to") ||
2979+
parseSILType(EltTy) ||
2980+
parseSILDebugLocation(InstLoc, B))
2981+
return true;
2982+
2983+
if (ToToken.str() != "to") {
2984+
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
2985+
return true;
2986+
}
2987+
ResultVal = B.createBindMemory(InstLoc, Val, IndexVal, EltTy);
2988+
break;
2989+
}
29682990
case ValueKind::StructInst: {
29692991
SILType StructTy;
29702992
if (parseSILType(StructTy) ||

lib/SIL/SILInstruction.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ namespace {
279279
return (X->getSrc() == RHS->getSrc() && X->getDest() == RHS->getDest());
280280
}
281281

282+
bool visitBindMemoryInst(const BindMemoryInst *RHS) {
283+
auto *X = cast<BindMemoryInst>(LHS);
284+
return X->getBoundType() == RHS->getBoundType();
285+
}
286+
282287
bool visitFunctionRefInst(const FunctionRefInst *RHS) {
283288
auto *X = cast<FunctionRefInst>(LHS);
284289
return X->getReferencedFunction() == RHS->getReferencedFunction();

lib/SIL/SILInstructions.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,33 @@ CopyAddrInst::CopyAddrInst(SILDebugLocation Loc, SILValue SrcLValue,
693693
IsInitializationOfDest(isInitializationOfDest),
694694
Operands(this, SrcLValue, DestLValue) {}
695695

696+
BindMemoryInst *
697+
BindMemoryInst::create(SILDebugLocation Loc, SILValue Base, SILValue Index,
698+
SILType BoundType, SILFunction &F,
699+
SILOpenedArchetypesState &OpenedArchetypes) {
700+
SmallVector<SILValue, 8> OpenedArchetypeOperands;
701+
collectOpenedArchetypeOperands(BoundType.getSwiftRValueType(),
702+
OpenedArchetypeOperands,
703+
OpenedArchetypes, F.getModule());
704+
void *Buffer = F.getModule().allocateInst(
705+
sizeof(BindMemoryInst) +
706+
sizeof(Operand) * (OpenedArchetypeOperands.size() + NumFixedOpers),
707+
alignof(BindMemoryInst));
708+
return ::new (Buffer)
709+
BindMemoryInst(Loc, Base, Index, BoundType, OpenedArchetypeOperands);
710+
}
711+
712+
BindMemoryInst::BindMemoryInst(SILDebugLocation Loc, SILValue Base,
713+
SILValue Index,
714+
SILType BoundType,
715+
ArrayRef<SILValue> OpenedArchetypeOperands)
716+
: SILInstruction(ValueKind::BindMemoryInst, Loc),
717+
BoundType(BoundType),
718+
NumOperands(NumFixedOpers + OpenedArchetypeOperands.size()) {
719+
TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
720+
Base, Index, OpenedArchetypeOperands);
721+
}
722+
696723
UncheckedRefCastAddrInst::UncheckedRefCastAddrInst(SILDebugLocation Loc,
697724
SILValue src,
698725
CanType srcType,

lib/SIL/SILPrinter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,13 @@ class SILPrinter : public SILVisitor<SILPrinter> {
10421042
*this << "[initialization] ";
10431043
*this << getIDAndType(CI->getDest());
10441044
}
1045+
1046+
void visitBindMemoryInst(BindMemoryInst *BI) {
1047+
*this << "bind_memory ";
1048+
*this << getIDAndType(BI->getBase()) << ", ";
1049+
*this << getIDAndType(BI->getIndex()) << " to ";
1050+
*this << BI->getBoundType();
1051+
}
10451052

10461053
void printUncheckedConversionInst(ConversionInst *CI, SILValue operand,
10471054
StringRef name) {

lib/SIL/SILVerifier.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,16 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
15391539
"Operand of destroy_addr must be address");
15401540
}
15411541

1542+
void checkBindMemoryInst(BindMemoryInst *BI) {
1543+
require(!BI->getType(), "BI must not produce a type");
1544+
require(BI->getBoundType(), "BI must have a bound type");
1545+
require(BI->getBase()->getType().is<BuiltinRawPointerType>(),
1546+
"bind_memory base be a RawPointer");
1547+
require(BI->getIndex()->getType()
1548+
== SILType::getBuiltinWordType(F.getASTContext()),
1549+
"bind_memory index must be a Word");
1550+
}
1551+
15421552
void checkIndexAddrInst(IndexAddrInst *IAI) {
15431553
require(IAI->getType().isAddress(), "index_addr must produce an address");
15441554
require(IAI->getType() == IAI->getBase()->getType(),

0 commit comments

Comments
 (0)