[PATCH] D144457: [clang][Interp] Handle global composite temporaries
This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG8a58f0d370b0: [clang][Interp] Handle global composite temporaries (authored by tbaeder). Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 Files: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/Descriptor.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h clang/lib/AST/Interp/Record.h clang/test/AST/Interp/records.cpp Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -114,6 +114,21 @@ static_assert(c2.a == 100, ""); static_assert(c2.b == 200, ""); + +/// A global, composite temporary variable. +constexpr const C = C().get(); + +/// Same, but with a bitfield. +class D { +public: + unsigned a : 4; + constexpr D() : a(15) {} + constexpr D get() const { +return *this; + } +}; +constexpr const D = D().get(); + constexpr int getB() { C c; int = c.b; Index: clang/lib/AST/Interp/Record.h === --- clang/lib/AST/Interp/Record.h +++ clang/lib/AST/Interp/Record.h @@ -87,7 +87,10 @@ } unsigned getNumBases() const { return Bases.size(); } - const Base *getBase(unsigned I) const { return [I]; } + const Base *getBase(unsigned I) const { +assert(I < getNumBases()); +return [I]; + } using const_virtual_iter = VirtualBaseList::const_iterator; llvm::iterator_range virtual_bases() const { Index: clang/lib/AST/Interp/Pointer.h === --- clang/lib/AST/Interp/Pointer.h +++ clang/lib/AST/Interp/Pointer.h @@ -27,6 +27,7 @@ class Block; class DeadBlock; class Pointer; +class Context; enum PrimType : unsigned; class Pointer; @@ -87,6 +88,9 @@ return reinterpret_cast(Pointee) + Offset; } + /// Converts the pointer to an APValue that is an rvalue. + APValue toRValue(const Context ) const; + /// Offsets a pointer inside an array. Pointer atIndex(unsigned Idx) const { if (Base == RootPtrMark) Index: clang/lib/AST/Interp/Pointer.cpp === --- clang/lib/AST/Interp/Pointer.cpp +++ clang/lib/AST/Interp/Pointer.cpp @@ -7,9 +7,14 @@ //===--===// #include "Pointer.h" +#include "Boolean.h" +#include "Context.h" +#include "Floating.h" #include "Function.h" +#include "Integral.h" #include "InterpBlock.h" #include "PrimType.h" +#include "Record.h" using namespace clang; using namespace clang::interp; @@ -217,3 +222,34 @@ bool Pointer::hasSameArray(const Pointer , const Pointer ) { return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray; } + +APValue Pointer::toRValue(const Context ) const { + // Primitives. + if (getFieldDesc()->isPrimitive()) { +PrimType PT = *Ctx.classify(getType()); +TYPE_SWITCH(PT, return deref().toAPValue()); +llvm_unreachable("Unhandled PrimType?"); + } + + APValue Result; + // Records. + if (getFieldDesc()->isRecord()) { +const Record *R = getRecord(); +Result = +APValue(APValue::UninitStruct(), R->getNumBases(), R->getNumFields()); + +for (unsigned I = 0; I != R->getNumFields(); ++I) { + const Pointer = this->atField(R->getField(I)->Offset); + Result.getStructField(I) = FieldPtr.toRValue(Ctx); +} + +for (unsigned I = 0; I != R->getNumBases(); ++I) { + const Pointer = this->atField(R->getBase(I)->Offset); + Result.getStructBase(I) = BasePtr.toRValue(Ctx); +} + } + + // TODO: Arrays + + return Result; +} Index: clang/lib/AST/Interp/Opcodes.td === --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -353,6 +353,12 @@ def InitGlobalTemp : AccessOpcode { let Args = [ArgUint32, ArgLETD]; } +// [Pointer] -> [Pointer] +def InitGlobalTempComp : Opcode { + let Args = [ArgLETD]; + let Types = []; + let HasGroup = 0; +} // [Value] -> [] def SetGlobal : AccessOpcode; Index: clang/lib/AST/Interp/Interp.h === --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -996,6 +996,19 @@ return true; } +/// 1) Converts the value on top of the stack to an APValue +/// 2) Sets that APValue on \Temp +/// 3) Initialized global with index \I with that +inline bool InitGlobalTempComp(InterpState , CodePtr OpPC, + const LifetimeExtendedTemporaryDecl *Temp) { + assert(Temp); + const Pointer = S.Stk.peek(); + APValue *Cached =
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
aaron.ballman accepted this revision. aaron.ballman added a comment. This revision is now accepted and ready to land. LGTM! CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder updated this revision to Diff 551435. tbaeder marked 6 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 Files: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/Descriptor.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h clang/lib/AST/Interp/Record.h clang/test/AST/Interp/records.cpp Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -114,6 +114,21 @@ static_assert(c2.a == 100, ""); static_assert(c2.b == 200, ""); + +/// A global, composite temporary variable. +constexpr const C = C().get(); + +/// Same, but with a bitfield. +class D { +public: + unsigned a : 4; + constexpr D() : a(15) {} + constexpr D get() const { +return *this; + } +}; +constexpr const D = D().get(); + constexpr int getB() { C c; int = c.b; Index: clang/lib/AST/Interp/Record.h === --- clang/lib/AST/Interp/Record.h +++ clang/lib/AST/Interp/Record.h @@ -88,7 +88,10 @@ } unsigned getNumBases() const { return Bases.size(); } - const Base *getBase(unsigned I) const { return [I]; } + const Base *getBase(unsigned I) const { +assert(I < getNumBases()); +return [I]; + } using const_virtual_iter = VirtualBaseList::const_iterator; llvm::iterator_range virtual_bases() const { Index: clang/lib/AST/Interp/Pointer.h === --- clang/lib/AST/Interp/Pointer.h +++ clang/lib/AST/Interp/Pointer.h @@ -27,6 +27,7 @@ class Block; class DeadBlock; class Pointer; +class Context; enum PrimType : unsigned; class Pointer; @@ -87,6 +88,9 @@ return reinterpret_cast(Pointee) + Offset; } + /// Converts the pointer to an APValue that is an rvalue. + APValue toRValue(const Context ) const; + /// Offsets a pointer inside an array. Pointer atIndex(unsigned Idx) const { if (Base == RootPtrMark) Index: clang/lib/AST/Interp/Pointer.cpp === --- clang/lib/AST/Interp/Pointer.cpp +++ clang/lib/AST/Interp/Pointer.cpp @@ -7,9 +7,14 @@ //===--===// #include "Pointer.h" +#include "Boolean.h" +#include "Context.h" +#include "Floating.h" #include "Function.h" +#include "Integral.h" #include "InterpBlock.h" #include "PrimType.h" +#include "Record.h" using namespace clang; using namespace clang::interp; @@ -217,3 +222,34 @@ bool Pointer::hasSameArray(const Pointer , const Pointer ) { return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray; } + +APValue Pointer::toRValue(const Context ) const { + // Primitives. + if (getFieldDesc()->isPrimitive()) { +PrimType PT = *Ctx.classify(getType()); +TYPE_SWITCH(PT, return deref().toAPValue()); +llvm_unreachable("Unhandled PrimType?"); + } + + APValue Result; + // Records. + if (getFieldDesc()->isRecord()) { +const Record *R = getRecord(); +Result = +APValue(APValue::UninitStruct(), R->getNumBases(), R->getNumFields()); + +for (unsigned I = 0; I != R->getNumFields(); ++I) { + const Pointer = this->atField(R->getField(I)->Offset); + Result.getStructField(I) = FieldPtr.toRValue(Ctx); +} + +for (unsigned I = 0; I != R->getNumBases(); ++I) { + const Pointer = this->atField(R->getBase(I)->Offset); + Result.getStructBase(I) = BasePtr.toRValue(Ctx); +} + } + + // TODO: Arrays + + return Result; +} Index: clang/lib/AST/Interp/Opcodes.td === --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -353,6 +353,12 @@ def InitGlobalTemp : AccessOpcode { let Args = [ArgUint32, ArgLETD]; } +// [Pointer] -> [Pointer] +def InitGlobalTempComp : Opcode { + let Args = [ArgLETD]; + let Types = []; + let HasGroup = 0; +} // [Value] -> [] def SetGlobal : AccessOpcode; Index: clang/lib/AST/Interp/Interp.h === --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -993,6 +993,19 @@ return true; } +/// 1) Converts the value on top of the stack to an APValue +/// 2) Sets that APValue on \Temp +/// 3) Initialized global with index \I with that +inline bool InitGlobalTempComp(InterpState , CodePtr OpPC, + const LifetimeExtendedTemporaryDecl *Temp) { + assert(Temp); + const Pointer = S.Stk.peek(); + APValue *Cached = Temp->getOrCreateValue(true); + + *Cached = P.toRValue(S.getCtx()); + return true; +} + template ::T> bool InitThisField(InterpState , CodePtr OpPC, uint32_t I) { if
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added inline comments. Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:852 + return false; +return this->emitInitGlobalTempComp(TempDecl, E); } aaron.ballman wrote: > Should this still happen even if `TempDecl` is null? It looks like > `getLifetimeExtendedTemporaryDecl()` can return a null pointer, but perhaps > there's a reason we can't get that result here? AFAIK it never returns null if the storage duration is `SD_Static`, but that's just based on what I was seeing. Could add an assertion to be sure. Comment at: clang/lib/AST/Interp/Pointer.cpp:236 +for (unsigned I = 0; I != R->getNumFields(); ++I) { + const Pointer FieldPtr = this->atField(R->getField(I)->Offset); + Result.getStructField(I) = FieldPtr.toRValue(Ctx); aaron.ballman wrote: > `const Pointer &` instead? :) Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
aaron.ballman added inline comments. Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:852 + return false; +return this->emitInitGlobalTempComp(TempDecl, E); } Should this still happen even if `TempDecl` is null? It looks like `getLifetimeExtendedTemporaryDecl()` can return a null pointer, but perhaps there's a reason we can't get that result here? Comment at: clang/lib/AST/Interp/Pointer.cpp:235-237 +for (unsigned I = 0; I != R->getNumFields(); ++I) { + const Pointer FieldPtr = this->atField(R->getField(I)->Offset); + Result.getStructField(I) = FieldPtr.toRValue(Ctx); Pointer to a field? That means, I would like tests that involve bit-fields. :-) Comment at: clang/lib/AST/Interp/Pointer.cpp:236 +for (unsigned I = 0; I != R->getNumFields(); ++I) { + const Pointer FieldPtr = this->atField(R->getField(I)->Offset); + Result.getStructField(I) = FieldPtr.toRValue(Ctx); Comment at: clang/lib/AST/Interp/Pointer.cpp:241 +for (unsigned I = 0; I != R->getNumBases(); ++I) { + const Pointer BasePtr = this->atField(R->getBase(I)->Offset); + Result.getStructBase(I) = BasePtr.toRValue(Ctx); Comment at: clang/lib/AST/Interp/Record.h:90 unsigned getNumBases() const { return Bases.size(); } + const Base *getBase(unsigned I) const { return [I]; } Base *getBase(unsigned I) { return [I]; } It might make sense to add an assert to both `getBase()` functions to verify that `I` is within a valid range. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added inline comments. Comment at: clang/lib/AST/Interp/Pointer.cpp:10 #include "Pointer.h" +#include "Boolean.h" +#include "Context.h" shafik wrote: > Are all these headers really needed for the change below? We access `.toAPValue()` on all of them in the `TYPE_SWITCH` below, so yes. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
shafik added a comment. I think it mostly makes sense but I want Aaron to also look at it. Comment at: clang/lib/AST/Interp/Pointer.cpp:10 #include "Pointer.h" +#include "Boolean.h" +#include "Context.h" Are all these headers really needed for the change below? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder added a comment. Thinking about this some more, the new `Pointer::toRValue()` is probably just the same thing we're already doing in `EvalEmitter::emtiRetValue()`. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144457/new/ https://reviews.llvm.org/D144457 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D144457: [clang][Interp] Handle global composite temporaries
tbaeder created this revision. tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik. Herald added a project: All. tbaeder requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. We only did this for primitive temporaries. Unfortunately, the existing Pointer::toAPValue() won't do here, since we're expected to set an rvalue on the LifetimeExtendedTemporaryDecl. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D144457 Files: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/Descriptor.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h clang/lib/AST/Interp/Record.h clang/test/AST/Interp/records.cpp Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -114,6 +114,9 @@ static_assert(c.a == 100, ""); static_assert(c.b == 200, ""); + +constexpr const C = C().get(); + constexpr int getB() { C c; int = c.b; Index: clang/lib/AST/Interp/Record.h === --- clang/lib/AST/Interp/Record.h +++ clang/lib/AST/Interp/Record.h @@ -87,6 +87,7 @@ } unsigned getNumBases() const { return Bases.size(); } + const Base *getBase(unsigned I) const { return [I]; } Base *getBase(unsigned I) { return [I]; } using const_virtual_iter = VirtualBaseList::const_iterator; Index: clang/lib/AST/Interp/Pointer.h === --- clang/lib/AST/Interp/Pointer.h +++ clang/lib/AST/Interp/Pointer.h @@ -27,6 +27,7 @@ class Block; class DeadBlock; class Pointer; +class Context; enum PrimType : unsigned; /// A pointer to a memory block, live or dead. @@ -78,6 +79,9 @@ /// Converts the pointer to an APValue. APValue toAPValue() const; + /// Converts the pointer to an APValue that is an rvalue. + APValue toRValue(const Context ) const; + /// Offsets a pointer inside an array. Pointer atIndex(unsigned Idx) const { if (!Pointee) Index: clang/lib/AST/Interp/Pointer.cpp === --- clang/lib/AST/Interp/Pointer.cpp +++ clang/lib/AST/Interp/Pointer.cpp @@ -7,9 +7,14 @@ //===--===// #include "Pointer.h" +#include "Boolean.h" +#include "Context.h" +#include "Floating.h" #include "Function.h" +#include "Integral.h" #include "InterpBlock.h" #include "PrimType.h" +#include "Record.h" using namespace clang; using namespace clang::interp; @@ -211,3 +216,34 @@ bool Pointer::hasSameArray(const Pointer , const Pointer ) { return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray; } + +APValue Pointer::toRValue(const Context ) const { + // Primitives. + if (getFieldDesc()->isPrimitive()) { +PrimType PT = *Ctx.classify(getType()); +TYPE_SWITCH(PT, return deref().toAPValue()); +llvm_unreachable("Unhandled PrimType?"); + } + + APValue Result; + // Records. + if (getFieldDesc()->isRecord()) { +const Record *R = getRecord(); +Result = +APValue(APValue::UninitStruct(), R->getNumBases(), R->getNumFields()); + +for (unsigned I = 0; I != R->getNumFields(); ++I) { + const Pointer FieldPtr = this->atField(R->getField(I)->Offset); + Result.getStructField(I) = FieldPtr.toRValue(Ctx); +} + +for (unsigned I = 0; I != R->getNumBases(); ++I) { + const Pointer BasePtr = this->atField(R->getBase(I)->Offset); + Result.getStructBase(I) = BasePtr.toRValue(Ctx); +} + } + + // TODO: Arrays + + return Result; +} Index: clang/lib/AST/Interp/Opcodes.td === --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -351,6 +351,12 @@ def InitGlobalTemp : AccessOpcode { let Args = [ArgUint32, ArgLETD]; } +// [Pointer] -> [Pointer] +def InitGlobalTempComp : Opcode { + let Args = [ArgLETD]; + let Types = []; + let HasGroup = 0; +} // [Value] -> [] def SetGlobal : AccessOpcode; Index: clang/lib/AST/Interp/Interp.h === --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -835,6 +835,19 @@ return true; } +/// 1) Converts the value on top of the stack to an APValue +/// 2) Sets that APValue on \Temp +/// 3) Initialized global with index \I with that +inline bool InitGlobalTempComp(InterpState , CodePtr OpPC, + const LifetimeExtendedTemporaryDecl *Temp) { + assert(Temp); + const Pointer = S.Stk.peek(); + APValue *Cached = Temp->getOrCreateValue(true); + + *Cached = P.toRValue(S.getCtx()); + return true; +} + template ::T> bool InitThisField(InterpState , CodePtr