Skip to content

Commit 99ea154

Browse files
authored
Merge pull request #7965 from jckarter/invariant-load
Add a `loadInvariant` builtin.
2 parents c082096 + 39ecc53 commit 99ea154

22 files changed

+151
-35
lines changed

include/swift/AST/Builtins.def

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,14 @@ BUILTIN_SIL_OPERATION(Load, "load", Special)
179179

180180
/// LoadRaw has type (Builtin.RawPointer) -> T
181181
/// This is a load of T from raw memory.
182-
/// It's address does not adhere to strict aliasing.
182+
/// Its address does not adhere to strict aliasing.
183183
BUILTIN_SIL_OPERATION(LoadRaw, "loadRaw", Special)
184184

185+
/// LoadInvariant has type (Builtin.RawPointer) -> T
186+
/// This is a load of T from raw memory.
187+
/// The load is marked as invariant.
188+
BUILTIN_SIL_OPERATION(LoadInvariant, "loadInvariant", Special)
189+
185190
/// Take has type (Builtin.RawPointer) -> T
186191
BUILTIN_SIL_OPERATION(Take, "take", Special)
187192

include/swift/SIL/SILBuilder.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,9 +657,11 @@ class SILBuilder {
657657
}
658658

659659
PointerToAddressInst *createPointerToAddress(SILLocation Loc, SILValue Op,
660-
SILType Ty, bool isStrict) {
660+
SILType Ty,
661+
bool isStrict,
662+
bool isInvariant = false){
661663
return insert(new (F.getModule()) PointerToAddressInst(
662-
getSILDebugLocation(Loc), Op, Ty, isStrict));
664+
getSILDebugLocation(Loc), Op, Ty, isStrict, isInvariant));
663665
}
664666

665667
UncheckedRefCastInst *createUncheckedRefCast(SILLocation Loc, SILValue Op,

include/swift/SIL/SILCloner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,8 @@ SILCloner<ImplClass>::visitPointerToAddressInst(PointerToAddressInst *Inst) {
928928
getBuilder().createPointerToAddress(getOpLocation(Inst->getLoc()),
929929
getOpValue(Inst->getOperand()),
930930
getOpType(Inst->getType()),
931-
Inst->isStrict()));
931+
Inst->isStrict(),
932+
Inst->isInvariant()));
932933
}
933934

934935
template<typename ImplClass>

include/swift/SIL/SILInstruction.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2416,17 +2416,22 @@ class PointerToAddressInst
24162416
{
24172417
friend SILBuilder;
24182418

2419-
bool IsStrict;
2419+
bool IsStrict, IsInvariant;
24202420

24212421
PointerToAddressInst(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty,
2422-
bool IsStrict)
2423-
: UnaryInstructionBase(DebugLoc, Operand, Ty), IsStrict(IsStrict) {}
2422+
bool IsStrict, bool IsInvariant)
2423+
: UnaryInstructionBase(DebugLoc, Operand, Ty),
2424+
IsStrict(IsStrict), IsInvariant(IsInvariant) {}
24242425

24252426
public:
24262427
/// Whether the returned address adheres to strict aliasing.
24272428
/// If true, then the type of each memory access dependent on
24282429
/// this address must be consistent with the memory's bound type.
24292430
bool isStrict() const { return IsStrict; }
2431+
/// Whether the returned address is invariant.
2432+
/// If true, then loading from an address derived from this pointer always
2433+
/// produces the same value.
2434+
bool isInvariant() const { return IsInvariant; }
24302435
};
24312436

24322437
/// Convert a heap object reference to a different type without any runtime

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 325; // Last change: unchecked_ownership_conver
57+
const uint16_t VERSION_MINOR = 326; // Last change: invariant bit on pointer_to_address
5858

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

lib/AST/Builtins.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
16021602

16031603
case BuiltinValueKind::Load:
16041604
case BuiltinValueKind::LoadRaw:
1605+
case BuiltinValueKind::LoadInvariant:
16051606
case BuiltinValueKind::Take:
16061607
if (!Types.empty()) return nullptr;
16071608
return getLoadOperation(Context, Id);

lib/IRGen/IRGenSIL.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3200,6 +3200,18 @@ void IRGenSILFunction::visitRefTailAddrInst(RefTailAddrInst *i) {
32003200
setLoweredAddress(i, TailAddr);
32013201
}
32023202

3203+
static bool isInvariantAddress(SILValue v) {
3204+
auto root = getUnderlyingAddressRoot(v);
3205+
if (auto ptrRoot = dyn_cast<PointerToAddressInst>(root)) {
3206+
return ptrRoot->isInvariant();
3207+
}
3208+
// TODO: We could be more aggressive about considering addresses based on
3209+
// `let` variables as invariant when the type of the address is known not to
3210+
// have any sharably-mutable interior storage (in other words, no weak refs,
3211+
// atomics, etc.)
3212+
return false;
3213+
}
3214+
32033215
void IRGenSILFunction::visitLoadInst(swift::LoadInst *i) {
32043216
Explosion lowered;
32053217
Address source = getLoweredAddress(i->getOperand());
@@ -3216,7 +3228,13 @@ void IRGenSILFunction::visitLoadInst(swift::LoadInst *i) {
32163228
typeInfo.loadAsCopy(*this, source, lowered);
32173229
break;
32183230
}
3219-
3231+
3232+
if (isInvariantAddress(i->getOperand())) {
3233+
// It'd be better to push this down into `loadAs` methods, perhaps...
3234+
for (auto value : lowered.getAll())
3235+
if (auto load = dyn_cast<llvm::LoadInst>(value))
3236+
setInvariantLoad(load);
3237+
}
32203238
setLoweredExplosion(i, lowered);
32213239
}
32223240

lib/Parse/ParseSIL.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,21 +2377,27 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
23772377
SILType Ty;
23782378
Identifier ToToken;
23792379
SourceLoc ToLoc;
2380-
bool isStrict = false;
2380+
StringRef attr;
23812381
if (parseTypedValueRef(Val, B) ||
23822382
parseSILIdentifier(ToToken, ToLoc,
2383-
diag::expected_tok_in_sil_instr, "to") ||
2384-
parseSILOptional(isStrict, *this, "strict") ||
2385-
parseSILType(Ty) ||
2383+
diag::expected_tok_in_sil_instr, "to"))
2384+
return true;
2385+
if (parseSILOptional(attr, *this) && attr.empty())
2386+
return true;
2387+
if (parseSILType(Ty) ||
23862388
parseSILDebugLocation(InstLoc, B))
23872389
return true;
23882390

2391+
bool isStrict = attr.equals("strict");
2392+
bool isInvariant = attr.equals("invariant");
2393+
23892394
if (ToToken.str() != "to") {
23902395
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
23912396
return true;
23922397
}
23932398

2394-
ResultVal = B.createPointerToAddress(InstLoc, Val, Ty, isStrict);
2399+
ResultVal = B.createPointerToAddress(InstLoc, Val, Ty,
2400+
isStrict, isInvariant);
23952401
break;
23962402
}
23972403
case ValueKind::RefToBridgeObjectInst: {

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,7 @@ BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(TryPin)
11101110
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Unpin)
11111111
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Load)
11121112
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(LoadRaw)
1113+
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(LoadInvariant)
11131114
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Take)
11141115
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Destroy)
11151116
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Assign)

lib/SIL/SILPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,8 @@ class SILPrinter : public SILVisitor<SILPrinter> {
12661266
*this << getIDAndType(CI->getOperand()) << " to ";
12671267
if (CI->isStrict())
12681268
*this << "[strict] ";
1269+
if (CI->isInvariant())
1270+
*this << "[invariant] ";
12691271
*this << CI->getType();
12701272
}
12711273
void visitUncheckedRefCastInst(UncheckedRefCastInst *CI) {

lib/SIL/SILValue.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToPtr)
661661
CONSTANT_OWNERSHIP_BUILTIN(Trivial, LShr)
662662
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Load)
663663
CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadRaw)
664+
CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadInvariant)
664665
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Mul)
665666
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Or)
666667
CONSTANT_OWNERSHIP_BUILTIN(Trivial, PtrToInt)

lib/SILGen/SILGenApply.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5287,7 +5287,9 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
52875287
// materialize for set is strictly typed, whether it is the local buffer or
52885288
// stored property.
52895289
SILValue address = results[0].getUnmanagedValue();
5290-
address = B.createPointerToAddress(loc, address, buffer->getType(), /*isStrict*/ true);
5290+
address = B.createPointerToAddress(loc, address, buffer->getType(),
5291+
/*isStrict*/ true,
5292+
/*isInvariant*/ false);
52915293

52925294
// Project out the optional callback.
52935295
SILValue optionalCallback = results[1].getUnmanagedValue();
@@ -5389,7 +5391,9 @@ emitAddressorAccessor(SILLocation loc, SILDeclRef addressor,
53895391
SILType::getRawPointerType(getASTContext()));
53905392

53915393
// Convert to the appropriate address type and return.
5392-
SILValue address = B.createPointerToAddress(loc, pointer, addressType, /*isStrict*/ true);
5394+
SILValue address = B.createPointerToAddress(loc, pointer, addressType,
5395+
/*isStrict*/ true,
5396+
/*isInvariant*/ false);
53935397

53945398
// Mark dependence as necessary.
53955399
switch (cast<FuncDecl>(addressor.getDecl())->getAddressorKind()) {

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ static ManagedValue emitBuiltinLoadOrTake(SILGenFunction &gen,
160160
CanFunctionType formalApplyType,
161161
SGFContext C,
162162
IsTake_t isTake,
163-
bool isStrict) {
163+
bool isStrict,
164+
bool isInvariant) {
164165
assert(substitutions.size() == 1 && "load should have single substitution");
165166
assert(args.size() == 1 && "load should have a single argument");
166167

@@ -173,7 +174,7 @@ static ManagedValue emitBuiltinLoadOrTake(SILGenFunction &gen,
173174
// Convert the pointer argument to a SIL address.
174175
SILValue addr = gen.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
175176
loadedType.getAddressType(),
176-
isStrict);
177+
isStrict, isInvariant);
177178
// Perform the load.
178179
return gen.emitLoad(loc, addr, rvalueTL, C, isTake);
179180
}
@@ -186,7 +187,7 @@ static ManagedValue emitBuiltinLoad(SILGenFunction &gen,
186187
SGFContext C) {
187188
return emitBuiltinLoadOrTake(gen, loc, substitutions, args,
188189
formalApplyType, C, IsNotTake,
189-
/*isStrict*/ true);
190+
/*isStrict*/ true, /*isInvariant*/ false);
190191
}
191192

192193
static ManagedValue emitBuiltinLoadRaw(SILGenFunction &gen,
@@ -197,7 +198,17 @@ static ManagedValue emitBuiltinLoadRaw(SILGenFunction &gen,
197198
SGFContext C) {
198199
return emitBuiltinLoadOrTake(gen, loc, substitutions, args,
199200
formalApplyType, C, IsNotTake,
200-
/*isStrict*/ false);
201+
/*isStrict*/ false, /*isInvariant*/ false);
202+
}
203+
static ManagedValue emitBuiltinLoadInvariant(SILGenFunction &gen,
204+
SILLocation loc,
205+
SubstitutionList substitutions,
206+
ArrayRef<ManagedValue> args,
207+
CanFunctionType formalApplyType,
208+
SGFContext C) {
209+
return emitBuiltinLoadOrTake(gen, loc, substitutions, args,
210+
formalApplyType, C, IsNotTake,
211+
/*isStrict*/ false, /*isInvariant*/ true);
201212
}
202213

203214
static ManagedValue emitBuiltinTake(SILGenFunction &gen,
@@ -207,7 +218,8 @@ static ManagedValue emitBuiltinTake(SILGenFunction &gen,
207218
CanFunctionType formalApplyType,
208219
SGFContext C) {
209220
return emitBuiltinLoadOrTake(gen, loc, substitutions, args,
210-
formalApplyType, C, IsTake, /*isStrict*/ true);
221+
formalApplyType, C, IsTake,
222+
/*isStrict*/ true, /*isInvariant*/ false);
211223
}
212224

213225
/// Specialized emitter for Builtin.destroy.
@@ -233,7 +245,8 @@ static ManagedValue emitBuiltinDestroy(SILGenFunction &gen,
233245
SILValue addr =
234246
gen.B.createPointerToAddress(loc, args[1].getUnmanagedValue(),
235247
destroyType.getAddressType(),
236-
/*isStrict*/ true);
248+
/*isStrict*/ true,
249+
/*isInvariant*/ false);
237250

238251
// Destroy the value indirectly. Canonicalization will promote to loads
239252
// and releases if appropriate.
@@ -260,7 +273,8 @@ static ManagedValue emitBuiltinAssign(SILGenFunction &gen,
260273
SILValue addr = gen.B.createPointerToAddress(loc,
261274
args.back().getUnmanagedValue(),
262275
assignType.getAddressType(),
263-
/*isStrict*/ true);
276+
/*isStrict*/ true,
277+
/*isInvariant*/ false);
264278

265279
// Build the value to be assigned, reconstructing tuples if needed.
266280
auto src = RValue::withPreExplodedElements(args.slice(0, args.size() - 1),
@@ -287,7 +301,8 @@ static ManagedValue emitBuiltinInit(SILGenFunction &gen,
287301
SILValue addr = gen.emitRValueAsSingleValue(args[1]).getUnmanagedValue();
288302
addr = gen.B.createPointerToAddress(
289303
loc, addr, formalTL.getLoweredType().getAddressType(),
290-
/*isStrict*/ true);
304+
/*isStrict*/ true,
305+
/*isInvariant*/ false);
291306

292307
TemporaryInitialization init(addr, CleanupHandle::invalid());
293308
gen.emitExprInto(args[0], &init);
@@ -504,7 +519,9 @@ static ManagedValue emitBuiltinGep(SILGenFunction &gen,
504519
SILType ElemTy = gen.getLoweredType(substitutions[0].getReplacement());
505520
SILType RawPtrType = args[0].getUnmanagedValue()->getType();
506521
SILValue addr = gen.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
507-
ElemTy.getAddressType(), true);
522+
ElemTy.getAddressType(),
523+
/*strict*/ true,
524+
/*invariant*/ false);
508525
addr = gen.B.createIndexAddr(loc, addr, args[1].getUnmanagedValue());
509526
addr = gen.B.createAddressToPointer(loc, addr, RawPtrType);
510527

@@ -525,7 +542,9 @@ static ManagedValue emitBuiltinGetTailAddr(SILGenFunction &gen,
525542
SILType TailTy = gen.getLoweredType(substitutions[1].getReplacement());
526543
SILType RawPtrType = args[0].getUnmanagedValue()->getType();
527544
SILValue addr = gen.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
528-
ElemTy.getAddressType(), true);
545+
ElemTy.getAddressType(),
546+
/*strict*/ true,
547+
/*invariant*/ false);
529548
addr = gen.B.createTailAddr(loc, addr, args[1].getUnmanagedValue(),
530549
TailTy.getAddressType());
531550
addr = gen.B.createAddressToPointer(loc, addr, RawPtrType);

lib/SILGen/SILGenExpr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,7 +1809,9 @@ VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &gen, SILLocation loc,
18091809

18101810
// Turn the pointer into an address.
18111811
basePtr = gen.B.createPointerToAddress(
1812-
loc, basePtr, baseTL.getLoweredType().getAddressType(), /*isStrict*/ true);
1812+
loc, basePtr, baseTL.getLoweredType().getAddressType(),
1813+
/*isStrict*/ true,
1814+
/*isInvariant*/ false);
18131815

18141816
return VarargsInfo(array, abortCleanup, basePtr, baseTL, baseAbstraction);
18151817
}

lib/SILGen/SILGenGlobalVariable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ SILGenFunction::emitGlobalVariableRef(SILLocation loc, VarDecl *var) {
108108
// address.
109109
addr = B.createPointerToAddress(
110110
loc, addr, getLoweredType(var->getInterfaceType()).getAddressType(),
111-
/*isStrict*/ true);
111+
/*isStrict*/ true, /*isInvariant*/ false);
112112
return ManagedValue::forLValue(addr);
113113
}
114114

lib/SILGen/SILGenMaterializeForSet.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,8 @@ MaterializeForSetEmitter::emitUsingGetterSetter(SILGenFunction &gen,
860860
resultBuffer =
861861
gen.B.createPointerToAddress(loc, resultBuffer,
862862
RequirementStorageType.getAddressType(),
863-
/*isStrict*/ true);
863+
/*isStrict*/ true,
864+
/*isInvariant*/ false);
864865
TemporaryInitialization init(resultBuffer, CleanupHandle::invalid());
865866

866867
// Evaluate the getter into the result buffer.
@@ -943,7 +944,8 @@ MaterializeForSetEmitter::createSetterCallback(SILFunction &F,
943944
// The callback gets the value at +1.
944945
auto &valueTL = gen.getTypeLowering(lvalue.getTypeOfRValue());
945946
value = gen.B.createPointerToAddress(
946-
loc, value, valueTL.getLoweredType().getAddressType(), /*isStrict*/ true);
947+
loc, value, valueTL.getLoweredType().getAddressType(),
948+
/*isStrict*/ true, /*isInvariant*/ false);
947949
if (valueTL.isLoadable() || !gen.silConv.useLoweredAddresses())
948950
value = valueTL.emitLoad(gen.B, loc, value, LoadOwnershipQualifier::Take);
949951
ManagedValue mValue = gen.emitManagedRValueWithCleanup(value, valueTL);

lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ static SILInstruction *createIndexAddrFrom(IndexRawPointerInst *I,
289289

290290
// index_raw_pointer's address type is currently always strict.
291291
auto *NewPTAI = Builder.createPointerToAddress(
292-
I->getLoc(), Ptr, InstanceType.getAddressType(), /*isStrict*/ true);
292+
I->getLoc(), Ptr, InstanceType.getAddressType(),
293+
/*isStrict*/ true, /*isInvariant*/ false);
293294

294295
auto *DistanceAsWord =
295296
Builder.createBuiltin(I->getLoc(), TruncOrBitCast->getName(),

lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ visitPointerToAddressInst(PointerToAddressInst *PTAI) {
140140

141141
auto *NewPTAI = Builder.createPointerToAddress(PTAI->getLoc(), Ptr,
142142
PTAI->getType(),
143-
PTAI->isStrict());
143+
PTAI->isStrict(),
144+
PTAI->isInvariant());
144145
auto DistanceAsWord = Builder.createBuiltin(
145146
PTAI->getLoc(), Trunc->getName(), Trunc->getType(), {}, Distance);
146147

@@ -181,7 +182,7 @@ visitPointerToAddressInst(PointerToAddressInst *PTAI) {
181182
SILValue Distance = Bytes->getArguments()[0];
182183
auto *NewPTAI =
183184
Builder.createPointerToAddress(PTAI->getLoc(), Ptr, PTAI->getType(),
184-
PTAI->isStrict());
185+
PTAI->isStrict(), PTAI->isInvariant());
185186
return Builder.createIndexAddr(PTAI->getLoc(), NewPTAI, Distance);
186187
}
187188
}

lib/Serialization/DeserializeSIL.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -913,12 +913,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
913913
assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
914914
"Layout should be OneTypeOneOperand.");
915915
bool isStrict = Attr & 0x01;
916+
bool isInvariant = Attr & 0x02;
916917
ResultVal = Builder.createPointerToAddress(
917918
Loc,
918919
getLocalValue(ValID, getSILType(MF->getType(TyID2),
919920
(SILValueCategory)TyCategory2)),
920921
getSILType(MF->getType(TyID), (SILValueCategory)TyCategory),
921-
isStrict);
922+
isStrict, isInvariant);
922923
break;
923924
}
924925
case ValueKind::DeallocExistentialBoxInst: {

0 commit comments

Comments
 (0)