Quellcode durchsuchen

[spirv] Turn SpirvEvalInfo into a class (#820)

Cleaned up methods on SpirvEvalInfo. Also added a new field or
lvalue/rvalue, which will be used later.
Lei Zhang vor 7 Jahren
Ursprung
Commit
6e874ab3fe

+ 3 - 1
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -211,7 +211,9 @@ SpirvEvalInfo DeclResultIdMapper::getDeclResultId(const NamedDecl *decl) {
           theBuilder.getPointerType(varType, info->storageClass),
           theBuilder.getPointerType(varType, info->storageClass),
           info->resultId, {theBuilder.getConstantInt32(info->indexInCTBuffer)});
           info->resultId, {theBuilder.getConstantInt32(info->indexInCTBuffer)});
 
 
-      return {elemId, info->storageClass, info->layoutRule};
+      return SpirvEvalInfo(elemId)
+          .setStorageClass(info->storageClass)
+          .setLayoutRule(info->layoutRule);
     } else {
     } else {
       return *info;
       return *info;
     }
     }

+ 3 - 1
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -220,7 +220,9 @@ private:
 
 
     /// Implicit conversion to SpirvEvalInfo.
     /// Implicit conversion to SpirvEvalInfo.
     operator SpirvEvalInfo() const {
     operator SpirvEvalInfo() const {
-      return SpirvEvalInfo(resultId, storageClass, layoutRule);
+      return SpirvEvalInfo(resultId)
+          .setStorageClass(storageClass)
+          .setLayoutRule(layoutRule);
     }
     }
 
 
     uint32_t resultId;
     uint32_t resultId;

+ 62 - 56
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -444,17 +444,19 @@ SpirvEvalInfo SPIRVEmitter::doExpr(const Expr *expr) {
 
 
   if (const auto *boolLiteral = dyn_cast<CXXBoolLiteralExpr>(expr)) {
   if (const auto *boolLiteral = dyn_cast<CXXBoolLiteralExpr>(expr)) {
     const bool value = boolLiteral->getValue();
     const bool value = boolLiteral->getValue();
-    return SpirvEvalInfo::withConst(theBuilder.getConstantBool(value));
+    return SpirvEvalInfo(theBuilder.getConstantBool(value)).setConstant();
   }
   }
 
 
   if (const auto *intLiteral = dyn_cast<IntegerLiteral>(expr)) {
   if (const auto *intLiteral = dyn_cast<IntegerLiteral>(expr)) {
-    return SpirvEvalInfo::withConst(
-        translateAPInt(intLiteral->getValue(), expr->getType()));
+    return SpirvEvalInfo(
+               translateAPInt(intLiteral->getValue(), expr->getType()))
+        .setConstant();
   }
   }
 
 
   if (const auto *floatLiteral = dyn_cast<FloatingLiteral>(expr)) {
   if (const auto *floatLiteral = dyn_cast<FloatingLiteral>(expr)) {
-    return SpirvEvalInfo::withConst(
-        translateAPFloat(floatLiteral->getValue(), expr->getType()));
+    return SpirvEvalInfo(
+               translateAPFloat(floatLiteral->getValue(), expr->getType()))
+        .setConstant();
   }
   }
 
 
   // CompoundAssignOperator is a subclass of BinaryOperator. It should be
   // CompoundAssignOperator is a subclass of BinaryOperator. It should be
@@ -503,10 +505,12 @@ SpirvEvalInfo SPIRVEmitter::doExpr(const Expr *expr) {
 
 
 SpirvEvalInfo SPIRVEmitter::loadIfGLValue(const Expr *expr) {
 SpirvEvalInfo SPIRVEmitter::loadIfGLValue(const Expr *expr) {
   auto info = doExpr(expr);
   auto info = doExpr(expr);
-  if (expr->isGLValue())
-    info.resultId = theBuilder.createLoad(
-        typeTranslator.translateType(expr->getType(), info.layoutRule),
-        info.resultId);
+  if (expr->isGLValue()) {
+    const uint32_t valType =
+        typeTranslator.translateType(expr->getType(), info.getLayoutRule());
+
+    info.setResultId(theBuilder.createLoad(valType, info));
+  }
 
 
   return info;
   return info;
 }
 }
@@ -556,7 +560,7 @@ void SPIRVEmitter::doFunctionDecl(const FunctionDecl *decl) {
     // Non-entry functions are added to the work queue following function
     // Non-entry functions are added to the work queue following function
     // calls. We have already assigned <result-id>s for it when translating
     // calls. We have already assigned <result-id>s for it when translating
     // its call site. Query it here.
     // its call site. Query it here.
-    funcId = declIdMapper.getDeclResultId(decl).resultId;
+    funcId = declIdMapper.getDeclResultId(decl);
   }
   }
 
 
   if (!needsLegalization &&
   if (!needsLegalization &&
@@ -1179,7 +1183,7 @@ void SPIRVEmitter::doReturnStmt(const ReturnStmt *stmt) {
   if (const auto *retVal = stmt->getRetValue()) {
   if (const auto *retVal = stmt->getRetValue()) {
     const auto retInfo = doExpr(retVal);
     const auto retInfo = doExpr(retVal);
     const auto retType = retVal->getType();
     const auto retType = retVal->getType();
-    if (retInfo.storageClass != spv::StorageClass::Function &&
+    if (retInfo.getStorageClass() != spv::StorageClass::Function &&
         retType->isStructureType()) {
         retType->isStructureType()) {
       // We are returning some value from a non-Function storage class. Need to
       // We are returning some value from a non-Function storage class. Need to
       // create a temporary variable to "convert" the value to Function storage
       // create a temporary variable to "convert" the value to Function storage
@@ -1284,9 +1288,9 @@ SPIRVEmitter::doArraySubscriptExpr(const ArraySubscriptExpr *expr) {
 
 
   if (!indices.empty()) {
   if (!indices.empty()) {
     const uint32_t ptrType = theBuilder.getPointerType(
     const uint32_t ptrType = theBuilder.getPointerType(
-        typeTranslator.translateType(expr->getType(), info.layoutRule),
-        info.storageClass);
-    info.resultId = theBuilder.createAccessChain(ptrType, info, indices);
+        typeTranslator.translateType(expr->getType(), info.getLayoutRule()),
+        info.getStorageClass());
+    info.setResultId(theBuilder.createAccessChain(ptrType, info, indices));
   }
   }
 
 
   return info;
   return info;
@@ -1448,8 +1452,10 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
 
 
     // Using lvalue as rvalue means we need to OpLoad the contents from
     // Using lvalue as rvalue means we need to OpLoad the contents from
     // the parameter/variable first.
     // the parameter/variable first.
-    info.resultId = theBuilder.createLoad(
-        typeTranslator.translateType(expr->getType(), info.layoutRule), info);
+    const uint32_t valType =
+        typeTranslator.translateType(expr->getType(), info.getLayoutRule());
+    info.setResultId(theBuilder.createLoad(valType, info));
+
     return info;
     return info;
   }
   }
   case CastKind::CK_NoOp:
   case CastKind::CK_NoOp:
@@ -1554,9 +1560,9 @@ SpirvEvalInfo SPIRVEmitter::doCastExpr(const CastExpr *expr) {
     const uint32_t matType = typeTranslator.translateType(toType);
     const uint32_t matType = typeTranslator.translateType(toType);
     llvm::SmallVector<uint32_t, 4> vectors(size_t(rowCount), vecSplat);
     llvm::SmallVector<uint32_t, 4> vectors(size_t(rowCount), vecSplat);
 
 
-    if (vecSplat.isConst) {
-      return SpirvEvalInfo::withConst(
-          theBuilder.getConstantComposite(matType, vectors));
+    if (vecSplat.isConstant()) {
+      return SpirvEvalInfo(theBuilder.getConstantComposite(matType, vectors))
+          .setConstant();
     } else {
     } else {
       return theBuilder.createCompositeConstruct(matType, vectors);
       return theBuilder.createCompositeConstruct(matType, vectors);
     }
     }
@@ -1850,7 +1856,7 @@ uint32_t SPIRVEmitter::processRWByteAddressBufferAtomicMethods(
       theBuilder.createBinaryOp(spv::Op::OpShiftRightLogical, uintType, offset,
       theBuilder.createBinaryOp(spv::Op::OpShiftRightLogical, uintType, offset,
                                 theBuilder.getConstantUint32(2));
                                 theBuilder.getConstantUint32(2));
   const auto ptrType =
   const auto ptrType =
-      theBuilder.getPointerType(uintType, objectInfo.storageClass);
+      theBuilder.getPointerType(uintType, objectInfo.getStorageClass());
   const uint32_t ptr =
   const uint32_t ptr =
       theBuilder.createAccessChain(ptrType, objectInfo, {zero, address});
       theBuilder.createAccessChain(ptrType, objectInfo, {zero, address});
 
 
@@ -2236,7 +2242,7 @@ uint32_t SPIRVEmitter::processByteAddressBufferLoadStore(
   // the address.
   // the address.
   const uint32_t uintTypeId = theBuilder.getUint32Type();
   const uint32_t uintTypeId = theBuilder.getUint32Type();
   const uint32_t ptrType =
   const uint32_t ptrType =
-      theBuilder.getPointerType(uintTypeId, objectInfo.storageClass);
+      theBuilder.getPointerType(uintTypeId, objectInfo.getStorageClass());
   const uint32_t constUint0 = theBuilder.getConstantUint32(0);
   const uint32_t constUint0 = theBuilder.getConstantUint32(0);
 
 
   if (doStore) {
   if (doStore) {
@@ -2300,13 +2306,13 @@ SPIRVEmitter::processStructuredBufferLoad(const CXXMemberCallExpr *expr) {
   const QualType structType =
   const QualType structType =
       hlsl::GetHLSLResourceResultType(buffer->getType());
       hlsl::GetHLSLResourceResultType(buffer->getType());
   const uint32_t ptrType = theBuilder.getPointerType(
   const uint32_t ptrType = theBuilder.getPointerType(
-      typeTranslator.translateType(structType, info.layoutRule),
-      info.storageClass);
+      typeTranslator.translateType(structType, info.getLayoutRule()),
+      info.getStorageClass());
 
 
   const uint32_t zero = theBuilder.getConstantInt32(0);
   const uint32_t zero = theBuilder.getConstantInt32(0);
   const uint32_t index = doExpr(expr->getArg(0));
   const uint32_t index = doExpr(expr->getArg(0));
 
 
-  info.resultId = theBuilder.createAccessChain(ptrType, info, {zero, index});
+  info.setResultId(theBuilder.createAccessChain(ptrType, info, {zero, index}));
   return info;
   return info;
 }
 }
 
 
@@ -2358,16 +2364,16 @@ SPIRVEmitter::processACSBufferAppendConsume(const CXXMemberCallExpr *expr) {
 
 
   const auto bufferElemTy = hlsl::GetHLSLResourceResultType(object->getType());
   const auto bufferElemTy = hlsl::GetHLSLResourceResultType(object->getType());
   const uint32_t bufferElemType =
   const uint32_t bufferElemType =
-      typeTranslator.translateType(bufferElemTy, bufferInfo.layoutRule);
+      typeTranslator.translateType(bufferElemTy, bufferInfo.getLayoutRule());
   // Get the pointer inside the {Append|Consume}StructuredBuffer
   // Get the pointer inside the {Append|Consume}StructuredBuffer
   const uint32_t bufferElemPtrType =
   const uint32_t bufferElemPtrType =
-      theBuilder.getPointerType(bufferElemType, bufferInfo.storageClass);
+      theBuilder.getPointerType(bufferElemType, bufferInfo.getStorageClass());
   const uint32_t bufferElemPtr = theBuilder.createAccessChain(
   const uint32_t bufferElemPtr = theBuilder.createAccessChain(
-      bufferElemPtrType, bufferInfo.resultId, {zero, index});
+      bufferElemPtrType, bufferInfo, {zero, index});
 
 
   if (isAppend) {
   if (isAppend) {
     // Write out the value
     // Write out the value
-    bufferInfo.resultId = bufferElemPtr;
+    bufferInfo.setResultId(bufferElemPtr);
     storeValue(bufferInfo, doExpr(expr->getArg(0)), bufferElemTy);
     storeValue(bufferInfo, doExpr(expr->getArg(0)), bufferElemTy);
 
 
     return 0;
     return 0;
@@ -2376,10 +2382,10 @@ SPIRVEmitter::processACSBufferAppendConsume(const CXXMemberCallExpr *expr) {
     // of .Consume() is not labelled as xvalue. That will cause OpLoad
     // of .Consume() is not labelled as xvalue. That will cause OpLoad
     // instruction missing. Load directly here.
     // instruction missing. Load directly here.
     if (bufferElemTy->isStructureType())
     if (bufferElemTy->isStructureType())
-      bufferInfo.resultId = bufferElemPtr;
+      bufferInfo.setResultId(bufferElemPtr);
     else
     else
-      bufferInfo.resultId =
-          theBuilder.createLoad(bufferElemType, bufferElemPtr);
+      bufferInfo.setResultId(
+          theBuilder.createLoad(bufferElemType, bufferElemPtr));
     return bufferInfo;
     return bufferInfo;
   }
   }
 }
 }
@@ -2790,9 +2796,9 @@ SPIRVEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
   }
   }
 
 
   const uint32_t ptrType = theBuilder.getPointerType(
   const uint32_t ptrType = theBuilder.getPointerType(
-      typeTranslator.translateType(expr->getType(), base.layoutRule),
-      base.storageClass);
-  base.resultId = theBuilder.createAccessChain(ptrType, base, indices);
+      typeTranslator.translateType(expr->getType(), base.getLayoutRule()),
+      base.getStorageClass());
+  base.setResultId(theBuilder.createAccessChain(ptrType, base, indices));
 
 
   return base;
   return base;
 }
 }
@@ -2831,7 +2837,7 @@ SPIRVEmitter::doExtMatrixElementExpr(const ExtMatrixElementExpr *expr) {
         indices[i] = theBuilder.getConstantInt32(indices[i]);
         indices[i] = theBuilder.getConstantInt32(indices[i]);
 
 
       const uint32_t ptrType =
       const uint32_t ptrType =
-          theBuilder.getPointerType(elemType, baseInfo.storageClass);
+          theBuilder.getPointerType(elemType, baseInfo.getStorageClass());
       if (!indices.empty()) {
       if (!indices.empty()) {
         // Load the element via access chain
         // Load the element via access chain
         elem = theBuilder.createAccessChain(ptrType, baseInfo, indices);
         elem = theBuilder.createAccessChain(ptrType, baseInfo, indices);
@@ -2891,7 +2897,7 @@ SPIRVEmitter::doHLSLVectorElementExpr(const HLSLVectorElementExpr *expr) {
     if (expr->getBase()->isGLValue()) { // E.g., v.x;
     if (expr->getBase()->isGLValue()) { // E.g., v.x;
       const auto baseInfo = doExpr(baseExpr);
       const auto baseInfo = doExpr(baseExpr);
       const uint32_t ptrType =
       const uint32_t ptrType =
-          theBuilder.getPointerType(type, baseInfo.storageClass);
+          theBuilder.getPointerType(type, baseInfo.getStorageClass());
       const uint32_t index = theBuilder.getConstantInt32(accessor.Swz0);
       const uint32_t index = theBuilder.getConstantInt32(accessor.Swz0);
       // We need a lvalue here. Do not try to load.
       // We need a lvalue here. Do not try to load.
       return theBuilder.createAccessChain(ptrType, baseInfo, {index});
       return theBuilder.createAccessChain(ptrType, baseInfo, {index});
@@ -2946,9 +2952,9 @@ SpirvEvalInfo SPIRVEmitter::doMemberExpr(const MemberExpr *expr) {
 
 
   if (!indices.empty()) {
   if (!indices.empty()) {
     const uint32_t ptrType = theBuilder.getPointerType(
     const uint32_t ptrType = theBuilder.getPointerType(
-        typeTranslator.translateType(expr->getType(), info.layoutRule),
-        info.storageClass);
-    info.resultId = theBuilder.createAccessChain(ptrType, info, indices);
+        typeTranslator.translateType(expr->getType(), info.getLayoutRule()),
+        info.getStorageClass());
+    info.setResultId(theBuilder.createAccessChain(ptrType, info, indices));
   }
   }
 
 
   return info;
   return info;
@@ -3156,7 +3162,7 @@ SpirvEvalInfo SPIRVEmitter::processAssignment(const Expr *lhs,
 
 
   // Normal assignment procedure
   // Normal assignment procedure
 
 
-  if (!lhsPtr.resultId)
+  if (!lhsPtr)
     lhsPtr = doExpr(lhs);
     lhsPtr = doExpr(lhs);
 
 
   storeValue(lhsPtr, rhs, lhs->getType());
   storeValue(lhsPtr, rhs, lhs->getType());
@@ -3172,7 +3178,7 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
   // If lhs and rhs has the same memory layout, we should be safe to load
   // If lhs and rhs has the same memory layout, we should be safe to load
   // from rhs and directly store into lhs and avoid decomposing rhs.
   // from rhs and directly store into lhs and avoid decomposing rhs.
   // TODO: is this optimization always correct?
   // TODO: is this optimization always correct?
-  if (lhsPtr.layoutRule == rhsVal.layoutRule ||
+  if (lhsPtr.getLayoutRule() == rhsVal.getLayoutRule() ||
       typeTranslator.isScalarType(valType) ||
       typeTranslator.isScalarType(valType) ||
       typeTranslator.isVectorType(valType) ||
       typeTranslator.isVectorType(valType) ||
       typeTranslator.isMxNMatrix(valType)) {
       typeTranslator.isMxNMatrix(valType)) {
@@ -3187,13 +3193,14 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
       const auto *field = cast<FieldDecl>(decl);
       const auto *field = cast<FieldDecl>(decl);
       assert(field);
       assert(field);
 
 
-      const auto subRhsValType =
-          typeTranslator.translateType(field->getType(), rhsVal.layoutRule);
+      const auto subRhsValType = typeTranslator.translateType(
+          field->getType(), rhsVal.getLayoutRule());
       const auto subRhsVal =
       const auto subRhsVal =
           theBuilder.createCompositeExtract(subRhsValType, rhsVal, {index});
           theBuilder.createCompositeExtract(subRhsValType, rhsVal, {index});
       const auto subLhsPtrType = theBuilder.getPointerType(
       const auto subLhsPtrType = theBuilder.getPointerType(
-          typeTranslator.translateType(field->getType(), lhsPtr.layoutRule),
-          lhsPtr.storageClass);
+          typeTranslator.translateType(field->getType(),
+                                       lhsPtr.getLayoutRule()),
+          lhsPtr.getStorageClass());
       const auto subLhsPtr = theBuilder.createAccessChain(
       const auto subLhsPtr = theBuilder.createAccessChain(
           subLhsPtrType, lhsPtr, {theBuilder.getConstantUint32(index)});
           subLhsPtrType, lhsPtr, {theBuilder.getConstantUint32(index)});
 
 
@@ -3210,12 +3217,12 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
 
 
     for (uint32_t i = 0; i < size; ++i) {
     for (uint32_t i = 0; i < size; ++i) {
       const auto subRhsValType =
       const auto subRhsValType =
-          typeTranslator.translateType(elemType, rhsVal.layoutRule);
+          typeTranslator.translateType(elemType, rhsVal.getLayoutRule());
       const auto subRhsVal =
       const auto subRhsVal =
           theBuilder.createCompositeExtract(subRhsValType, rhsVal, {i});
           theBuilder.createCompositeExtract(subRhsValType, rhsVal, {i});
       const auto subLhsPtrType = theBuilder.getPointerType(
       const auto subLhsPtrType = theBuilder.getPointerType(
-          typeTranslator.translateType(elemType, lhsPtr.layoutRule),
-          lhsPtr.storageClass);
+          typeTranslator.translateType(elemType, lhsPtr.getLayoutRule()),
+          lhsPtr.getStorageClass());
       const auto subLhsPtr = theBuilder.createAccessChain(
       const auto subLhsPtr = theBuilder.createAccessChain(
           subLhsPtrType, lhsPtr, {theBuilder.getConstantUint32(i)});
           subLhsPtrType, lhsPtr, {theBuilder.getConstantUint32(i)});
 
 
@@ -3302,10 +3309,9 @@ SpirvEvalInfo SPIRVEmitter::processBinaryOp(const Expr *lhs, const Expr *rhs,
   case BO_XorAssign:
   case BO_XorAssign:
   case BO_ShlAssign:
   case BO_ShlAssign:
   case BO_ShrAssign: {
   case BO_ShrAssign: {
-    const auto result =
-        theBuilder.createBinaryOp(spvOp, resultType, lhsVal, rhsVal);
-    return lhsVal.isRelaxedPrecision || rhsVal.isRelaxedPrecision
-               ? SpirvEvalInfo::withRelaxedPrecision(result)
+    auto result = theBuilder.createBinaryOp(spvOp, resultType, lhsVal, rhsVal);
+    return lhsVal.isRelaxedPrecision() || rhsVal.isRelaxedPrecision()
+               ? SpirvEvalInfo(result).setRelaxedPrecision()
                : result;
                : result;
   }
   }
   case BO_Assign:
   case BO_Assign:
@@ -3504,7 +3510,7 @@ SpirvEvalInfo SPIRVEmitter::createVectorSplat(const Expr *scalarExpr,
 
 
   // Just return the scalar value for vector splat with size 1
   // Just return the scalar value for vector splat with size 1
   if (size == 1)
   if (size == 1)
-    return isConstVal ? SpirvEvalInfo::withConst(scalarVal) : scalarVal;
+    return isConstVal ? SpirvEvalInfo(scalarVal).setConstant() : scalarVal;
 
 
   const uint32_t vecType = theBuilder.getVecType(
   const uint32_t vecType = theBuilder.getVecType(
       typeTranslator.translateType(scalarExpr->getType()), size);
       typeTranslator.translateType(scalarExpr->getType()), size);
@@ -3513,8 +3519,8 @@ SpirvEvalInfo SPIRVEmitter::createVectorSplat(const Expr *scalarExpr,
   if (isConstVal) {
   if (isConstVal) {
     // TODO: we are saying the constant has Function storage class here.
     // TODO: we are saying the constant has Function storage class here.
     // Should find a more meaningful one.
     // Should find a more meaningful one.
-    return SpirvEvalInfo::withConst(
-        theBuilder.getConstantComposite(vecType, elements));
+    return SpirvEvalInfo(theBuilder.getConstantComposite(vecType, elements))
+        .setConstant();
   } else {
   } else {
     return theBuilder.createCompositeConstruct(vecType, elements);
     return theBuilder.createCompositeConstruct(vecType, elements);
   }
   }
@@ -3792,7 +3798,7 @@ SPIRVEmitter::tryToAssignToMatrixElements(const Expr *lhs,
       rhsElem = theBuilder.createCompositeExtract(elemTypeId, rhs, {i});
       rhsElem = theBuilder.createCompositeExtract(elemTypeId, rhs, {i});
 
 
     const uint32_t ptrType =
     const uint32_t ptrType =
-        theBuilder.getPointerType(elemTypeId, base.storageClass);
+        theBuilder.getPointerType(elemTypeId, base.getStorageClass());
 
 
     // If the lhs is actually a matrix of size 1x1, we don't need the access
     // If the lhs is actually a matrix of size 1x1, we don't need the access
     // chain. base is already the dest pointer.
     // chain. base is already the dest pointer.

+ 83 - 34
tools/clang/lib/SPIRV/SpirvEvalInfo.h

@@ -29,14 +29,21 @@ enum class LayoutRule {
 /// Struct contains SPIR-V information from evaluating a Clang AST node.
 /// Struct contains SPIR-V information from evaluating a Clang AST node.
 ///
 ///
 /// We need to report more information than just the <result-id> for SPIR-V:
 /// We need to report more information than just the <result-id> for SPIR-V:
-/// * Constness: enables generating SPIR-V constant instructions
+///
 /// * Storage class: for getting correct (pointer) types
 /// * Storage class: for getting correct (pointer) types
 /// * Layout rule: for getting correct (pointer) types
 /// * Layout rule: for getting correct (pointer) types
+/// * LValue or RValue
+/// * Constness: enables generating SPIR-V constant instructions
 /// * Relaxed precision: for emitting PrelaxedPrecision decoration
 /// * Relaxed precision: for emitting PrelaxedPrecision decoration
 ///
 ///
 /// For most cases, the evaluation result of a Clang AST node will just be
 /// For most cases, the evaluation result of a Clang AST node will just be
-/// a SPIR-V <result-id> that is not a constant, with storage class Function,
-/// layout rule Void, and not relaxed precision.
+/// a SPIR-V <result-id> with storage class Function, layout rule Void,
+/// not constant, and not relaxed precision.
+///
+/// So the constructor only takes in a <result-id>. It initializes storage
+/// class to Function, layout rule to Void, constness to false, relaxed
+/// precision to false. It sets the <result-id> as lvalue. Setters are
+/// provided to tweak these bits.
 ///
 ///
 /// The evaluation result of a Clang Expr can be considered as SPIR-V constant
 /// The evaluation result of a Clang Expr can be considered as SPIR-V constant
 /// as long as all its operands are SPIR-V constants and we are creating a
 /// as long as all its operands are SPIR-V constants and we are creating a
@@ -55,34 +62,16 @@ enum class LayoutRule {
 /// information out of evaluating a Clang AST node. When doing such construction
 /// information out of evaluating a Clang AST node. When doing such construction
 /// or conversion, all other information are defaulted to what are meaningful
 /// or conversion, all other information are defaulted to what are meaningful
 /// for a function temporary variable.
 /// for a function temporary variable.
-struct SpirvEvalInfo {
-  /// Constructor from various evaluation information
-  SpirvEvalInfo(uint32_t id)
-      : resultId(id), isConst(false), storageClass(spv::StorageClass::Function),
-        layoutRule(LayoutRule::Void), isRelaxedPrecision(false) {}
-  SpirvEvalInfo(uint32_t id, spv::StorageClass sc, LayoutRule rule)
-      : resultId(id), isConst(false), storageClass(sc), layoutRule(rule),
-        isRelaxedPrecision(false) {}
-
-  static SpirvEvalInfo withConst(uint32_t id) {
-    SpirvEvalInfo info = id;
-    info.isConst = true;
-    return info;
-  }
-
-  static SpirvEvalInfo withRelaxedPrecision(uint32_t id) {
-    SpirvEvalInfo info = id;
-    info.isRelaxedPrecision = true;
-    return info;
-  }
-
-  /// Returns a new SpirvEvalInfo with an updated SPIR-V <result-id>. Keeps the
-  /// other fields the same.
-  SpirvEvalInfo substResultId(uint32_t newId) const {
-    SpirvEvalInfo info = *this;
-    info.resultId = newId;
-    return info;
-  }
+class SpirvEvalInfo {
+public:
+  /// Implicit constructor
+  inline SpirvEvalInfo(uint32_t id);
+
+  /// Changes the <result-id> in this eval info.
+  inline SpirvEvalInfo &setResultId(uint32_t id);
+  /// Returns a new eval info with the given <result-id> and inheriting all
+  /// other bits from this eval info.
+  inline SpirvEvalInfo substResultId(uint32_t id) const;
 
 
   /// Handy implicit conversion to get the <result-id>.
   /// Handy implicit conversion to get the <result-id>.
   operator uint32_t() const { return resultId; }
   operator uint32_t() const { return resultId; }
@@ -90,13 +79,73 @@ struct SpirvEvalInfo {
   /// Handly implicit conversion to test whether the <result-id> is valid.
   /// Handly implicit conversion to test whether the <result-id> is valid.
   operator bool() const { return resultId != 0; }
   operator bool() const { return resultId != 0; }
 
 
-  uint32_t resultId; ///< SPIR-V <result-id>
-  bool isConst;      ///< Whether the <result-id> is for a SPIR-V constant
+  inline SpirvEvalInfo &setStorageClass(spv::StorageClass sc);
+  spv::StorageClass getStorageClass() const { return storageClass; }
+
+  inline SpirvEvalInfo &setLayoutRule(LayoutRule rule);
+  LayoutRule getLayoutRule() const { return layoutRule; }
+
+  inline SpirvEvalInfo &setRValue();
+  bool isRValue() const { return isRValue_; }
+
+  inline SpirvEvalInfo &setConstant();
+  bool isConstant() const { return isConstant_; }
+
+  inline SpirvEvalInfo &setRelaxedPrecision();
+  bool isRelaxedPrecision() const { return isRelaxedPrecision_; }
+
+private:
+  uint32_t resultId;
+
   spv::StorageClass storageClass;
   spv::StorageClass storageClass;
   LayoutRule layoutRule;
   LayoutRule layoutRule;
-  bool isRelaxedPrecision;
+
+  bool isRValue_;
+  bool isConstant_;
+  bool isRelaxedPrecision_;
 };
 };
 
 
+SpirvEvalInfo::SpirvEvalInfo(uint32_t id)
+    : resultId(id), storageClass(spv::StorageClass::Function),
+      layoutRule(LayoutRule::Void), isRValue_(false), isConstant_(false),
+      isRelaxedPrecision_(false) {}
+
+SpirvEvalInfo &SpirvEvalInfo::setResultId(uint32_t id) {
+  resultId = id;
+  return *this;
+}
+
+SpirvEvalInfo SpirvEvalInfo::substResultId(uint32_t newId) const {
+  SpirvEvalInfo info = *this;
+  info.resultId = newId;
+  return info;
+}
+
+SpirvEvalInfo &SpirvEvalInfo::setStorageClass(spv::StorageClass sc) {
+  storageClass = sc;
+  return *this;
+}
+
+SpirvEvalInfo &SpirvEvalInfo::setLayoutRule(LayoutRule rule) {
+  layoutRule = rule;
+  return *this;
+}
+
+SpirvEvalInfo &SpirvEvalInfo::setRValue() {
+  isRValue_ = true;
+  return *this;
+}
+
+SpirvEvalInfo &SpirvEvalInfo::setConstant() {
+  isConstant_ = true;
+  return *this;
+}
+
+SpirvEvalInfo &SpirvEvalInfo::setRelaxedPrecision() {
+  isRelaxedPrecision_ = true;
+  return *this;
+}
+
 } // end namespace spirv
 } // end namespace spirv
 } // end namespace clang
 } // end namespace clang