Skip to content

Commit 056ebe3

Browse files
committed
Add Builtin.assumeAlignment(RawPointer, Int64)
1 parent 89878a7 commit 056ebe3

File tree

9 files changed

+57
-6
lines changed

9 files changed

+57
-6
lines changed

include/swift/AST/Builtins.def

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,24 @@ BUILTIN_MISC_OPERATION(Move, "move", "", Special)
820820
/// the SILVerifier.
821821
BUILTIN_MISC_OPERATION(Copy, "copy", "", Special)
822822

823+
/// Unchecked pointer alignment assertion. Allows the compiler to assume
824+
/// alignment of the pointer to emit more efficient code.
825+
///
826+
/// %alignedPtr = builtin "assumeAlignment" (%ptr : $Builtin.RawPointer,
827+
/// %alignment : $Builtin.Int)
828+
/// : $Builtin.RawPointer
829+
/// %address = pointer_to_address %alignedPtr
830+
/// : $Builtin.RawPointer to [align=1] $*Int
831+
/// %val = load %address : $*Int
832+
///
833+
/// With compile-time knowledge of the value of `%alignment` the compiler can
834+
/// optimize any downstream 'pointer_to_address' instruction by refining its
835+
/// '[align=]' flag . That `[align=]` flag can be used by IRGen to refine the
836+
/// alignment on LLVM load instructions that use the resulting address.
837+
///
838+
/// (Builtin.RawPointer, Builtin.Word) -> Builtin.RawPointer
839+
BUILTIN_MISC_OPERATION(AssumeAlignment, "assumeAlignment", "n", Special)
840+
823841
// BUILTIN_MISC_OPERATION_WITH_SILGEN - Miscellaneous operations that are
824842
// specially emitted during SIL generation.
825843
//

include/swift/SIL/SILCloner.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,11 +1430,11 @@ template<typename ImplClass>
14301430
void
14311431
SILCloner<ImplClass>::visitPointerToAddressInst(PointerToAddressInst *Inst) {
14321432
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1433-
recordClonedInstruction(Inst, getBuilder().createPointerToAddress(
1434-
getOpLocation(Inst->getLoc()),
1435-
getOpValue(Inst->getOperand()),
1436-
getOpType(Inst->getType()),
1437-
Inst->isStrict(), Inst->isInvariant()));
1433+
recordClonedInstruction(
1434+
Inst, getBuilder().createPointerToAddress(
1435+
getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()),
1436+
getOpType(Inst->getType()), Inst->isStrict(),
1437+
Inst->isInvariant(), Inst->alignment()));
14381438
}
14391439

14401440
template<typename ImplClass>

lib/AST/Builtins.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,12 @@ static ValueDecl *getCopyOperation(ASTContext &ctx, Identifier id) {
861861
_parameters(_typeparam(0)), _typeparam(0));
862862
}
863863

864+
static ValueDecl *getAssumeAlignment(ASTContext &ctx, Identifier id) {
865+
// This is always "(Builtin.RawPointer, Builtin.Word) -> Builtin.RawPointer"
866+
return getBuiltinFunction(ctx, id, _thin, _parameters(_rawPointer, _word),
867+
_rawPointer);
868+
}
869+
864870
static ValueDecl *getTransferArrayOperation(ASTContext &ctx, Identifier id) {
865871
return getBuiltinFunction(ctx, id, _thin,
866872
_generics(_unrestricted),
@@ -2552,6 +2558,11 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
25522558
return nullptr;
25532559
return getCopyOperation(Context, Id);
25542560

2561+
case BuiltinValueKind::AssumeAlignment:
2562+
if (!Types.empty())
2563+
return nullptr;
2564+
return getAssumeAlignment(Context, Id);
2565+
25552566
#define BUILTIN(id, name, Attrs)
25562567
#define BUILTIN_BINARY_OPERATION(id, name, attrs)
25572568
#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \

lib/IRGen/GenBuiltin.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,18 @@ if (Builtin.ID == BuiltinValueKind::id) { \
13381338
addrTI.initializeWithCopy(IGF, resultAttr, inputAttr, addrTy, false);
13391339
return;
13401340
}
1341+
if (Builtin.ID == BuiltinValueKind::AssumeAlignment) {
1342+
// A no-op pointer cast that passes on its first value. Common occurences of
1343+
// this builtin should already be removed with the alignment guarantee moved
1344+
// to the subsequent load or store.
1345+
//
1346+
// TODO: Consider lowering to an LLVM intrinsic if there is any benefit:
1347+
// 'call void @llvm.assume(i1 true) ["align"(i32* %arg0, i32 %arg1)]'
1348+
auto pointerSrc = args.claimNext();
1349+
(void)args.claimAll();
1350+
out.add(pointerSrc);
1351+
return;
1352+
}
13411353

13421354
llvm_unreachable("IRGen unimplemented for this builtin!");
13431355
}

lib/IRGen/LoadableByAddress.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2113,7 +2113,7 @@ static void rewriteFunction(StructLoweringState &pass,
21132113
currSILType);
21142114
auto *newInstr = pointerBuilder.createPointerToAddress(
21152115
instr->getLoc(), instr->getOperand(), newSILType.getAddressType(),
2116-
instr->isStrict());
2116+
instr->isStrict(), instr->isInvariant(), instr->alignment());
21172117
instr->replaceAllUsesWith(newInstr);
21182118
instr->getParent()->erase(instr);
21192119
}

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssignCopyArrayNoAlias)
647647
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssignCopyArrayFrontToBack)
648648
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssignCopyArrayBackToFront)
649649
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssignTakeArray)
650+
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssumeAlignment)
650651
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssumeNonNegative)
651652
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssumeTrue)
652653
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AtomicLoad)

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, Add)
393393
CONSTANT_OWNERSHIP_BUILTIN(None, GenericAdd)
394394
CONSTANT_OWNERSHIP_BUILTIN(None, And)
395395
CONSTANT_OWNERSHIP_BUILTIN(None, GenericAnd)
396+
CONSTANT_OWNERSHIP_BUILTIN(None, AssumeAlignment)
396397
CONSTANT_OWNERSHIP_BUILTIN(None, AssumeNonNegative)
397398
CONSTANT_OWNERSHIP_BUILTIN(None, AssumeTrue)
398399
CONSTANT_OWNERSHIP_BUILTIN(None, BitCast)

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ static bool isBarrier(SILInstruction *inst) {
151151
case BuiltinValueKind::DestroyTaskGroup:
152152
case BuiltinValueKind::StackAlloc:
153153
case BuiltinValueKind::StackDealloc:
154+
case BuiltinValueKind::AssumeAlignment:
154155
return false;
155156

156157
// Handle some rare builtins that may be sensitive to object lifetime

test/SILGen/builtins.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,3 +886,10 @@ func valueToBridgeObject(_ x: UInt) -> Builtin.BridgeObject {
886886
func assumeTrue(_ x: Builtin.Int1) {
887887
Builtin.assume_Int1(x)
888888
}
889+
890+
// CHECK: sil hidden [ossa] @$s8builtins15assumeAlignmentyyBp_BwtF : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
891+
// CHECK: builtin "assumeAlignment"(%{{.*}} : $Builtin.RawPointer, %{{.*}} : $Builtin.Word) : $Builtin.RawPointer
892+
// CHECK: return
893+
func assumeAlignment(_ p: Builtin.RawPointer, _ x: Builtin.Word) {
894+
Builtin.assumeAlignment(p, x)
895+
}

0 commit comments

Comments
 (0)