Files
clang-p2996/llvm/test/CodeGen/SPIRV/instructions/scalar-integer-arithmetic.ll
Vyacheslav Levytskyy 8ac46d6b4f [SPIR-V] Implement builtins for OpIAddCarry/OpISubBorrow and improve/fix type inference (#115192)
This PR is to solve several intertwined issues with type inference while
adding support for builtins for OpIAddCarry and OpISubBorrow:
* OpIAddCarry and OpISubBorrow generation in a way of supporting SPIR-V
friendly builtins `__spirv_...` -- introduces a new element to account
for, namely, `ptr sret (%struct) %0` argument that is a place to put a
result of the instruction;
* fix early definition of SPIR-V types during call lowering -- namely,
the goal of the PR is to ensure that correct types are applied to
virtual registers which were used as arguments in call lowering and so
caused early definition of SPIR-V types; reproducers are attached as a
new test cases;
* improve parsing of builtin names (e.g., understand a name of a kind
`"anon<int, int> __spirv_IAddCarry<int, int>(int, int)"` that was
incorrectly parsed as `anon` before the PR);
* improve type inference and fix access to erased from parent after
visit instructions -- before the PR visiting of instructions in
emitintrinsics pass replaced old alloca's, bitcast's, etc. instructions
with a newly generated internal SPIR-V intrinsics and after erasing old
instructions there were still references to them in a postprocessing
working list, while records for newly deduced pointee types were lost;
this PR fixes the issue by adding as consistent wrt. internal data
structures action `SPIRVEmitIntrinsics::replaceAllUsesWith()` that fixes
above mentioned problems;
* LLVM IR add/sub instructions result in logical SPIR-V instructions
when applied to bool type;
* fix validation of pointer types for frexp and lgamma_r,
* fix hardcoded reference to AS0 as a Function storage class in
lib/Target/SPIRV/SPIRVBuiltins.cpp -- now it's
`storageClassToAddressSpace(SPIRV::StorageClass::Function)`,
* re-use the same OpTypeStruct for two identical references to struct's
in arithmetic with overflow instructions.
2024-11-14 15:30:05 +01:00

126 lines
4.0 KiB
LLVM

; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: OpName [[BOOL_ADD:%.+]] "bool_add"
; CHECK-DAG: OpName [[BOOL_SUB:%.+]] "bool_sub"
; CHECK-DAG: OpName [[SCALAR_ADD:%.+]] "scalar_add"
; CHECK-DAG: OpName [[SCALAR_SUB:%.+]] "scalar_sub"
; CHECK-DAG: OpName [[SCALAR_MUL:%.+]] "scalar_mul"
; CHECK-DAG: OpName [[SCALAR_UDIV:%.+]] "scalar_udiv"
; CHECK-DAG: OpName [[SCALAR_SDIV:%.+]] "scalar_sdiv"
;; TODO: add tests for urem + srem
;; TODO: add test for OpSNegate
; CHECK-NOT: DAG-FENCE
; CHECK-DAG: [[BOOL:%.+]] = OpTypeBool
; CHECK-DAG: [[SCALAR:%.+]] = OpTypeInt 32
; CHECK-DAG: [[SCALAR_FN:%.+]] = OpTypeFunction [[SCALAR]] [[SCALAR]] [[SCALAR]]
; CHECK-DAG: [[BOOL_FN:%.+]] = OpTypeFunction [[BOOL]] [[BOOL]] [[BOOL]]
; CHECK-NOT: DAG-FENCE
;; Test add on scalar:
define i1 @bool_add(i1 %a, i1 %b) {
%c = add i1 %a, %b
ret i1 %c
}
; CHECK: [[BOOL_ADD]] = OpFunction [[BOOL]] None [[BOOL_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[BOOL]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[BOOL]]
; CHECK: OpLabel
; CHECK: [[C:%.+]] = OpLogicalNotEqual [[BOOL]] [[A]] [[B]]
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd
define i32 @scalar_add(i32 %a, i32 %b) {
%c = add i32 %a, %b
ret i32 %c
}
; CHECK: [[SCALAR_ADD]] = OpFunction [[SCALAR]] None [[SCALAR_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK: OpLabel
; CHECK: [[C:%.+]] = OpIAdd [[SCALAR]] [[A]] [[B]]
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd
;; Test sub on scalar:
define i1 @bool_sub(i1 %a, i1 %b) {
%c = sub i1 %a, %b
ret i1 %c
}
; CHECK: [[BOOL_SUB]] = OpFunction [[BOOL]] None [[BOOL_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[BOOL]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[BOOL]]
; CHECK: OpLabel
; CHECK: [[C:%.+]] = OpLogicalNotEqual [[BOOL]] [[A]] [[B]]
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd
define i32 @scalar_sub(i32 %a, i32 %b) {
%c = sub i32 %a, %b
ret i32 %c
}
; CHECK: [[SCALAR_SUB]] = OpFunction [[SCALAR]] None [[SCALAR_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK: OpLabel
; CHECK: [[C:%.+]] = OpISub [[SCALAR]] [[A]] [[B]]
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd
;; Test mul on scalar:
define i32 @scalar_mul(i32 %a, i32 %b) {
%c = mul i32 %a, %b
ret i32 %c
}
; CHECK: [[SCALAR_MUL]] = OpFunction [[SCALAR]] None [[SCALAR_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK: OpLabel
; CHECK: [[C:%.+]] = OpIMul [[SCALAR]] [[A]] [[B]]
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd
;; Test udiv on scalar:
define i32 @scalar_udiv(i32 %a, i32 %b) {
%c = udiv i32 %a, %b
ret i32 %c
}
; CHECK: [[SCALAR_UDIV]] = OpFunction [[SCALAR]] None [[SCALAR_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK: OpLabel
; CHECK: [[C:%.+]] = OpUDiv [[SCALAR]] [[A]] [[B]]
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd
;; Test sdiv on scalar:
define i32 @scalar_sdiv(i32 %a, i32 %b) {
%c = sdiv i32 %a, %b
ret i32 %c
}
; CHECK: [[SCALAR_SDIV]] = OpFunction [[SCALAR]] None [[SCALAR_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK: OpLabel
; CHECK: [[C:%.+]] = OpSDiv [[SCALAR]] [[A]] [[B]]
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd