Exemplo n.º 1
0
// Make sure the canonical use works before going into smaller details:
int atomic_inc(int *addr) {
  int Failure, OldVal;
  do {
    OldVal = __builtin_arm_ldrex(addr);
    Failure = __builtin_arm_strex(OldVal + 1, addr);
  } while (Failure);

  return OldVal;
}
Exemplo n.º 2
0
__int128 test_ldrex_128(__int128 *addr) {
// CHECK-ARM64-LABEL: @test_ldrex_128

  return __builtin_arm_ldrex(addr);
// CHECK-ARM64: [[ADDR8:%.*]] = bitcast i128* %addr to i8*
// CHECK-ARM64: [[STRUCTRES:%.*]] = tail call { i64, i64 } @llvm.aarch64.ldxp(i8* [[ADDR8]])
// CHECK-ARM64: [[RESHI:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 1
// CHECK-ARM64: [[RESLO:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 0
// CHECK-ARM64: [[RESHI64:%.*]] = zext i64 [[RESHI]] to i128
// CHECK-ARM64: [[RESLO64:%.*]] = zext i64 [[RESLO]] to i128
// CHECK-ARM64: [[RESHIHI:%.*]] = shl nuw i128 [[RESHI64]], 64
// CHECK-ARM64: [[INTRES:%.*]] = or i128 [[RESLO64]], [[RESHIHI]]
// CHECK-ARM64: ret i128 [[INTRES]]
}
Exemplo n.º 3
0
int test_ldrex(char *addr, long long *addr64, float *addrfloat) {
// CHECK-LABEL: @test_ldrex
// CHECK-ARM64-LABEL: @test_ldrex
  int sum = 0;
  sum += __builtin_arm_ldrex(addr);
// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i8(i8* %addr)
// CHECK: and i32 [[INTRES]], 255

// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldxr.p0i8(i8* %addr)
// CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
// CHECK-ARM64: [[SEXTTMP:%.*]] = shl i32 [[TRUNCRES]], 24
// CHECK-ARM64: ashr exact i32 [[SEXTTMP]], 24

  sum += __builtin_arm_ldrex((short *)addr);
// CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i16(i16* [[ADDR16]])
// CHECK: [[TMPSEXT:%.*]] = shl i32 [[INTRES]], 16
// CHECK: ashr exact i32 [[TMPSEXT]], 16

// CHECK-ARM64: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldxr.p0i16(i16* [[ADDR16]])
// CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
// CHECK-ARM64: [[TMPSEXT:%.*]] = shl i32 [[TRUNCRES]], 16
// CHECK-ARM64: ashr exact i32 [[TMPSEXT]], 16

  sum += __builtin_arm_ldrex((int *)addr);
// CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
// CHECK:  call i32 @llvm.arm.ldrex.p0i32(i32* [[ADDR32]])

// CHECK-ARM64: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldxr.p0i32(i32* [[ADDR32]])
// CHECK-ARM64: trunc i64 [[INTRES]] to i32

  sum += __builtin_arm_ldrex((long long *)addr);
// CHECK: call { i32, i32 } @llvm.arm.ldrexd(i8* %addr)

// CHECK-ARM64: [[ADDR64:%.*]] = bitcast i8* %addr to i64*
// CHECK-ARM64: call i64 @llvm.aarch64.ldxr.p0i64(i64* [[ADDR64]])

  sum += __builtin_arm_ldrex(addr64);
// CHECK: [[ADDR64_AS8:%.*]] = bitcast i64* %addr64 to i8*
// CHECK: call { i32, i32 } @llvm.arm.ldrexd(i8* [[ADDR64_AS8]])

// CHECK-ARM64: call i64 @llvm.aarch64.ldxr.p0i64(i64* %addr64)

  sum += __builtin_arm_ldrex(addrfloat);
// CHECK: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i32(i32* [[INTADDR]])
// CHECK: bitcast i32 [[INTRES]] to float

// CHECK-ARM64: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldxr.p0i32(i32* [[INTADDR]])
// CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
// CHECK-ARM64: bitcast i32 [[TRUNCRES]] to float

  sum += __builtin_arm_ldrex((double *)addr);
// CHECK: [[STRUCTRES:%.*]] = tail call { i32, i32 } @llvm.arm.ldrexd(i8* %addr)
// CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1
// CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0
// CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64
// CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64
// CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32
// CHECK: [[INTRES:%.*]] = or i64 [[RESLO64]], [[RESHIHI]]
// CHECK: bitcast i64 [[INTRES]] to double

// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldxr.p0i64(i64* [[ADDR64]])
// CHECK-ARM64: bitcast i64 [[INTRES]] to double

  sum += *__builtin_arm_ldrex((int **)addr);
// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i32(i32* [[ADDR32]])
// CHECK: inttoptr i32 [[INTRES]] to i32*

// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldxr.p0i64(i64* [[ADDR64]])
// CHECK-ARM64: inttoptr i64 [[INTRES]] to i32*

  sum += __builtin_arm_ldrex((struct Simple **)addr)->a;
// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldrex.p0i32(i32* [[ADDR32]])
// CHECK: inttoptr i32 [[INTRES]] to %struct.Simple*

// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldxr.p0i64(i64* [[ADDR64]])
// CHECK-ARM64: inttoptr i64 [[INTRES]] to %struct.Simple*
  return sum;
}
int test_ldrex(char *addr) {
    int sum = 0;
    sum += __builtin_arm_ldrex(addr);
    sum += __builtin_arm_ldrex((short *)addr);
    sum += __builtin_arm_ldrex((int *)addr);
    sum += __builtin_arm_ldrex((long long *)addr);
    sum += __builtin_arm_ldrex((float *)addr);
    sum += __builtin_arm_ldrex((double *)addr);
    sum += *__builtin_arm_ldrex((int **)addr);
    sum += __builtin_arm_ldrex((struct Simple **)addr)->a;
    sum += __builtin_arm_ldrex((volatile char *)addr);
    sum += __builtin_arm_ldrex((const volatile char *)addr);

    // In principle this might be valid, but stick to ints and floats for scalar
    // types at the moment.
    sum += __builtin_arm_ldrex((struct Simple *)addr).a; // expected-error {{address argument to atomic builtin must be a pointer to}}

    sum += __builtin_arm_ldrex((__int128 *)addr); // expected-error {{__int128 is not supported on this target}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 1,2,4 or 8 byte type}}

    __builtin_arm_ldrex(); // expected-error {{too few arguments to function call}}
    __builtin_arm_ldrex(1, 2); // expected-error {{too many arguments to function call}}
    return sum;
}