/// <summary cref="IBackendCodeGenerator.GenerateCode(ReturnTerminator)"/>
 public void GenerateCode(ReturnTerminator returnTerminator)
 {
     if (!returnTerminator.IsVoidReturn)
     {
         var resultRegister = Load(returnTerminator.ReturnValue);
         EmitStoreParam(ReturnParamName, resultRegister);
     }
     Command(
         Uniforms.IsUniform(returnTerminator)
             ? PTXInstructions.UniformReturnOperation
             : PTXInstructions.ReturnOperation);
 }
        /// <summary cref="IBackendCodeGenerator.GenerateCode(IfBranch)"/>
        public void GenerateCode(IfBranch branch)
        {
            var primitiveCondition = LoadPrimitive(branch.Condition);
            var condition          = EnsureHardwareRegister(primitiveCondition);

            // Use the actual branch targets from the schedule
            var(trueTarget, falseTarget) = branch.NotInvertedBranchTargets;

            // Determine the branch operation to be used
            var branchOperation = Uniforms.IsUniform(branch)
                ? PTXInstructions.UniformBranchOperation
                : PTXInstructions.BranchOperation;

            // The current schedule has inverted all if conditions with implicit branch
            // targets to simplify the work of the PTX assembler
            if (Schedule.IsImplicitSuccessor(branch.BasicBlock, trueTarget))
            {
                // Jump to false target in the else case
                using var command = BeginCommand(
                          branchOperation,
                          new PredicateConfiguration(
                              condition,
                              isTrue: branch.IsInverted));
                var targetLabel = blockLookup[falseTarget];
                command.AppendLabel(targetLabel);
            }
            else
            {
                if (branch.IsInverted)
                {
                    Utilities.Swap(ref trueTarget, ref falseTarget);
                }
                using (var command = BeginCommand(
                           branchOperation,
                           new PredicateConfiguration(condition, isTrue: true)))
                {
                    var targetLabel = blockLookup[trueTarget];
                    command.AppendLabel(targetLabel);
                }

                // Jump to false target in the else case
                using (var command = BeginCommand(PTXInstructions.UniformBranchOperation))
                {
                    var targetLabel = blockLookup[falseTarget];
                    command.AppendLabel(targetLabel);
                }
            }
        }
        /// <summary cref="IBackendCodeGenerator.GenerateCode(UnconditionalBranch)"/>
        public void GenerateCode(UnconditionalBranch branch)
        {
            if (Schedule.IsImplicitSuccessor(branch.BasicBlock, branch.Target))
            {
                return;
            }

            // Determine the branch operation to be used
            var branchOperation = Uniforms.IsUniform(branch)
                ? PTXInstructions.UniformBranchOperation
                : PTXInstructions.BranchOperation;

            using var command = BeginCommand(branchOperation);
            var targetLabel = blockLookup[branch.Target];

            command.AppendLabel(targetLabel);
        }
        /// <summary cref="IBackendCodeGenerator.GenerateCode(SwitchBranch)"/>
        public void GenerateCode(SwitchBranch branch)
        {
            bool isUniform = Uniforms.IsUniform(branch);
            var  idx       = LoadPrimitive(branch.Condition);

            using (var lowerBoundsScope = new PredicateScope(this))
            {
                // Emit less than
                var lessThanCommand = PTXInstructions.GetCompareOperation(
                    CompareKind.LessThan,
                    CompareFlags.None,
                    ArithmeticBasicValueType.Int32);
                using (var command = BeginCommand(
                           lessThanCommand))
                {
                    command.AppendArgument(lowerBoundsScope.PredicateRegister);
                    command.AppendArgument(idx);
                    command.AppendConstant(0);
                }

                using var upperBoundsScope = new PredicateScope(this);
                using (var command = BeginCommand(
                           PTXInstructions.BranchIndexRangeComparison))
                {
                    command.AppendArgument(upperBoundsScope.PredicateRegister);
                    command.AppendArgument(idx);
                    command.AppendConstant(branch.NumCasesWithoutDefault);
                    command.AppendArgument(lowerBoundsScope.PredicateRegister);
                }
                using (var command = BeginCommand(
                           isUniform
                        ? PTXInstructions.UniformBranchOperation
                        : PTXInstructions.BranchOperation,
                           new PredicateConfiguration(
                               upperBoundsScope.PredicateRegister,
                               true)))
                {
                    var defaultTarget = blockLookup[branch.DefaultBlock];
                    command.AppendLabel(defaultTarget);
                }
            }

            var targetLabel = DeclareLabel();

            MarkLabel(targetLabel);
            Builder.Append('\t');
            Builder.Append(PTXInstructions.BranchTargetsDeclaration);
            Builder.Append(' ');
            for (int i = 0, e = branch.NumCasesWithoutDefault; i < e; ++i)
            {
                var caseTarget = branch.GetCaseTarget(i);
                var caseLabel  = blockLookup[caseTarget];
                Builder.Append(caseLabel);
                if (i + 1 < e)
                {
                    Builder.Append(", ");
                }
            }
            Builder.AppendLine(";");

            using (var command = BeginCommand(
                       isUniform
                    ? PTXInstructions.UniformBranchIndexOperation
                    : PTXInstructions.BranchIndexOperation))
            {
                command.AppendArgument(idx);
                command.AppendLabel(targetLabel);
            }
        }