|
@@ -2000,14 +2000,50 @@ void SpirvEmitter::doWhileStmt(const WhileStmt *whileStmt,
|
|
// | merge |
|
|
// | merge |
|
|
// +-------+
|
|
// +-------+
|
|
//
|
|
//
|
|
|
|
+ // The only exception is when the condition cannot be expressed in a single
|
|
|
|
+ // block. Specifically, short-circuited operators end up producing multiple
|
|
|
|
+ // blocks. In that case, we cannot treat the <check> block as the header
|
|
|
|
+ // block, and must instead have a bespoke <header> block. The condition is
|
|
|
|
+ // then moved into the loop. For example, given a loop in the form
|
|
|
|
+ // while (a && b) { <body> }
|
|
|
|
+ // we will generate instructions for the equivalent loop
|
|
|
|
+ // while (true) { if (!(a && b)) { break } <body> }
|
|
|
|
+ // +----------+
|
|
|
|
+ // | header | <------------------+
|
|
|
|
+ // +----------+ |
|
|
|
|
+ // | |
|
|
|
|
+ // v |
|
|
|
|
+ // +----------+ |
|
|
|
|
+ // | check | |
|
|
|
|
+ // +----------+ |
|
|
|
|
+ // | |
|
|
|
|
+ // +-------+-------+ |
|
|
|
|
+ // | false | true |
|
|
|
|
+ // | v |
|
|
|
|
+ // | +------+ +------------------+
|
|
|
|
+ // | | body | --> | continue (no-op) |
|
|
|
|
+ // v +------+ +------------------+
|
|
|
|
+ // +-------+
|
|
|
|
+ // | merge |
|
|
|
|
+ // +-------+
|
|
|
|
+ // The reason we don't unconditionally apply this transformation, which is
|
|
|
|
+ // technically always legal, is because it prevents loop unrolling in SPIR-V
|
|
|
|
+ // Tools, which does not support unrolling loops with early breaks.
|
|
// For more details, see "2.11. Structured Control Flow" in the SPIR-V spec.
|
|
// For more details, see "2.11. Structured Control Flow" in the SPIR-V spec.
|
|
|
|
|
|
const spv::LoopControlMask loopControl =
|
|
const spv::LoopControlMask loopControl =
|
|
attrs.empty() ? spv::LoopControlMask::MaskNone
|
|
attrs.empty() ? spv::LoopControlMask::MaskNone
|
|
: translateLoopAttribute(whileStmt, *attrs.front());
|
|
: translateLoopAttribute(whileStmt, *attrs.front());
|
|
|
|
|
|
|
|
+ const Expr *check = whileStmt->getCond();
|
|
|
|
+ const Stmt *body = whileStmt->getBody();
|
|
|
|
+ bool checkHasShortcircuitedOp = stmtTreeContainsShortCircuitedOp(check);
|
|
|
|
+
|
|
// Create basic blocks
|
|
// Create basic blocks
|
|
auto *checkBB = spvBuilder.createBasicBlock("while.check");
|
|
auto *checkBB = spvBuilder.createBasicBlock("while.check");
|
|
|
|
+ auto *headerBB = checkHasShortcircuitedOp
|
|
|
|
+ ? spvBuilder.createBasicBlock("while.header")
|
|
|
|
+ : checkBB;
|
|
auto *bodyBB = spvBuilder.createBasicBlock("while.body");
|
|
auto *bodyBB = spvBuilder.createBasicBlock("while.body");
|
|
auto *continueBB = spvBuilder.createBasicBlock("while.continue");
|
|
auto *continueBB = spvBuilder.createBasicBlock("while.continue");
|
|
auto *mergeBB = spvBuilder.createBasicBlock("while.merge");
|
|
auto *mergeBB = spvBuilder.createBasicBlock("while.merge");
|
|
@@ -2017,42 +2053,80 @@ void SpirvEmitter::doWhileStmt(const WhileStmt *whileStmt,
|
|
continueStack.push(continueBB);
|
|
continueStack.push(continueBB);
|
|
breakStack.push(mergeBB);
|
|
breakStack.push(mergeBB);
|
|
|
|
|
|
- // Process the <check> block
|
|
|
|
- spvBuilder.createBranch(checkBB, whileStmt->getLocStart());
|
|
|
|
- spvBuilder.addSuccessor(checkBB);
|
|
|
|
- spvBuilder.setInsertPoint(checkBB);
|
|
|
|
-
|
|
|
|
- // If we have:
|
|
|
|
- // while (int a = foo()) {...}
|
|
|
|
- // we should evaluate 'a' by calling 'foo()' every single time the check has
|
|
|
|
- // to occur.
|
|
|
|
- if (const auto *condVarDecl = whileStmt->getConditionVariableDeclStmt())
|
|
|
|
- doStmt(condVarDecl);
|
|
|
|
|
|
+ spvBuilder.createBranch(headerBB, whileStmt->getLocStart());
|
|
|
|
+ spvBuilder.addSuccessor(headerBB);
|
|
|
|
+ spvBuilder.setInsertPoint(headerBB);
|
|
|
|
+ if (checkHasShortcircuitedOp) {
|
|
|
|
+ // Process the <header> block.
|
|
|
|
+ spvBuilder.setInsertPoint(headerBB);
|
|
|
|
+ spvBuilder.createBranch(
|
|
|
|
+ checkBB,
|
|
|
|
+ check ? check->getLocStart()
|
|
|
|
+ : (body ? body->getLocStart() : whileStmt->getLocStart()),
|
|
|
|
+ mergeBB, continueBB, loopControl,
|
|
|
|
+ check
|
|
|
|
+ ? check->getSourceRange()
|
|
|
|
+ : SourceRange(whileStmt->getLocStart(), whileStmt->getLocStart()));
|
|
|
|
+ spvBuilder.addSuccessor(checkBB);
|
|
|
|
+ // The current basic block has a OpLoopMerge instruction. We need to set
|
|
|
|
+ // its continue and merge target.
|
|
|
|
+ spvBuilder.setContinueTarget(continueBB);
|
|
|
|
+ spvBuilder.setMergeTarget(mergeBB);
|
|
|
|
|
|
- SpirvInstruction *condition = nullptr;
|
|
|
|
- const Expr *check = whileStmt->getCond();
|
|
|
|
- if (check) {
|
|
|
|
- condition = doExpr(check);
|
|
|
|
|
|
+ // Process the <check> block.
|
|
|
|
+ spvBuilder.setInsertPoint(checkBB);
|
|
|
|
+
|
|
|
|
+ // If we have:
|
|
|
|
+ // while (int a = foo()) {...}
|
|
|
|
+ // we should evaluate 'a' by calling 'foo()' every single time the check has
|
|
|
|
+ // to occur.
|
|
|
|
+ if (const auto *condVarDecl = whileStmt->getConditionVariableDeclStmt())
|
|
|
|
+ doStmt(condVarDecl);
|
|
|
|
+
|
|
|
|
+ SpirvInstruction *condition = doExpr(check);
|
|
|
|
+ spvBuilder.createConditionalBranch(
|
|
|
|
+ condition, bodyBB, mergeBB,
|
|
|
|
+ check ? check->getLocEnd()
|
|
|
|
+ : (body ? body->getLocStart() : whileStmt->getLocStart()),
|
|
|
|
+ nullptr, nullptr, spv::SelectionControlMask::MaskNone,
|
|
|
|
+ spv::LoopControlMask::MaskNone,
|
|
|
|
+ check
|
|
|
|
+ ? check->getSourceRange()
|
|
|
|
+ : SourceRange(whileStmt->getLocStart(), whileStmt->getLocStart()));
|
|
|
|
+ spvBuilder.addSuccessor(bodyBB);
|
|
|
|
+ spvBuilder.addSuccessor(mergeBB);
|
|
} else {
|
|
} else {
|
|
- condition = spvBuilder.getConstantBool(true);
|
|
|
|
|
|
+ // In the case of simple or empty conditions, we can use a
|
|
|
|
+ // single block for <check> and <header>.
|
|
|
|
+
|
|
|
|
+ // If we have:
|
|
|
|
+ // while (int a = foo()) {...}
|
|
|
|
+ // we should evaluate 'a' by calling 'foo()' every single time the check has
|
|
|
|
+ // to occur.
|
|
|
|
+ if (const auto *condVarDecl = whileStmt->getConditionVariableDeclStmt())
|
|
|
|
+ doStmt(condVarDecl);
|
|
|
|
+
|
|
|
|
+ SpirvInstruction *condition = nullptr;
|
|
|
|
+ if (check) {
|
|
|
|
+ condition = doExpr(check);
|
|
|
|
+ } else {
|
|
|
|
+ condition = spvBuilder.getConstantBool(true);
|
|
|
|
+ }
|
|
|
|
+ spvBuilder.createConditionalBranch(
|
|
|
|
+ condition, bodyBB, mergeBB, whileStmt->getLocStart(), mergeBB,
|
|
|
|
+ continueBB, spv::SelectionControlMask::MaskNone, loopControl,
|
|
|
|
+ check ? check->getSourceRange()
|
|
|
|
+ : SourceRange(whileStmt->getWhileLoc(), whileStmt->getLocEnd()));
|
|
|
|
+ spvBuilder.addSuccessor(bodyBB);
|
|
|
|
+ spvBuilder.addSuccessor(mergeBB);
|
|
|
|
+ // The current basic block has OpLoopMerge instruction. We need to set its
|
|
|
|
+ // continue and merge target.
|
|
|
|
+ spvBuilder.setContinueTarget(continueBB);
|
|
|
|
+ spvBuilder.setMergeTarget(mergeBB);
|
|
}
|
|
}
|
|
- spvBuilder.createConditionalBranch(
|
|
|
|
- condition, bodyBB,
|
|
|
|
- /*false branch*/ mergeBB, whileStmt->getLocStart(),
|
|
|
|
- /*merge*/ mergeBB, continueBB, spv::SelectionControlMask::MaskNone,
|
|
|
|
- loopControl,
|
|
|
|
- check ? check->getSourceRange()
|
|
|
|
- : SourceRange(whileStmt->getWhileLoc(), whileStmt->getLocEnd()));
|
|
|
|
- spvBuilder.addSuccessor(bodyBB);
|
|
|
|
- spvBuilder.addSuccessor(mergeBB);
|
|
|
|
- // The current basic block has OpLoopMerge instruction. We need to set its
|
|
|
|
- // continue and merge target.
|
|
|
|
- spvBuilder.setContinueTarget(continueBB);
|
|
|
|
- spvBuilder.setMergeTarget(mergeBB);
|
|
|
|
|
|
|
|
- // Process the <body> block
|
|
|
|
|
|
+ // Process the <body> block.
|
|
spvBuilder.setInsertPoint(bodyBB);
|
|
spvBuilder.setInsertPoint(bodyBB);
|
|
- const Stmt *body = whileStmt->getBody();
|
|
|
|
if (body) {
|
|
if (body) {
|
|
doStmt(body);
|
|
doStmt(body);
|
|
}
|
|
}
|
|
@@ -2061,12 +2135,12 @@ void SpirvEmitter::doWhileStmt(const WhileStmt *whileStmt,
|
|
spvBuilder.addSuccessor(continueBB);
|
|
spvBuilder.addSuccessor(continueBB);
|
|
|
|
|
|
// Process the <continue> block. While loops do not have an explicit
|
|
// Process the <continue> block. While loops do not have an explicit
|
|
- // continue block. The continue block just branches to the <check> block.
|
|
|
|
|
|
+ // continue block. The continue block just branches to the <header> block.
|
|
spvBuilder.setInsertPoint(continueBB);
|
|
spvBuilder.setInsertPoint(continueBB);
|
|
- spvBuilder.createBranch(checkBB, whileStmt->getLocEnd());
|
|
|
|
- spvBuilder.addSuccessor(checkBB);
|
|
|
|
|
|
+ spvBuilder.createBranch(headerBB, whileStmt->getLocEnd());
|
|
|
|
+ spvBuilder.addSuccessor(headerBB);
|
|
|
|
|
|
- // Set insertion point to the <merge> block for subsequent statements
|
|
|
|
|
|
+ // Set insertion point to the <merge> block for subsequent statements.
|
|
spvBuilder.setInsertPoint(mergeBB);
|
|
spvBuilder.setInsertPoint(mergeBB);
|
|
|
|
|
|
// Done with the current scope's continue and merge blocks.
|
|
// Done with the current scope's continue and merge blocks.
|
|
@@ -2108,13 +2182,56 @@ void SpirvEmitter::doForStmt(const ForStmt *forStmt,
|
|
// | merge |
|
|
// | merge |
|
|
// +-------+
|
|
// +-------+
|
|
//
|
|
//
|
|
|
|
+ // The only exception is when the condition cannot be expressed in a single
|
|
|
|
+ // block. Specifically, short-circuited operators end up producing multiple
|
|
|
|
+ // blocks. In that case, we cannot treat the <check> block as the header
|
|
|
|
+ // block, and must instead have a bespoke <header> block. The condition is
|
|
|
|
+ // then moved into the loop. For example, given a loop in the form
|
|
|
|
+ // for (<init>; a && b; <continue>) { <body> }
|
|
|
|
+ // we will generate instructions for the equivalent loop
|
|
|
|
+ // for (<init>; ; <continue>) { if (!(a && b)) { break } <body> }
|
|
|
|
+ // +--------+
|
|
|
|
+ // | init |
|
|
|
|
+ // +--------+
|
|
|
|
+ // |
|
|
|
|
+ // v
|
|
|
|
+ // +----------+
|
|
|
|
+ // | header | <---------------+
|
|
|
|
+ // +----------+ |
|
|
|
|
+ // | |
|
|
|
|
+ // v |
|
|
|
|
+ // +----------+ |
|
|
|
|
+ // | check | |
|
|
|
|
+ // +----------+ |
|
|
|
|
+ // | |
|
|
|
|
+ // +-------+-------+ |
|
|
|
|
+ // | false | true |
|
|
|
|
+ // | v |
|
|
|
|
+ // | +------+ +----------+
|
|
|
|
+ // | | body | --> | continue |
|
|
|
|
+ // v +------+ +----------+
|
|
|
|
+ // +-------+
|
|
|
|
+ // | merge |
|
|
|
|
+ // +-------+
|
|
|
|
+ // The reason we don't unconditionally apply this transformation, which is
|
|
|
|
+ // technically always legal, is because it prevents loop unrolling in SPIR-V
|
|
|
|
+ // Tools, which does not support unrolling loops with early breaks.
|
|
// For more details, see "2.11. Structured Control Flow" in the SPIR-V spec.
|
|
// For more details, see "2.11. Structured Control Flow" in the SPIR-V spec.
|
|
const spv::LoopControlMask loopControl =
|
|
const spv::LoopControlMask loopControl =
|
|
attrs.empty() ? spv::LoopControlMask::MaskNone
|
|
attrs.empty() ? spv::LoopControlMask::MaskNone
|
|
: translateLoopAttribute(forStmt, *attrs.front());
|
|
: translateLoopAttribute(forStmt, *attrs.front());
|
|
|
|
|
|
- // Create basic blocks
|
|
|
|
|
|
+ const Stmt *initStmt = forStmt->getInit();
|
|
|
|
+ const Stmt *body = forStmt->getBody();
|
|
|
|
+ const Expr *check = forStmt->getCond();
|
|
|
|
+
|
|
|
|
+ bool checkHasShortcircuitedOp = stmtTreeContainsShortCircuitedOp(check);
|
|
|
|
+
|
|
|
|
+ // Create basic blocks.
|
|
auto *checkBB = spvBuilder.createBasicBlock("for.check");
|
|
auto *checkBB = spvBuilder.createBasicBlock("for.check");
|
|
|
|
+ auto *headerBB = checkHasShortcircuitedOp
|
|
|
|
+ ? spvBuilder.createBasicBlock("for.header")
|
|
|
|
+ : checkBB;
|
|
auto *bodyBB = spvBuilder.createBasicBlock("for.body");
|
|
auto *bodyBB = spvBuilder.createBasicBlock("for.body");
|
|
auto *continueBB = spvBuilder.createBasicBlock("for.continue");
|
|
auto *continueBB = spvBuilder.createBasicBlock("for.continue");
|
|
auto *mergeBB = spvBuilder.createBasicBlock("for.merge");
|
|
auto *mergeBB = spvBuilder.createBasicBlock("for.merge");
|
|
@@ -2124,47 +2241,78 @@ void SpirvEmitter::doForStmt(const ForStmt *forStmt,
|
|
continueStack.push(continueBB);
|
|
continueStack.push(continueBB);
|
|
breakStack.push(mergeBB);
|
|
breakStack.push(mergeBB);
|
|
|
|
|
|
- // Process the <init> block
|
|
|
|
- const Stmt *initStmt = forStmt->getInit();
|
|
|
|
|
|
+ // Process the <init> block.
|
|
if (initStmt) {
|
|
if (initStmt) {
|
|
doStmt(initStmt);
|
|
doStmt(initStmt);
|
|
}
|
|
}
|
|
- const Expr *check = forStmt->getCond();
|
|
|
|
spvBuilder.createBranch(
|
|
spvBuilder.createBranch(
|
|
- checkBB, check ? check->getLocStart() : forStmt->getLocStart(), nullptr,
|
|
|
|
|
|
+ headerBB, check ? check->getLocStart() : forStmt->getLocStart(), nullptr,
|
|
nullptr, spv::LoopControlMask::MaskNone,
|
|
nullptr, spv::LoopControlMask::MaskNone,
|
|
initStmt ? initStmt->getSourceRange()
|
|
initStmt ? initStmt->getSourceRange()
|
|
: SourceRange(forStmt->getLocStart(), forStmt->getLocStart()));
|
|
: SourceRange(forStmt->getLocStart(), forStmt->getLocStart()));
|
|
- spvBuilder.addSuccessor(checkBB);
|
|
|
|
|
|
+ spvBuilder.addSuccessor(headerBB);
|
|
|
|
|
|
- // Process the <check> block
|
|
|
|
- spvBuilder.setInsertPoint(checkBB);
|
|
|
|
- SpirvInstruction *condition = nullptr;
|
|
|
|
- if (check) {
|
|
|
|
- condition = doExpr(check);
|
|
|
|
|
|
+ if (checkHasShortcircuitedOp) {
|
|
|
|
+ // Process the <header> block.
|
|
|
|
+ spvBuilder.setInsertPoint(headerBB);
|
|
|
|
+ spvBuilder.createBranch(
|
|
|
|
+ checkBB,
|
|
|
|
+ check ? check->getLocStart()
|
|
|
|
+ : (body ? body->getLocStart() : forStmt->getLocStart()),
|
|
|
|
+ mergeBB, continueBB, loopControl,
|
|
|
|
+ check ? check->getSourceRange()
|
|
|
|
+ : (initStmt ? initStmt->getSourceRange()
|
|
|
|
+ : SourceRange(forStmt->getLocStart(),
|
|
|
|
+ forStmt->getLocStart())));
|
|
|
|
+ spvBuilder.addSuccessor(checkBB);
|
|
|
|
+ // The current basic block has a OpLoopMerge instruction. We need to set
|
|
|
|
+ // its continue and merge target.
|
|
|
|
+ spvBuilder.setContinueTarget(continueBB);
|
|
|
|
+ spvBuilder.setMergeTarget(mergeBB);
|
|
|
|
+
|
|
|
|
+ // Process the <check> block.
|
|
|
|
+ spvBuilder.setInsertPoint(checkBB);
|
|
|
|
+ SpirvInstruction *condition = doExpr(check);
|
|
|
|
+ spvBuilder.createConditionalBranch(
|
|
|
|
+ condition, bodyBB, mergeBB,
|
|
|
|
+ check ? check->getLocEnd()
|
|
|
|
+ : (body ? body->getLocStart() : forStmt->getLocStart()),
|
|
|
|
+ nullptr, nullptr, spv::SelectionControlMask::MaskNone,
|
|
|
|
+ spv::LoopControlMask::MaskNone,
|
|
|
|
+ check ? check->getSourceRange()
|
|
|
|
+ : (initStmt ? initStmt->getSourceRange()
|
|
|
|
+ : SourceRange(forStmt->getLocStart(),
|
|
|
|
+ forStmt->getLocStart())));
|
|
|
|
+ spvBuilder.addSuccessor(bodyBB);
|
|
|
|
+ spvBuilder.addSuccessor(mergeBB);
|
|
} else {
|
|
} else {
|
|
- condition = spvBuilder.getConstantBool(true);
|
|
|
|
|
|
+ // In the case of simple or empty conditions, we can use a
|
|
|
|
+ // single block for <check> and <header>.
|
|
|
|
+ spvBuilder.setInsertPoint(checkBB);
|
|
|
|
+ SpirvInstruction *condition = nullptr;
|
|
|
|
+ if (check) {
|
|
|
|
+ condition = doExpr(check);
|
|
|
|
+ } else {
|
|
|
|
+ condition = spvBuilder.getConstantBool(true);
|
|
|
|
+ }
|
|
|
|
+ spvBuilder.createConditionalBranch(
|
|
|
|
+ condition, bodyBB, mergeBB,
|
|
|
|
+ check ? check->getLocEnd()
|
|
|
|
+ : (body ? body->getLocStart() : forStmt->getLocStart()),
|
|
|
|
+ mergeBB, continueBB, spv::SelectionControlMask::MaskNone, loopControl,
|
|
|
|
+ check ? check->getSourceRange()
|
|
|
|
+ : (initStmt ? initStmt->getSourceRange()
|
|
|
|
+ : SourceRange(forStmt->getLocStart(),
|
|
|
|
+ forStmt->getLocStart())));
|
|
|
|
+ spvBuilder.addSuccessor(bodyBB);
|
|
|
|
+ spvBuilder.addSuccessor(mergeBB);
|
|
|
|
+ // The current basic block has a OpLoopMerge instruction. We need to set
|
|
|
|
+ // its continue and merge target.
|
|
|
|
+ spvBuilder.setContinueTarget(continueBB);
|
|
|
|
+ spvBuilder.setMergeTarget(mergeBB);
|
|
}
|
|
}
|
|
- const Stmt *body = forStmt->getBody();
|
|
|
|
- spvBuilder.createConditionalBranch(
|
|
|
|
- condition, bodyBB,
|
|
|
|
- /*false branch*/ mergeBB,
|
|
|
|
- check ? check->getLocEnd()
|
|
|
|
- : (body ? body->getLocStart() : forStmt->getLocStart()),
|
|
|
|
- /*merge*/ mergeBB, continueBB, spv::SelectionControlMask::MaskNone,
|
|
|
|
- loopControl,
|
|
|
|
- check ? check->getSourceRange()
|
|
|
|
- : (initStmt ? initStmt->getSourceRange()
|
|
|
|
- : SourceRange(forStmt->getLocStart(),
|
|
|
|
- forStmt->getLocStart())));
|
|
|
|
- spvBuilder.addSuccessor(bodyBB);
|
|
|
|
- spvBuilder.addSuccessor(mergeBB);
|
|
|
|
- // The current basic block has OpLoopMerge instruction. We need to set its
|
|
|
|
- // continue and merge target.
|
|
|
|
- spvBuilder.setContinueTarget(continueBB);
|
|
|
|
- spvBuilder.setMergeTarget(mergeBB);
|
|
|
|
|
|
|
|
- // Process the <body> block
|
|
|
|
|
|
+ // Process the <body> block.
|
|
spvBuilder.setInsertPoint(bodyBB);
|
|
spvBuilder.setInsertPoint(bodyBB);
|
|
if (body) {
|
|
if (body) {
|
|
doStmt(body);
|
|
doStmt(body);
|
|
@@ -2178,20 +2326,19 @@ void SpirvEmitter::doForStmt(const ForStmt *forStmt,
|
|
: SourceRange(forStmt->getLocStart(), forStmt->getLocStart()));
|
|
: SourceRange(forStmt->getLocStart(), forStmt->getLocStart()));
|
|
spvBuilder.addSuccessor(continueBB);
|
|
spvBuilder.addSuccessor(continueBB);
|
|
|
|
|
|
- // Process the <continue> block
|
|
|
|
|
|
+ // Process the <continue> block. It will jump back to the header.
|
|
spvBuilder.setInsertPoint(continueBB);
|
|
spvBuilder.setInsertPoint(continueBB);
|
|
if (cont) {
|
|
if (cont) {
|
|
doExpr(cont);
|
|
doExpr(cont);
|
|
}
|
|
}
|
|
- // <continue> should jump back to header
|
|
|
|
spvBuilder.createBranch(
|
|
spvBuilder.createBranch(
|
|
- checkBB, forStmt->getLocEnd(), nullptr, nullptr,
|
|
|
|
|
|
+ headerBB, forStmt->getLocEnd(), nullptr, nullptr,
|
|
spv::LoopControlMask::MaskNone,
|
|
spv::LoopControlMask::MaskNone,
|
|
cont ? cont->getSourceRange()
|
|
cont ? cont->getSourceRange()
|
|
: SourceRange(forStmt->getLocStart(), forStmt->getLocStart()));
|
|
: SourceRange(forStmt->getLocStart(), forStmt->getLocStart()));
|
|
- spvBuilder.addSuccessor(checkBB);
|
|
|
|
|
|
+ spvBuilder.addSuccessor(headerBB);
|
|
|
|
|
|
- // Set insertion point to the <merge> block for subsequent statements
|
|
|
|
|
|
+ // Set insertion point to the <merge> block for subsequent statements.
|
|
spvBuilder.setInsertPoint(mergeBB);
|
|
spvBuilder.setInsertPoint(mergeBB);
|
|
|
|
|
|
// Done with the current scope's continue block and merge block.
|
|
// Done with the current scope's continue block and merge block.
|
|
@@ -6479,6 +6626,38 @@ bool SpirvEmitter::isVectorShuffle(const Expr *expr) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+bool SpirvEmitter::isShortCircuitedOp(const Expr *expr) {
|
|
|
|
+ if (!expr || !getCompilerInstance().getLangOpts().EnableShortCircuit) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const auto *binOp = dyn_cast<BinaryOperator>(expr->IgnoreParens());
|
|
|
|
+ if (binOp) {
|
|
|
|
+ return binOp->getOpcode() == BO_LAnd || binOp->getOpcode() == BO_LOr;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const auto *condOp = dyn_cast<ConditionalOperator>(expr->IgnoreParens());
|
|
|
|
+ return condOp;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool SpirvEmitter::stmtTreeContainsShortCircuitedOp(const Stmt *stmt) {
|
|
|
|
+ if (!stmt) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (isShortCircuitedOp(dyn_cast<Expr>(stmt))) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (const auto *child : stmt->children()) {
|
|
|
|
+ if (stmtTreeContainsShortCircuitedOp(child)) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
bool SpirvEmitter::isTextureMipsSampleIndexing(const CXXOperatorCallExpr *expr,
|
|
bool SpirvEmitter::isTextureMipsSampleIndexing(const CXXOperatorCallExpr *expr,
|
|
const Expr **base,
|
|
const Expr **base,
|
|
const Expr **location,
|
|
const Expr **location,
|