diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-09-19 15:27:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-09-19 15:27:50 -0400 |
| commit | 653fe976af88fcf86162ca5bb1b46d4378864572 (patch) | |
| tree | 882307a3377e6a4587231721d681daa061a56c78 | |
| parent | a37b3539d94c434c5d74ab524eae2988e48e0756 (diff) | |
Support for IRStringLit (#645)
* * Added support for strings in IR with IRStringLit - with storage of chars after it
* Added kIRDecorationOp_Transitory - can be used for detecting instructions constructed on stack
* Made IRConstant hashing work off type
* Fix comment that is out of date about how an instruction is determines to hold a transitory string.
| -rw-r--r-- | source/core/hash.h | 11 | ||||
| -rw-r--r-- | source/core/slang-string.h | 5 | ||||
| -rw-r--r-- | source/slang/bytecode.cpp | 8 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 14 | ||||
| -rw-r--r-- | source/slang/ir-inst-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 7 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 357 | ||||
| -rw-r--r-- | source/slang/ir.h | 59 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 4 | ||||
| -rw-r--r-- | tests/ir/string-literal.slang | 9 | ||||
| -rw-r--r-- | tests/ir/string-literal.slang.expected | 20 |
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 = { +} |
