Skip to content

Add SIL and IRGen support for a ConstantStringLiteral instruction #8692

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
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
15 changes: 15 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,21 @@ class SILBuilder {
getSILDebugLocation(Loc), text.toStringRef(Out), encoding, F));
}

ConstStringLiteralInst *
createConstStringLiteral(SILLocation Loc, StringRef text,
ConstStringLiteralInst::Encoding encoding) {
return insert(ConstStringLiteralInst::create(getSILDebugLocation(Loc), text,
encoding, F));
}

ConstStringLiteralInst *
createConstStringLiteral(SILLocation Loc, const Twine &text,
ConstStringLiteralInst::Encoding encoding) {
SmallVector<char, 256> Out;
return insert(ConstStringLiteralInst::create(
getSILDebugLocation(Loc), text.toStringRef(Out), encoding, F));
}

LoadInst *createLoad(SILLocation Loc, SILValue LV,
LoadOwnershipQualifier Qualifier) {
assert((Qualifier != LoadOwnershipQualifier::Unqualified) ||
Expand Down
15 changes: 12 additions & 3 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -665,9 +665,18 @@ SILCloner<ImplClass>::visitStringLiteralInst(StringLiteralInst *Inst) {
Inst->getEncoding()));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitLoadInst(LoadInst *Inst) {
template <typename ImplClass>
void SILCloner<ImplClass>::visitConstStringLiteralInst(
ConstStringLiteralInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst,
getBuilder().createConstStringLiteral(
getOpLocation(Inst->getLoc()), Inst->getValue(),
Inst->getEncoding()));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitLoadInst(LoadInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst, getBuilder().createLoad(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand()),
Expand Down
45 changes: 45 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,51 @@ class StringLiteralInst final : public LiteralInst,
}
};

/// ConstStringLiteralInst - Encapsulates a string constant, as defined
/// originally by
/// a StringLiteralExpr. This produces the address of the string data as a
/// Builtin.RawPointer.
class ConstStringLiteralInst final
: public LiteralInst,
private llvm::TrailingObjects<ConstStringLiteralInst, char> {
friend TrailingObjects;
friend SILBuilder;

public:
enum class Encoding {
UTF8,
UTF16,
};

private:
unsigned Length;
Encoding TheEncoding;

ConstStringLiteralInst(SILDebugLocation DebugLoc, StringRef text,
Encoding encoding, SILType ty);

static ConstStringLiteralInst *create(SILDebugLocation DebugLoc,
StringRef Text, Encoding encoding,
SILFunction &F);

public:
/// getValue - Return the string data for the literal, in UTF-8.
StringRef getValue() const { return {getTrailingObjects<char>(), Length}; }

/// getEncoding - Return the desired encoding of the text.
Encoding getEncoding() const { return TheEncoding; }

/// getCodeUnitCount - Return encoding-based length of the string
/// literal in code units.
uint64_t getCodeUnitCount();

ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> getAllOperands() { return {}; }

static bool classof(const ValueBase *V) {
return V->getKind() == ValueKind::ConstStringLiteralInst;
}
};
//===----------------------------------------------------------------------===//
// Memory instructions.
//===----------------------------------------------------------------------===//
Expand Down
3 changes: 2 additions & 1 deletion include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
INST(IntegerLiteralInst, LiteralInst, integer_literal, None, DoesNotRelease)
INST(FloatLiteralInst, LiteralInst, float_literal, None, DoesNotRelease)
INST(StringLiteralInst, LiteralInst, string_literal, None, DoesNotRelease)
VALUE_RANGE(LiteralInst, FunctionRefInst, StringLiteralInst)
INST(ConstStringLiteralInst, LiteralInst, const_string_literal, None, DoesNotRelease)
VALUE_RANGE(LiteralInst, FunctionRefInst, ConstStringLiteralInst)

// Dynamic Dispatch
ABSTRACT_VALUE(MethodInst, SILInstruction)
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 @@ -54,7 +54,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 = 331; // Last change: type witness substitutions
const uint16_t VERSION_MINOR = 332; // Last change: constant_string_literal

using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
Expand Down
165 changes: 165 additions & 0 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
#include "swift/AST/TypeMemberVisitor.h"
#include "swift/AST/Types.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/IRGen/Linking.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/SIL/FormalLinkage.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILModule.h"
Expand Down Expand Up @@ -3079,6 +3081,169 @@ llvm::Constant *IRGenModule::getAddrOfGlobalUTF16String(StringRef utf8) {
return address;
}

static llvm::Constant *getMetatypeDeclarationFor(IRGenModule &IGM,
StringRef name) {
auto *storageType = IGM.ObjCClassStructTy;

// We may have defined the variable already.
if (auto existing = IGM.Module.getNamedGlobal(name))
return getElementBitCast(existing, storageType);

auto linkage = llvm::GlobalValue::ExternalLinkage;
auto visibility = llvm::GlobalValue::DefaultVisibility;
auto storageClass = llvm::GlobalValue::DefaultStorageClass;

auto var = new llvm::GlobalVariable(IGM.Module, storageType,
/*constant*/ false, linkage,
/*initializer*/ nullptr, name);
var->setVisibility(visibility);
var->setDLLStorageClass(storageClass);
var->setAlignment(IGM.getPointerAlignment().getValue());

return var;
}
#define STRINGIFY_IMPL(x) #x
#define REALLY_STRINGIFY( x) STRINGIFY_IMPL(x)

llvm::Constant *
IRGenModule::getAddrOfGlobalConstantString(StringRef utf8) {
auto &entry = GlobalConstantStrings[utf8];
if (entry)
return entry;

// If not, create it. This implicitly adds a trailing null.
auto data = llvm::ConstantDataArray::getString(LLVMContext, utf8);
auto *dataTy = data->getType();

llvm::Type *constantStringTy[] = {
RefCountedStructTy,
Int32Ty,
Int32Ty,
Int8Ty,
dataTy
};
auto *ConstantStringTy =
llvm::StructType::get(getLLVMContext(), constantStringTy,
/*packed*/ false);

auto metaclass = getMetatypeDeclarationFor(
*this, REALLY_STRINGIFY(CLASS_METADATA_SYM(s20_Latin1StringStorage)));

metaclass = llvm::ConstantExpr::getBitCast(metaclass, TypeMetadataPtrTy);

// Get a reference count of two.
auto *strongRefCountInit = llvm::ConstantInt::get(
Int32Ty,
InlineRefCountBits(0 /*unowned ref count*/, 2 /*strong ref count*/)
.getBitsValue());
auto *unownedRefCountInit = llvm::ConstantInt::get(Int32Ty, 0);

auto *count = llvm::ConstantInt::get(Int32Ty, utf8.size());
// Capacitity is length plus one because of the implicitly added '\0'
// character.
auto *capacity = llvm::ConstantInt::get(Int32Ty, utf8.size() + 1);
auto *flags = llvm::ConstantInt::get(Int8Ty, 0);

// FIXME: Big endian-ness.
llvm::Constant *heapObjectHeaderFields[] = {
metaclass, strongRefCountInit, unownedRefCountInit
};

auto *initRefCountStruct = llvm::ConstantStruct::get(
RefCountedStructTy, makeArrayRef(heapObjectHeaderFields));

llvm::Constant *fields[] = {
initRefCountStruct, count, capacity, flags, data};
auto *init =
llvm::ConstantStruct::get(ConstantStringTy, makeArrayRef(fields));

auto global = new llvm::GlobalVariable(Module, init->getType(), true,
llvm::GlobalValue::PrivateLinkage,
init);
global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);

// Cache string entry.
entry = global;

return global;
}

llvm::Constant *
IRGenModule::getAddrOfGlobalUTF16ConstantString(StringRef utf8) {
auto &entry = GlobalConstantUTF16Strings[utf8];
if (entry)
return entry;

// If not, first transcode it to UTF16.
SmallVector<llvm::UTF16, 128> buffer(utf8.size() + 1); // +1 for ending nulls.
const llvm::UTF8 *fromPtr = (const llvm::UTF8 *) utf8.data();
llvm::UTF16 *toPtr = &buffer[0];
(void) ConvertUTF8toUTF16(&fromPtr, fromPtr + utf8.size(),
&toPtr, toPtr + utf8.size(),
llvm::strictConversion);

// The length of the transcoded string in UTF-8 code points.
size_t utf16Length = toPtr - &buffer[0];

// Null-terminate the UTF-16 string.
*toPtr = 0;
ArrayRef<llvm::UTF16> utf16(&buffer[0], utf16Length + 1);

auto *data = llvm::ConstantDataArray::get(LLVMContext, utf16);
auto *dataTy = data->getType();

llvm::Type *constantUTFStringTy[] = {
RefCountedStructTy,
Int32Ty,
Int32Ty,
Int8Ty,
Int8Ty, // For 16-byte alignment.
dataTy
};
auto *ConstantUTFStringTy =
llvm::StructType::get(getLLVMContext(), constantUTFStringTy,
/*packed*/ false);

auto metaclass = getMetatypeDeclarationFor(
*this, REALLY_STRINGIFY(CLASS_METADATA_SYM(s19_UTF16StringStorage)));

metaclass = llvm::ConstantExpr::getBitCast(metaclass, TypeMetadataPtrTy);

// Get a reference count of two.
auto *strongRefCountInit = llvm::ConstantInt::get(
Int32Ty,
InlineRefCountBits(0 /*unowned ref count*/, 2 /*strong ref count*/)
.getBitsValue());
auto *unownedRefCountInit = llvm::ConstantInt::get(Int32Ty, 0);

auto *count = llvm::ConstantInt::get(Int32Ty, utf16Length);
auto *capacity = llvm::ConstantInt::get(Int32Ty, utf16Length + 1);
auto *flags = llvm::ConstantInt::get(Int8Ty, 0);
auto *padding = llvm::ConstantInt::get(Int8Ty, 0);

llvm::Constant *heapObjectHeaderFields[] = {
metaclass, strongRefCountInit, unownedRefCountInit
};

auto *initRefCountStruct = llvm::ConstantStruct::get(
RefCountedStructTy, makeArrayRef(heapObjectHeaderFields));

llvm::Constant *fields[] = {
initRefCountStruct, count, capacity, flags, padding, data};
auto *init =
llvm::ConstantStruct::get(ConstantUTFStringTy, makeArrayRef(fields));

auto global = new llvm::GlobalVariable(Module, init->getType(), true,
llvm::GlobalValue::PrivateLinkage,
init);
global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);

// Cache string entry.
entry = global;

return global;
}

/// Do we have to use resilient access patterns when working with this
/// declaration?
///
Expand Down
5 changes: 2 additions & 3 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
});
FullBoxMetadataPtrTy = FullBoxMetadataStructTy->getPointerTo(DefaultAS);


llvm::Type *refCountedElts[] = { TypeMetadataPtrTy, Int32Ty, Int32Ty };
llvm::Type *refCountedElts[] = {TypeMetadataPtrTy, Int32Ty, Int32Ty};
RefCountedStructTy->setBody(refCountedElts);

PtrSize = Size(DataLayout.getPointerSize(DefaultAS));
Expand Down Expand Up @@ -351,7 +350,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
openedErrorTriple,
/*packed*/ false);
OpenedErrorTriplePtrTy = OpenedErrorTripleTy->getPointerTo(DefaultAS);

InvariantMetadataID = LLVMContext.getMDKindID("invariant.load");
InvariantNode = llvm::MDNode::get(LLVMContext, {});
DereferenceableID = LLVMContext.getMDKindID("dereferenceable");
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,8 @@ class IRGenModule {
llvm::Constant *getAddrOfGlobalString(StringRef utf8,
bool willBeRelativelyAddressed = false);
llvm::Constant *getAddrOfGlobalUTF16String(StringRef utf8);
llvm::Constant *getAddrOfGlobalConstantString(StringRef utf8);
llvm::Constant *getAddrOfGlobalUTF16ConstantString(StringRef utf8);
llvm::Constant *getAddrOfObjCSelectorRef(StringRef selector);
llvm::Constant *getAddrOfObjCMethodName(StringRef methodName);
llvm::Constant *getAddrOfObjCProtocolRecord(ProtocolDecl *proto,
Expand Down Expand Up @@ -693,6 +695,10 @@ class IRGenModule {
llvm::StringMap<llvm::Constant*> ObjCSelectorRefs;
llvm::StringMap<llvm::Constant*> ObjCMethodNames;

/// Maps to constant swift 'String's.
llvm::StringMap<llvm::Constant*> GlobalConstantStrings;
llvm::StringMap<llvm::Constant*> GlobalConstantUTF16Strings;

/// LLVMUsed - List of global values which are required to be
/// present in the object file; bitcast to i8*. This is used for
/// forcing visibility of symbols which may otherwise be optimized
Expand Down
17 changes: 17 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ class IRGenSILFunction :
void visitIntegerLiteralInst(IntegerLiteralInst *i);
void visitFloatLiteralInst(FloatLiteralInst *i);
void visitStringLiteralInst(StringLiteralInst *i);
void visitConstStringLiteralInst(ConstStringLiteralInst *i);

void visitLoadInst(LoadInst *i);
void visitStoreInst(StoreInst *i);
Expand Down Expand Up @@ -2343,6 +2344,22 @@ void IRGenSILFunction::visitStringLiteralInst(swift::StringLiteralInst *i) {
setLoweredExplosion(i, e);
}

void IRGenSILFunction::visitConstStringLiteralInst(
swift::ConstStringLiteralInst *i) {

llvm::Constant *addr;
if (i->getEncoding() == ConstStringLiteralInst::Encoding::UTF8)
addr = IGM.getAddrOfGlobalConstantString(i->getValue());
else
addr = IGM.getAddrOfGlobalUTF16ConstantString(i->getValue());

addr = llvm::ConstantExpr::getBitCast(addr, IGM.Int8PtrTy);

Explosion e;
e.add(addr);
setLoweredExplosion(i, e);
}

void IRGenSILFunction::visitUnreachableInst(swift::UnreachableInst *i) {
Builder.CreateUnreachable();
}
Expand Down
Loading