// #target: macos-x64
module test;

struct Foo { int x, y; }
Foo[10] array;

fn void foo() {}

extern fn void *dlclose(void*);

fn void ap_os_dso_unload(void *handle)
{
    dlclose(handle);
    return;
}

extern fn void foo2(int, double, float);

fn void bar(int x) {
  foo2(x, x ? 1.0 : 12.5, 1.0f);
}

extern fn int tolower(int);

fn char *rangematch(char *pattern, int teste, int c) {

  if ((c <= teste) | (tolower(c) <= tolower((char)(teste)))) return (char*)(0);

  return pattern;
}

struct Foostruct {
  short x;
}

extern fn int foo3(Foostruct ic);

fn void teste2() {
  Foostruct xqic;
  foo3(xqic);
}

struct Vertex
{
    float a, b, c;
}
struct Edge_rec
{
  Vertex *v;
  Edge_rec *next;
  int wasseen;
  int more_data;
}

alias QuadEdge = Edge_rec*;

struct EdgePair {
  QuadEdge left, right;
}

struct EdgeStack {
    int ptr;
    QuadEdge *elts;
    int stack_size;
}

fn int do_merge(QuadEdge ldo, QuadEdge rdo) {
  int lvalid;
  QuadEdge basel;
  QuadEdge rcand;
  while (1) {
    if (!lvalid) {
      return (int)((iptr)(basel.next));
    }
  }
}

fn int test(int x) {
  return x;
}

extern fn void abc(int *x);
fn int deff(int y, int z) {
  abc(&z);
  return y;
}

struct Test { short x, x2; int y, z; }

fn int testing(Test *a) {
  return a.x2+a.y;
}

fn int test2(int x, Test a, int y) {
  return x+y+a.x2+a.y;
}
fn int test3(Test a, Test b) {
  return a.x2+a.y+b.y+b.z;
}

fn Test test4(Test a) {
  return a;
}

fn int test6() {
  int[200] b;
  return b[4];
}

struct STest2 { int x; short[4] y; double z; }

fn STest2 test7(STest2 x) {
  return x;
}

extern fn int printf(char * format, ...);

fn int main2() {
  long v = 123455678902L;
  printf("%lld\n", v);
  return 1;
}

double afoo = 17;
double abar = 12.0;
float axx = 12.0f;

char*[*] procnames = {
  "EXIT"
};

void *[*] data = { &afoo, &abar, &axx };

/* #expect: test.ll

%Foo = type { i32, i32 }
%Foostruct = type { i16 }
%Test = type { i16, i16, i32, i32 }
%STest2 = type { i32, [4 x i16], double }

@test.array = local_unnamed_addr global [10 x %Foo] zeroinitializer, align 16
@test.afoo = global double 1.700000e+01, align 8
@test.abar = global double 1.200000e+01, align 8
@test.axx = global float 1.200000e+01, align 4
@.str = private unnamed_addr constant [5 x i8] c"EXIT\00", align 1
@test.procnames = local_unnamed_addr global [1 x ptr] [ptr @.str], align 8
@test.data = local_unnamed_addr global [3 x ptr] [ptr @test.afoo, ptr @test.abar, ptr @test.axx], align 16
@.str.6 = private unnamed_addr constant [6 x i8] c"%lld\0A\00", align 1

; Function Attrs:
define void @test.foo() #0 {
entry:
  ret void
}

; Function Attrs:
declare ptr @dlclose(ptr) #0

; Function Attrs:
define void @test.ap_os_dso_unload(ptr %0) #0 {
entry:
  %1 = call ptr @dlclose(ptr %0)
  ret void
}

; Function Attrs:
declare void @foo2(i32, double, float) #0

; Function Attrs:
define void @test.bar(i32 %0) #0 {
entry:
  %i2b = icmp ne i32 %0, 0
  %ternary = select i1 %i2b, double 1.000000e+00, double 1.250000e+01
  call void @foo2(i32 %0, double %ternary, float 1.000000e+00)
  ret void
}

; Function Attrs:
declare i32 @tolower(i32) #0

; Function Attrs:
define ptr @test.rangematch(ptr %0, i32 %1, i32 %2) #0 {
entry:
  %le = icmp sle i32 %2, %1
  %3 = call i32 @tolower(i32 %2)
  %trunc = trunc i32 %1 to i8
  %zext = zext i8 %trunc to i32
  %4 = call i32 @tolower(i32 %zext)
  %le1 = icmp sle i32 %3, %4
  %or = or i1 %le, %le1
  br i1 %or, label %if.then, label %if.exit

if.then:                                          ; preds = %entry
  ret ptr null

if.exit:                                          ; preds = %entry
  ret ptr %0
}

; Function Attrs:
declare i32 @foo3(i16) #0

; Function Attrs:
define void @test.teste2() #0 {
entry:
  %xqic = alloca %Foostruct, align 2
  store i16 0, ptr %xqic, align 2
  %0 = load i16, ptr %xqic, align 2
  %1 = call i32 @foo3(i16 %0)
  ret void
}

; Function Attrs:
define i32 @test.do_merge(ptr %0, ptr %1) #0 {
entry:
  %lvalid = alloca i32, align 4
  %basel = alloca ptr, align 8
  %rcand = alloca ptr, align 8
  store i32 0, ptr %lvalid, align 4
  store ptr null, ptr %basel, align 8
  store ptr null, ptr %rcand, align 8
  br label %loop.body

loop.body:                                        ; preds = %if.exit, %entry
  %2 = load i32, ptr %lvalid, align 4
  %i2nb = icmp eq i32 %2, 0
  br i1 %i2nb, label %if.then, label %if.exit

if.then:                                          ; preds = %loop.body
  %3 = load ptr, ptr %basel, align 8
  %ptradd = getelementptr inbounds i8, ptr %3, i64 8
  %4 = load ptr, ptr %ptradd, align 8
  %ptrxi = ptrtoint ptr %4 to i32
  ret i32 %ptrxi

if.exit:                                          ; preds = %loop.body
  br label %loop.body
}

; Function Attrs:
define i32 @test.test(i32 %0) #0 {
entry:
  ret i32 %0
}

; Function Attrs:
declare void @abc(ptr) #0

; Function Attrs:
define i32 @test.deff(i32 %0, i32 %1) #0 {
entry:
  %z = alloca i32, align 4
  store i32 %1, ptr %z, align 4
  call void @abc(ptr %z)
  ret i32 %0
}

; Function Attrs:
define i32 @test.testing(ptr %0) #0 {
entry:
  %ptradd = getelementptr inbounds i8, ptr %0, i64 2
  %1 = load i16, ptr %ptradd, align 2
  %sext = sext i16 %1 to i32
  %ptradd1 = getelementptr inbounds i8, ptr %0, i64 4
  %2 = load i32, ptr %ptradd1, align 4
  %add = add i32 %sext, %2
  ret i32 %add
}

; Function Attrs:
define i32 @test.test2(i32 %0, i64 %1, i32 %2, i32 %3) #0 {
entry:
  %a = alloca %Test, align 8
  store i64 %1, ptr %a, align 8
  %ptradd = getelementptr inbounds i8, ptr %a, i64 8
  store i32 %2, ptr %ptradd, align 8
  %add = add i32 %0, %3
  %ptradd1 = getelementptr inbounds i8, ptr %a, i64 2
  %4 = load i16, ptr %ptradd1, align 2
  %sext = sext i16 %4 to i32
  %add2 = add i32 %add, %sext
  %ptradd3 = getelementptr inbounds i8, ptr %a, i64 4
  %5 = load i32, ptr %ptradd3, align 4
  %add4 = add i32 %add2, %5
  ret i32 %add4
}

; Function Attrs:
define i32 @test.test3(i64 %0, i32 %1, i64 %2, i32 %3) #0 {
entry:
  %a = alloca %Test, align 8
  %b = alloca %Test, align 8
  store i64 %0, ptr %a, align 8
  %ptradd = getelementptr inbounds i8, ptr %a, i64 8
  store i32 %1, ptr %ptradd, align 8
  store i64 %2, ptr %b, align 8
  %ptradd1 = getelementptr inbounds i8, ptr %b, i64 8
  store i32 %3, ptr %ptradd1, align 8
  %ptradd2 = getelementptr inbounds i8, ptr %a, i64 2
  %4 = load i16, ptr %ptradd2, align 2
  %sext = sext i16 %4 to i32
  %ptradd3 = getelementptr inbounds i8, ptr %a, i64 4
  %5 = load i32, ptr %ptradd3, align 4
  %add = add i32 %sext, %5
  %ptradd4 = getelementptr inbounds i8, ptr %b, i64 4
  %6 = load i32, ptr %ptradd4, align 4
  %add5 = add i32 %add, %6
  %ptradd6 = getelementptr inbounds i8, ptr %b, i64 8
  %7 = load i32, ptr %ptradd6, align 8
  %add7 = add i32 %add5, %7
  ret i32 %add7
}

; Function Attrs:
define { i64, i32 } @test.test4(i64 %0, i32 %1) #0 {
entry:
  %a = alloca %Test, align 8
  %tempcoerce = alloca { i64, i32 }, align 8
  store i64 %0, ptr %a, align 8
  %ptradd = getelementptr inbounds i8, ptr %a, i64 8
  store i32 %1, ptr %ptradd, align 8
  call void @llvm.memcpy.p0.p0.i32(ptr align 8 %tempcoerce, ptr align 8 %a, i32 12, i1 false)
  %2 = load { i64, i32 }, ptr %tempcoerce, align 8
  ret { i64, i32 } %2
}

; Function Attrs:
define i32 @test.test6() #0 {
entry:
  %b = alloca [200 x i32], align 16
  call void @llvm.memset.p0.i64(ptr align 16 %b, i8 0, i64 800, i1 false)
  %ptradd = getelementptr inbounds i8, ptr %b, i64 16
  %0 = load i32, ptr %ptradd, align 4
  ret i32 %0
}

; Function Attrs:
define void @test.test7(ptr noalias sret(%STest2) align 8 %0, ptr byval(%STest2) align 8 %1) #0 {
entry:
  call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %1, i32 24, i1 false)
  ret void
}

; Function Attrs:
declare i32 @printf(ptr, ...) #0

; Function Attrs:
define i32 @test.main2() #0 {
entry:
  %v = alloca i64, align 8
  store i64 123455678902, ptr %v, align 8
  %0 = load i64, ptr %v, align 8
  %1 = call i32 (ptr, ...) @printf(ptr @.str.6, i64 %0)
  ret i32 1
}
