Add builtins to generate instructions for tail-allocated arrays in SIL.

Those builtins are: allocWithTailElems_<n>, getTailAddr and projectTailElems
Also rename the "gep" builtin, which indexes raw bytes, to "gepRaw" and add a new "gep" builtin to index in a typed array.
This commit is contained in:
Erik Eckstein
2016-09-09 13:52:20 -07:00
parent 34a4e6df0a
commit d89a21460e
9 changed files with 256 additions and 20 deletions

View File

@@ -252,9 +252,23 @@ BUILTIN_SIL_OPERATION(ReinterpretCast, "reinterpretCast", Special)
/// valid within the scope of the statement for logical lvalues.
BUILTIN_SIL_OPERATION(AddressOf, "addressof", Special)
/// GetElementPtr has type (Builtin.RawPointer, T) -> Builtin.RawPointer
/// GepRaw(Builtin.RawPointer, Builtin.Word) -> Builtin.RawPointer
///
/// Adds index bytes to a base pointer.
BUILTIN_SIL_OPERATION(GepRaw, "gepRaw", Integer)
/// Gep (Builtin.RawPointer, Builtin.Word, T.Type) -> Builtin.RawPointer
///
/// Like the GepRaw-bultin, but multiplies the index by stride-of type 'T'.
BUILTIN_SIL_OPERATION(Gep, "gep", Integer)
/// getTailAddr(Builtin.RawPointer,
/// Builtin.Word, T.Type, E.Type) -> Builtin.RawPointer
///
/// Like the Gep-builtin, but rounds up the resulting address to a tail-
/// allocated element type 'E'.
BUILTIN_SIL_OPERATION(GetTailAddr, "getTailAddr", Integer)
/// condfail(Int1) -> ()
/// Triggers a runtime failure if the condition is true.
BUILTIN_SIL_OPERATION(CondFail, "condfail", Special)
@@ -314,6 +328,18 @@ BUILTIN_SIL_OPERATION(IsUniqueOrPinned_native, "isUniqueOrPinned_native",
/// bindMemory : <T> (Builtin.RawPointer, Builtin.Word, T.Type) -> ()
BUILTIN_SIL_OPERATION(BindMemory, "bindMemory", Special)
/// allocWithTailElems_<n>(C.Type,
/// Builtin.Word, E1.Type, ... , Builtin.Word, En.Type) -> C\
///
/// The integer suffix <n> specifies the number of tail-allocated arrays.
/// Each tail-allocated array adds a counter and an element meta-type parameter.
BUILTIN_SIL_OPERATION(AllocWithTailElems, "allocWithTailElems", Special)
/// projectTailElems : <C,E> (C) -> Builtin.RawPointer
///
/// Projects the first tail-allocated element of type E from a class C.
BUILTIN_SIL_OPERATION(ProjectTailElems, "projectTailElems", Special)
#undef BUILTIN_SIL_OPERATION
// BUILTIN_RUNTIME_CALL - A call into a runtime function.

View File

@@ -250,7 +250,7 @@ getBuiltinGenericFunction(Identifier Id,
}
/// Build a getelementptr operation declaration.
static ValueDecl *getGepOperation(Identifier Id, Type ArgType) {
static ValueDecl *getGepRawOperation(Identifier Id, Type ArgType) {
auto &Context = ArgType->getASTContext();
// This is always "(i8*, IntTy) -> i8*"
@@ -427,6 +427,11 @@ static ValueDecl *getCastOperation(ASTContext &Context, Identifier Id,
static const char * const GenericParamNames[] = {
"T",
"U",
"V",
"W",
"X",
"Y",
"Z"
};
static std::pair<ArchetypeType*, GenericTypeParamDecl*>
@@ -680,6 +685,53 @@ static ValueDecl *getBindMemoryOperation(ASTContext &Context, Identifier Id) {
return builder.build(Id);
}
static ValueDecl *getAllocWithTailElemsOperation(ASTContext &Context,
Identifier Id,
int NumTailTypes) {
if (NumTailTypes < 1 ||
1 + NumTailTypes > (int)llvm::array_lengthof(GenericParamNames))
return nullptr;
GenericSignatureBuilder builder(Context, 1 + NumTailTypes);
builder.addParameter(makeMetatype(makeGenericParam(0)));
for (int Idx = 0; Idx < NumTailTypes; ++Idx) {
builder.addParameter(makeConcrete(BuiltinIntegerType::getWordType(Context)));
builder.addParameter(makeMetatype(makeGenericParam(Idx + 1)));
}
builder.setResult(makeGenericParam(0));
return builder.build(Id);
}
static ValueDecl *getProjectTailElemsOperation(ASTContext &Context,
Identifier Id) {
GenericSignatureBuilder builder(Context, 2);
builder.addParameter(makeGenericParam(0));
builder.addParameter(makeMetatype(makeGenericParam(1)));
builder.setResult(makeConcrete(Context.TheRawPointerType));
return builder.build(Id);
}
/// Build a getelementptr operation declaration.
static ValueDecl *getGepOperation(ASTContext &Context, Identifier Id,
Type ArgType) {
GenericSignatureBuilder builder(Context, 1);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(ArgType));
builder.addParameter(makeMetatype(makeGenericParam(0)));
builder.setResult(makeConcrete(Context.TheRawPointerType));
return builder.build(Id);
}
static ValueDecl *getGetTailAddrOperation(ASTContext &Context, Identifier Id,
Type ArgType) {
GenericSignatureBuilder builder(Context, 2);
builder.addParameter(makeConcrete(Context.TheRawPointerType));
builder.addParameter(makeConcrete(ArgType));
builder.addParameter(makeMetatype(makeGenericParam(0)));
builder.addParameter(makeMetatype(makeGenericParam(1)));
builder.setResult(makeConcrete(Context.TheRawPointerType));
return builder.build(Id);
}
static ValueDecl *getSizeOrAlignOfOperation(ASTContext &Context,
Identifier Id) {
GenericSignatureBuilder builder(Context);
@@ -1452,6 +1504,14 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
return nullptr;
return getAtomicStoreOperation(Context, Id, T);
}
if (OperationName.startswith("allocWithTailElems_")) {
OperationName = OperationName.drop_front(strlen("allocWithTailElems_"));
int NumTailTypes = 0;
if (OperationName.getAsInteger(10, NumTailTypes))
return nullptr;
return getAllocWithTailElemsOperation(Context, Id, NumTailTypes);
}
BuiltinValueKind BV = llvm::StringSwitch<BuiltinValueKind>(OperationName)
#define BUILTIN(id, name, Attrs) \
@@ -1473,12 +1533,21 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
case BuiltinValueKind::AtomicRMW:
case BuiltinValueKind::AtomicLoad:
case BuiltinValueKind::AtomicStore:
case BuiltinValueKind::AllocWithTailElems:
llvm_unreachable("Handled above");
case BuiltinValueKind::None: return nullptr;
case BuiltinValueKind::GepRaw:
if (Types.size() != 1) return nullptr;
return getGepRawOperation(Id, Types[0]);
case BuiltinValueKind::Gep:
if (Types.size() != 1) return nullptr;
return getGepOperation(Id, Types[0]);
return getGepOperation(Context, Id, Types[0]);
case BuiltinValueKind::GetTailAddr:
if (Types.size() != 1) return nullptr;
return getGetTailAddrOperation(Context, Id, Types[0]);
#define BUILTIN(id, name, Attrs)
#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) case BuiltinValueKind::id:
@@ -1556,6 +1625,10 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
if (!Types.empty()) return nullptr;
return getBindMemoryOperation(Context, Id);
case BuiltinValueKind::ProjectTailElems:
if (!Types.empty()) return nullptr;
return getProjectTailElemsOperation(Context, Id);
case BuiltinValueKind::Sizeof:
case BuiltinValueKind::Strideof:
case BuiltinValueKind::Alignof:

View File

@@ -463,6 +463,8 @@ const BuiltinInfo &SILModule::getBuiltinInfo(Identifier ID) {
Info.ID = BuiltinValueKind::AtomicLoad;
else if (OperationName.startswith("atomicstore_"))
Info.ID = BuiltinValueKind::AtomicStore;
else if (OperationName.startswith("allocWithTailElems_"))
Info.ID = BuiltinValueKind::AllocWithTailElems;
else {
// Switch through the rest of builtins.
Info.ID = llvm::StringSwitch<BuiltinValueKind>(OperationName)

View File

@@ -478,6 +478,21 @@ static ManagedValue emitBuiltinAddressOf(SILGenFunction &gen,
return ManagedValue::forUnmanaged(result);
}
/// Specialized emitter for Builtin.gepRaw.
static ManagedValue emitBuiltinGepRaw(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
CanFunctionType formalApplyType,
SGFContext C) {
assert(args.size() == 2 && "gepRaw should be given two arguments");
SILValue offsetPtr = gen.B.createIndexRawPointer(loc,
args[0].getUnmanagedValue(),
args[1].getUnmanagedValue());
return ManagedValue::forUnmanaged(offsetPtr);
}
/// Specialized emitter for Builtin.gep.
static ManagedValue emitBuiltinGep(SILGenFunction &gen,
SILLocation loc,
@@ -485,12 +500,39 @@ static ManagedValue emitBuiltinGep(SILGenFunction &gen,
ArrayRef<ManagedValue> args,
CanFunctionType formalApplyType,
SGFContext C) {
assert(args.size() == 2 && "gep should be given two arguments");
assert(substitutions.size() == 1 && "gep should have two substitutions");
assert(args.size() == 3 && "gep should be given three arguments");
SILValue offsetPtr = gen.B.createIndexRawPointer(loc,
args[0].getUnmanagedValue(),
args[1].getUnmanagedValue());
return ManagedValue::forUnmanaged(offsetPtr);
SILType ElemTy = gen.getLoweredType(substitutions[0].getReplacement());
SILType RawPtrType = args[0].getUnmanagedValue()->getType();
SILValue addr = gen.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
ElemTy.getAddressType(), true);
addr = gen.B.createIndexAddr(loc, addr, args[1].getUnmanagedValue());
addr = gen.B.createAddressToPointer(loc, addr, RawPtrType);
return ManagedValue::forUnmanaged(addr);
}
/// Specialized emitter for Builtin.getTailAddr.
static ManagedValue emitBuiltinGetTailAddr(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> substitutions,
ArrayRef<ManagedValue> args,
CanFunctionType formalApplyType,
SGFContext C) {
assert(substitutions.size() == 2 && "getTailAddr should have two substitutions");
assert(args.size() == 4 && "gep should be given four arguments");
SILType ElemTy = gen.getLoweredType(substitutions[0].getReplacement());
SILType TailTy = gen.getLoweredType(substitutions[1].getReplacement());
SILType RawPtrType = args[0].getUnmanagedValue()->getType();
SILValue addr = gen.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
ElemTy.getAddressType(), true);
addr = gen.B.createTailAddr(loc, addr, args[1].getUnmanagedValue(),
TailTy.getAddressType());
addr = gen.B.createAddressToPointer(loc, addr, RawPtrType);
return ManagedValue::forUnmanaged(addr);
}
/// Specialized emitter for Builtin.condfail.
@@ -804,6 +846,55 @@ static ManagedValue emitBuiltinBindMemory(SILGenFunction &gen,
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}
static ManagedValue emitBuiltinAllocWithTailElems(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> subs,
ArrayRef<ManagedValue> args,
CanFunctionType formalApplyType,
SGFContext C) {
unsigned NumTailTypes = subs.size() - 1;
assert(args.size() == NumTailTypes * 2 + 1 &&
"wrong number of substitutions for allocWithTailElems");
// The substitution determines the element type for bound memory.
SILType RefType = gen.getLoweredType(subs[0].getReplacement()->
getCanonicalType()).getObjectType();
SmallVector<SILValue, 4> Counts;
SmallVector<SILType, 4> ElemTypes;
for (unsigned Idx = 0; Idx < NumTailTypes; ++Idx) {
Counts.push_back(args[Idx * 2 + 1].getValue());
ElemTypes.push_back(gen.getLoweredType(subs[Idx+1].getReplacement()->
getCanonicalType()).getObjectType());
}
SILValue result = gen.B.createAllocRef(loc, RefType, false, ElemTypes, Counts);
return ManagedValue::forUnmanaged(result);
}
static ManagedValue emitBuiltinProjectTailElems(SILGenFunction &gen,
SILLocation loc,
ArrayRef<Substitution> subs,
ArrayRef<ManagedValue> args,
CanFunctionType formalApplyType,
SGFContext C) {
assert(subs.size() == 2 &&
"allocWithTailElems should have two substitutions");
assert(args.size() == 2 &&
"allocWithTailElems should have three arguments");
// The substitution determines the element type for bound memory.
SILType ElemType = gen.getLoweredType(subs[1].getReplacement()->
getCanonicalType()).getObjectType();
SILValue result = gen.B.createRefTailAddr(loc, args[0].getValue(),
ElemType.getAddressType());
SILType rawPointerType = SILType::getRawPointerType(gen.F.getASTContext());
result = gen.B.createAddressToPointer(loc, result, rawPointerType);
return ManagedValue::forUnmanaged(result);
}
/// Specialized emitter for type traits.
template<TypeTraitResult (TypeBase::*Trait)(),
BuiltinValueKind Kind>

View File

@@ -489,7 +489,7 @@ public func < <Pointee>(lhs: ${Self}<Pointee>, rhs: ${Self}<Pointee>) -> Bool {
@_transparent
public func + <Pointee>(lhs: ${Self}<Pointee>, rhs: Int) -> ${Self}<Pointee> {
return ${Self}(Builtin.gep_Word(
lhs._rawValue, (rhs &* MemoryLayout<Pointee>.stride)._builtinWordValue))
lhs._rawValue, rhs._builtinWordValue, Pointee.self))
}
@_transparent

View File

@@ -468,7 +468,7 @@ public struct Unsafe${Mutable}RawPointer : Strideable, Hashable, _Pointer {
/// Returns `self + n`.
public func advanced(by n: Int) -> ${Self} {
return ${Self}(Builtin.gep_Word(_rawValue, n._builtinWordValue))
return ${Self}(Builtin.gepRaw_Word(_rawValue, n._builtinWordValue))
}
}

View File

@@ -120,9 +120,9 @@ func !=(lhs: Int, rhs: Int) -> Bool {
// CHECK: icmp ne i32
}
func gep_test(_ ptr: Builtin.RawPointer, offset: Builtin.Int64)
func gepRaw_test(_ ptr: Builtin.RawPointer, offset: Builtin.Int64)
-> Builtin.RawPointer {
return Builtin.gep_Int64(ptr, offset)
return Builtin.gepRaw_Int64(ptr, offset)
// CHECK: getelementptr inbounds i8, i8*
}

View File

@@ -345,18 +345,62 @@ func existential_from_raw_pointer(_ p: Builtin.RawPointer) -> AnyObject {
return Builtin.bridgeFromRawPointer(p)
}
// CHECK-LABEL: sil hidden @_TF8builtins5gep64
func gep64(_ p: Builtin.RawPointer, i: Builtin.Int64) -> Builtin.RawPointer {
// CHECK-LABEL: sil hidden @_TF8builtins9gep_raw64
func gep_raw64(_ p: Builtin.RawPointer, i: Builtin.Int64) -> Builtin.RawPointer {
// CHECK: [[GEP:%.*]] = index_raw_pointer
// CHECK: return [[GEP]]
return Builtin.gep_Int64(p, i)
return Builtin.gepRaw_Int64(p, i)
}
// CHECK-LABEL: sil hidden @_TF8builtins5gep32
func gep32(_ p: Builtin.RawPointer, i: Builtin.Int32) -> Builtin.RawPointer {
// CHECK-LABEL: sil hidden @_TF8builtins9gep_raw32
func gep_raw32(_ p: Builtin.RawPointer, i: Builtin.Int32) -> Builtin.RawPointer {
// CHECK: [[GEP:%.*]] = index_raw_pointer
// CHECK: return [[GEP]]
return Builtin.gep_Int32(p, i)
return Builtin.gepRaw_Int32(p, i)
}
// CHECK-LABEL: sil hidden @_TF8builtins3gep
func gep<Elem>(_ p: Builtin.RawPointer, i: Builtin.Word, e: Elem.Type) -> Builtin.RawPointer {
// CHECK: [[P2A:%.*]] = pointer_to_address %0
// CHECK: [[GEP:%.*]] = index_addr [[P2A]] : $*Elem, %1 : $Builtin.Word
// CHECK: [[A2P:%.*]] = address_to_pointer [[GEP]]
// CHECK: return [[A2P]]
return Builtin.gep_Word(p, i, e)
}
public final class Header { }
// CHECK-LABEL: sil hidden @_TF8builtins20allocWithTailElems_1
func allocWithTailElems_1<T>(n: Builtin.Word, ty: T.Type) -> Header {
// CHECK: [[M:%.*]] = metatype $@thick Header.Type
// CHECK: [[A:%.*]] = alloc_ref [tail_elems $T * %0 : $Builtin.Word] $Header
// CHECK: return [[A]]
return Builtin.allocWithTailElems_1(Header.self, n, ty)
}
// CHECK-LABEL: sil hidden @_TF8builtins20allocWithTailElems_3
func allocWithTailElems_3<T1, T2, T3>(n1: Builtin.Word, ty1: T1.Type, n2: Builtin.Word, ty2: T2.Type, n3: Builtin.Word, ty3: T3.Type) -> Header {
// CHECK: [[M:%.*]] = metatype $@thick Header.Type
// CHECK: [[A:%.*]] = alloc_ref [tail_elems $T1 * %0 : $Builtin.Word] [tail_elems $T2 * %2 : $Builtin.Word] [tail_elems $T3 * %4 : $Builtin.Word] $Header
// CHECK: return [[A]]
return Builtin.allocWithTailElems_3(Header.self, n1, ty1, n2, ty2, n3, ty3)
}
// CHECK-LABEL: sil hidden @_TF8builtins16projectTailElems
func projectTailElems<T>(h: Header, ty: T.Type) -> Builtin.RawPointer {
// CHECK: [[TA:%.*]] = ref_tail_addr %0 : $Header
// CHECK: [[A2P:%.*]] = address_to_pointer [[TA]]
// CHECK: return [[A2P]]
return Builtin.projectTailElems(h, ty)
}
// CHECK-LABEL: sil hidden @_TF8builtins11getTailAddr
func getTailAddr<T1, T2>(start: Builtin.RawPointer, i: Builtin.Word, ty1: T1.Type, ty2: T2.Type) -> Builtin.RawPointer {
// CHECK: [[P2A:%.*]] = pointer_to_address %0
// CHECK: [[TA:%.*]] = tail_addr [[P2A]] : $*T1, %1 : $Builtin.Word, $T2
// CHECK: [[A2P:%.*]] = address_to_pointer [[TA]]
// CHECK: return [[A2P]]
return Builtin.getTailAddr_Word(start, i, ty1, ty2)
}
// CHECK-LABEL: sil hidden @_TF8builtins8condfail

View File

@@ -30,5 +30,5 @@ public class C {}
}
@_transparent public func gep32(p p: Builtin.RawPointer, i: Builtin.Int32) -> Builtin.RawPointer {
return Builtin.gep_Int32(p, i)
return Builtin.gepRaw_Int32(p, i)
}