2474 lines
92 KiB
LLVM
2474 lines
92 KiB
LLVM
|
; RUN: llc -O0 -aarch64-enable-atomic-cfg-tidy=0 -mattr=+lse -stop-after=irtranslator -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s
|
||
|
; RUN: llc -O3 -aarch64-enable-atomic-cfg-tidy=0 -mattr=+lse -stop-after=irtranslator -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s --check-prefix=O3
|
||
|
|
||
|
; This file checks that the translation from llvm IR to generic MachineInstr
|
||
|
; is correct.
|
||
|
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
|
||
|
target triple = "aarch64--"
|
||
|
|
||
|
; Tests for add.
|
||
|
; CHECK-LABEL: name: addi64
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s64) = COPY $x1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s64) = G_ADD [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $x0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $x0
|
||
|
define i64 @addi64(i64 %arg1, i64 %arg2) {
|
||
|
%res = add i64 %arg1, %arg2
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: muli64
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s64) = COPY $x1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s64) = G_MUL [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $x0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $x0
|
||
|
define i64 @muli64(i64 %arg1, i64 %arg2) {
|
||
|
%res = mul i64 %arg1, %arg2
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; Tests for alloca
|
||
|
; CHECK-LABEL: name: allocai64
|
||
|
; CHECK: stack:
|
||
|
; CHECK-NEXT: - { id: 0, name: ptr1, type: default, offset: 0, size: 8, alignment: 8,
|
||
|
; CHECK-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
|
||
|
; CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||
|
; CHECK-NEXT: - { id: 1, name: ptr2, type: default, offset: 0, size: 8, alignment: 1,
|
||
|
; CHECK-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
|
||
|
; CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||
|
; CHECK-NEXT: - { id: 2, name: ptr3, type: default, offset: 0, size: 128, alignment: 8,
|
||
|
; CHECK-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true,
|
||
|
; CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||
|
; CHECK-NEXT: - { id: 3, name: ptr4, type: default, offset: 0, size: 1, alignment: 8,
|
||
|
; CHECK: %{{[0-9]+}}:_(p0) = G_FRAME_INDEX %stack.0.ptr1
|
||
|
; CHECK: %{{[0-9]+}}:_(p0) = G_FRAME_INDEX %stack.1.ptr2
|
||
|
; CHECK: %{{[0-9]+}}:_(p0) = G_FRAME_INDEX %stack.2.ptr3
|
||
|
; CHECK: %{{[0-9]+}}:_(p0) = G_FRAME_INDEX %stack.3.ptr4
|
||
|
define void @allocai64() {
|
||
|
%ptr1 = alloca i64
|
||
|
%ptr2 = alloca i64, align 1
|
||
|
%ptr3 = alloca i64, i32 16
|
||
|
%ptr4 = alloca [0 x i64]
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; Tests for br.
|
||
|
; CHECK-LABEL: name: uncondbr
|
||
|
; CHECK: body:
|
||
|
;
|
||
|
; ABI/constant lowering and IR-level entry basic block.
|
||
|
; CHECK: bb.{{[0-9]+}}.{{[a-zA-Z0-9.]+}}:
|
||
|
;
|
||
|
; Make sure we have one successor and only one.
|
||
|
; CHECK-NEXT: successors: %[[BB2:bb.[0-9]+]](0x80000000)
|
||
|
;
|
||
|
; Check that we emit the correct branch.
|
||
|
; CHECK: G_BR %[[BB2]]
|
||
|
;
|
||
|
; Check that end contains the return instruction.
|
||
|
; CHECK: [[END:bb.[0-9]+]].{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK-NEXT: RET_ReallyLR
|
||
|
;
|
||
|
; CHECK: bb.{{[0-9]+}}.{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK-NEXT: successors: %[[END]](0x80000000)
|
||
|
; CHECK: G_BR %[[END]]
|
||
|
define void @uncondbr() {
|
||
|
entry:
|
||
|
br label %bb2
|
||
|
end:
|
||
|
ret void
|
||
|
bb2:
|
||
|
br label %end
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: uncondbr_fallthrough
|
||
|
; CHECK: body:
|
||
|
; CHECK: bb.{{[0-9]+}}.{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK-NEXT: successors: %[[END:bb.[0-9]+]](0x80000000)
|
||
|
; CHECK: [[END]].{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK-NEXT: RET_ReallyLR
|
||
|
define void @uncondbr_fallthrough() {
|
||
|
entry:
|
||
|
br label %end
|
||
|
end:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; Tests for conditional br.
|
||
|
; CHECK-LABEL: name: condbr
|
||
|
; CHECK: body:
|
||
|
;
|
||
|
; ABI/constant lowering and IR-level entry basic block.
|
||
|
; CHECK: bb.{{[0-9]+}} (%ir-block.{{[0-9]+}}):
|
||
|
; Make sure we have two successors
|
||
|
; CHECK-NEXT: successors: %[[TRUE:bb.[0-9]+]](0x40000000),
|
||
|
; CHECK: %[[FALSE:bb.[0-9]+]](0x40000000)
|
||
|
;
|
||
|
; CHECK: [[ADDR:%.*]]:_(p0) = COPY $x0
|
||
|
;
|
||
|
; Check that we emit the correct branch.
|
||
|
; CHECK: [[TST:%.*]]:_(s1) = G_LOAD [[ADDR]](p0)
|
||
|
; CHECK: G_BRCOND [[TST]](s1), %[[TRUE]]
|
||
|
; CHECK: G_BR %[[FALSE]]
|
||
|
;
|
||
|
; Check that each successor contains the return instruction.
|
||
|
; CHECK: [[TRUE]].{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK-NEXT: RET_ReallyLR
|
||
|
; CHECK: [[FALSE]].{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK-NEXT: RET_ReallyLR
|
||
|
define void @condbr(ptr %tstaddr) {
|
||
|
%tst = load i1, ptr %tstaddr
|
||
|
br i1 %tst, label %true, label %false
|
||
|
true:
|
||
|
ret void
|
||
|
false:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; Tests for indirect br.
|
||
|
; CHECK-LABEL: name: indirectbr
|
||
|
; CHECK: body:
|
||
|
;
|
||
|
; ABI/constant lowering and IR-level entry basic block.
|
||
|
; CHECK: bb.{{[0-9]+.[a-zA-Z0-9.]+}}:
|
||
|
; Make sure we have one successor
|
||
|
; CHECK-NEXT: successors: %[[BB_L1:bb.[0-9]+]](0x80000000)
|
||
|
;
|
||
|
; Check basic block L1 has 2 successors: BBL1 and BBL2
|
||
|
; CHECK: [[BB_L1]].{{[a-zA-Z0-9.]+}} (ir-block-address-taken %ir-block.{{[a-zA-Z0-9.]+}}):
|
||
|
; CHECK-NEXT: successors: %[[BB_L1]](0x40000000),
|
||
|
; CHECK: %[[BB_L2:bb.[0-9]+]](0x40000000)
|
||
|
; CHECK: G_BRINDIRECT %{{[0-9]+}}(p0)
|
||
|
;
|
||
|
; Check basic block L2 is the return basic block
|
||
|
; CHECK: [[BB_L2]].{{[a-zA-Z0-9.]+}} (ir-block-address-taken %ir-block.{{[a-zA-Z0-9.]+}}):
|
||
|
; CHECK-NEXT: RET_ReallyLR
|
||
|
|
||
|
@indirectbr.L = internal unnamed_addr constant [3 x ptr] [ptr blockaddress(@indirectbr, %L1), ptr blockaddress(@indirectbr, %L2), ptr null], align 8
|
||
|
|
||
|
define void @indirectbr() {
|
||
|
entry:
|
||
|
br label %L1
|
||
|
L1: ; preds = %entry, %L1
|
||
|
%i = phi i32 [ 0, %entry ], [ %inc, %L1 ]
|
||
|
%inc = add i32 %i, 1
|
||
|
%idxprom = zext i32 %i to i64
|
||
|
%arrayidx = getelementptr inbounds [3 x ptr], ptr @indirectbr.L, i64 0, i64 %idxprom
|
||
|
%brtarget = load ptr, ptr %arrayidx, align 8
|
||
|
indirectbr ptr %brtarget, [label %L1, label %L2]
|
||
|
L2: ; preds = %L1
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; Tests for or.
|
||
|
; CHECK-LABEL: name: ori64
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s64) = COPY $x1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s64) = G_OR [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $x0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $x0
|
||
|
define i64 @ori64(i64 %arg1, i64 %arg2) {
|
||
|
%res = or i64 %arg1, %arg2
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: ori32
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_OR [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @ori32(i32 %arg1, i32 %arg2) {
|
||
|
%res = or i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; Tests for xor.
|
||
|
; CHECK-LABEL: name: xori64
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s64) = COPY $x1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s64) = G_XOR [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $x0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $x0
|
||
|
define i64 @xori64(i64 %arg1, i64 %arg2) {
|
||
|
%res = xor i64 %arg1, %arg2
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: xori32
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_XOR [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @xori32(i32 %arg1, i32 %arg2) {
|
||
|
%res = xor i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; Tests for and.
|
||
|
; CHECK-LABEL: name: andi64
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s64) = COPY $x1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s64) = G_AND [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $x0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $x0
|
||
|
define i64 @andi64(i64 %arg1, i64 %arg2) {
|
||
|
%res = and i64 %arg1, %arg2
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: andi32
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_AND [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @andi32(i32 %arg1, i32 %arg2) {
|
||
|
%res = and i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; Tests for sub.
|
||
|
; CHECK-LABEL: name: subi64
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s64) = COPY $x1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s64) = G_SUB [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $x0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $x0
|
||
|
define i64 @subi64(i64 %arg1, i64 %arg2) {
|
||
|
%res = sub i64 %arg1, %arg2
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: subi32
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_SUB [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @subi32(i32 %arg1, i32 %arg2) {
|
||
|
%res = sub i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: ptrtoint
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = G_PTRTOINT [[ARG1]]
|
||
|
; CHECK: $x0 = COPY [[RES]]
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
define i64 @ptrtoint(ptr %a) {
|
||
|
%val = ptrtoint ptr %a to i64
|
||
|
ret i64 %val
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: inttoptr
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(p0) = G_INTTOPTR [[ARG1]]
|
||
|
; CHECK: $x0 = COPY [[RES]]
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
define ptr @inttoptr(i64 %a) {
|
||
|
%val = inttoptr i64 %a to ptr
|
||
|
ret ptr %val
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: trivial_bitcast
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: $x0 = COPY [[ARG1]]
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
define ptr @trivial_bitcast(ptr %a) {
|
||
|
ret ptr %a
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: trivial_bitcast_with_copy
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s64) = COPY $d0
|
||
|
; CHECK: G_BR %[[CAST:bb\.[0-9]+]]
|
||
|
|
||
|
; CHECK: [[END:bb\.[0-9]+]].{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK: $x0 = COPY [[A]]
|
||
|
|
||
|
; CHECK: [[CAST]].{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK: G_BR %[[END]]
|
||
|
define i64 @trivial_bitcast_with_copy(double %a) {
|
||
|
br label %cast
|
||
|
|
||
|
end:
|
||
|
ret i64 %val
|
||
|
|
||
|
cast:
|
||
|
%val = bitcast double %a to i64
|
||
|
br label %end
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: bitcast
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK: [[RES1:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[ARG1]]
|
||
|
; CHECK: [[RES2:%[0-9]+]]:_(s64) = G_BITCAST [[RES1]]
|
||
|
; CHECK: $x0 = COPY [[RES2]]
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
define i64 @bitcast(i64 %a) {
|
||
|
%res1 = bitcast i64 %a to <2 x i32>
|
||
|
%res2 = bitcast <2 x i32> %res1 to i64
|
||
|
ret i64 %res2
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: addrspacecast
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(p1) = COPY $x0
|
||
|
; CHECK: [[RES1:%[0-9]+]]:_(p2) = G_ADDRSPACE_CAST [[ARG1]]
|
||
|
; CHECK: [[RES2:%[0-9]+]]:_(p0) = G_ADDRSPACE_CAST [[RES1]]
|
||
|
; CHECK: $x0 = COPY [[RES2]]
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
define ptr @addrspacecast(ptr addrspace(1) %a) {
|
||
|
%res1 = addrspacecast ptr addrspace(1) %a to ptr addrspace(2)
|
||
|
%res2 = addrspacecast ptr addrspace(2) %res1 to ptr
|
||
|
ret ptr %res2
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: trunc
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<4 x s32>) = G_LOAD
|
||
|
; CHECK: [[RES1:%[0-9]+]]:_(s8) = G_TRUNC [[ARG1]]
|
||
|
; CHECK: [[RES2:%[0-9]+]]:_(<4 x s16>) = G_TRUNC [[VEC]]
|
||
|
define void @trunc(i64 %a) {
|
||
|
%vecptr = alloca <4 x i32>
|
||
|
%vec = load <4 x i32>, ptr %vecptr
|
||
|
%res1 = trunc i64 %a to i8
|
||
|
%res2 = trunc <4 x i32> %vec to <4 x i16>
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: load
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[ADDR42:%[0-9]+]]:_(p42) = COPY $x1
|
||
|
; CHECK: [[VAL1:%[0-9]+]]:_(s64) = G_LOAD [[ADDR]](p0) :: (load (s64) from %ir.addr, align 16)
|
||
|
; CHECK: [[VAL2:%[0-9]+]]:_(s64) = G_LOAD [[ADDR42]](p42) :: (load (s64) from %ir.addr42, addrspace 42)
|
||
|
; CHECK: [[SUM2:%.*]]:_(s64) = G_ADD [[VAL1]], [[VAL2]]
|
||
|
; CHECK: [[VAL3:%[0-9]+]]:_(s64) = G_LOAD [[ADDR]](p0) :: (volatile load (s64) from %ir.addr)
|
||
|
; CHECK: [[SUM3:%[0-9]+]]:_(s64) = G_ADD [[SUM2]], [[VAL3]]
|
||
|
; CHECK: [[VAL4:%[0-9]+]]:_(s64) = G_LOAD [[ADDR]](p0) :: (load (s64) from %ir.addr, !range !0)
|
||
|
; CHECK: [[SUM4:%[0-9]+]]:_(s64) = G_ADD [[SUM3]], [[VAL4]]
|
||
|
; CHECK: $x0 = COPY [[SUM4]]
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
define i64 @load(ptr %addr, ptr addrspace(42) %addr42) {
|
||
|
%val1 = load i64, ptr %addr, align 16
|
||
|
|
||
|
%val2 = load i64, ptr addrspace(42) %addr42
|
||
|
%sum2 = add i64 %val1, %val2
|
||
|
|
||
|
%val3 = load volatile i64, ptr %addr
|
||
|
%sum3 = add i64 %sum2, %val3
|
||
|
|
||
|
%val4 = load i64, ptr %addr, !range !0
|
||
|
%sum4 = add i64 %sum3, %val4
|
||
|
ret i64 %sum4
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: store
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[ADDR42:%[0-9]+]]:_(p42) = COPY $x1
|
||
|
; CHECK: [[VAL1:%[0-9]+]]:_(s64) = COPY $x2
|
||
|
; CHECK: [[VAL2:%[0-9]+]]:_(s64) = COPY $x3
|
||
|
; CHECK: G_STORE [[VAL1]](s64), [[ADDR]](p0) :: (store (s64) into %ir.addr, align 16)
|
||
|
; CHECK: G_STORE [[VAL2]](s64), [[ADDR42]](p42) :: (store (s64) into %ir.addr42, addrspace 42)
|
||
|
; CHECK: G_STORE [[VAL1]](s64), [[ADDR]](p0) :: (volatile store (s64) into %ir.addr)
|
||
|
; CHECK: RET_ReallyLR
|
||
|
define void @store(ptr %addr, ptr addrspace(42) %addr42, i64 %val1, i64 %val2) {
|
||
|
store i64 %val1, ptr %addr, align 16
|
||
|
store i64 %val2, ptr addrspace(42) %addr42
|
||
|
store volatile i64 %val1, ptr %addr
|
||
|
%sum = add i64 %val1, %val2
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: intrinsics
|
||
|
; CHECK: [[CUR:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[BITS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[PTR:%[0-9]+]]:_(p0) = G_INTRINSIC intrinsic(@llvm.returnaddress), 0
|
||
|
; CHECK: [[PTR_VEC:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.ptr.vec
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<8 x s8>) = G_LOAD [[PTR_VEC]]
|
||
|
; CHECK: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.neon.st2), [[VEC]](<8 x s8>), [[VEC]](<8 x s8>), [[PTR]](p0)
|
||
|
; CHECK: RET_ReallyLR
|
||
|
declare ptr @llvm.returnaddress(i32)
|
||
|
declare void @llvm.aarch64.neon.st2.v8i8.p0(<8 x i8>, <8 x i8>, ptr)
|
||
|
declare { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld2.v8i8.p0(ptr)
|
||
|
define void @intrinsics(i32 %cur, i32 %bits) {
|
||
|
%ptr = call ptr @llvm.returnaddress(i32 0)
|
||
|
%ptr.vec = alloca <8 x i8>
|
||
|
%vec = load <8 x i8>, ptr %ptr.vec
|
||
|
call void @llvm.aarch64.neon.st2.v8i8.p0(<8 x i8> %vec, <8 x i8> %vec, ptr %ptr)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_phi
|
||
|
; CHECK: G_BRCOND {{%.*}}, %[[TRUE:bb\.[0-9]+]]
|
||
|
; CHECK: G_BR %[[FALSE:bb\.[0-9]+]]
|
||
|
|
||
|
; CHECK: [[TRUE]].{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK: [[RES1:%[0-9]+]]:_(s32) = G_LOAD
|
||
|
|
||
|
; CHECK: [[FALSE]].{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK: [[RES2:%[0-9]+]]:_(s32) = G_LOAD
|
||
|
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_PHI [[RES1]](s32), %[[TRUE]], [[RES2]](s32), %[[FALSE]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
define i32 @test_phi(ptr %addr1, ptr %addr2, i1 %tst) {
|
||
|
br i1 %tst, label %true, label %false
|
||
|
|
||
|
true:
|
||
|
%res1 = load i32, ptr %addr1
|
||
|
br label %end
|
||
|
|
||
|
false:
|
||
|
%res2 = load i32, ptr %addr2
|
||
|
br label %end
|
||
|
|
||
|
end:
|
||
|
%res = phi i32 [%res1, %true], [%res2, %false]
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: unreachable
|
||
|
; CHECK: G_ADD
|
||
|
; CHECK-NEXT: {{^$}}
|
||
|
; CHECK-NEXT: ...
|
||
|
define void @unreachable(i32 %a) {
|
||
|
%sum = add i32 %a, %a
|
||
|
unreachable
|
||
|
}
|
||
|
|
||
|
; It's important that constants are after argument passing, but before the
|
||
|
; rest of the entry block.
|
||
|
; CHECK-LABEL: name: constant_int
|
||
|
; CHECK: [[IN:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[ONE:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
|
||
|
; CHECK: bb.{{[0-9]+}}.{{[a-zA-Z0-9.]+}}:
|
||
|
; CHECK: [[SUM1:%[0-9]+]]:_(s32) = G_ADD [[IN]], [[ONE]]
|
||
|
; CHECK: [[SUM2:%[0-9]+]]:_(s32) = G_ADD [[IN]], [[ONE]]
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_ADD [[SUM1]], [[SUM2]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
|
||
|
define i32 @constant_int(i32 %in) {
|
||
|
br label %next
|
||
|
|
||
|
next:
|
||
|
%sum1 = add i32 %in, 1
|
||
|
%sum2 = add i32 %in, 1
|
||
|
%res = add i32 %sum1, %sum2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: constant_int_start
|
||
|
; CHECK: [[TWO:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
|
||
|
; CHECK: [[ANSWER:%[0-9]+]]:_(s32) = G_CONSTANT i32 42
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_CONSTANT i32 44
|
||
|
define i32 @constant_int_start() {
|
||
|
%res = add i32 2, 42
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_undef
|
||
|
; CHECK: [[UNDEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
|
||
|
; CHECK: $w0 = COPY [[UNDEF]]
|
||
|
define i32 @test_undef() {
|
||
|
ret i32 undef
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_constant_inttoptr
|
||
|
; CHECK: [[ONE:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
|
||
|
; CHECK: [[PTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[ONE]]
|
||
|
; CHECK: $x0 = COPY [[PTR]]
|
||
|
define ptr @test_constant_inttoptr() {
|
||
|
ret ptr inttoptr(i64 1 to ptr)
|
||
|
}
|
||
|
|
||
|
; This failed purely because the Constant -> VReg map was kept across
|
||
|
; functions, so reuse the "i64 1" from above.
|
||
|
; CHECK-LABEL: name: test_reused_constant
|
||
|
; CHECK: [[ONE:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
|
||
|
; CHECK: $x0 = COPY [[ONE]]
|
||
|
define i64 @test_reused_constant() {
|
||
|
ret i64 1
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_sext
|
||
|
; CHECK: [[IN:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = G_SEXT [[IN]]
|
||
|
; CHECK: $x0 = COPY [[RES]]
|
||
|
define i64 @test_sext(i32 %in) {
|
||
|
%res = sext i32 %in to i64
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_zext
|
||
|
; CHECK: [[IN:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = G_ZEXT [[IN]]
|
||
|
; CHECK: $x0 = COPY [[RES]]
|
||
|
define i64 @test_zext(i32 %in) {
|
||
|
%res = zext i32 %in to i64
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_shl
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_SHL [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @test_shl(i32 %arg1, i32 %arg2) {
|
||
|
%res = shl i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
|
||
|
; CHECK-LABEL: name: test_lshr
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_LSHR [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @test_lshr(i32 %arg1, i32 %arg2) {
|
||
|
%res = lshr i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_ashr
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_ASHR [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @test_ashr(i32 %arg1, i32 %arg2) {
|
||
|
%res = ashr i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_sdiv
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_SDIV [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @test_sdiv(i32 %arg1, i32 %arg2) {
|
||
|
%res = sdiv i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_udiv
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_UDIV [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @test_udiv(i32 %arg1, i32 %arg2) {
|
||
|
%res = udiv i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_srem
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_SREM [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @test_srem(i32 %arg1, i32 %arg2) {
|
||
|
%res = srem i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_urem
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_UREM [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0
|
||
|
define i32 @test_urem(i32 %arg1, i32 %arg2) {
|
||
|
%res = urem i32 %arg1, %arg2
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_constant_null
|
||
|
; CHECK: [[NULL:%[0-9]+]]:_(p0) = G_CONSTANT i64 0
|
||
|
; CHECK: $x0 = COPY [[NULL]]
|
||
|
define ptr @test_constant_null() {
|
||
|
ret ptr null
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_struct_memops
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[VAL1:%[0-9]+]]:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr, align 4)
|
||
|
; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_PTR_ADD [[ADDR]], [[CST1]](s64)
|
||
|
; CHECK: [[VAL2:%[0-9]+]]:_(s32) = G_LOAD [[GEP1]](p0) :: (load (s32) from %ir.addr + 4)
|
||
|
; CHECK: G_STORE [[VAL1]](s8), [[ADDR]](p0) :: (store (s8) into %ir.addr, align 4)
|
||
|
; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_PTR_ADD [[ADDR]], [[CST1]](s64)
|
||
|
; CHECK: G_STORE [[VAL2]](s32), [[GEP2]](p0) :: (store (s32) into %ir.addr + 4)
|
||
|
define void @test_struct_memops(ptr %addr) {
|
||
|
%val = load { i8, i32 }, ptr %addr
|
||
|
store { i8, i32 } %val, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_i1_memops
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s1) = G_LOAD [[ADDR]](p0) :: (load (s1) from %ir.addr)
|
||
|
; CHECK: G_STORE [[VAL]](s1), [[ADDR]](p0) :: (store (s1) into %ir.addr)
|
||
|
define void @test_i1_memops(ptr %addr) {
|
||
|
%val = load i1, ptr %addr
|
||
|
store i1 %val, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: int_comparison
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[TST:%[0-9]+]]:_(s1) = G_ICMP intpred(ne), [[LHS]](s32), [[RHS]]
|
||
|
; CHECK: G_STORE [[TST]](s1), [[ADDR]](p0)
|
||
|
define void @int_comparison(i32 %a, i32 %b, ptr %addr) {
|
||
|
%res = icmp ne i32 %a, %b
|
||
|
store i1 %res, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: ptr_comparison
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(p0) = COPY $x1
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[TST:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), [[LHS]](p0), [[RHS]]
|
||
|
; CHECK: G_STORE [[TST]](s1), [[ADDR]](p0)
|
||
|
define void @ptr_comparison(ptr %a, ptr %b, ptr %addr) {
|
||
|
%res = icmp eq ptr %a, %b
|
||
|
store i1 %res, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_fadd
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_FADD [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $s0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $s0
|
||
|
define float @test_fadd(float %arg1, float %arg2) {
|
||
|
%res = fadd float %arg1, %arg2
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_fsub
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_FSUB [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $s0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $s0
|
||
|
define float @test_fsub(float %arg1, float %arg2) {
|
||
|
%res = fsub float %arg1, %arg2
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_fmul
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_FMUL [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $s0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $s0
|
||
|
define float @test_fmul(float %arg1, float %arg2) {
|
||
|
%res = fmul float %arg1, %arg2
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_fdiv
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_FDIV [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $s0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $s0
|
||
|
define float @test_fdiv(float %arg1, float %arg2) {
|
||
|
%res = fdiv float %arg1, %arg2
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_frem
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK-NEXT: [[ARG2:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s32) = G_FREM [[ARG1]], [[ARG2]]
|
||
|
; CHECK-NEXT: $s0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $s0
|
||
|
define float @test_frem(float %arg1, float %arg2) {
|
||
|
%res = frem float %arg1, %arg2
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_sadd_overflow
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_SADDO [[LHS]], [[RHS]]
|
||
|
; CHECK: G_STORE [[VAL]](s32), [[ADDR]](p0) :: (store (s32) into %ir.addr)
|
||
|
; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_PTR_ADD [[ADDR]], [[CST]](s64)
|
||
|
; CHECK: G_STORE [[OVERFLOW]](s1), [[GEP]](p0) :: (store (s1) into %ir.addr + 4, align 4)
|
||
|
declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32)
|
||
|
define void @test_sadd_overflow(i32 %lhs, i32 %rhs, ptr %addr) {
|
||
|
%res = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %lhs, i32 %rhs)
|
||
|
store { i32, i1 } %res, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_uadd_overflow
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_UADDO [[LHS]], [[RHS]]
|
||
|
; CHECK: G_STORE [[VAL]](s32), [[ADDR]](p0) :: (store (s32) into %ir.addr)
|
||
|
; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_PTR_ADD [[ADDR]], [[CST]](s64)
|
||
|
; CHECK: G_STORE [[OVERFLOW]](s1), [[GEP]](p0) :: (store (s1) into %ir.addr + 4, align 4)
|
||
|
declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32)
|
||
|
define void @test_uadd_overflow(i32 %lhs, i32 %rhs, ptr %addr) {
|
||
|
%res = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %lhs, i32 %rhs)
|
||
|
store { i32, i1 } %res, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_ssub_overflow
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_SSUBO [[LHS]], [[RHS]]
|
||
|
; CHECK: G_STORE [[VAL]](s32), [[ADDR]](p0) :: (store (s32) into %ir.subr)
|
||
|
; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_PTR_ADD [[ADDR]], [[CST]](s64)
|
||
|
; CHECK: G_STORE [[OVERFLOW]](s1), [[GEP]](p0) :: (store (s1) into %ir.subr + 4, align 4)
|
||
|
declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32)
|
||
|
define void @test_ssub_overflow(i32 %lhs, i32 %rhs, ptr %subr) {
|
||
|
%res = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %lhs, i32 %rhs)
|
||
|
store { i32, i1 } %res, ptr %subr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_usub_overflow
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_USUBO [[LHS]], [[RHS]]
|
||
|
; CHECK: G_STORE [[VAL]](s32), [[ADDR]](p0) :: (store (s32) into %ir.subr)
|
||
|
; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_PTR_ADD [[ADDR]], [[CST]](s64)
|
||
|
; CHECK: G_STORE [[OVERFLOW]](s1), [[GEP]](p0) :: (store (s1) into %ir.subr + 4, align 4)
|
||
|
declare { i32, i1 } @llvm.usub.with.overflow.i32(i32, i32)
|
||
|
define void @test_usub_overflow(i32 %lhs, i32 %rhs, ptr %subr) {
|
||
|
%res = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %lhs, i32 %rhs)
|
||
|
store { i32, i1 } %res, ptr %subr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_smul_overflow
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_SMULO [[LHS]], [[RHS]]
|
||
|
; CHECK: G_STORE [[VAL]](s32), [[ADDR]](p0) :: (store (s32) into %ir.addr)
|
||
|
; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_PTR_ADD [[ADDR]], [[CST]](s64)
|
||
|
; CHECK: G_STORE [[OVERFLOW]](s1), [[GEP]](p0) :: (store (s1) into %ir.addr + 4, align 4)
|
||
|
declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32)
|
||
|
define void @test_smul_overflow(i32 %lhs, i32 %rhs, ptr %addr) {
|
||
|
%res = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %lhs, i32 %rhs)
|
||
|
store { i32, i1 } %res, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_umul_overflow
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_UMULO [[LHS]], [[RHS]]
|
||
|
; CHECK: G_STORE [[VAL]](s32), [[ADDR]](p0) :: (store (s32) into %ir.addr)
|
||
|
; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_PTR_ADD [[ADDR]], [[CST]](s64)
|
||
|
; CHECK: G_STORE [[OVERFLOW]](s1), [[GEP]](p0) :: (store (s1) into %ir.addr + 4, align 4)
|
||
|
declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32)
|
||
|
define void @test_umul_overflow(i32 %lhs, i32 %rhs, ptr %addr) {
|
||
|
%res = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %lhs, i32 %rhs)
|
||
|
store { i32, i1 } %res, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_extractvalue
|
||
|
; CHECK: %0:_(p0) = COPY $x0
|
||
|
; CHECK: [[LD1:%[0-9]+]]:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr, align 4)
|
||
|
; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST1]](s64)
|
||
|
; CHECK: [[LD2:%[0-9]+]]:_(s8) = G_LOAD [[GEP1]](p0) :: (load (s8) from %ir.addr + 4, align 4)
|
||
|
; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||
|
; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST2]](s64)
|
||
|
; CHECK: [[LD3:%[0-9]+]]:_(s32) = G_LOAD [[GEP2]](p0) :: (load (s32) from %ir.addr + 8)
|
||
|
; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 12
|
||
|
; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST3]](s64)
|
||
|
; CHECK: [[LD4:%[0-9]+]]:_(s32) = G_LOAD [[GEP3]](p0) :: (load (s32) from %ir.addr + 12)
|
||
|
; CHECK: $w0 = COPY [[LD3]](s32)
|
||
|
%struct.nested = type {i8, { i8, i32 }, i32}
|
||
|
define i32 @test_extractvalue(ptr %addr) {
|
||
|
%struct = load %struct.nested, ptr %addr
|
||
|
%res = extractvalue %struct.nested %struct, 1, 1
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_extractvalue_agg
|
||
|
; CHECK: %0:_(p0) = COPY $x0
|
||
|
; CHECK: %1:_(p0) = COPY $x1
|
||
|
; CHECK: [[LD1:%[0-9]+]]:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr, align 4)
|
||
|
; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST1]](s64)
|
||
|
; CHECK: [[LD2:%[0-9]+]]:_(s8) = G_LOAD [[GEP1]](p0) :: (load (s8) from %ir.addr + 4, align 4)
|
||
|
; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||
|
; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST2]](s64)
|
||
|
; CHECK: [[LD3:%[0-9]+]]:_(s32) = G_LOAD [[GEP2]](p0) :: (load (s32) from %ir.addr + 8)
|
||
|
; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 12
|
||
|
; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST3]](s64)
|
||
|
; CHECK: [[LD4:%[0-9]+]]:_(s32) = G_LOAD [[GEP3]](p0) :: (load (s32) from %ir.addr + 12)
|
||
|
; CHECK: G_STORE [[LD2]](s8), %1(p0) :: (store (s8) into %ir.addr2, align 4)
|
||
|
; CHECK: [[GEP4:%[0-9]+]]:_(p0) = G_PTR_ADD %1, [[CST1]](s64)
|
||
|
; CHECK: G_STORE [[LD3]](s32), [[GEP4]](p0) :: (store (s32) into %ir.addr2 + 4)
|
||
|
define void @test_extractvalue_agg(ptr %addr, ptr %addr2) {
|
||
|
%struct = load %struct.nested, ptr %addr
|
||
|
%res = extractvalue %struct.nested %struct, 1
|
||
|
store {i8, i32} %res, ptr %addr2
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_trivial_extract_ptr
|
||
|
; CHECK: [[STRUCT:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[VAL32:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_TRUNC [[VAL32]]
|
||
|
; CHECK: G_STORE [[VAL]](s8), [[STRUCT]](p0)
|
||
|
define void @test_trivial_extract_ptr([1 x ptr] %s, i8 %val) {
|
||
|
%addr = extractvalue [1 x ptr] %s, 0
|
||
|
store i8 %val, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_insertvalue
|
||
|
; CHECK: %0:_(p0) = COPY $x0
|
||
|
; CHECK: %1:_(s32) = COPY $w1
|
||
|
; CHECK: [[LD1:%[0-9]+]]:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr, align 4)
|
||
|
; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST1]](s64)
|
||
|
; CHECK: [[LD2:%[0-9]+]]:_(s8) = G_LOAD [[GEP1]](p0) :: (load (s8) from %ir.addr + 4, align 4)
|
||
|
; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||
|
; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST2]](s64)
|
||
|
; CHECK: [[LD3:%[0-9]+]]:_(s32) = G_LOAD [[GEP2]](p0) :: (load (s32) from %ir.addr + 8)
|
||
|
; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 12
|
||
|
; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST3]](s64)
|
||
|
; CHECK: [[LD4:%[0-9]+]]:_(s32) = G_LOAD [[GEP3]](p0) :: (load (s32) from %ir.addr + 12)
|
||
|
; CHECK: G_STORE [[LD1]](s8), %0(p0) :: (store (s8) into %ir.addr, align 4)
|
||
|
; CHECK: [[GEP4:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST1]](s64)
|
||
|
; CHECK: G_STORE [[LD2]](s8), [[GEP4]](p0) :: (store (s8) into %ir.addr + 4, align 4)
|
||
|
; CHECK: [[GEP5:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST2]](s64)
|
||
|
; CHECK: G_STORE %1(s32), [[GEP5]](p0) :: (store (s32) into %ir.addr + 8)
|
||
|
; CHECK: [[GEP6:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST3]](s64)
|
||
|
; CHECK: G_STORE [[LD4]](s32), [[GEP6]](p0) :: (store (s32) into %ir.addr + 12)
|
||
|
define void @test_insertvalue(ptr %addr, i32 %val) {
|
||
|
%struct = load %struct.nested, ptr %addr
|
||
|
%newstruct = insertvalue %struct.nested %struct, i32 %val, 1, 1
|
||
|
store %struct.nested %newstruct, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define [1 x i64] @test_trivial_insert([1 x i64] %s, i64 %val) {
|
||
|
; CHECK-LABEL: name: test_trivial_insert
|
||
|
; CHECK: [[STRUCT:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s64) = COPY $x1
|
||
|
; CHECK: $x0 = COPY [[VAL]]
|
||
|
%res = insertvalue [1 x i64] %s, i64 %val, 0
|
||
|
ret [1 x i64] %res
|
||
|
}
|
||
|
|
||
|
define [1 x ptr] @test_trivial_insert_ptr([1 x ptr] %s, ptr %val) {
|
||
|
; CHECK-LABEL: name: test_trivial_insert_ptr
|
||
|
; CHECK: [[STRUCT:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(p0) = COPY $x1
|
||
|
; CHECK: $x0 = COPY [[VAL]]
|
||
|
%res = insertvalue [1 x ptr] %s, ptr %val, 0
|
||
|
ret [1 x ptr] %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_insertvalue_agg
|
||
|
; CHECK: %0:_(p0) = COPY $x0
|
||
|
; CHECK: %1:_(p0) = COPY $x1
|
||
|
; CHECK: [[LD1:%[0-9]+]]:_(s8) = G_LOAD %1(p0) :: (load (s8) from %ir.addr2, align 4)
|
||
|
; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_PTR_ADD %1, [[CST1]](s64)
|
||
|
; CHECK: [[LD2:%[0-9]+]]:_(s32) = G_LOAD [[GEP1]](p0) :: (load (s32) from %ir.addr2 + 4)
|
||
|
; CHECK: [[LD3:%[0-9]+]]:_(s8) = G_LOAD %0(p0) :: (load (s8) from %ir.addr, align 4)
|
||
|
; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST1]](s64)
|
||
|
; CHECK: [[LD4:%[0-9]+]]:_(s8) = G_LOAD [[GEP2]](p0) :: (load (s8) from %ir.addr + 4, align 4)
|
||
|
; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||
|
; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST3]](s64)
|
||
|
; CHECK: [[LD5:%[0-9]+]]:_(s32) = G_LOAD [[GEP3]](p0) :: (load (s32) from %ir.addr + 8)
|
||
|
; CHECK: [[CST4:%[0-9]+]]:_(s64) = G_CONSTANT i64 12
|
||
|
; CHECK: [[GEP4:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST4]](s64)
|
||
|
; CHECK: [[LD6:%[0-9]+]]:_(s32) = G_LOAD [[GEP4]](p0) :: (load (s32) from %ir.addr + 12)
|
||
|
; CHECK: G_STORE [[LD3]](s8), %0(p0) :: (store (s8) into %ir.addr, align 4)
|
||
|
; CHECK: [[GEP5:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST1]](s64)
|
||
|
; CHECK: G_STORE [[LD1]](s8), [[GEP5]](p0) :: (store (s8) into %ir.addr + 4, align 4)
|
||
|
; CHECK: [[GEP6:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST3]](s64)
|
||
|
; CHECK: G_STORE [[LD2]](s32), [[GEP6]](p0) :: (store (s32) into %ir.addr + 8)
|
||
|
; CHECK: [[GEP7:%[0-9]+]]:_(p0) = G_PTR_ADD %0, [[CST4]](s64)
|
||
|
; CHECK: G_STORE [[LD6]](s32), [[GEP7]](p0) :: (store (s32) into %ir.addr + 12)
|
||
|
define void @test_insertvalue_agg(ptr %addr, ptr %addr2) {
|
||
|
%smallstruct = load {i8, i32}, ptr %addr2
|
||
|
%struct = load %struct.nested, ptr %addr
|
||
|
%res = insertvalue %struct.nested %struct, {i8, i32} %smallstruct, 1
|
||
|
store %struct.nested %res, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_select
|
||
|
; CHECK: [[TST_C:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[TSTEXT:%[0-9]+]]:_(s8) = G_TRUNC [[TST_C]]
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w2
|
||
|
; CHECK: [[TSTASSERT:%[0-9]+]]:_(s8) = G_ASSERT_ZEXT [[TSTEXT]], 1
|
||
|
; CHECK: [[TST:%[0-9]+]]:_(s1) = G_TRUNC [[TSTASSERT]]
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_SELECT [[TST]](s1), [[LHS]], [[RHS]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
define i32 @test_select(i1 %tst, i32 %lhs, i32 %rhs) {
|
||
|
%res = select i1 %tst, i32 %lhs, i32 %rhs
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_select_flags
|
||
|
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[TRUNC8:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]]
|
||
|
; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK: [[TRUNCASSERT:%[0-9]+]]:_(s8) = G_ASSERT_ZEXT [[TRUNC8]], 1
|
||
|
; CHECK: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[TRUNCASSERT]]
|
||
|
; CHECK: [[SELECT:%[0-9]+]]:_(s32) = nnan G_SELECT [[TRUNC]](s1), [[COPY1]], [[COPY2]]
|
||
|
define float @test_select_flags(i1 %tst, float %lhs, float %rhs) {
|
||
|
%res = select nnan i1 %tst, float %lhs, float %rhs
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
; Don't take the flags from the compare condition
|
||
|
; CHECK-LABEL: name: test_select_cmp_flags
|
||
|
; CHECK: [[COPY0:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY $s2
|
||
|
; CHECK: [[COPY3:%[0-9]+]]:_(s32) = COPY $s3
|
||
|
; CHECK: [[CMP:%[0-9]+]]:_(s1) = nsz G_FCMP floatpred(oeq), [[COPY0]](s32), [[COPY1]]
|
||
|
; CHECK: [[SELECT:%[0-9]+]]:_(s32) = G_SELECT [[CMP]](s1), [[COPY2]], [[COPY3]]
|
||
|
define float @test_select_cmp_flags(float %cmp0, float %cmp1, float %lhs, float %rhs) {
|
||
|
%tst = fcmp nsz oeq float %cmp0, %cmp1
|
||
|
%res = select i1 %tst, float %lhs, float %rhs
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_select_ptr
|
||
|
; CHECK: [[TST_C:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[TSTEXT:%[0-9]+]]:_(s8) = G_TRUNC [[TST_C]]
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(p0) = COPY $x1
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[TSTASSERT:%[0-9]+]]:_(s8) = G_ASSERT_ZEXT [[TSTEXT]], 1
|
||
|
; CHECK: [[TST:%[0-9]+]]:_(s1) = G_TRUNC [[TSTASSERT]]
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(p0) = G_SELECT [[TST]](s1), [[LHS]], [[RHS]]
|
||
|
; CHECK: $x0 = COPY [[RES]]
|
||
|
define ptr @test_select_ptr(i1 %tst, ptr %lhs, ptr %rhs) {
|
||
|
%res = select i1 %tst, ptr %lhs, ptr %rhs
|
||
|
ret ptr %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_select_vec
|
||
|
; CHECK: [[TST_C:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[TSTEXT:%[0-9]+]]:_(s8) = G_TRUNC [[TST_C]]
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(<4 x s32>) = COPY $q0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(<4 x s32>) = COPY $q1
|
||
|
; CHECK: [[TSTASSERT:%[0-9]+]]:_(s8) = G_ASSERT_ZEXT [[TSTEXT]], 1
|
||
|
; CHECK: [[TST:%[0-9]+]]:_(s1) = G_TRUNC [[TSTASSERT]]
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(<4 x s32>) = G_SELECT [[TST]](s1), [[LHS]], [[RHS]]
|
||
|
; CHECK: $q0 = COPY [[RES]]
|
||
|
define <4 x i32> @test_select_vec(i1 %tst, <4 x i32> %lhs, <4 x i32> %rhs) {
|
||
|
%res = select i1 %tst, <4 x i32> %lhs, <4 x i32> %rhs
|
||
|
ret <4 x i32> %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_vselect_vec
|
||
|
; CHECK: [[TST32:%[0-9]+]]:_(<4 x s32>) = COPY $q0
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(<4 x s32>) = COPY $q1
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(<4 x s32>) = COPY $q2
|
||
|
; CHECK: [[TST:%[0-9]+]]:_(<4 x s1>) = G_TRUNC [[TST32]](<4 x s32>)
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(<4 x s32>) = G_SELECT [[TST]](<4 x s1>), [[LHS]], [[RHS]]
|
||
|
; CHECK: $q0 = COPY [[RES]]
|
||
|
define <4 x i32> @test_vselect_vec(<4 x i32> %tst32, <4 x i32> %lhs, <4 x i32> %rhs) {
|
||
|
%tst = trunc <4 x i32> %tst32 to <4 x i1>
|
||
|
%res = select <4 x i1> %tst, <4 x i32> %lhs, <4 x i32> %rhs
|
||
|
ret <4 x i32> %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_fptosi
|
||
|
; CHECK: [[FPADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[FP:%[0-9]+]]:_(s32) = G_LOAD [[FPADDR]](p0)
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = G_FPTOSI [[FP]](s32)
|
||
|
; CHECK: $x0 = COPY [[RES]]
|
||
|
define i64 @test_fptosi(ptr %fp.addr) {
|
||
|
%fp = load float, ptr %fp.addr
|
||
|
%res = fptosi float %fp to i64
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_fptoui
|
||
|
; CHECK: [[FPADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[FP:%[0-9]+]]:_(s32) = G_LOAD [[FPADDR]](p0)
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = G_FPTOUI [[FP]](s32)
|
||
|
; CHECK: $x0 = COPY [[RES]]
|
||
|
define i64 @test_fptoui(ptr %fp.addr) {
|
||
|
%fp = load float, ptr %fp.addr
|
||
|
%res = fptoui float %fp to i64
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_sitofp
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[IN:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[FP:%[0-9]+]]:_(s64) = G_SITOFP [[IN]](s32)
|
||
|
; CHECK: G_STORE [[FP]](s64), [[ADDR]](p0)
|
||
|
define void @test_sitofp(ptr %addr, i32 %in) {
|
||
|
%fp = sitofp i32 %in to double
|
||
|
store double %fp, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_uitofp
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[IN:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[FP:%[0-9]+]]:_(s64) = G_UITOFP [[IN]](s32)
|
||
|
; CHECK: G_STORE [[FP]](s64), [[ADDR]](p0)
|
||
|
define void @test_uitofp(ptr %addr, i32 %in) {
|
||
|
%fp = uitofp i32 %in to double
|
||
|
store double %fp, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_fpext
|
||
|
; CHECK: [[IN:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = G_FPEXT [[IN]](s32)
|
||
|
; CHECK: $d0 = COPY [[RES]]
|
||
|
define double @test_fpext(float %in) {
|
||
|
%res = fpext float %in to double
|
||
|
ret double %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_fptrunc
|
||
|
; CHECK: [[IN:%[0-9]+]]:_(s64) = COPY $d0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_FPTRUNC [[IN]](s64)
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
define float @test_fptrunc(double %in) {
|
||
|
%res = fptrunc double %in to float
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_constant_float
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[TMP:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.500000e+00
|
||
|
; CHECK: G_STORE [[TMP]](s32), [[ADDR]](p0)
|
||
|
define void @test_constant_float(ptr %addr) {
|
||
|
store float 1.5, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: float_comparison
|
||
|
; CHECK: [[LHSADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[RHSADDR:%[0-9]+]]:_(p0) = COPY $x1
|
||
|
; CHECK: [[BOOLADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = G_LOAD [[LHSADDR]](p0)
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = G_LOAD [[RHSADDR]](p0)
|
||
|
; CHECK: [[TST:%[0-9]+]]:_(s1) = nnan ninf nsz arcp contract afn reassoc G_FCMP floatpred(oge), [[LHS]](s32), [[RHS]]
|
||
|
; CHECK: G_STORE [[TST]](s1), [[BOOLADDR]](p0)
|
||
|
define void @float_comparison(ptr %a.addr, ptr %b.addr, ptr %bool.addr) {
|
||
|
%a = load float, ptr %a.addr
|
||
|
%b = load float, ptr %b.addr
|
||
|
%res = fcmp nnan ninf nsz arcp contract afn reassoc oge float %a, %b
|
||
|
store i1 %res, ptr %bool.addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: trivial_float_comparison
|
||
|
; CHECK: [[ENTRY_R1:%[0-9]+]]:_(s1) = G_CONSTANT i1 false
|
||
|
; CHECK: [[ENTRY_R2:%[0-9]+]]:_(s1) = G_CONSTANT i1 true
|
||
|
; CHECK: [[R1:%[0-9]+]]:_(s1) = COPY [[ENTRY_R1]](s1)
|
||
|
; CHECK: [[R2:%[0-9]+]]:_(s1) = COPY [[ENTRY_R2]](s1)
|
||
|
; CHECK: G_ADD [[R1]], [[R2]]
|
||
|
define i1 @trivial_float_comparison(double %a, double %b) {
|
||
|
%r1 = fcmp false double %a, %b
|
||
|
%r2 = fcmp true double %a, %b
|
||
|
%sum = add i1 %r1, %r2
|
||
|
ret i1 %sum
|
||
|
}
|
||
|
|
||
|
@var = global i32 0
|
||
|
|
||
|
define ptr @test_global() {
|
||
|
; CHECK-LABEL: name: test_global
|
||
|
; CHECK: [[TMP:%[0-9]+]]:_(p0) = G_GLOBAL_VALUE @var{{$}}
|
||
|
; CHECK: $x0 = COPY [[TMP]](p0)
|
||
|
|
||
|
ret ptr @var
|
||
|
}
|
||
|
|
||
|
@var1 = addrspace(42) global i32 0
|
||
|
define ptr addrspace(42) @test_global_addrspace() {
|
||
|
; CHECK-LABEL: name: test_global
|
||
|
; CHECK: [[TMP:%[0-9]+]]:_(p42) = G_GLOBAL_VALUE @var1{{$}}
|
||
|
; CHECK: $x0 = COPY [[TMP]](p42)
|
||
|
|
||
|
ret ptr addrspace(42) @var1
|
||
|
}
|
||
|
|
||
|
|
||
|
define ptr @test_global_func() {
|
||
|
; CHECK-LABEL: name: test_global_func
|
||
|
; CHECK: [[TMP:%[0-9]+]]:_(p0) = G_GLOBAL_VALUE @allocai64{{$}}
|
||
|
; CHECK: $x0 = COPY [[TMP]](p0)
|
||
|
|
||
|
ret ptr @allocai64
|
||
|
}
|
||
|
|
||
|
declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
|
||
|
define void @test_memcpy(ptr %dst, ptr %src, i64 %size) {
|
||
|
; CHECK-LABEL: name: test_memcpy
|
||
|
; CHECK: [[DST:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[SRC:%[0-9]+]]:_(p0) = COPY $x1
|
||
|
; CHECK: [[SIZE:%[0-9]+]]:_(s64) = COPY $x2
|
||
|
; CHECK: G_MEMCPY [[DST]](p0), [[SRC]](p0), [[SIZE]](s64), 0 :: (store (s8) into %ir.dst), (load (s8) from %ir.src)
|
||
|
call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 %size, i1 0)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define void @test_memcpy_tail(ptr %dst, ptr %src, i64 %size) {
|
||
|
; CHECK-LABEL: name: test_memcpy_tail
|
||
|
; CHECK: [[DST:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[SRC:%[0-9]+]]:_(p0) = COPY $x1
|
||
|
; CHECK: [[SIZE:%[0-9]+]]:_(s64) = COPY $x2
|
||
|
; CHECK: G_MEMCPY [[DST]](p0), [[SRC]](p0), [[SIZE]](s64), 1 :: (store (s8) into %ir.dst), (load (s8) from %ir.src)
|
||
|
tail call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 %size, i1 0)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare void @llvm.memcpy.p1.p1.i64(ptr addrspace(1), ptr addrspace(1), i64, i1)
|
||
|
define void @test_memcpy_nonzero_as(ptr addrspace(1) %dst, ptr addrspace(1) %src, i64 %size) {
|
||
|
; CHECK-LABEL: name: test_memcpy_nonzero_as
|
||
|
; CHECK: [[DST:%[0-9]+]]:_(p1) = COPY $x0
|
||
|
; CHECK: [[SRC:%[0-9]+]]:_(p1) = COPY $x1
|
||
|
; CHECK: [[SIZE:%[0-9]+]]:_(s64) = COPY $x2
|
||
|
; CHECK: G_MEMCPY [[DST]](p1), [[SRC]](p1), [[SIZE]](s64), 0 :: (store (s8) into %ir.dst, addrspace 1), (load (s8) from %ir.src, addrspace 1)
|
||
|
call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dst, ptr addrspace(1) %src, i64 %size, i1 0)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare void @llvm.memmove.p0.p0.i64(ptr, ptr, i64, i1)
|
||
|
define void @test_memmove(ptr %dst, ptr %src, i64 %size) {
|
||
|
; CHECK-LABEL: name: test_memmove
|
||
|
; CHECK: [[DST:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[SRC:%[0-9]+]]:_(p0) = COPY $x1
|
||
|
; CHECK: [[SIZE:%[0-9]+]]:_(s64) = COPY $x2
|
||
|
; CHECK: G_MEMMOVE [[DST]](p0), [[SRC]](p0), [[SIZE]](s64), 0 :: (store (s8) into %ir.dst), (load (s8) from %ir.src)
|
||
|
call void @llvm.memmove.p0.p0.i64(ptr %dst, ptr %src, i64 %size, i1 0)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare void @llvm.memset.p0.i64(ptr, i8, i64, i1)
|
||
|
define void @test_memset(ptr %dst, i8 %val, i64 %size) {
|
||
|
; CHECK-LABEL: name: test_memset
|
||
|
; CHECK: [[DST:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[SRC_C:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[SRC:%[0-9]+]]:_(s8) = G_TRUNC [[SRC_C]]
|
||
|
; CHECK: [[SIZE:%[0-9]+]]:_(s64) = COPY $x2
|
||
|
; CHECK: G_MEMSET [[DST]](p0), [[SRC]](s8), [[SIZE]](s64), 0 :: (store (s8) into %ir.dst)
|
||
|
call void @llvm.memset.p0.i64(ptr %dst, i8 %val, i64 %size, i1 0)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define void @test_large_const(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_large_const
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s128) = G_CONSTANT i128 42
|
||
|
; CHECK: G_STORE [[VAL]](s128), [[ADDR]](p0)
|
||
|
store i128 42, ptr %addr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; When there was no formal argument handling (so the first BB was empty) we used
|
||
|
; to insert the constants at the end of the block, even if they were encountered
|
||
|
; after the block's terminators had been emitted. Also make sure the order is
|
||
|
; correct.
|
||
|
define ptr @test_const_placement() {
|
||
|
; CHECK-LABEL: name: test_const_placement
|
||
|
; CHECK: bb.{{[0-9]+}} (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK: [[VAL_INT:%[0-9]+]]:_(s32) = G_CONSTANT i32 42
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(p0) = G_INTTOPTR [[VAL_INT]](s32)
|
||
|
; CHECK: bb.{{[0-9]+}}.{{[a-zA-Z0-9.]+}}:
|
||
|
br label %next
|
||
|
|
||
|
next:
|
||
|
ret ptr inttoptr(i32 42 to ptr)
|
||
|
}
|
||
|
|
||
|
declare void @llvm.va_end(ptr)
|
||
|
define void @test_va_end(ptr %list) {
|
||
|
; CHECK-LABEL: name: test_va_end
|
||
|
; CHECK-NOT: va_end
|
||
|
; CHECK-NOT: INTRINSIC
|
||
|
; CHECK: RET_ReallyLR
|
||
|
call void @llvm.va_end(ptr %list)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define void @test_va_arg(ptr %list) {
|
||
|
; CHECK-LABEL: test_va_arg
|
||
|
; CHECK: [[LIST:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: G_VAARG [[LIST]](p0), 8
|
||
|
; CHECK: G_VAARG [[LIST]](p0), 1
|
||
|
; CHECK: G_VAARG [[LIST]](p0), 16
|
||
|
|
||
|
%v0 = va_arg ptr %list, i64
|
||
|
%v1 = va_arg ptr %list, i8
|
||
|
%v2 = va_arg ptr %list, i128
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare float @llvm.pow.f32(float, float)
|
||
|
define float @test_pow_intrin(float %l, float %r) {
|
||
|
; CHECK-LABEL: name: test_pow_intrin
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FPOW [[LHS]], [[RHS]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.pow.f32(float %l, float %r)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.powi.f32.i32(float, i32)
|
||
|
define float @test_powi_intrin(float %l, i32 %r) {
|
||
|
; CHECK-LABEL: name: test_powi_intrin
|
||
|
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FPOWI [[LHS]], [[RHS]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.powi.f32.i32(float %l, i32 %r)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.fma.f32(float, float, float)
|
||
|
define float @test_fma_intrin(float %a, float %b, float %c) {
|
||
|
; CHECK-LABEL: name: test_fma_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[B:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK: [[C:%[0-9]+]]:_(s32) = COPY $s2
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FMA [[A]], [[B]], [[C]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.fma.f32(float %a, float %b, float %c)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.exp.f32(float)
|
||
|
define float @test_exp_intrin(float %a) {
|
||
|
; CHECK-LABEL: name: test_exp_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FEXP [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.exp.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.exp2.f32(float)
|
||
|
define float @test_exp2_intrin(float %a) {
|
||
|
; CHECK-LABEL: name: test_exp2_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FEXP2 [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.exp2.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.log.f32(float)
|
||
|
define float @test_log_intrin(float %a) {
|
||
|
; CHECK-LABEL: name: test_log_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FLOG [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.log.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.log2.f32(float)
|
||
|
define float @test_log2_intrin(float %a) {
|
||
|
; CHECK-LABEL: name: test_log2_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_FLOG2 [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call float @llvm.log2.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.log10.f32(float)
|
||
|
define float @test_log10_intrin(float %a) {
|
||
|
; CHECK-LABEL: name: test_log10_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FLOG10 [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.log10.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.fabs.f32(float)
|
||
|
define float @test_fabs_intrin(float %a) {
|
||
|
; CHECK-LABEL: name: test_fabs_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FABS [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.fabs.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.copysign.f32(float, float)
|
||
|
define float @test_fcopysign_intrin(float %a, float %b) {
|
||
|
; CHECK-LABEL: name: test_fcopysign_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[B:%[0-9]+]]:_(s32) = COPY $s1
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FCOPYSIGN [[A]], [[B]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.copysign.f32(float %a, float %b)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.canonicalize.f32(float)
|
||
|
define float @test_fcanonicalize_intrin(float %a) {
|
||
|
; CHECK-LABEL: name: test_fcanonicalize_intrin
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FCANONICALIZE [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call nnan ninf nsz arcp contract afn reassoc float @llvm.canonicalize.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.trunc.f32(float)
|
||
|
define float @test_intrinsic_trunc(float %a) {
|
||
|
; CHECK-LABEL: name: test_intrinsic_trunc
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_INTRINSIC_TRUNC [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call float @llvm.trunc.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare float @llvm.round.f32(float)
|
||
|
define float @test_intrinsic_round(float %a) {
|
||
|
; CHECK-LABEL: name: test_intrinsic_round
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_INTRINSIC_ROUND [[A]]
|
||
|
; CHECK: $s0 = COPY [[RES]]
|
||
|
%res = call float @llvm.round.f32(float %a)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
declare i32 @llvm.lrint.i32.f32(float)
|
||
|
define i32 @test_intrinsic_lrint(float %a) {
|
||
|
; CHECK-LABEL: name: test_intrinsic_lrint
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_INTRINSIC_LRINT [[A]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
%res = call i32 @llvm.lrint.i32.f32(float %a)
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare i32 @llvm.ctlz.i32(i32, i1)
|
||
|
define i32 @test_ctlz_intrinsic_zero_not_undef(i32 %a) {
|
||
|
; CHECK-LABEL: name: test_ctlz_intrinsic_zero_not_undef
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_CTLZ [[A]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
%res = call i32 @llvm.ctlz.i32(i32 %a, i1 0)
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare i32 @llvm.cttz.i32(i32, i1)
|
||
|
define i32 @test_cttz_intrinsic_zero_undef(i32 %a) {
|
||
|
; CHECK-LABEL: name: test_cttz_intrinsic_zero_undef
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_CTTZ_ZERO_UNDEF [[A]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
%res = call i32 @llvm.cttz.i32(i32 %a, i1 1)
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare i32 @llvm.ctpop.i32(i32)
|
||
|
define i32 @test_ctpop_intrinsic(i32 %a) {
|
||
|
; CHECK-LABEL: name: test_ctpop
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_CTPOP [[A]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
%res = call i32 @llvm.ctpop.i32(i32 %a)
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare i32 @llvm.bitreverse.i32(i32)
|
||
|
define i32 @test_bitreverse_intrinsic(i32 %a) {
|
||
|
; CHECK-LABEL: name: test_bitreverse
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_BITREVERSE [[A]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
%res = call i32 @llvm.bitreverse.i32(i32 %a)
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare i32 @llvm.fshl.i32(i32, i32, i32)
|
||
|
define i32 @test_fshl_intrinsic(i32 %a, i32 %b, i32 %c) {
|
||
|
; CHECK-LABEL: name: test_fshl_intrinsic
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[B:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[C:%[0-9]+]]:_(s32) = COPY $w2
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_FSHL [[A]], [[B]], [[C]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
%res = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare i32 @llvm.fshr.i32(i32, i32, i32)
|
||
|
define i32 @test_fshr_intrinsic(i32 %a, i32 %b, i32 %c) {
|
||
|
; CHECK-LABEL: name: test_fshr_intrinsic
|
||
|
; CHECK: [[A:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[B:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[C:%[0-9]+]]:_(s32) = COPY $w2
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_FSHR [[A]], [[B]], [[C]]
|
||
|
; CHECK: $w0 = COPY [[RES]]
|
||
|
%res = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare void @llvm.lifetime.start.p0(i64, ptr)
|
||
|
declare void @llvm.lifetime.end.p0(i64, ptr)
|
||
|
define void @test_lifetime_intrin() {
|
||
|
; CHECK-LABEL: name: test_lifetime_intrin
|
||
|
; CHECK: RET_ReallyLR
|
||
|
; O3-LABEL: name: test_lifetime_intrin
|
||
|
; O3: {{%[0-9]+}}:_(p0) = G_FRAME_INDEX %stack.0.slot
|
||
|
; O3-NEXT: LIFETIME_START %stack.0.slot
|
||
|
; O3-NEXT: G_STORE
|
||
|
; O3-NEXT: LIFETIME_END %stack.0.slot
|
||
|
; O3-NEXT: RET_ReallyLR
|
||
|
%slot = alloca i8, i32 4
|
||
|
call void @llvm.lifetime.start.p0(i64 0, ptr %slot)
|
||
|
store volatile i8 10, ptr %slot
|
||
|
call void @llvm.lifetime.end.p0(i64 0, ptr %slot)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define void @test_load_store_atomics(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_load_store_atomics
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[V0:%[0-9]+]]:_(s8) = G_LOAD [[ADDR]](p0) :: (load unordered (s8) from %ir.addr)
|
||
|
; CHECK: G_STORE [[V0]](s8), [[ADDR]](p0) :: (store monotonic (s8) into %ir.addr)
|
||
|
; CHECK: [[V1:%[0-9]+]]:_(s8) = G_LOAD [[ADDR]](p0) :: (load acquire (s8) from %ir.addr)
|
||
|
; CHECK: G_STORE [[V1]](s8), [[ADDR]](p0) :: (store release (s8) into %ir.addr)
|
||
|
; CHECK: [[V2:%[0-9]+]]:_(s8) = G_LOAD [[ADDR]](p0) :: (load syncscope("singlethread") seq_cst (s8) from %ir.addr)
|
||
|
; CHECK: G_STORE [[V2]](s8), [[ADDR]](p0) :: (store syncscope("singlethread") monotonic (s8) into %ir.addr)
|
||
|
%v0 = load atomic i8, ptr %addr unordered, align 1
|
||
|
store atomic i8 %v0, ptr %addr monotonic, align 1
|
||
|
|
||
|
%v1 = load atomic i8, ptr %addr acquire, align 1
|
||
|
store atomic i8 %v1, ptr %addr release, align 1
|
||
|
|
||
|
%v2 = load atomic i8, ptr %addr syncscope("singlethread") seq_cst, align 1
|
||
|
store atomic i8 %v2, ptr %addr syncscope("singlethread") monotonic, align 1
|
||
|
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define float @test_fneg_f32(float %x) {
|
||
|
; CHECK-LABEL: name: test_fneg_f32
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_FNEG [[ARG]]
|
||
|
; CHECK: $s0 = COPY [[RES]](s32)
|
||
|
%neg = fneg float %x
|
||
|
ret float %neg
|
||
|
}
|
||
|
|
||
|
define float @test_fneg_f32_fmf(float %x) {
|
||
|
; CHECK-LABEL: name: test_fneg_f32
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FNEG [[ARG]]
|
||
|
; CHECK: $s0 = COPY [[RES]](s32)
|
||
|
%neg = fneg fast float %x
|
||
|
ret float %neg
|
||
|
}
|
||
|
|
||
|
define double @test_fneg_f64(double %x) {
|
||
|
; CHECK-LABEL: name: test_fneg_f64
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(s64) = COPY $d0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = G_FNEG [[ARG]]
|
||
|
; CHECK: $d0 = COPY [[RES]](s64)
|
||
|
%neg = fneg double %x
|
||
|
ret double %neg
|
||
|
}
|
||
|
|
||
|
define double @test_fneg_f64_fmf(double %x) {
|
||
|
; CHECK-LABEL: name: test_fneg_f64
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(s64) = COPY $d0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = nnan ninf nsz arcp contract afn reassoc G_FNEG [[ARG]]
|
||
|
; CHECK: $d0 = COPY [[RES]](s64)
|
||
|
%neg = fneg fast double %x
|
||
|
ret double %neg
|
||
|
}
|
||
|
|
||
|
define void @test_trivial_inlineasm() {
|
||
|
; CHECK-LABEL: name: test_trivial_inlineasm
|
||
|
; CHECK: INLINEASM &wibble, 1
|
||
|
; CHECK: INLINEASM &wibble, 0
|
||
|
call void asm sideeffect "wibble", ""()
|
||
|
call void asm "wibble", ""()
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define <2 x i32> @test_insertelement(<2 x i32> %vec, i32 %elt, i32 %idx){
|
||
|
; CHECK-LABEL: name: test_insertelement
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK: [[ELT:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[IDX:%[0-9]+]]:_(s32) = COPY $w1
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(<2 x s32>) = G_INSERT_VECTOR_ELT [[VEC]], [[ELT]](s32), [[IDX]](s32)
|
||
|
; CHECK: $d0 = COPY [[RES]](<2 x s32>)
|
||
|
%res = insertelement <2 x i32> %vec, i32 %elt, i32 %idx
|
||
|
ret <2 x i32> %res
|
||
|
}
|
||
|
|
||
|
define i32 @test_extractelement(<2 x i32> %vec, i32 %idx) {
|
||
|
; CHECK-LABEL: name: test_extractelement
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK: [[IDX:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[IDXEXT:%[0-9]+]]:_(s64) = G_ZEXT [[IDX]]
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_EXTRACT_VECTOR_ELT [[VEC]](<2 x s32>), [[IDXEXT]](s64)
|
||
|
; CHECK: $w0 = COPY [[RES]](s32)
|
||
|
%res = extractelement <2 x i32> %vec, i32 %idx
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
define i32 @test_extractelement_const_idx(<2 x i32> %vec) {
|
||
|
; CHECK-LABEL: name: test_extractelement
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK: [[IDX:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_EXTRACT_VECTOR_ELT [[VEC]](<2 x s32>), [[IDX]](s64)
|
||
|
; CHECK: $w0 = COPY [[RES]](s32)
|
||
|
%res = extractelement <2 x i32> %vec, i32 1
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
define i32 @test_extractelement_const_idx_zext_i1(<2 x i32> %vec) {
|
||
|
; CHECK-LABEL: name: test_extractelement
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK: [[IDX:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_EXTRACT_VECTOR_ELT [[VEC]](<2 x s32>), [[IDX]](s64)
|
||
|
; CHECK: $w0 = COPY [[RES]](s32)
|
||
|
%res = extractelement <2 x i32> %vec, i1 true
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
define i32 @test_extractelement_const_idx_zext_i8(<2 x i32> %vec) {
|
||
|
; CHECK-LABEL: name: test_extractelement
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK: [[IDX:%[0-9]+]]:_(s64) = G_CONSTANT i64 255
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_EXTRACT_VECTOR_ELT [[VEC]](<2 x s32>), [[IDX]](s64)
|
||
|
; CHECK: $w0 = COPY [[RES]](s32)
|
||
|
%res = extractelement <2 x i32> %vec, i8 255
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
|
||
|
define i32 @test_singleelementvector(i32 %elt){
|
||
|
; CHECK-LABEL: name: test_singleelementvector
|
||
|
; CHECK: [[ELT:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-NOT: G_INSERT_VECTOR_ELT
|
||
|
; CHECK-NOT: G_EXTRACT_VECTOR_ELT
|
||
|
; CHECK: $w0 = COPY [[ELT]](s32)
|
||
|
%vec = insertelement <1 x i32> undef, i32 %elt, i32 0
|
||
|
%res = extractelement <1 x i32> %vec, i32 0
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
define <2 x i32> @test_constantaggzerovector_v2i32() {
|
||
|
; CHECK-LABEL: name: test_constantaggzerovector_v2i32
|
||
|
; CHECK: [[ZERO:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[ZERO]](s32), [[ZERO]](s32)
|
||
|
; CHECK: $d0 = COPY [[VEC]](<2 x s32>)
|
||
|
ret <2 x i32> zeroinitializer
|
||
|
}
|
||
|
|
||
|
define <2 x float> @test_constantaggzerovector_v2f32() {
|
||
|
; CHECK-LABEL: name: test_constantaggzerovector_v2f32
|
||
|
; CHECK: [[ZERO:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[ZERO]](s32), [[ZERO]](s32)
|
||
|
; CHECK: $d0 = COPY [[VEC]](<2 x s32>)
|
||
|
ret <2 x float> zeroinitializer
|
||
|
}
|
||
|
|
||
|
define i32 @test_constantaggzerovector_v3i32() {
|
||
|
; CHECK-LABEL: name: test_constantaggzerovector_v3i32
|
||
|
; CHECK: [[ZERO:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<3 x s32>) = G_BUILD_VECTOR [[ZERO]](s32), [[ZERO]](s32), [[ZERO]](s32)
|
||
|
; CHECK: G_EXTRACT_VECTOR_ELT [[VEC]](<3 x s32>)
|
||
|
%elt = extractelement <3 x i32> zeroinitializer, i32 1
|
||
|
ret i32 %elt
|
||
|
}
|
||
|
|
||
|
define <2 x i32> @test_constantdatavector_v2i32() {
|
||
|
; CHECK-LABEL: name: test_constantdatavector_v2i32
|
||
|
; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[C1]](s32), [[C2]](s32)
|
||
|
; CHECK: $d0 = COPY [[VEC]](<2 x s32>)
|
||
|
ret <2 x i32> <i32 1, i32 2>
|
||
|
}
|
||
|
|
||
|
define i32 @test_constantdatavector_v3i32() {
|
||
|
; CHECK-LABEL: name: test_constantdatavector_v3i32
|
||
|
; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
|
||
|
; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<3 x s32>) = G_BUILD_VECTOR [[C1]](s32), [[C2]](s32), [[C3]](s32)
|
||
|
; CHECK: G_EXTRACT_VECTOR_ELT [[VEC]](<3 x s32>)
|
||
|
%elt = extractelement <3 x i32> <i32 1, i32 2, i32 3>, i32 1
|
||
|
ret i32 %elt
|
||
|
}
|
||
|
|
||
|
define <4 x i32> @test_constantdatavector_v4i32() {
|
||
|
; CHECK-LABEL: name: test_constantdatavector_v4i32
|
||
|
; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
|
||
|
; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
|
||
|
; CHECK: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C1]](s32), [[C2]](s32), [[C3]](s32), [[C4]](s32)
|
||
|
; CHECK: $q0 = COPY [[VEC]](<4 x s32>)
|
||
|
ret <4 x i32> <i32 1, i32 2, i32 3, i32 4>
|
||
|
}
|
||
|
|
||
|
define <2 x double> @test_constantdatavector_v2f64() {
|
||
|
; CHECK-LABEL: name: test_constantdatavector_v2f64
|
||
|
; CHECK: [[FC1:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+00
|
||
|
; CHECK: [[FC2:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s64>) = G_BUILD_VECTOR [[FC1]](s64), [[FC2]](s64)
|
||
|
; CHECK: $q0 = COPY [[VEC]](<2 x s64>)
|
||
|
ret <2 x double> <double 1.0, double 2.0>
|
||
|
}
|
||
|
|
||
|
define i32 @test_constantaggzerovector_v1s32(i32 %arg){
|
||
|
; CHECK-LABEL: name: test_constantaggzerovector_v1s32
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[C0:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
|
||
|
; CHECK-NOT: G_MERGE_VALUES
|
||
|
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY [[C0]]
|
||
|
; CHECK-NOT: G_MERGE_VALUES
|
||
|
; CHECK: G_ADD [[ARG]], [[COPY]]
|
||
|
%vec = insertelement <1 x i32> undef, i32 %arg, i32 0
|
||
|
%add = add <1 x i32> %vec, zeroinitializer
|
||
|
%res = extractelement <1 x i32> %add, i32 0
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
define i32 @test_constantdatavector_v1s32(i32 %arg){
|
||
|
; CHECK-LABEL: name: test_constantdatavector_v1s32
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NOT: G_MERGE_VALUES
|
||
|
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY [[C0]]
|
||
|
; CHECK-NOT: G_MERGE_VALUES
|
||
|
; CHECK: G_ADD [[ARG]], [[COPY]]
|
||
|
%vec = insertelement <1 x i32> undef, i32 %arg, i32 0
|
||
|
%add = add <1 x i32> %vec, <i32 1>
|
||
|
%res = extractelement <1 x i32> %add, i32 0
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
declare ghccc float @different_call_conv_target(float %x)
|
||
|
define float @test_different_call_conv_target(float %x) {
|
||
|
; CHECK-LABEL: name: test_different_call_conv
|
||
|
; CHECK: [[X:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: $s8 = COPY [[X]]
|
||
|
; CHECK: BL @different_call_conv_target, csr_aarch64_noregs, implicit-def $lr, implicit $sp, implicit $s8, implicit-def $s0
|
||
|
%res = call ghccc float @different_call_conv_target(float %x)
|
||
|
ret float %res
|
||
|
}
|
||
|
|
||
|
define <2 x i32> @test_shufflevector_s32_v2s32(i32 %arg) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_s32_v2s32
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK-DAG: [[UNDEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_SHUFFLE_VECTOR [[ARG]](s32), [[UNDEF]], shufflemask(0, 0)
|
||
|
; CHECK: $d0 = COPY [[VEC]](<2 x s32>)
|
||
|
%vec = insertelement <1 x i32> undef, i32 %arg, i32 0
|
||
|
%res = shufflevector <1 x i32> %vec, <1 x i32> undef, <2 x i32> zeroinitializer
|
||
|
ret <2 x i32> %res
|
||
|
}
|
||
|
|
||
|
define i32 @test_shufflevector_v2s32_s32(<2 x i32> %arg) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_v2s32_s32
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s32) = G_SHUFFLE_VECTOR [[ARG]](<2 x s32>), [[UNDEF]], shufflemask(1)
|
||
|
; CHECK: $w0 = COPY [[RES]](s32)
|
||
|
%vec = shufflevector <2 x i32> %arg, <2 x i32> undef, <1 x i32> <i32 1>
|
||
|
%res = extractelement <1 x i32> %vec, i32 0
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
define <2 x i32> @test_shufflevector_v2s32_v2s32_undef(<2 x i32> %arg) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_v2s32_v2s32_undef
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK-DAG: [[UNDEF:%[0-9]+]]:_(<2 x s32>) = G_IMPLICIT_DEF
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_SHUFFLE_VECTOR [[ARG]](<2 x s32>), [[UNDEF]], shufflemask(undef, undef)
|
||
|
; CHECK: $d0 = COPY [[VEC]](<2 x s32>)
|
||
|
%res = shufflevector <2 x i32> %arg, <2 x i32> undef, <2 x i32> undef
|
||
|
ret <2 x i32> %res
|
||
|
}
|
||
|
|
||
|
define <2 x i32> @test_shufflevector_v2s32_v2s32_undef_0(<2 x i32> %arg) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_v2s32_v2s32_undef_0
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK-DAG: [[UNDEF:%[0-9]+]]:_(<2 x s32>) = G_IMPLICIT_DEF
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_SHUFFLE_VECTOR [[ARG]](<2 x s32>), [[UNDEF]], shufflemask(undef, 0)
|
||
|
; CHECK: $d0 = COPY [[VEC]](<2 x s32>)
|
||
|
%res = shufflevector <2 x i32> %arg, <2 x i32> undef, <2 x i32> <i32 undef, i32 0>
|
||
|
ret <2 x i32> %res
|
||
|
}
|
||
|
|
||
|
define <2 x i32> @test_shufflevector_v2s32_v2s32_0_undef(<2 x i32> %arg) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_v2s32_v2s32_0_undef
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK-DAG: [[UNDEF:%[0-9]+]]:_(<2 x s32>) = G_IMPLICIT_DEF
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_SHUFFLE_VECTOR [[ARG]](<2 x s32>), [[UNDEF]], shufflemask(0, undef)
|
||
|
; CHECK: $d0 = COPY [[VEC]](<2 x s32>)
|
||
|
%res = shufflevector <2 x i32> %arg, <2 x i32> undef, <2 x i32> <i32 0, i32 undef>
|
||
|
ret <2 x i32> %res
|
||
|
}
|
||
|
|
||
|
define i32 @test_shufflevector_v2s32_v3s32(<2 x i32> %arg) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_v2s32_v3s32
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK-DAG: [[UNDEF:%[0-9]+]]:_(<2 x s32>) = G_IMPLICIT_DEF
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<3 x s32>) = G_SHUFFLE_VECTOR [[ARG]](<2 x s32>), [[UNDEF]], shufflemask(1, 0, 1)
|
||
|
; CHECK: G_EXTRACT_VECTOR_ELT [[VEC]](<3 x s32>)
|
||
|
%vec = shufflevector <2 x i32> %arg, <2 x i32> undef, <3 x i32> <i32 1, i32 0, i32 1>
|
||
|
%res = extractelement <3 x i32> %vec, i32 0
|
||
|
ret i32 %res
|
||
|
}
|
||
|
|
||
|
define <4 x i32> @test_shufflevector_v2s32_v4s32(<2 x i32> %arg1, <2 x i32> %arg2) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_v2s32_v4s32
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(<2 x s32>) = COPY $d0
|
||
|
; CHECK: [[ARG2:%[0-9]+]]:_(<2 x s32>) = COPY $d1
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<4 x s32>) = G_SHUFFLE_VECTOR [[ARG1]](<2 x s32>), [[ARG2]], shufflemask(0, 1, 2, 3)
|
||
|
; CHECK: $q0 = COPY [[VEC]](<4 x s32>)
|
||
|
%res = shufflevector <2 x i32> %arg1, <2 x i32> %arg2, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||
|
ret <4 x i32> %res
|
||
|
}
|
||
|
|
||
|
define <2 x i32> @test_shufflevector_v4s32_v2s32(<4 x i32> %arg) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_v4s32_v2s32
|
||
|
; CHECK: [[ARG:%[0-9]+]]:_(<4 x s32>) = COPY $q0
|
||
|
; CHECK-DAG: [[UNDEF:%[0-9]+]]:_(<4 x s32>) = G_IMPLICIT_DEF
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_SHUFFLE_VECTOR [[ARG]](<4 x s32>), [[UNDEF]], shufflemask(1, 3)
|
||
|
; CHECK: $d0 = COPY [[VEC]](<2 x s32>)
|
||
|
%res = shufflevector <4 x i32> %arg, <4 x i32> undef, <2 x i32> <i32 1, i32 3>
|
||
|
ret <2 x i32> %res
|
||
|
}
|
||
|
|
||
|
|
||
|
define <16 x i8> @test_shufflevector_v8s8_v16s8(<8 x i8> %arg1, <8 x i8> %arg2) {
|
||
|
; CHECK-LABEL: name: test_shufflevector_v8s8_v16s8
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(<8 x s8>) = COPY $d0
|
||
|
; CHECK: [[ARG2:%[0-9]+]]:_(<8 x s8>) = COPY $d1
|
||
|
; CHECK: [[VEC:%[0-9]+]]:_(<16 x s8>) = G_SHUFFLE_VECTOR [[ARG1]](<8 x s8>), [[ARG2]], shufflemask(0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15)
|
||
|
; CHECK: $q0 = COPY [[VEC]](<16 x s8>)
|
||
|
%res = shufflevector <8 x i8> %arg1, <8 x i8> %arg2, <16 x i32> <i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11, i32 4, i32 12, i32 5, i32 13, i32 6, i32 14, i32 7, i32 15>
|
||
|
ret <16 x i8> %res
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: test_constant_vector
|
||
|
; CHECK: [[UNDEF:%[0-9]+]]:_(s16) = G_IMPLICIT_DEF
|
||
|
; CHECK: [[F:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH3C00
|
||
|
; CHECK: [[M:%[0-9]+]]:_(<4 x s16>) = G_BUILD_VECTOR [[UNDEF]](s16), [[UNDEF]](s16), [[UNDEF]](s16), [[F]](s16)
|
||
|
; CHECK: $d0 = COPY [[M]](<4 x s16>)
|
||
|
define <4 x half> @test_constant_vector() {
|
||
|
ret <4 x half> <half undef, half undef, half undef, half 0xH3C00>
|
||
|
}
|
||
|
|
||
|
define i32 @test_target_mem_intrinsic(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_target_mem_intrinsic
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[VAL:%[0-9]+]]:_(s64) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.ldxr), [[ADDR]](p0) :: (volatile load (s32) from %ir.addr)
|
||
|
; CHECK: G_TRUNC [[VAL]](s64)
|
||
|
%val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %addr)
|
||
|
%trunc = trunc i64 %val to i32
|
||
|
ret i32 %trunc
|
||
|
}
|
||
|
|
||
|
declare i64 @llvm.aarch64.ldxr.p0(ptr) nounwind
|
||
|
|
||
|
%zerosize_type = type {}
|
||
|
|
||
|
define %zerosize_type @test_empty_load_store(ptr %ptr, %zerosize_type %in) noinline optnone {
|
||
|
; CHECK-LABEL: name: test_empty_load_store
|
||
|
; CHECK-NOT: G_STORE
|
||
|
; CHECK-NOT: G_LOAD
|
||
|
; CHECK: RET_ReallyLR
|
||
|
entry:
|
||
|
store %zerosize_type undef, ptr undef, align 4
|
||
|
%val = load %zerosize_type, ptr %ptr, align 4
|
||
|
ret %zerosize_type %in
|
||
|
}
|
||
|
|
||
|
|
||
|
define i64 @test_phi_loop(i32 %n) {
|
||
|
; CHECK-LABEL: name: test_phi_loop
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(s32) = COPY $w0
|
||
|
; CHECK: [[CST1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK: [[CST2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
|
||
|
; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
|
||
|
; CHECK: [[CST4:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
|
||
|
|
||
|
; CHECK: [[PN1:%[0-9]+]]:_(s32) = G_PHI [[ARG1]](s32), %bb.1, [[SUB:%[0-9]+]](s32), %bb.2
|
||
|
; CHECK: [[PN2:%[0-9]+]]:_(s64) = G_PHI [[CST3]](s64), %bb.1, [[PN3:%[0-9]+]](s64), %bb.2
|
||
|
; CHECK: [[PN3]]:_(s64) = G_PHI [[CST4]](s64), %bb.1, [[ADD:%[0-9]+]](s64), %bb.2
|
||
|
; CHECK: [[ADD]]:_(s64) = G_ADD [[PN2]], [[PN3]]
|
||
|
; CHECK: [[SUB]]:_(s32) = G_SUB [[PN1]], [[CST1]]
|
||
|
; CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(sle), [[PN1]](s32), [[CST2]]
|
||
|
; CHECK: G_BRCOND [[CMP]](s1), %bb.3
|
||
|
; CHECK: G_BR %bb.2
|
||
|
|
||
|
; CHECK: $x0 = COPY [[PN2]](s64)
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
entry:
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
%counter = phi i32 [ %n, %entry ], [ %counter.dec, %loop ]
|
||
|
%elem = phi { i64, i64 } [ { i64 0, i64 1 }, %entry ], [ %updated, %loop ]
|
||
|
%prev = extractvalue { i64, i64 } %elem, 0
|
||
|
%curr = extractvalue { i64, i64 } %elem, 1
|
||
|
%next = add i64 %prev, %curr
|
||
|
%shifted = insertvalue { i64, i64 } %elem, i64 %curr, 0
|
||
|
%updated = insertvalue { i64, i64 } %shifted, i64 %next, 1
|
||
|
%counter.dec = sub i32 %counter, 1
|
||
|
%cond = icmp sle i32 %counter, 0
|
||
|
br i1 %cond, label %exit, label %loop
|
||
|
|
||
|
exit:
|
||
|
%res = extractvalue { i64, i64 } %elem, 0
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
define void @test_phi_diamond(ptr %a.ptr, ptr %b.ptr, i1 %selector, ptr %dst) {
|
||
|
; CHECK-LABEL: name: test_phi_diamond
|
||
|
; CHECK: [[ARG1:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[ARG2:%[0-9]+]]:_(p0) = COPY $x1
|
||
|
; CHECK: [[ARG3:%[0-9]+]]:_(s32) = COPY $w2
|
||
|
; CHECK: [[TRUNC8:%[0-9]+]]:_(s8) = G_TRUNC [[ARG3]]
|
||
|
; CHECK: [[ARG4:%[0-9]+]]:_(p0) = COPY $x3
|
||
|
; CHECK: [[TRUNCASSERT:%[0-9]+]]:_(s8) = G_ASSERT_ZEXT [[TRUNC8]], 1
|
||
|
; CHECK: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[TRUNCASSERT]]
|
||
|
; CHECK: G_BRCOND [[TRUNC]](s1), %bb.2
|
||
|
; CHECK: G_BR %bb.3
|
||
|
|
||
|
; CHECK: [[LD1:%[0-9]+]]:_(s8) = G_LOAD [[ARG1]](p0) :: (load (s8) from %ir.a.ptr, align 4)
|
||
|
; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
|
||
|
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_PTR_ADD [[ARG1]], [[CST1]](s64)
|
||
|
; CHECK: [[LD2:%[0-9]+]]:_(s16) = G_LOAD [[GEP1]](p0) :: (load (s16) from %ir.a.ptr + 2)
|
||
|
; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_PTR_ADD [[ARG1]], [[CST2]](s64)
|
||
|
; CHECK: [[LD3:%[0-9]+]]:_(s32) = G_LOAD [[GEP2]](p0) :: (load (s32) from %ir.a.ptr + 4)
|
||
|
; CHECK: G_BR %bb.4
|
||
|
|
||
|
; CHECK: [[LD4:%[0-9]+]]:_(s8) = G_LOAD [[ARG2]](p0) :: (load (s8) from %ir.b.ptr, align 4)
|
||
|
; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
|
||
|
; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_PTR_ADD [[ARG2]], [[CST3]](s64)
|
||
|
; CHECK: [[LD5:%[0-9]+]]:_(s16) = G_LOAD [[GEP3]](p0) :: (load (s16) from %ir.b.ptr + 2)
|
||
|
; CHECK: [[CST4:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP4:%[0-9]+]]:_(p0) = G_PTR_ADD [[ARG2]], [[CST4]](s64)
|
||
|
; CHECK: [[LD6:%[0-9]+]]:_(s32) = G_LOAD [[GEP4]](p0) :: (load (s32) from %ir.b.ptr + 4)
|
||
|
|
||
|
; CHECK: [[PN1:%[0-9]+]]:_(s8) = G_PHI [[LD1]](s8), %bb.2, [[LD4]](s8), %bb.3
|
||
|
; CHECK: [[PN2:%[0-9]+]]:_(s16) = G_PHI [[LD2]](s16), %bb.2, [[LD5]](s16), %bb.3
|
||
|
; CHECK: [[PN3:%[0-9]+]]:_(s32) = G_PHI [[LD3]](s32), %bb.2, [[LD6]](s32), %bb.3
|
||
|
; CHECK: G_STORE [[PN1]](s8), [[ARG4]](p0) :: (store (s8) into %ir.dst, align 4)
|
||
|
; CHECK: [[CST5:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
|
||
|
; CHECK: [[GEP5:%[0-9]+]]:_(p0) = G_PTR_ADD [[ARG4]], [[CST5]](s64)
|
||
|
; CHECK: G_STORE [[PN2]](s16), [[GEP5]](p0) :: (store (s16) into %ir.dst + 2)
|
||
|
; CHECK: [[CST6:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP6:%[0-9]+]]:_(p0) = G_PTR_ADD [[ARG4]], [[CST6]](s64)
|
||
|
; CHECK: G_STORE [[PN3]](s32), [[GEP6]](p0) :: (store (s32) into %ir.dst + 4)
|
||
|
; CHECK: RET_ReallyLR
|
||
|
|
||
|
entry:
|
||
|
br i1 %selector, label %store.a, label %store.b
|
||
|
|
||
|
store.a:
|
||
|
%a = load { i8, i16, i32 }, ptr %a.ptr
|
||
|
br label %join
|
||
|
|
||
|
store.b:
|
||
|
%b = load { i8, i16, i32 }, ptr %b.ptr
|
||
|
br label %join
|
||
|
|
||
|
join:
|
||
|
%v = phi { i8, i16, i32 } [ %a, %store.a ], [ %b, %store.b ]
|
||
|
store { i8, i16, i32 } %v, ptr %dst
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
%agg.inner.inner = type {i64, i64}
|
||
|
%agg.inner = type {i16, i8, %agg.inner.inner }
|
||
|
%agg.nested = type {i32, i32, %agg.inner, i32}
|
||
|
|
||
|
define void @test_nested_aggregate_const(ptr %ptr) {
|
||
|
; CHECK-LABEL: name: test_nested_aggregate_const
|
||
|
; CHECK: [[BASE:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK: [[CST1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK: [[CST2:%[0-9]+]]:_(s16) = G_CONSTANT i16 2
|
||
|
; CHECK: [[CST3:%[0-9]+]]:_(s8) = G_CONSTANT i8 3
|
||
|
; CHECK: [[CST4:%[0-9]+]]:_(s64) = G_CONSTANT i64 5
|
||
|
; CHECK: [[CST5:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||
|
; CHECK: [[CST6:%[0-9]+]]:_(s32) = G_CONSTANT i32 13
|
||
|
; CHECK: G_STORE [[CST1]](s32), [[BASE]](p0) :: (store (s32) into %ir.ptr, align 8)
|
||
|
; CHECK: [[CST7:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_PTR_ADD [[BASE]], [[CST7]](s64)
|
||
|
; CHECK: G_STORE [[CST1]](s32), [[GEP1]](p0) :: (store (s32) into %ir.ptr + 4)
|
||
|
; CHECK: [[CST8:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||
|
; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_PTR_ADD [[BASE]], [[CST8]](s64)
|
||
|
; CHECK: G_STORE [[CST2]](s16), [[GEP2]](p0) :: (store (s16) into %ir.ptr + 8, align 8)
|
||
|
; CHECK: [[CST9:%[0-9]+]]:_(s64) = G_CONSTANT i64 10
|
||
|
; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_PTR_ADD [[BASE]], [[CST9]](s64)
|
||
|
; CHECK: G_STORE [[CST3]](s8), [[GEP3]](p0) :: (store (s8) into %ir.ptr + 10, align 2)
|
||
|
; CHECK: [[CST10:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
|
||
|
; CHECK: [[GEP4:%[0-9]+]]:_(p0) = G_PTR_ADD [[BASE]], [[CST10]](s64)
|
||
|
; CHECK: G_STORE [[CST4]](s64), [[GEP4]](p0) :: (store (s64) into %ir.ptr + 16)
|
||
|
; CHECK: [[CST11:%[0-9]+]]:_(s64) = G_CONSTANT i64 24
|
||
|
; CHECK: [[GEP5:%[0-9]+]]:_(p0) = G_PTR_ADD [[BASE]], [[CST11]](s64)
|
||
|
; CHECK: G_STORE [[CST5]](s64), [[GEP5]](p0) :: (store (s64) into %ir.ptr + 24)
|
||
|
; CHECK: [[CST12:%[0-9]+]]:_(s64) = G_CONSTANT i64 32
|
||
|
; CHECK: [[GEP6:%[0-9]+]]:_(p0) = G_PTR_ADD [[BASE]], [[CST12]](s64)
|
||
|
; CHECK: G_STORE [[CST6]](s32), [[GEP6]](p0) :: (store (s32) into %ir.ptr + 32, align 8)
|
||
|
store %agg.nested { i32 1, i32 1, %agg.inner { i16 2, i8 3, %agg.inner.inner {i64 5, i64 8} }, i32 13}, ptr %ptr
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define i1 @return_i1_zext() {
|
||
|
; AAPCS ABI says that booleans can only be 1 or 0, so we need to zero-extend.
|
||
|
; CHECK-LABEL: name: return_i1_zext
|
||
|
; CHECK: [[CST:%[0-9]+]]:_(s1) = G_CONSTANT i1 true
|
||
|
; CHECK: [[ZEXT:%[0-9]+]]:_(s8) = G_ZEXT [[CST]](s1)
|
||
|
; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[ZEXT]](s8)
|
||
|
; CHECK: $w0 = COPY [[ANYEXT]](s32)
|
||
|
; CHECK: RET_ReallyLR implicit $w0
|
||
|
ret i1 true
|
||
|
}
|
||
|
|
||
|
; Try one cmpxchg
|
||
|
define i32 @test_atomic_cmpxchg_1(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomic_cmpxchg_1
|
||
|
; CHECK: bb.1.entry:
|
||
|
; CHECK-NEXT: successors: %bb.{{[^)]+}}
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[OLDVAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
|
||
|
; CHECK-NEXT: [[NEWVAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK: bb.2.repeat:
|
||
|
; CHECK-NEXT: successors: %bb.3({{[^)]+}}), %bb.2({{[^)]+}})
|
||
|
; CHECK: [[OLDVALRES:%[0-9]+]]:_(s32), [[SUCCESS:%[0-9]+]]:_(s1) = G_ATOMIC_CMPXCHG_WITH_SUCCESS [[ADDR]](p0), [[OLDVAL]], [[NEWVAL]] :: (load store monotonic monotonic (s32) on %ir.addr)
|
||
|
; CHECK-NEXT: G_BRCOND [[SUCCESS]](s1), %bb.3
|
||
|
; CHECK-NEXT: G_BR %bb.2
|
||
|
; CHECK: bb.3.done:
|
||
|
entry:
|
||
|
br label %repeat
|
||
|
repeat:
|
||
|
%val_success = cmpxchg ptr %addr, i32 0, i32 1 monotonic monotonic
|
||
|
%value_loaded = extractvalue { i32, i1 } %val_success, 0
|
||
|
%success = extractvalue { i32, i1 } %val_success, 1
|
||
|
br i1 %success, label %done, label %repeat
|
||
|
done:
|
||
|
ret i32 %value_loaded
|
||
|
}
|
||
|
|
||
|
; Try one cmpxchg
|
||
|
define i32 @test_weak_atomic_cmpxchg_1(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_weak_atomic_cmpxchg_1
|
||
|
; CHECK: bb.1.entry:
|
||
|
; CHECK-NEXT: successors: %bb.{{[^)]+}}
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[OLDVAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
|
||
|
; CHECK-NEXT: [[NEWVAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK: bb.2.repeat:
|
||
|
; CHECK-NEXT: successors: %bb.3({{[^)]+}}), %bb.2({{[^)]+}})
|
||
|
; CHECK: [[OLDVALRES:%[0-9]+]]:_(s32), [[SUCCESS:%[0-9]+]]:_(s1) = G_ATOMIC_CMPXCHG_WITH_SUCCESS [[ADDR]](p0), [[OLDVAL]], [[NEWVAL]] :: (load store monotonic monotonic (s32) on %ir.addr)
|
||
|
; CHECK-NEXT: G_BRCOND [[SUCCESS]](s1), %bb.3
|
||
|
; CHECK-NEXT: G_BR %bb.2
|
||
|
; CHECK: bb.3.done:
|
||
|
entry:
|
||
|
br label %repeat
|
||
|
repeat:
|
||
|
%val_success = cmpxchg weak ptr %addr, i32 0, i32 1 monotonic monotonic
|
||
|
%value_loaded = extractvalue { i32, i1 } %val_success, 0
|
||
|
%success = extractvalue { i32, i1 } %val_success, 1
|
||
|
br i1 %success, label %done, label %repeat
|
||
|
done:
|
||
|
ret i32 %value_loaded
|
||
|
}
|
||
|
|
||
|
; Try one cmpxchg with a small type and high atomic ordering.
|
||
|
define i16 @test_atomic_cmpxchg_2(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomic_cmpxchg_2
|
||
|
; CHECK: bb.1.entry:
|
||
|
; CHECK-NEXT: successors: %bb.2({{[^)]+}})
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[OLDVAL:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
|
||
|
; CHECK-NEXT: [[NEWVAL:%[0-9]+]]:_(s16) = G_CONSTANT i16 1
|
||
|
; CHECK: bb.2.repeat:
|
||
|
; CHECK-NEXT: successors: %bb.3({{[^)]+}}), %bb.2({{[^)]+}})
|
||
|
; CHECK: [[OLDVALRES:%[0-9]+]]:_(s16), [[SUCCESS:%[0-9]+]]:_(s1) = G_ATOMIC_CMPXCHG_WITH_SUCCESS [[ADDR]](p0), [[OLDVAL]], [[NEWVAL]] :: (load store seq_cst seq_cst (s16) on %ir.addr)
|
||
|
; CHECK-NEXT: G_BRCOND [[SUCCESS]](s1), %bb.3
|
||
|
; CHECK-NEXT: G_BR %bb.2
|
||
|
; CHECK: bb.3.done:
|
||
|
entry:
|
||
|
br label %repeat
|
||
|
repeat:
|
||
|
%val_success = cmpxchg ptr %addr, i16 0, i16 1 seq_cst seq_cst
|
||
|
%value_loaded = extractvalue { i16, i1 } %val_success, 0
|
||
|
%success = extractvalue { i16, i1 } %val_success, 1
|
||
|
br i1 %success, label %done, label %repeat
|
||
|
done:
|
||
|
ret i16 %value_loaded
|
||
|
}
|
||
|
|
||
|
; Try one cmpxchg where the success order and failure order differ.
|
||
|
define i64 @test_atomic_cmpxchg_3(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomic_cmpxchg_3
|
||
|
; CHECK: bb.1.entry:
|
||
|
; CHECK-NEXT: successors: %bb.2({{[^)]+}})
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[OLDVAL:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
|
||
|
; CHECK-NEXT: [[NEWVAL:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
|
||
|
; CHECK: bb.2.repeat:
|
||
|
; CHECK-NEXT: successors: %bb.3({{[^)]+}}), %bb.2({{[^)]+}})
|
||
|
; CHECK: [[OLDVALRES:%[0-9]+]]:_(s64), [[SUCCESS:%[0-9]+]]:_(s1) = G_ATOMIC_CMPXCHG_WITH_SUCCESS [[ADDR]](p0), [[OLDVAL]], [[NEWVAL]] :: (load store seq_cst acquire (s64) on %ir.addr)
|
||
|
; CHECK-NEXT: G_BRCOND [[SUCCESS]](s1), %bb.3
|
||
|
; CHECK-NEXT: G_BR %bb.2
|
||
|
; CHECK: bb.3.done:
|
||
|
entry:
|
||
|
br label %repeat
|
||
|
repeat:
|
||
|
%val_success = cmpxchg ptr %addr, i64 0, i64 1 seq_cst acquire
|
||
|
%value_loaded = extractvalue { i64, i1 } %val_success, 0
|
||
|
%success = extractvalue { i64, i1 } %val_success, 1
|
||
|
br i1 %success, label %done, label %repeat
|
||
|
done:
|
||
|
ret i64 %value_loaded
|
||
|
}
|
||
|
|
||
|
; Try a monotonic atomicrmw xchg
|
||
|
define i32 @test_atomicrmw_xchg(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_xchg
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_XCHG [[ADDR]](p0), [[VAL]] :: (load store monotonic (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw xchg ptr %addr, i32 1 monotonic
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an acquire atomicrmw add
|
||
|
define i32 @test_atomicrmw_add(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_add
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_ADD [[ADDR]](p0), [[VAL]] :: (load store acquire (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw add ptr %addr, i32 1 acquire
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try a release atomicrmw sub
|
||
|
define i32 @test_atomicrmw_sub(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_sub
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_SUB [[ADDR]](p0), [[VAL]] :: (load store release (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw sub ptr %addr, i32 1 release
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an acq_rel atomicrmw and
|
||
|
define i32 @test_atomicrmw_and(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_and
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_AND [[ADDR]](p0), [[VAL]] :: (load store acq_rel (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw and ptr %addr, i32 1 acq_rel
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an seq_cst atomicrmw nand. NAND isn't supported by LSE, so it
|
||
|
; expands to G_ATOMIC_CMPXCHG_WITH_SUCCESS.
|
||
|
define i32 @test_atomicrmw_nand(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_nand
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: successors: %bb.2(0x80000000)
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[NEG1:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1
|
||
|
; CHECK-NEXT: [[OLDVALSTART:%[0-9]+]]:_(s32) = G_LOAD [[ADDR]](p0) :: (load (s32) from %ir.addr)
|
||
|
; CHECK: bb.2.atomicrmw.start:
|
||
|
; CHECK-NEXT: successors: %bb.3({{[^)]+}}), %bb.2({{[^)]+}})
|
||
|
; CHECK: [[OLDVAL:%[0-9]+]]:_(s32) = G_PHI [[OLDVALSTART]](s32), %bb.1, [[OLDVALRES:%[0-9]+]](s32), %bb.2
|
||
|
; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[OLDVAL]], [[VAL]]
|
||
|
; CHECK-NEXT: [[NEWVAL:%[0-9]+]]:_(s32) = G_XOR [[AND]], [[NEG1]]
|
||
|
; CHECK: [[OLDVALRES]]:_(s32), [[SUCCESS:%[0-9]+]]:_(s1) = G_ATOMIC_CMPXCHG_WITH_SUCCESS [[ADDR]](p0), [[OLDVAL]], [[NEWVAL]] :: (load store seq_cst seq_cst (s32) on %ir.addr)
|
||
|
; CHECK-NEXT: G_BRCOND [[SUCCESS]](s1), %bb.3
|
||
|
; CHECK-NEXT: G_BR %bb.2
|
||
|
; CHECK: bb.3.atomicrmw.end:
|
||
|
%oldval = atomicrmw nand ptr %addr, i32 1 seq_cst
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an seq_cst atomicrmw or
|
||
|
define i32 @test_atomicrmw_or(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_or
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_OR [[ADDR]](p0), [[VAL]] :: (load store seq_cst (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw or ptr %addr, i32 1 seq_cst
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an seq_cst atomicrmw xor
|
||
|
define i32 @test_atomicrmw_xor(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_xor
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_XOR [[ADDR]](p0), [[VAL]] :: (load store seq_cst (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw xor ptr %addr, i32 1 seq_cst
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an seq_cst atomicrmw min
|
||
|
define i32 @test_atomicrmw_min(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_min
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_MIN [[ADDR]](p0), [[VAL]] :: (load store seq_cst (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw min ptr %addr, i32 1 seq_cst
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an seq_cst atomicrmw max
|
||
|
define i32 @test_atomicrmw_max(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_max
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_MAX [[ADDR]](p0), [[VAL]] :: (load store seq_cst (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw max ptr %addr, i32 1 seq_cst
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an seq_cst atomicrmw unsigned min
|
||
|
define i32 @test_atomicrmw_umin(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_umin
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_UMIN [[ADDR]](p0), [[VAL]] :: (load store seq_cst (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw umin ptr %addr, i32 1 seq_cst
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
; Try an seq_cst atomicrmw unsigned max
|
||
|
define i32 @test_atomicrmw_umax(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_atomicrmw_umax
|
||
|
; CHECK: bb.1 (%ir-block.{{[0-9]+}}):
|
||
|
; CHECK-NEXT: liveins: $x0
|
||
|
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[VAL:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
||
|
; CHECK-NEXT: [[OLDVALRES:%[0-9]+]]:_(s32) = G_ATOMICRMW_UMAX [[ADDR]](p0), [[VAL]] :: (load store seq_cst (s32) on %ir.addr)
|
||
|
%oldval = atomicrmw umax ptr %addr, i32 1 seq_cst
|
||
|
ret i32 %oldval
|
||
|
}
|
||
|
|
||
|
@addr = global ptr null
|
||
|
|
||
|
define void @test_blockaddress() {
|
||
|
; CHECK-LABEL: name: test_blockaddress
|
||
|
; CHECK: [[BADDR:%[0-9]+]]:_(p0) = G_BLOCK_ADDR blockaddress(@test_blockaddress, %ir-block.block)
|
||
|
; CHECK: G_STORE [[BADDR]](p0)
|
||
|
store ptr blockaddress(@test_blockaddress, %block), ptr @addr
|
||
|
indirectbr ptr blockaddress(@test_blockaddress, %block), [label %block]
|
||
|
block:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
%t = type { i32 }
|
||
|
declare ptr @llvm.invariant.start.p0(i64, ptr nocapture) readonly nounwind
|
||
|
declare void @llvm.invariant.end.p0(ptr, i64, ptr nocapture) nounwind
|
||
|
define void @test_invariant_intrin() {
|
||
|
; CHECK-LABEL: name: test_invariant_intrin
|
||
|
; CHECK: %{{[0-9]+}}:_(s64) = G_IMPLICIT_DEF
|
||
|
; CHECK-NEXT: RET_ReallyLR
|
||
|
%x = alloca %t
|
||
|
%inv = call ptr @llvm.invariant.start.p0(i64 8, ptr %x)
|
||
|
call void @llvm.invariant.end.p0(ptr %inv, i64 8, ptr %x)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare float @llvm.ceil.f32(float)
|
||
|
define float @test_ceil_f32(float %x) {
|
||
|
; CHECK-LABEL: name: test_ceil_f32
|
||
|
; CHECK: %{{[0-9]+}}:_(s32) = G_FCEIL %{{[0-9]+}}
|
||
|
%y = call float @llvm.ceil.f32(float %x)
|
||
|
ret float %y
|
||
|
}
|
||
|
|
||
|
declare double @llvm.ceil.f64(double)
|
||
|
define double @test_ceil_f64(double %x) {
|
||
|
; CHECK-LABEL: name: test_ceil_f64
|
||
|
; CHECK: %{{[0-9]+}}:_(s64) = G_FCEIL %{{[0-9]+}}
|
||
|
%y = call double @llvm.ceil.f64(double %x)
|
||
|
ret double %y
|
||
|
}
|
||
|
|
||
|
declare <2 x float> @llvm.ceil.v2f32(<2 x float>)
|
||
|
define <2 x float> @test_ceil_v2f32(<2 x float> %x) {
|
||
|
; CHECK-LABEL: name: test_ceil_v2f32
|
||
|
; CHECK: %{{[0-9]+}}:_(<2 x s32>) = G_FCEIL %{{[0-9]+}}
|
||
|
%y = call <2 x float> @llvm.ceil.v2f32(<2 x float> %x)
|
||
|
ret <2 x float> %y
|
||
|
}
|
||
|
|
||
|
declare <4 x float> @llvm.ceil.v4f32(<4 x float>)
|
||
|
define <4 x float> @test_ceil_v4f32(<4 x float> %x) {
|
||
|
; CHECK-LABEL: name: test_ceil_v4f32
|
||
|
; CHECK: %{{[0-9]+}}:_(<4 x s32>) = G_FCEIL %{{[0-9]+}}
|
||
|
; SELECT: %{{[0-9]+}}:fpr128 = FRINTPv4f32 %{{[0-9]+}}
|
||
|
%y = call <4 x float> @llvm.ceil.v4f32(<4 x float> %x)
|
||
|
ret <4 x float> %y
|
||
|
}
|
||
|
|
||
|
declare <2 x double> @llvm.ceil.v2f64(<2 x double>)
|
||
|
define <2 x double> @test_ceil_v2f64(<2 x double> %x) {
|
||
|
; CHECK-LABEL: name: test_ceil_v2f64
|
||
|
; CHECK: %{{[0-9]+}}:_(<2 x s64>) = G_FCEIL %{{[0-9]+}}
|
||
|
%y = call <2 x double> @llvm.ceil.v2f64(<2 x double> %x)
|
||
|
ret <2 x double> %y
|
||
|
}
|
||
|
|
||
|
declare float @llvm.cos.f32(float)
|
||
|
define float @test_cos_f32(float %x) {
|
||
|
; CHECK-LABEL: name: test_cos_f32
|
||
|
; CHECK: %{{[0-9]+}}:_(s32) = G_FCOS %{{[0-9]+}}
|
||
|
%y = call float @llvm.cos.f32(float %x)
|
||
|
ret float %y
|
||
|
}
|
||
|
|
||
|
declare float @llvm.sin.f32(float)
|
||
|
define float @test_sin_f32(float %x) {
|
||
|
; CHECK-LABEL: name: test_sin_f32
|
||
|
; CHECK: %{{[0-9]+}}:_(s32) = G_FSIN %{{[0-9]+}}
|
||
|
%y = call float @llvm.sin.f32(float %x)
|
||
|
ret float %y
|
||
|
}
|
||
|
|
||
|
declare float @llvm.sqrt.f32(float)
|
||
|
define float @test_sqrt_f32(float %x) {
|
||
|
; CHECK-LABEL: name: test_sqrt_f32
|
||
|
; CHECK: %{{[0-9]+}}:_(s32) = G_FSQRT %{{[0-9]+}}
|
||
|
%y = call float @llvm.sqrt.f32(float %x)
|
||
|
ret float %y
|
||
|
}
|
||
|
|
||
|
declare float @llvm.floor.f32(float)
|
||
|
define float @test_floor_f32(float %x) {
|
||
|
; CHECK-LABEL: name: test_floor_f32
|
||
|
; CHECK: %{{[0-9]+}}:_(s32) = G_FFLOOR %{{[0-9]+}}
|
||
|
%y = call float @llvm.floor.f32(float %x)
|
||
|
ret float %y
|
||
|
}
|
||
|
|
||
|
declare float @llvm.nearbyint.f32(float)
|
||
|
define float @test_nearbyint_f32(float %x) {
|
||
|
; CHECK-LABEL: name: test_nearbyint_f32
|
||
|
; CHECK: %{{[0-9]+}}:_(s32) = G_FNEARBYINT %{{[0-9]+}}
|
||
|
%y = call float @llvm.nearbyint.f32(float %x)
|
||
|
ret float %y
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: name: test_llvm.aarch64.neon.ld3.v4i32.p0i32
|
||
|
; CHECK: %1:_(<4 x s32>), %2:_(<4 x s32>), %3:_(<4 x s32>) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.neon.ld3), %0(p0) :: (load (s384) from %ir.ptr, align 64)
|
||
|
define void @test_llvm.aarch64.neon.ld3.v4i32.p0i32(ptr %ptr) {
|
||
|
%arst = call { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld3.v4i32.p0(ptr %ptr)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld3.v4i32.p0(ptr) #3
|
||
|
|
||
|
define void @test_i1_arg_zext(ptr %f) {
|
||
|
; CHECK-LABEL: name: test_i1_arg_zext
|
||
|
; CHECK: [[I1:%[0-9]+]]:_(s1) = G_CONSTANT i1 true
|
||
|
; CHECK: [[ZEXT0:%[0-9]+]]:_(s8) = G_ZEXT [[I1]](s1)
|
||
|
; CHECK: [[ZEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[ZEXT0]](s8)
|
||
|
; CHECK: $w0 = COPY [[ZEXT1]](s32)
|
||
|
call void %f(i1 true)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare ptr @llvm.stacksave()
|
||
|
declare void @llvm.stackrestore(ptr)
|
||
|
define void @test_stacksaverestore() {
|
||
|
; CHECK-LABEL: name: test_stacksaverestore
|
||
|
; CHECK: [[SAVE:%[0-9]+]]:_(p0) = G_STACKSAVE
|
||
|
; CHECK-NEXT: G_STACKRESTORE [[SAVE]]
|
||
|
; CHECK-NEXT: RET_ReallyLR
|
||
|
%sp = call ptr @llvm.stacksave()
|
||
|
call void @llvm.stackrestore(ptr %sp)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare float @llvm.rint.f32(float)
|
||
|
define float @test_rint_f32(float %x) {
|
||
|
; CHECK-LABEL: name: test_rint_f32
|
||
|
; CHECK: %{{[0-9]+}}:_(s32) = G_FRINT %{{[0-9]+}}
|
||
|
%y = call float @llvm.rint.f32(float %x)
|
||
|
ret float %y
|
||
|
}
|
||
|
|
||
|
declare void @llvm.assume(i1)
|
||
|
define void @test_assume(i1 %x) {
|
||
|
; CHECK-LABEL: name: test_assume
|
||
|
; CHECK-NOT: llvm.assume
|
||
|
; CHECK: RET_ReallyLR
|
||
|
call void @llvm.assume(i1 %x)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare void @llvm.experimental.noalias.scope.decl(metadata)
|
||
|
define void @test.llvm.noalias.scope.decl(ptr %P, ptr %Q) nounwind ssp {
|
||
|
tail call void @llvm.experimental.noalias.scope.decl(metadata !3)
|
||
|
; CHECK-LABEL: name: test.llvm.noalias.scope.decl
|
||
|
; CHECK-NOT: llvm.experimental.noalias.scope.decl
|
||
|
; CHECK: RET_ReallyLR
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
!3 = !{ !4 }
|
||
|
!4 = distinct !{ !4, !5, !"test1: var" }
|
||
|
!5 = distinct !{ !5, !"test1" }
|
||
|
|
||
|
|
||
|
declare void @llvm.sideeffect()
|
||
|
define void @test_sideeffect() {
|
||
|
; CHECK-LABEL: name: test_sideeffect
|
||
|
; CHECK-NOT: llvm.sideeffect
|
||
|
; CHECK: RET_ReallyLR
|
||
|
call void @llvm.sideeffect()
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare void @llvm.var.annotation(ptr, ptr, ptr, i32, ptr)
|
||
|
define void @test_var_annotation(ptr, ptr, ptr, i32) {
|
||
|
; CHECK-LABEL: name: test_var_annotation
|
||
|
; CHECK-NOT: llvm.var.annotation
|
||
|
; CHECK: RET_ReallyLR
|
||
|
call void @llvm.var.annotation(ptr %0, ptr %1, ptr %2, i32 %3, ptr null)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare i64 @llvm.readcyclecounter()
|
||
|
define i64 @test_readcyclecounter() {
|
||
|
; CHECK-LABEL: name: test_readcyclecounter
|
||
|
; CHECK: [[RES:%[0-9]+]]:_(s64) = G_READCYCLECOUNTER{{$}}
|
||
|
; CHECK-NEXT: $x0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $x0
|
||
|
%res = call i64 @llvm.readcyclecounter()
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
define i64 @test_freeze(i64 %a) {
|
||
|
; CHECK-LABEL: name: test_freeze
|
||
|
; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
|
||
|
; CHECK-NEXT: [[RES:%[0-9]+]]:_(s64) = G_FREEZE [[COPY]]
|
||
|
; CHECK-NEXT: $x0 = COPY [[RES]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $x0
|
||
|
%res = freeze i64 %a
|
||
|
ret i64 %res
|
||
|
}
|
||
|
|
||
|
define {i8, i32} @test_freeze_struct(ptr %addr) {
|
||
|
; CHECK-LABEL: name: test_freeze_struct
|
||
|
; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
|
||
|
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s8) = G_LOAD [[COPY]](p0)
|
||
|
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||
|
; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]]
|
||
|
; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD]](p0)
|
||
|
; CHECK-NEXT: [[FREEZE:%[0-9]+]]:_(s8) = G_FREEZE [[LOAD]]
|
||
|
; CHECK-NEXT: [[FREEZE1:%[0-9]+]]:_(s32) = G_FREEZE [[LOAD1]]
|
||
|
; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FREEZE]]
|
||
|
; CHECK-NEXT: $w0 = COPY [[ANYEXT]]
|
||
|
; CHECK-NEXT: $w1 = COPY [[FREEZE1]]
|
||
|
; CHECK-NEXT: RET_ReallyLR implicit $w0, implicit $w1
|
||
|
%load = load { i8, i32 }, ptr %addr
|
||
|
%res = freeze {i8, i32} %load
|
||
|
ret {i8, i32} %res
|
||
|
}
|
||
|
|
||
|
!0 = !{ i64 0, i64 2 }
|
||
|
|
||
|
declare i64 @llvm.lround.i64.f32(float) nounwind readnone
|
||
|
define i64 @lround(float %x) {
|
||
|
; CHECK-LABEL: name: lround
|
||
|
; CHECK: bb.1 (%ir-block.0):
|
||
|
; CHECK: liveins: $s0
|
||
|
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[LROUND:%[0-9]+]]:_(s64) = G_LROUND [[COPY]](s32)
|
||
|
; CHECK: $x0 = COPY [[LROUND]](s64)
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
%lround = tail call i64 @llvm.lround.i64.f32(float %x)
|
||
|
ret i64 %lround
|
||
|
}
|
||
|
|
||
|
declare i64 @llvm.llround.i64.f32(float) nounwind readnone
|
||
|
define i64 @llround(float %x) {
|
||
|
; CHECK-LABEL: name: llround
|
||
|
; CHECK: bb.1 (%ir-block.0):
|
||
|
; CHECK: liveins: $s0
|
||
|
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $s0
|
||
|
; CHECK: [[LLROUND:%[0-9]+]]:_(s64) = G_LLROUND [[COPY]](s32)
|
||
|
; CHECK: $x0 = COPY [[LLROUND]](s64)
|
||
|
; CHECK: RET_ReallyLR implicit $x0
|
||
|
%lround = tail call i64 @llvm.llround.i64.f32(float %x)
|
||
|
ret i64 %lround
|
||
|
}
|