/* { dg-do compile { target x86_64-*-* } } */
/* { dg-require-effective-target lp64 } */

#include "analyzer-decls.h"

#include <stdint.h>

int test_1 (int src)
{
  int dst;
  asm ("mov %1, %0\n\t"
       "add $1, %0"
       : "=r" (dst)
       : "r" (src));
  return dst;
}

uint32_t test_2 (uint32_t Mask)
{
  uint32_t Index;
  asm ("bsfl %[aMask], %[aIndex]"
       : [aIndex] "=r" (Index)
       : [aMask] "r" (Mask)
       : "cc");
  return Index;
}

int test_3a (int p1, int p2)
{
  asm goto ("btl %1, %0\n\t"
	    "jc %l2"
	    : // No outputs
	    : "r" (p1), "r" (p2)
	    : "cc"
	    : carry);

  return 0;

 carry:
  return 1;
}

int test_3b (int p1, int p2)
{
  asm goto ("btl %1, %0\n\t"
	    "jc %l[carry]"
	    : // No outputs
	    : "r" (p1), "r" (p2)
	    : "cc"
	    : carry);

  return 0;

 carry:
  return 1;
}

uint64_t test_4 (void)
{
  uint64_t start_time, end_time;

  // Get start time
  asm volatile ("rdtsc\n\t"    // Returns the time in EDX:EAX.
		"shl $32, %%rdx\n\t"  // Shift the upper bits left.
		"or %%rdx, %0"        // 'Or' in the lower bits.
		: "=a" (start_time)
		:
		: "rdx");

  // could do other work here

  // Get end time
  asm volatile ("rdtsc\n\t"    // Returns the time in EDX:EAX.
		"shl $32, %%rdx\n\t"  // Shift the upper bits left.
		"or %%rdx, %0"        // 'Or' in the lower bits.
		: "=a" (end_time)
		:
		: "rdx");

  __analyzer_eval (start_time == end_time); /* { dg-warning "UNKNOWN" } */

  // Get elapsed time
  return end_time - start_time;
}

static uint64_t get_time (void)
{
  uint64_t result;
  asm volatile ("rdtsc\n\t"    // Returns the time in EDX:EAX.
		"shl $32, %%rdx\n\t"  // Shift the upper bits left.
		"or %%rdx, %0"        // 'Or' in the lower bits.
		: "=a" (result)
		:
		: "rdx");
  return result;
}

uint64_t test_4a (void)
{
  uint64_t start_time, end_time;

  start_time = get_time ();
  // could do other work here
  end_time = get_time ();

  __analyzer_eval (start_time == end_time); /* { dg-warning "UNKNOWN" } */

  // Get elapsed time
  return end_time - start_time;
}

asm ("\t.pushsection .text\n"
     "\t.globl add_asm\n"
     "\t.type add_asm, @function\n"
     "add_asm:\n"
     "\tmovq %rdi, %rax\n"
     "\tadd %rsi, %rax\n"
     "\tret\n"
     "\t.popsection\n");

int test_5 (int count)
{
  asm goto ("dec %0; jb %l[stop]"
	    : "+r" (count)
	    :
	    :
	    : stop);
  return count;
stop:
  return 0;
}
