summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/core/hash.h11
-rw-r--r--source/core/slang-string.h5
-rw-r--r--source/slang/bytecode.cpp8
-rw-r--r--source/slang/emit.cpp14
-rw-r--r--source/slang/ir-inst-defs.h3
-rw-r--r--source/slang/ir-insts.h7
-rw-r--r--source/slang/ir.cpp357
-rw-r--r--source/slang/ir.h59
-rw-r--r--source/slang/lower-to-ir.cpp4
-rw-r--r--tests/ir/string-literal.slang9
-rw-r--r--tests/ir/string-literal.slang.expected20
11 files changed, 414 insertions, 83 deletions
diff --git a/source/core/hash.h b/source/core/hash.h
index 26450029d..ca6172fc7 100644
--- a/source/core/hash.h
+++ b/source/core/hash.h
@@ -34,7 +34,16 @@ namespace Slang
{
return GetHashCode(const_cast<const char *>(buffer));
}
-
+ inline int GetHashCode(const char * buffer, size_t numChars)
+ {
+ int hash = 0;
+ for (size_t i = 0; i < numChars; ++i)
+ {
+ hash = int(buffer[i]) + (hash << 6) + (hash << 16) - hash;
+ }
+ return hash;
+ }
+
template<int IsInt>
class Hash
{
diff --git a/source/core/slang-string.h b/source/core/slang-string.h
index 2609b37ab..df1055795 100644
--- a/source/core/slang-string.h
+++ b/source/core/slang-string.h
@@ -717,6 +717,11 @@ namespace Slang
{
return Slang::GetHashCode((const char*)begin());
}
+
+ UnownedStringSlice getUnownedSlice() const
+ {
+ return StringRepresentation::asSlice(buffer);
+ }
};
class StringBuilder : public String
diff --git a/source/slang/bytecode.cpp b/source/slang/bytecode.cpp
index 63af9512a..b92476cb1 100644
--- a/source/slang/bytecode.cpp
+++ b/source/slang/bytecode.cpp
@@ -382,7 +382,7 @@ void generateBytecodeForInst(
// TODO: probably want distinct encodings
// for signed vs. unsigned here.
- encodeUInt(context, UInt(ii->u.intVal));
+ encodeUInt(context, UInt(ii->value.intVal));
// destination:
encodeOperand(context, inst);
@@ -397,7 +397,7 @@ void generateBytecodeForInst(
static const UInt size = sizeof(IRFloatingPointValue);
unsigned char buffer[size];
- memcpy(buffer, &cInst->u.floatVal, sizeof(buffer));
+ memcpy(buffer, &cInst->value.floatVal, sizeof(buffer));
for(UInt ii = 0; ii < size; ++ii)
{
@@ -413,7 +413,7 @@ void generateBytecodeForInst(
{
auto ii = (IRConstant*) inst;
encodeUInt(context, ii->op);
- encodeUInt(context, ii->u.intVal ? 1 : 0);
+ encodeUInt(context, ii->value.intVal ? 1 : 0);
// destination:
encodeOperand(context, inst);
@@ -962,7 +962,7 @@ BytecodeGenerationPtr<BCModule> generateBytecodeForModule(
case kIROp_IntLit:
{
auto ptr = allocate<IRIntegerValue>(context);
- *ptr = irConstant->u.intVal;
+ *ptr = irConstant->value.intVal;
bcConstants[cc].ptr = ptr.bitCast<uint8_t>();
}
break;
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 2d774d8d8..74678ef94 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -1015,7 +1015,7 @@ struct EmitVisitor
}
const IRConstant* irConst = (const IRConstant*)elementCountInst;
- const IRIntegerValue elementCount = irConst->u.intVal;
+ const IRIntegerValue elementCount = irConst->value.intVal;
if (elementCount <= 0)
{
SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "Vector size must be greater than 0");
@@ -2277,16 +2277,16 @@ struct EmitVisitor
switch(inst->op)
{
case kIROp_IntLit:
- emit(((IRConstant*) inst)->u.intVal);
+ emit(((IRConstant*) inst)->value.intVal);
break;
case kIROp_FloatLit:
- Emit(((IRConstant*) inst)->u.floatVal);
+ Emit(((IRConstant*) inst)->value.floatVal);
break;
case kIROp_boolConst:
{
- bool val = ((IRConstant*)inst)->u.intVal != 0;
+ bool val = ((IRConstant*)inst)->value.intVal != 0;
emit(val ? "true" : "false");
}
break;
@@ -3611,7 +3611,7 @@ struct EmitVisitor
SLANG_RELEASE_ASSERT(irElementIndex->op == kIROp_IntLit);
IRConstant* irConst = (IRConstant*)irElementIndex;
- UInt elementIndex = (UInt)irConst->u.intVal;
+ UInt elementIndex = (UInt)irConst->value.intVal;
SLANG_RELEASE_ASSERT(elementIndex < 4);
char const* kComponents[] = { "x", "y", "z", "w" };
@@ -3767,7 +3767,7 @@ struct EmitVisitor
SLANG_RELEASE_ASSERT(irElementIndex->op == kIROp_IntLit);
IRConstant* irConst = (IRConstant*)irElementIndex;
- UInt elementIndex = (UInt)irConst->u.intVal;
+ UInt elementIndex = (UInt)irConst->value.intVal;
SLANG_RELEASE_ASSERT(elementIndex < 4);
char const* kComponents[] = { "x", "y", "z", "w" };
@@ -3792,7 +3792,7 @@ struct EmitVisitor
SLANG_RELEASE_ASSERT(irElementIndex->op == kIROp_IntLit);
IRConstant* irConst = (IRConstant*)irElementIndex;
- UInt elementIndex = (UInt)irConst->u.intVal;
+ UInt elementIndex = (UInt)irConst->value.intVal;
SLANG_RELEASE_ASSERT(elementIndex < 4);
char const* kComponents[] = { "x", "y", "z", "w" };
diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h
index 196fae68e..25ef86eaf 100644
--- a/source/slang/ir-inst-defs.h
+++ b/source/slang/ir-inst-defs.h
@@ -189,7 +189,8 @@ INST_RANGE(ParentInst, StructType, Block)
INST(boolConst, boolConst, 0, 0)
INST(IntLit, integer_constant, 0, 0)
INST(FloatLit, float_constant, 0, 0)
-INST_RANGE(Constant, boolConst, FloatLit)
+ INST(StringLit, string_constant, 0, 0)
+INST_RANGE(Constant, boolConst, StringLit)
INST(undefined, undefined, 0, 0)
diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h
index f57e69ba1..69b8a6bf2 100644
--- a/source/slang/ir-insts.h
+++ b/source/slang/ir-insts.h
@@ -460,9 +460,9 @@ struct IRConstantKey
{
IRConstant* inst;
- int GetHashCode();
+ bool operator==(const IRConstantKey& rhs) const { return inst->equal(*rhs.inst); }
+ int GetHashCode() const { return inst->getHashCode(); }
};
-bool operator==(IRConstantKey const& left, IRConstantKey const& right);
struct SharedIRBuilder
{
@@ -520,11 +520,14 @@ struct IRBuilder
IRInst* getBoolValue(bool value);
IRInst* getIntValue(IRType* type, IRIntegerValue value);
IRInst* getFloatValue(IRType* type, IRFloatingPointValue value);
+ IRStringLit* getStringValue(const UnownedStringSlice& slice);
IRBasicType* getBasicType(BaseType baseType);
IRBasicType* getVoidType();
IRBasicType* getBoolType();
IRBasicType* getIntType();
+ IRStringType* getStringType();
+
IRBasicBlockType* getBasicBlockType();
IRType* getWitnessTableType() { return nullptr; }
IRType* getKeyType() { return nullptr; }
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index 6b2939987..c9131325b 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -172,7 +172,7 @@ namespace Slang
UNREACHABLE_RETURN(0);
case kIROp_IntLit:
- return ((IRConstant*)inst)->u.intVal;
+ return static_cast<IRConstant*>(inst)->value.intVal;
break;
}
}
@@ -837,6 +837,28 @@ namespace Slang
return inst;
}
+ static IRInst* createInstWithSizeImpl(
+ IRBuilder* builder,
+ IROp op,
+ IRType* type,
+ size_t sizeInBytes)
+ {
+ auto module = builder->getModule();
+ IRInst* inst = (IRInst*)module->memoryArena.allocate(sizeInBytes);
+ // Zero only the 'type'
+ memset(inst, 0, sizeof(IRInst));
+ // TODO: Do we need to run ctor after zeroing?
+ new (inst) IRInst;
+
+ inst->op = op;
+ if (type)
+ {
+ inst->typeUse.init(inst, type);
+ }
+ maybeSetSourceLoc(builder, inst);
+ return inst;
+ }
+
template<typename T>
static T* createInstImpl(
IRBuilder* builder,
@@ -1036,38 +1058,96 @@ namespace Slang
return code;
}
- //
+ UnownedStringSlice IRConstant::getStringSlice() const
+ {
+ assert(op == kIROp_StringLit);
+ // If the transitory decoration is set, then this is uses the transitoryStringVal for the text storage.
+ // This is typically used when we are using a transitory IRInst held on the stack (such that it can be looked up in cached),
+ // that just points to a string elsewhere, and NOT the typical normal style, where the string is held after the instruction in memory.
+ if (firstDecoration && firstDecoration->op == kIRDecorationOp_Transitory)
+ {
+ return UnownedStringSlice(value.transitoryStringVal.chars, value.transitoryStringVal.numChars);
+ }
+ else
+ {
+ return UnownedStringSlice(value.stringVal.chars, value.stringVal.numChars);
+ }
+ }
- bool operator==(IRConstantKey const& left, IRConstantKey const& right)
+ /// True if constants are equal
+ bool IRConstant::equal(IRConstant& rhs)
{
- if(left.inst->op != right.inst->op) return false;
- if(left.inst->getFullType() != right.inst->getFullType()) return false;
- if(left.inst->u.ptrData[0] != right.inst->u.ptrData[0]) return false;
- if(left.inst->u.ptrData[1] != right.inst->u.ptrData[1]) return false;
- return true;
+ // If they are literally the same thing..
+ if (this == &rhs)
+ {
+ return true;
+ }
+ // Check the type and they are the same op
+ if (op != rhs.op ||
+ getFullType() != rhs.getFullType())
+ {
+ return false;
+ }
+ switch (op)
+ {
+ case kIROp_boolConst:
+ case kIROp_FloatLit:
+ case kIROp_IntLit:
+ {
+ SLANG_COMPILE_TIME_ASSERT(sizeof(IRFloatingPointValue) == sizeof(IRIntegerValue));
+ // ... we can just compare as bits
+ return value.intVal == rhs.value.intVal;
+ }
+ case kIROp_StringLit:
+ {
+ return getStringSlice() == rhs.getStringSlice();
+ }
+ default: break;
+ }
+
+ SLANG_ASSERT(!"Unhandled type");
+ return false;
}
- int IRConstantKey::GetHashCode()
+ int IRConstant::getHashCode()
{
- auto code = Slang::GetHashCode(inst->op);
- code = combineHash(code, Slang::GetHashCode(inst->getFullType()));
- code = combineHash(code, Slang::GetHashCode(inst->u.ptrData[0]));
- code = combineHash(code, Slang::GetHashCode(inst->u.ptrData[1]));
- return code;
+ auto code = Slang::GetHashCode(op);
+ code = combineHash(code, Slang::GetHashCode(getFullType()));
+
+ switch (op)
+ {
+ case kIROp_boolConst:
+ case kIROp_FloatLit:
+ case kIROp_IntLit:
+ {
+ SLANG_COMPILE_TIME_ASSERT(sizeof(IRFloatingPointValue) == sizeof(IRIntegerValue));
+ // ... we can just compare as bits
+ return combineHash(code, Slang::GetHashCode(value.intVal));
+ }
+ case kIROp_StringLit:
+ {
+ const UnownedStringSlice slice = getStringSlice();
+ return combineHash(code, Slang::GetHashCode(slice.begin(), slice.size()));
+ }
+ default:
+ {
+ SLANG_ASSERT(!"Invalid type");
+ return 0;
+ }
+ }
}
static IRConstant* findOrEmitConstant(
IRBuilder* builder,
- IROp op,
- IRType* type,
- UInt valueSize,
- void const* value)
+ IRConstant& keyInst)
{
- IRConstant keyInst;
- memset(&keyInst, 0, sizeof(keyInst));
- keyInst.op = op;
- keyInst.typeUse.usedValue = type;
- memcpy(&keyInst.u, value, valueSize);
+ // We now know where we want to insert, but there might
+ // already be an equivalent instruction in that block.
+ //
+ // We will check for such an instruction in a slightly hacky
+ // way: we will construct a temporary instruction and
+ // then use it to look up in a cache of instructions.
+ // The 'fake' instruction is passed in as keyInst.
IRConstantKey key;
key.inst = &keyInst;
@@ -1078,16 +1158,45 @@ namespace Slang
// We found a match, so just use that.
return irValue;
}
+
+ // Calculate the minimum object size (ie not including the payload of value)
+ const size_t prefixSize = offsetof(IRConstant, value);
- // We now know where we want to insert, but there might
- // already be an equivalent instruction in that block.
- //
- // We will check for such an instruction in a slightly hacky
- // way: we will construct a temporary instruction and
- // then use it to look up in a cache of instructions.
+ switch (keyInst.op)
+ {
+ case kIROp_boolConst:
+ case kIROp_IntLit:
+ {
+ irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.op, keyInst.getFullType(), prefixSize + sizeof(IRIntegerValue)));
+ irValue->value.intVal = keyInst.value.intVal;
+ break;
+ }
+ case kIROp_FloatLit:
+ {
+ irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.op, keyInst.getFullType(), prefixSize + sizeof(IRFloatingPointValue)));
+ irValue->value.floatVal = keyInst.value.floatVal;
+ break;
+ }
+ case kIROp_StringLit:
+ {
+ const UnownedStringSlice slice = keyInst.getStringSlice();
+
+ const size_t sliceSize = slice.size();
+ const size_t instSize = prefixSize + offsetof(IRConstant::StringValue, chars) + sliceSize;
+
+ irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.op, keyInst.getFullType(), instSize));
+
+ IRConstant::StringValue& dstString = irValue->value.stringVal;
+
+ dstString.numChars = uint32_t(sliceSize);
+ // Turn into pointer to avoid warning of array overrun
+ char* dstChars = dstString.chars;
+ // Copy the chars
+ memcpy(dstChars, slice.begin(), sliceSize);
- irValue = createInst<IRConstant>(builder, op, type);
- memcpy(&irValue->u, value, valueSize);
+ break;
+ }
+ }
key.inst = irValue;
builder->sharedBuilder->constantMap.Add(key, irValue);
@@ -1097,40 +1206,57 @@ namespace Slang
return irValue;
}
-
//
IRInst* IRBuilder::getBoolValue(bool inValue)
{
- IRIntegerValue value = inValue;
- return findOrEmitConstant(
- this,
- kIROp_boolConst,
- getBoolType(),
- sizeof(value),
- &value);
+ IRConstant keyInst;
+ memset(&keyInst, 0, sizeof(keyInst));
+ keyInst.op = kIROp_boolConst;
+ keyInst.typeUse.usedValue = getBoolType();
+ keyInst.value.intVal = IRIntegerValue(inValue);
+ return findOrEmitConstant(this, keyInst);
}
- IRInst* IRBuilder::getIntValue(IRType* type, IRIntegerValue value)
+ IRInst* IRBuilder::getIntValue(IRType* type, IRIntegerValue inValue)
{
- return findOrEmitConstant(
- this,
- kIROp_IntLit,
- type,
- sizeof(value),
- &value);
+ IRConstant keyInst;
+ memset(&keyInst, 0, sizeof(keyInst));
+ keyInst.op = kIROp_IntLit;
+ keyInst.typeUse.usedValue = type;
+ keyInst.value.intVal = inValue;
+ return findOrEmitConstant(this, keyInst);
}
- IRInst* IRBuilder::getFloatValue(IRType* type, IRFloatingPointValue value)
+ IRInst* IRBuilder::getFloatValue(IRType* type, IRFloatingPointValue inValue)
{
- return findOrEmitConstant(
- this,
- kIROp_FloatLit,
- type,
- sizeof(value),
- &value);
+ IRConstant keyInst;
+ memset(&keyInst, 0, sizeof(keyInst));
+ keyInst.op = kIROp_FloatLit;
+ keyInst.typeUse.usedValue = type;
+ keyInst.value.floatVal = inValue;
+ return findOrEmitConstant(this, keyInst);
}
+ IRStringLit* IRBuilder::getStringValue(const UnownedStringSlice& inSlice)
+ {
+ IRConstant keyInst;
+ memset(&keyInst, 0, sizeof(keyInst));
+
+ // Mark that this is on the stack...
+ static IRDecoration stackDecoration = IRDecoration::make(kIRDecorationOp_Transitory);
+ keyInst.firstDecoration = &stackDecoration;
+
+ keyInst.op = kIROp_StringLit;
+ keyInst.typeUse.usedValue = getStringType();
+
+ IRConstant::StringSliceValue& dstSlice = keyInst.value.transitoryStringVal;
+ dstSlice.chars = const_cast<char*>(inSlice.begin());
+ dstSlice.numChars = uint32_t(inSlice.size());
+
+ return static_cast<IRStringLit*>(findOrEmitConstant(this, keyInst));
+ }
+
IRInst* findOrEmitHoistableInst(
IRBuilder* builder,
IRType* type,
@@ -1278,6 +1404,11 @@ namespace Slang
return (IRBasicType*)getType(kIROp_IntType);
}
+ IRStringType* IRBuilder::getStringType()
+ {
+ return (IRStringType*)getType(kIROp_StringType);
+ }
+
IRBasicBlockType* IRBuilder::getBasicBlockType()
{
return (IRBasicBlockType*)getType(kIROp_BasicBlockType);
@@ -2405,6 +2536,110 @@ namespace Slang
}
}
+
+
+ struct StringEncoder
+ {
+ static char getHexChar(int v)
+ {
+ return (v <= 9) ? char(v + '0') : char(v - 10 + 'A');
+ }
+
+ void flush(const char* pos)
+ {
+ if (pos > m_runStart)
+ {
+ m_builder->append(m_runStart, pos);
+ }
+ m_runStart = pos + 1;
+ }
+
+ void appendEscapedChar(const char* pos, char encodeChar)
+ {
+ flush(pos);
+ const char chars[] = { '\\', encodeChar };
+ m_builder->Append(chars, 2);
+ }
+
+ void appendAsHex(const char* pos)
+ {
+ flush(pos);
+
+ const int v = *(const uint8_t*)pos;
+
+ char buf[5];
+ buf[0] = '\\';
+ buf[1] = 'x';
+ buf[2] = '0';
+
+ buf[3] = getHexChar(v >> 4);
+ buf[4] = getHexChar(v & 0xf);
+
+ m_builder->Append(buf, 5);
+ }
+
+ StringEncoder(StringBuilder* builder, const char* start):
+ m_runStart(start),
+ m_builder(builder)
+ {}
+
+ StringBuilder* m_builder;
+ const char* m_runStart;
+ };
+
+ static void dumpEncodeString(
+ IRDumpContext* context,
+ const UnownedStringSlice& slice)
+ {
+ // https://msdn.microsoft.com/en-us/library/69ze775t.aspx
+
+ StringBuilder& builder = *context->builder;
+ builder.Append('"');
+
+ {
+ const char* cur = slice.begin();
+ StringEncoder encoder(&builder, cur);
+ const char* end = slice.end();
+
+ for (; cur < end; cur++)
+ {
+ const int8_t c = uint8_t(*cur);
+ switch (c)
+ {
+ case '\\':
+ encoder.appendEscapedChar(cur, '\\');
+ break;
+ case '"':
+ encoder.appendEscapedChar(cur, '"');
+ break;
+ case '\n':
+ encoder.appendEscapedChar(cur, 'n');
+ break;
+ case '\t':
+ encoder.appendEscapedChar(cur, 't');
+ break;
+ case '\r':
+ encoder.appendEscapedChar(cur, 'r');
+ break;
+ case '\0':
+ encoder.appendEscapedChar(cur, '0');
+ break;
+ default:
+ {
+ if (c < 32)
+ {
+ encoder.appendAsHex(cur);
+ }
+ break;
+ }
+ }
+ }
+ encoder.flush(end);
+ }
+
+ builder.Append('"');
+ }
+
static void dumpType(
IRDumpContext* context,
IRType* type);
@@ -2427,15 +2662,18 @@ namespace Slang
switch (inst->op)
{
case kIROp_IntLit:
- dump(context, ((IRConstant*)inst)->u.intVal);
+ dump(context, ((IRConstant*)inst)->value.intVal);
return;
case kIROp_FloatLit:
- dump(context, ((IRConstant*)inst)->u.floatVal);
+ dump(context, ((IRConstant*)inst)->value.floatVal);
return;
case kIROp_boolConst:
- dump(context, ((IRConstant*)inst)->u.intVal ? "true" : "false");
+ dump(context, ((IRConstant*)inst)->value.intVal ? "true" : "false");
+ return;
+ case kIROp_StringLit:
+ dumpEncodeString(context, static_cast<IRConstant*>(inst)->getStringSlice());
return;
default:
@@ -2763,6 +3001,7 @@ namespace Slang
case kIROp_IntLit:
case kIROp_FloatLit:
case kIROp_boolConst:
+ case kIROp_StringLit:
dumpOperand(context, inst);
break;
@@ -4870,7 +5109,7 @@ namespace Slang
case kIROp_boolConst:
{
IRConstant* c = (IRConstant*)originalValue;
- return builder->getBoolValue(c->u.intVal != 0);
+ return builder->getBoolValue(c->value.intVal != 0);
}
break;
@@ -4878,14 +5117,14 @@ namespace Slang
case kIROp_IntLit:
{
IRConstant* c = (IRConstant*)originalValue;
- return builder->getIntValue(cloneType(this, c->getDataType()), c->u.intVal);
+ return builder->getIntValue(cloneType(this, c->getDataType()), c->value.intVal);
}
break;
case kIROp_FloatLit:
{
IRConstant* c = (IRConstant*)originalValue;
- return builder->getFloatValue(cloneType(this, c->getDataType()), c->u.floatVal);
+ return builder->getFloatValue(cloneType(this, c->getDataType()), c->value.floatVal);
}
break;
diff --git a/source/slang/ir.h b/source/slang/ir.h
index a7f2cb4fb..15edb9b6c 100644
--- a/source/slang/ir.h
+++ b/source/slang/ir.h
@@ -128,6 +128,10 @@ enum IRDecorationOp : uint16_t
kIRDecorationOp_Semantic,
kIRDecorationOp_InterpolationMode,
kIRDecorationOp_NameHint,
+ /** The _instruction_ is transitory. Such a decoration should NEVER be found on an output instruction a module.
+ Typically used mark an instruction so can be specially handled - say when creating a IRConstant literal, and the payload of
+ needs to be special cased for lookup. */
+ kIRDecorationOp_Transitory,
};
// represents an object allocated in an IR memory arena
@@ -140,6 +144,14 @@ struct IRObject
// for preserving high-level source information.
struct IRDecoration : public IRObject
{
+ static IRDecoration make(IRDecorationOp opIn, IRDecoration* nextIn = nullptr)
+ {
+ IRDecoration dec;
+ dec.next = nextIn;
+ dec.op = opIn;
+ return dec;
+ }
+
// Next decoration attached to the same instruction
IRDecoration* next;
@@ -173,7 +185,6 @@ struct IRInst : public IRObject
return operandCount;
}
-
// Source location information for this value, if any
SourceLoc sourceLoc;
@@ -427,6 +438,8 @@ struct IRBoolType : IRBasicType
IR_LEAF_ISA(BoolType)
};
+SIMPLE_IR_TYPE(StringType, Type)
+
// Constant Instructions
typedef int64_t IRIntegerValue;
@@ -434,21 +447,47 @@ typedef double IRFloatingPointValue;
struct IRConstant : IRInst
{
- union
+ struct StringValue
+ {
+ uint32_t numChars; ///< The number of chars
+ char chars[1]; ///< Chars added at end. NOTE! Must be last member of struct!
+ };
+ struct StringSliceValue
+ {
+ uint32_t numChars;
+ char* chars;
+ };
+
+ union ValueUnion
{
- IRIntegerValue intVal;
+ IRIntegerValue intVal; ///< Used for integrals and boolean
IRFloatingPointValue floatVal;
- // HACK: allows us to hash the value easily
- void* ptrData[2];
- } u;
+ /// Either of these types could be set with kIROp_StringLit.
+ /// Which is used is currently determined with IRDecorationOp - if a kDecorationOp_Transitory is set, then the transitory StringVal is used, else stringVal
+ // which relies on chars being held after the struct).
+ StringValue stringVal;
+ StringSliceValue transitoryStringVal;
+ };
+
+ /// Returns a string slice (or empty string if not appropriate)
+ UnownedStringSlice getStringSlice() const;
+
+ /// True if constants are equal
+ bool equal(IRConstant& rhs);
+ /// Get the hash
+ int getHashCode();
IR_PARENT_ISA(Constant)
+
+ // Must be last member, because data may be held behind
+ // NOTE! The total size of IRConstant may not be allocated - only enough space is allocated for the value type held in the union.
+ ValueUnion value;
};
struct IRIntLit : IRConstant
{
- IRIntegerValue getValue() { return u.intVal; }
+ IRIntegerValue getValue() { return value.intVal; }
IR_LEAF_ISA(IntLit);
};
@@ -457,6 +496,12 @@ struct IRIntLit : IRConstant
// if it has one, and assert-fail otherwise.
IRIntegerValue GetIntVal(IRInst* inst);
+struct IRStringLit : IRConstant
+{
+
+ IR_LEAF_ISA(StringLit);
+};
+
// A instruction that ends a basic block (usually because of control flow)
struct IRTerminatorInst : IRInst
{
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index d57872fc9..8f9335c0a 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -1638,9 +1638,9 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
return LoweredValInfo::simple(context->irBuilder->getFloatValue(type, expr->value));
}
- LoweredValInfo visitStringLiteralExpr(StringLiteralExpr*)
+ LoweredValInfo visitStringLiteralExpr(StringLiteralExpr* expr)
{
- SLANG_UNEXPECTED("string literal encountered during code emit");
+ return LoweredValInfo::simple(context->irBuilder->getStringValue(expr->value.getUnownedSlice()));
}
LoweredValInfo visitAggTypeCtorExpr(AggTypeCtorExpr* /*expr*/)
diff --git a/tests/ir/string-literal.slang b/tests/ir/string-literal.slang
new file mode 100644
index 000000000..e0c893014
--- /dev/null
+++ b/tests/ir/string-literal.slang
@@ -0,0 +1,9 @@
+//TEST(compute):SIMPLE:-dump-ir -profile cs_5_0 -entry main
+
+[numthreads(1, 1, 1)]
+void main(
+ uint tid : SV_DispatchThreadIndex)
+{
+ "Hello \t\n\0x083 World";
+}
+
diff --git a/tests/ir/string-literal.slang.expected b/tests/ir/string-literal.slang.expected
new file mode 100644
index 000000000..8df3ff00e
--- /dev/null
+++ b/tests/ir/string-literal.slang.expected
@@ -0,0 +1,20 @@
+result code = 0
+standard error = {
+let %1 : _ = UInt()
+let %2 : _ = Void()
+let %3 : _ = Func(%2, %1)
+let %4 : _ = BasicBlock()
+Ptr(%1)
+let %5 : _ = String()
+let %6 : %5 = string_constant("Hello \t\n\0x083 World")
+
+func @_S04mainp1puV : %3
+{
+block %7(
+ param %8 : %1):
+ return_void()
+}
+
+}
+standard output = {
+}