arm64-fp128.ll 6.46 KB
; RUN: llc -mtriple=arm64-linux-gnu -verify-machineinstrs -mcpu=cyclone -aarch64-enable-atomic-cfg-tidy=0 < %s | FileCheck -enable-var-scope %s

@lhs = global fp128 zeroinitializer, align 16
@rhs = global fp128 zeroinitializer, align 16

define fp128 @test_add() {
; CHECK-LABEL: test_add:

  %lhs = load fp128, fp128* @lhs, align 16
  %rhs = load fp128, fp128* @rhs, align 16
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]

  %val = fadd fp128 %lhs, %rhs
; CHECK: bl __addtf3
  ret fp128 %val
}

define fp128 @test_sub() {
; CHECK-LABEL: test_sub:

  %lhs = load fp128, fp128* @lhs, align 16
  %rhs = load fp128, fp128* @rhs, align 16
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]

  %val = fsub fp128 %lhs, %rhs
; CHECK: bl __subtf3
  ret fp128 %val
}

define fp128 @test_mul() {
; CHECK-LABEL: test_mul:

  %lhs = load fp128, fp128* @lhs, align 16
  %rhs = load fp128, fp128* @rhs, align 16
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]

  %val = fmul fp128 %lhs, %rhs
; CHECK: bl __multf3
  ret fp128 %val
}

define fp128 @test_div() {
; CHECK-LABEL: test_div:

  %lhs = load fp128, fp128* @lhs, align 16
  %rhs = load fp128, fp128* @rhs, align 16
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]

  %val = fdiv fp128 %lhs, %rhs
; CHECK: bl __divtf3
  ret fp128 %val
}

@var32 = global i32 0
@var64 = global i64 0

define void @test_fptosi() {
; CHECK-LABEL: test_fptosi:
  %val = load fp128, fp128* @lhs, align 16

  %val32 = fptosi fp128 %val to i32
  store i32 %val32, i32* @var32
; CHECK: bl __fixtfsi

  %val64 = fptosi fp128 %val to i64
  store i64 %val64, i64* @var64
; CHECK: bl __fixtfdi

  ret void
}

define void @test_fptoui() {
; CHECK-LABEL: test_fptoui:
  %val = load fp128, fp128* @lhs, align 16

  %val32 = fptoui fp128 %val to i32
  store i32 %val32, i32* @var32
; CHECK: bl __fixunstfsi

  %val64 = fptoui fp128 %val to i64
  store i64 %val64, i64* @var64
; CHECK: bl __fixunstfdi

  ret void
}

define void @test_sitofp() {
; CHECK-LABEL: test_sitofp:

  %src32 = load i32, i32* @var32
  %val32 = sitofp i32 %src32 to fp128
  store volatile fp128 %val32, fp128* @lhs
; CHECK: bl __floatsitf

  %src64 = load i64, i64* @var64
  %val64 = sitofp i64 %src64 to fp128
  store volatile fp128 %val64, fp128* @lhs
; CHECK: bl __floatditf

  ret void
}

define void @test_uitofp() {
; CHECK-LABEL: test_uitofp:

  %src32 = load i32, i32* @var32
  %val32 = uitofp i32 %src32 to fp128
  store volatile fp128 %val32, fp128* @lhs
; CHECK: bl __floatunsitf

  %src64 = load i64, i64* @var64
  %val64 = uitofp i64 %src64 to fp128
  store volatile fp128 %val64, fp128* @lhs
; CHECK: bl __floatunditf

  ret void
}

define i1 @test_setcc1() {
; CHECK-LABEL: test_setcc1:

  %lhs = load fp128, fp128* @lhs, align 16
  %rhs = load fp128, fp128* @rhs, align 16
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]

; Technically, everything after the call to __letf2 is redundant, but we'll let
; LLVM have its fun for now.
  %val = fcmp ole fp128 %lhs, %rhs
; CHECK: bl __letf2
; CHECK: cmp w0, #0
; CHECK: cset w0, le

  ret i1 %val
; CHECK: ret
}

define i1 @test_setcc2() {
; CHECK-LABEL: test_setcc2:

  %lhs = load fp128, fp128* @lhs, align 16
  %rhs = load fp128, fp128* @rhs, align 16
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]

  %val = fcmp ugt fp128 %lhs, %rhs
; CHECK: bl      __letf2
; CHECK: cmp     w0, #0
; CHECK: cset    w0, gt

  ret i1 %val
; CHECK: ret
}

define i1 @test_setcc3() {
; CHECK-LABEL: test_setcc3:

  %lhs = load fp128, fp128* @lhs, align 16
  %rhs = load fp128, fp128* @rhs, align 16
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]

  %val = fcmp ueq fp128 %lhs, %rhs
; CHECK: bl __eqtf2
; CHECK: cmp     w0, #0
; CHECK: cset    w19, eq
; CHECK: bl __unordtf2
; CHECK: cmp     w0, #0
; CHECK: cset    w8, ne
; CHECK: orr     w0, w8, w19

  ret i1 %val
; CHECK: ret
}


define i32 @test_br_cc() {
; CHECK-LABEL: test_br_cc:

  %lhs = load fp128, fp128* @lhs, align 16
  %rhs = load fp128, fp128* @rhs, align 16
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]

  ; olt == !uge, which LLVM optimizes this to.
  %cond = fcmp olt fp128 %lhs, %rhs
; CHECK: bl      __lttf2
; CHECK-NEXT: cmp     w0, #0
; CHECK-NEXT: b.ge {{.LBB[0-9]+_[0-9]+}}
  br i1 %cond, label %iftrue, label %iffalse

iftrue:
  ret i32 42
; CHECK-NEXT: %bb.
; CHECK-NEXT: mov w0, #42
; CHECK: ret
iffalse:
  ret i32 29
; CHECK: mov w0, #29
; CHECK: ret
}

define void @test_select(i1 %cond, fp128 %lhs, fp128 %rhs) {
; CHECK-LABEL: test_select:

  %val = select i1 %cond, fp128 %lhs, fp128 %rhs
  store fp128 %val, fp128* @lhs, align 16
; CHECK: tst w0, #0x1
; CHECK-NEXT: b.eq [[IFFALSE:.LBB[0-9]+_[0-9]+]]
; CHECK-NEXT: %bb.
; CHECK-NEXT: mov v[[VAL:[0-9]+]].16b, v0.16b
; CHECK-NEXT: [[IFFALSE]]:
; CHECK: str q[[VAL]], [{{x[0-9]+}}, :lo12:lhs]
  ret void
; CHECK: ret
}

@varfloat = global float 0.0, align 4
@vardouble = global double 0.0, align 8

define void @test_round() {
; CHECK-LABEL: test_round:

  %val = load fp128, fp128* @lhs, align 16

  %float = fptrunc fp128 %val to float
  store float %float, float* @varfloat, align 4
; CHECK: bl __trunctfsf2
; CHECK: str s0, [{{x[0-9]+}}, :lo12:varfloat]

  %double = fptrunc fp128 %val to double
  store double %double, double* @vardouble, align 8
; CHECK: bl __trunctfdf2
; CHECK: str d0, [{{x[0-9]+}}, :lo12:vardouble]

  ret void
}

define void @test_extend() {
; CHECK-LABEL: test_extend:

  %val = load fp128, fp128* @lhs, align 16

  %float = load float, float* @varfloat
  %fromfloat = fpext float %float to fp128
  store volatile fp128 %fromfloat, fp128* @lhs, align 16
; CHECK: bl __extendsftf2
; CHECK: str q0, [{{x[0-9]+}}, :lo12:lhs]

  %double = load double, double* @vardouble
  %fromdouble = fpext double %double to fp128
  store volatile fp128 %fromdouble, fp128* @lhs, align 16
; CHECK: bl __extenddftf2
; CHECK: str q0, [{{x[0-9]+}}, :lo12:lhs]

  ret void
; CHECK: ret
}

define fp128 @test_neg(fp128 %in) {
; CHECK: [[$MINUS0:.LCPI[0-9]+_0]]:
; Make sure the weird hex constant below *is* -0.0
; CHECK-NEXT: fp128 -0

; CHECK-LABEL: test_neg:

  ; Could in principle be optimized to fneg which we can't select, this makes
  ; sure that doesn't happen.
  %ret = fsub fp128 0xL00000000000000008000000000000000, %in
; CHECK: mov v1.16b, v0.16b
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:[[$MINUS0]]]
; CHECK: bl __subtf3

  ret fp128 %ret
; CHECK: ret
}