llvm/clang/test/CodeGen/arm64_32-vaarg.c

// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs -emit-llvm -o - -O1 -ffreestanding %s | FileCheck %s

#include <stdarg.h>

typedef struct {
  int a;
} OneInt;

// No realignment should be needed here: slot size is 4 bytes.
int test_int(OneInt input, va_list *mylist) {
// CHECK-LABEL: define{{.*}} i32 @test_int(i32 %input
// CHECK: [[START:%.*]] = load ptr, ptr %mylist
// CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, ptr [[START]], i32 4
// CHECK: store ptr [[NEXT]], ptr %mylist

// CHECK: [[RES:%.*]] = load i32, ptr [[START]]
// CHECK: ret i32 [[RES]]

  return va_arg(*mylist, OneInt).a;
}


typedef struct {
  long long a;
} OneLongLong;

// Minimum slot size is 4 bytes, so address needs rounding up to multiple of 8.
long long test_longlong(OneLongLong input, va_list *mylist) {
  // CHECK-LABEL: define{{.*}} i64 @test_longlong(i64 %input
  // CHECK: [[STARTPTR:%.*]] = load ptr, ptr %mylist
  // CHECK: [[ALIGN_TMP:%.+]] = getelementptr inbounds i8, ptr [[STARTPTR]], i32 7
  // CHECK: [[ALIGNED_ADDR:%.+]] = tail call align 8 ptr @llvm.ptrmask.p0.i32(ptr nonnull [[ALIGN_TMP]], i32 -8)
  // CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, ptr [[ALIGNED_ADDR]], i32 8
  // CHECK: store ptr [[NEXT]], ptr %mylist

  // CHECK: [[RES:%.*]] = load i64, ptr [[ALIGNED_ADDR]]
  // CHECK: ret i64 [[RES]]

  return va_arg(*mylist, OneLongLong).a;
}


typedef struct {
  float arr[4];
} HFA;

// HFAs take priority over passing large structs indirectly.
float test_hfa(va_list *mylist) {
// CHECK-LABEL: define{{.*}} float @test_hfa
// CHECK: [[START:%.*]] = load ptr, ptr %mylist

// CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, ptr [[START]], i32 16
// CHECK: store ptr [[NEXT]], ptr %mylist

// CHECK: [[RES:%.*]] = load float, ptr [[START]]
// CHECK: ret float [[RES]]

  return va_arg(*mylist, HFA).arr[0];
}

// armv7k does not return HFAs normally for variadic functions, so we must match
// that.
HFA test_hfa_return(int n, ...) {
// CHECK-LABEL: define{{.*}} [2 x i64] @test_hfa_return
  HFA h = {0};
  return h;
}

typedef struct {
  long long a, b;
  char c;
} BigStruct;

// Structs bigger than 16 bytes are passed indirectly: a pointer is placed on
// the stack.
long long test_bigstruct(BigStruct input, va_list *mylist) {
// CHECK-LABEL: define{{.*}} i64 @test_bigstruct(ptr
// CHECK: [[START:%.*]] = load ptr, ptr %mylist
// CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, ptr [[START]], i32 4
// CHECK: store ptr [[NEXT]], ptr %mylist

// CHECK: [[ADDR:%.*]] = load ptr, ptr [[START]]
// CHECK: [[RES:%.*]] = load i64, ptr [[ADDR]]
// CHECK: ret i64 [[RES]]

  return va_arg(*mylist, BigStruct).a;
}

typedef struct {
  short arr[3];
} ThreeShorts;

// Slot sizes are 4-bytes on arm64_32, so structs with less than 32-bit
// alignment must be passed via "[N x i32]" to be correctly allocated in the
// backend.
short test_threeshorts(ThreeShorts input, va_list *mylist) {
// CHECK-LABEL: define{{.*}} signext i16 @test_threeshorts([2 x i32] %input

// CHECK: [[START:%.*]] = load ptr, ptr %mylist
// CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, ptr [[START]], i32 8
// CHECK: store ptr [[NEXT]], ptr %mylist

// CHECK: [[RES:%.*]] = load i16, ptr [[START]]
// CHECK: ret i16 [[RES]]

  return va_arg(*mylist, ThreeShorts).arr[0];
}