1311 lines
36 KiB
LLVM
1311 lines
36 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s \
|
|
; RUN: -riscv-experimental-rv64-legal-i32 | FileCheck %s -check-prefix=RV64
|
|
|
|
;
|
|
; Get the actual value of the overflow bit.
|
|
;
|
|
define zeroext i1 @saddo1.i32(i32 signext %v1, i32 signext %v2, ptr %res) {
|
|
; RV64-LABEL: saddo1.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addw a3, a0, a1
|
|
; RV64-NEXT: slt a0, a3, a0
|
|
; RV64-NEXT: slti a1, a1, 0
|
|
; RV64-NEXT: xor a0, a1, a0
|
|
; RV64-NEXT: sw a3, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
; Test the immediate version.
|
|
define zeroext i1 @saddo2.i32(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: saddo2.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addiw a2, a0, 4
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 4)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
; Test negative immediates.
|
|
define zeroext i1 @saddo3.i32(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: saddo3.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addiw a2, a0, -4
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 -4)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
; Test immediates that are too large to be encoded.
|
|
define zeroext i1 @saddo4.i32(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: saddo4.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: lui a2, 4096
|
|
; RV64-NEXT: addi a2, a2, -1
|
|
; RV64-NEXT: addw a2, a0, a2
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 16777215)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @saddo1.i64(i64 %v1, i64 %v2, ptr %res) {
|
|
; RV64-LABEL: saddo1.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a3, a0, a1
|
|
; RV64-NEXT: slt a0, a3, a0
|
|
; RV64-NEXT: slti a1, a1, 0
|
|
; RV64-NEXT: xor a0, a1, a0
|
|
; RV64-NEXT: sd a3, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @saddo2.i64(i64 %v1, ptr %res) {
|
|
; RV64-LABEL: saddo2.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addi a2, a0, 4
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: sd a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 4)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @saddo3.i64(i64 %v1, ptr %res) {
|
|
; RV64-LABEL: saddo3.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addi a2, a0, -4
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: sd a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 -4)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @uaddo.i32(i32 signext %v1, i32 signext %v2, ptr %res) {
|
|
; RV64-LABEL: uaddo.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addw a1, a0, a1
|
|
; RV64-NEXT: sltu a0, a1, a0
|
|
; RV64-NEXT: sw a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @uaddo.i32.constant(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: uaddo.i32.constant:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addiw a2, a0, -2
|
|
; RV64-NEXT: sltu a0, a2, a0
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 -2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @uaddo.i32.constant_one(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: uaddo.i32.constant_one:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addiw a2, a0, 1
|
|
; RV64-NEXT: seqz a0, a2
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 1)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @uaddo.i64(i64 %v1, i64 %v2, ptr %res) {
|
|
; RV64-LABEL: uaddo.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a1, a0, a1
|
|
; RV64-NEXT: sltu a0, a1, a0
|
|
; RV64-NEXT: sd a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @uaddo.i64.constant_one(i64 %v1, ptr %res) {
|
|
; RV64-LABEL: uaddo.i64.constant_one:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addi a2, a0, 1
|
|
; RV64-NEXT: seqz a0, a2
|
|
; RV64-NEXT: sd a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 1)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @ssubo1.i32(i32 signext %v1, i32 signext %v2, ptr %res) {
|
|
; RV64-LABEL: ssubo1.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sgtz a3, a1
|
|
; RV64-NEXT: subw a1, a0, a1
|
|
; RV64-NEXT: slt a0, a1, a0
|
|
; RV64-NEXT: xor a0, a3, a0
|
|
; RV64-NEXT: sw a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @ssubo2.i32(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: ssubo2.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addiw a2, a0, 4
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %v1, i32 -4)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @ssubo.i64(i64 %v1, i64 %v2, ptr %res) {
|
|
; RV64-LABEL: ssubo.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sgtz a3, a1
|
|
; RV64-NEXT: sub a1, a0, a1
|
|
; RV64-NEXT: slt a0, a1, a0
|
|
; RV64-NEXT: xor a0, a3, a0
|
|
; RV64-NEXT: sd a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @usubo.i32(i32 signext %v1, i32 signext %v2, ptr %res) {
|
|
; RV64-LABEL: usubo.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: subw a1, a0, a1
|
|
; RV64-NEXT: sltu a0, a0, a1
|
|
; RV64-NEXT: sw a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @usubo.i32.constant.rhs(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: usubo.i32.constant.rhs:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addiw a2, a0, 2
|
|
; RV64-NEXT: sltu a0, a0, a2
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %v1, i32 -2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @usubo.i32.constant.lhs(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: usubo.i32.constant.lhs:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: li a2, -2
|
|
; RV64-NEXT: subw a2, a2, a0
|
|
; RV64-NEXT: addi a0, a2, 1
|
|
; RV64-NEXT: seqz a0, a0
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 -2, i32 %v1)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @usubo.i64(i64 %v1, i64 %v2, ptr %res) {
|
|
; RV64-LABEL: usubo.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sub a1, a0, a1
|
|
; RV64-NEXT: sltu a0, a0, a1
|
|
; RV64-NEXT: sd a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @smulo.i32(i32 signext %v1, i32 signext %v2, ptr %res) {
|
|
; RV64-LABEL: smulo.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mul a1, a0, a1
|
|
; RV64-NEXT: srai a0, a1, 32
|
|
; RV64-NEXT: sraiw a3, a1, 31
|
|
; RV64-NEXT: xor a0, a0, a3
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: sw a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @smulo2.i32(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: smulo2.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: li a2, 13
|
|
; RV64-NEXT: mul a2, a0, a2
|
|
; RV64-NEXT: srai a0, a2, 32
|
|
; RV64-NEXT: sraiw a3, a2, 31
|
|
; RV64-NEXT: xor a0, a0, a3
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 13)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @smulo.i64(i64 %v1, i64 %v2, ptr %res) {
|
|
; RV64-LABEL: smulo.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mulh a3, a0, a1
|
|
; RV64-NEXT: mul a1, a0, a1
|
|
; RV64-NEXT: srai a0, a1, 63
|
|
; RV64-NEXT: xor a0, a3, a0
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: sd a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @smulo2.i64(i64 %v1, ptr %res) {
|
|
; RV64-LABEL: smulo2.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: li a2, 13
|
|
; RV64-NEXT: mulh a3, a0, a2
|
|
; RV64-NEXT: mul a2, a0, a2
|
|
; RV64-NEXT: srai a0, a2, 63
|
|
; RV64-NEXT: xor a0, a3, a0
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: sd a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 13)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @umulo.i32(i32 signext %v1, i32 signext %v2, ptr %res) {
|
|
; RV64-LABEL: umulo.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: slli a1, a1, 32
|
|
; RV64-NEXT: slli a0, a0, 32
|
|
; RV64-NEXT: mulhu a1, a0, a1
|
|
; RV64-NEXT: srai a0, a1, 32
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: sw a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @umulo2.i32(i32 signext %v1, ptr %res) {
|
|
; RV64-LABEL: umulo2.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: li a2, 13
|
|
; RV64-NEXT: slli a2, a2, 32
|
|
; RV64-NEXT: slli a0, a0, 32
|
|
; RV64-NEXT: mulhu a2, a0, a2
|
|
; RV64-NEXT: srli a0, a2, 32
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: sw a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %v1, i32 13)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
store i32 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
; Similar to umulo.i32, but storing the overflow and returning the result.
|
|
define signext i32 @umulo3.i32(i32 signext %0, i32 signext %1, ptr %2) {
|
|
; RV64-LABEL: umulo3.i32:
|
|
; RV64: # %bb.0:
|
|
; RV64-NEXT: slli a1, a1, 32
|
|
; RV64-NEXT: slli a0, a0, 32
|
|
; RV64-NEXT: mulhu a0, a0, a1
|
|
; RV64-NEXT: srai a1, a0, 32
|
|
; RV64-NEXT: snez a1, a1
|
|
; RV64-NEXT: sext.w a0, a0
|
|
; RV64-NEXT: sw a1, 0(a2)
|
|
; RV64-NEXT: ret
|
|
%4 = tail call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %0, i32 %1)
|
|
%5 = extractvalue { i32, i1 } %4, 1
|
|
%6 = extractvalue { i32, i1 } %4, 0
|
|
%7 = zext i1 %5 to i32
|
|
store i32 %7, ptr %2, align 4
|
|
ret i32 %6
|
|
}
|
|
|
|
define zeroext i1 @umulo.i64(i64 %v1, i64 %v2, ptr %res) {
|
|
; RV64-LABEL: umulo.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mulhu a3, a0, a1
|
|
; RV64-NEXT: snez a3, a3
|
|
; RV64-NEXT: mul a0, a0, a1
|
|
; RV64-NEXT: sd a0, 0(a2)
|
|
; RV64-NEXT: mv a0, a3
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @umulo2.i64(i64 %v1, ptr %res) {
|
|
; RV64-LABEL: umulo2.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: li a3, 13
|
|
; RV64-NEXT: mulhu a2, a0, a3
|
|
; RV64-NEXT: snez a2, a2
|
|
; RV64-NEXT: mul a0, a0, a3
|
|
; RV64-NEXT: sd a0, 0(a1)
|
|
; RV64-NEXT: mv a0, a2
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 13)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
|
|
;
|
|
; Check the use of the overflow bit in combination with a select instruction.
|
|
;
|
|
define i32 @saddo.select.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: saddo.select.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addw a2, a0, a1
|
|
; RV64-NEXT: slt a2, a2, a0
|
|
; RV64-NEXT: slti a3, a1, 0
|
|
; RV64-NEXT: bne a3, a2, .LBB28_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB28_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = select i1 %obit, i32 %v1, i32 %v2
|
|
ret i32 %ret
|
|
}
|
|
|
|
define i1 @saddo.not.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: saddo.not.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addw a2, a0, a1
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: slti a1, a1, 0
|
|
; RV64-NEXT: xor a0, a1, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i64 @saddo.select.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: saddo.select.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a2, a0, a1
|
|
; RV64-NEXT: slt a2, a2, a0
|
|
; RV64-NEXT: slti a3, a1, 0
|
|
; RV64-NEXT: bne a3, a2, .LBB30_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB30_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = select i1 %obit, i64 %v1, i64 %v2
|
|
ret i64 %ret
|
|
}
|
|
|
|
define i1 @saddo.not.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: saddo.not.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a2, a0, a1
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: slti a1, a1, 0
|
|
; RV64-NEXT: xor a0, a1, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i32 @uaddo.select.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: uaddo.select.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addw a2, a0, a1
|
|
; RV64-NEXT: bltu a2, a0, .LBB32_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB32_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = select i1 %obit, i32 %v1, i32 %v2
|
|
ret i32 %ret
|
|
}
|
|
|
|
define i1 @uaddo.not.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: uaddo.not.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addw a1, a0, a1
|
|
; RV64-NEXT: sltu a0, a1, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i64 @uaddo.select.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: uaddo.select.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a2, a0, a1
|
|
; RV64-NEXT: bltu a2, a0, .LBB34_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB34_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = select i1 %obit, i64 %v1, i64 %v2
|
|
ret i64 %ret
|
|
}
|
|
|
|
define i1 @uaddo.not.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: uaddo.not.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a1, a0, a1
|
|
; RV64-NEXT: sltu a0, a1, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i32 @ssubo.select.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: ssubo.select.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sgtz a2, a1
|
|
; RV64-NEXT: subw a3, a0, a1
|
|
; RV64-NEXT: slt a3, a3, a0
|
|
; RV64-NEXT: bne a2, a3, .LBB36_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB36_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = select i1 %obit, i32 %v1, i32 %v2
|
|
ret i32 %ret
|
|
}
|
|
|
|
define i1 @ssubo.not.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: ssubo.not.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sgtz a2, a1
|
|
; RV64-NEXT: subw a1, a0, a1
|
|
; RV64-NEXT: slt a0, a1, a0
|
|
; RV64-NEXT: xor a0, a2, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i64 @ssubo.select.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: ssubo.select.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sgtz a2, a1
|
|
; RV64-NEXT: sub a3, a0, a1
|
|
; RV64-NEXT: slt a3, a3, a0
|
|
; RV64-NEXT: bne a2, a3, .LBB38_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB38_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = select i1 %obit, i64 %v1, i64 %v2
|
|
ret i64 %ret
|
|
}
|
|
|
|
define i1 @ssub.not.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: ssub.not.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sgtz a2, a1
|
|
; RV64-NEXT: sub a1, a0, a1
|
|
; RV64-NEXT: slt a0, a1, a0
|
|
; RV64-NEXT: xor a0, a2, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i32 @usubo.select.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: usubo.select.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: subw a2, a0, a1
|
|
; RV64-NEXT: bltu a0, a2, .LBB40_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB40_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = select i1 %obit, i32 %v1, i32 %v2
|
|
ret i32 %ret
|
|
}
|
|
|
|
define i1 @usubo.not.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: usubo.not.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: subw a1, a0, a1
|
|
; RV64-NEXT: sltu a0, a0, a1
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i64 @usubo.select.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: usubo.select.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sub a2, a0, a1
|
|
; RV64-NEXT: bltu a0, a2, .LBB42_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB42_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = select i1 %obit, i64 %v1, i64 %v2
|
|
ret i64 %ret
|
|
}
|
|
|
|
define i1 @usubo.not.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: usubo.not.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sub a1, a0, a1
|
|
; RV64-NEXT: sltu a0, a0, a1
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i32 @smulo.select.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: smulo.select.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mul a2, a0, a1
|
|
; RV64-NEXT: srai a3, a2, 32
|
|
; RV64-NEXT: sraiw a2, a2, 31
|
|
; RV64-NEXT: bne a3, a2, .LBB44_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB44_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = select i1 %obit, i32 %v1, i32 %v2
|
|
ret i32 %ret
|
|
}
|
|
|
|
define i1 @smulo.not.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: smulo.not.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mul a0, a0, a1
|
|
; RV64-NEXT: srai a1, a0, 32
|
|
; RV64-NEXT: sraiw a0, a0, 31
|
|
; RV64-NEXT: xor a0, a1, a0
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i64 @smulo.select.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: smulo.select.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mulh a2, a0, a1
|
|
; RV64-NEXT: mul a3, a0, a1
|
|
; RV64-NEXT: srai a3, a3, 63
|
|
; RV64-NEXT: bne a2, a3, .LBB46_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB46_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = select i1 %obit, i64 %v1, i64 %v2
|
|
ret i64 %ret
|
|
}
|
|
|
|
define i1 @smulo.not.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: smulo.not.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mulh a2, a0, a1
|
|
; RV64-NEXT: mul a0, a0, a1
|
|
; RV64-NEXT: srai a0, a0, 63
|
|
; RV64-NEXT: xor a0, a2, a0
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i32 @umulo.select.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: umulo.select.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: slli a2, a1, 32
|
|
; RV64-NEXT: slli a3, a0, 32
|
|
; RV64-NEXT: mulhu a2, a3, a2
|
|
; RV64-NEXT: srai a2, a2, 32
|
|
; RV64-NEXT: bnez a2, .LBB48_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB48_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = select i1 %obit, i32 %v1, i32 %v2
|
|
ret i32 %ret
|
|
}
|
|
|
|
define i1 @umulo.not.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: umulo.not.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: slli a1, a1, 32
|
|
; RV64-NEXT: slli a0, a0, 32
|
|
; RV64-NEXT: mulhu a0, a0, a1
|
|
; RV64-NEXT: srai a0, a0, 32
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i64 @umulo.select.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: umulo.select.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mulhu a2, a0, a1
|
|
; RV64-NEXT: bnez a2, .LBB50_2
|
|
; RV64-NEXT: # %bb.1: # %entry
|
|
; RV64-NEXT: mv a0, a1
|
|
; RV64-NEXT: .LBB50_2: # %entry
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = select i1 %obit, i64 %v1, i64 %v2
|
|
ret i64 %ret
|
|
}
|
|
|
|
define i1 @umulo.not.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: umulo.not.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mulhu a0, a0, a1
|
|
; RV64-NEXT: snez a0, a0
|
|
; RV64-NEXT: xori a0, a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
%ret = xor i1 %obit, true
|
|
ret i1 %ret
|
|
}
|
|
|
|
|
|
;
|
|
; Check the use of the overflow bit in combination with a branch instruction.
|
|
;
|
|
define zeroext i1 @saddo.br.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: saddo.br.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addw a2, a0, a1
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: slti a1, a1, 0
|
|
; RV64-NEXT: beq a1, a0, .LBB52_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB52_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @saddo.br.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: saddo.br.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a2, a0, a1
|
|
; RV64-NEXT: slt a0, a2, a0
|
|
; RV64-NEXT: slti a1, a1, 0
|
|
; RV64-NEXT: beq a1, a0, .LBB53_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB53_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @uaddo.br.i32(i32 %v1, i32 %v2) {
|
|
; RV64-LABEL: uaddo.br.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addw a1, a0, a1
|
|
; RV64-NEXT: sext.w a0, a0
|
|
; RV64-NEXT: bgeu a1, a0, .LBB54_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB54_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @uaddo.br.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: uaddo.br.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a1, a0, a1
|
|
; RV64-NEXT: bgeu a1, a0, .LBB55_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB55_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @ssubo.br.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: ssubo.br.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sgtz a2, a1
|
|
; RV64-NEXT: subw a1, a0, a1
|
|
; RV64-NEXT: slt a0, a1, a0
|
|
; RV64-NEXT: beq a2, a0, .LBB56_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB56_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @ssubo.br.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: ssubo.br.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sgtz a2, a1
|
|
; RV64-NEXT: sub a1, a0, a1
|
|
; RV64-NEXT: slt a0, a1, a0
|
|
; RV64-NEXT: beq a2, a0, .LBB57_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB57_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.ssub.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @usubo.br.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: usubo.br.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: subw a1, a0, a1
|
|
; RV64-NEXT: bgeu a0, a1, .LBB58_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB58_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @usubo.br.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: usubo.br.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: sub a1, a0, a1
|
|
; RV64-NEXT: bgeu a0, a1, .LBB59_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB59_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @smulo.br.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: smulo.br.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mul a0, a0, a1
|
|
; RV64-NEXT: srai a1, a0, 32
|
|
; RV64-NEXT: sraiw a0, a0, 31
|
|
; RV64-NEXT: beq a1, a0, .LBB60_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB60_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @smulo.br.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: smulo.br.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mulh a2, a0, a1
|
|
; RV64-NEXT: mul a0, a0, a1
|
|
; RV64-NEXT: srai a0, a0, 63
|
|
; RV64-NEXT: beq a2, a0, .LBB61_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB61_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @smulo2.br.i64(i64 %v1) {
|
|
; RV64-LABEL: smulo2.br.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: li a1, -13
|
|
; RV64-NEXT: mulh a2, a0, a1
|
|
; RV64-NEXT: mul a0, a0, a1
|
|
; RV64-NEXT: srai a0, a0, 63
|
|
; RV64-NEXT: beq a2, a0, .LBB62_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB62_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.smul.with.overflow.i64(i64 %v1, i64 -13)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @umulo.br.i32(i32 signext %v1, i32 signext %v2) {
|
|
; RV64-LABEL: umulo.br.i32:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: slli a1, a1, 32
|
|
; RV64-NEXT: slli a0, a0, 32
|
|
; RV64-NEXT: mulhu a0, a0, a1
|
|
; RV64-NEXT: srai a0, a0, 32
|
|
; RV64-NEXT: beqz a0, .LBB63_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB63_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %v1, i32 %v2)
|
|
%val = extractvalue {i32, i1} %t, 0
|
|
%obit = extractvalue {i32, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @umulo.br.i64(i64 %v1, i64 %v2) {
|
|
; RV64-LABEL: umulo.br.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: mulhu a0, a0, a1
|
|
; RV64-NEXT: beqz a0, .LBB64_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB64_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 %v2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @umulo2.br.i64(i64 %v1) {
|
|
; RV64-LABEL: umulo2.br.i64:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: add a1, a0, a0
|
|
; RV64-NEXT: bgeu a1, a0, .LBB65_2
|
|
; RV64-NEXT: # %bb.1: # %overflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: ret
|
|
; RV64-NEXT: .LBB65_2: # %continue
|
|
; RV64-NEXT: li a0, 1
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.umul.with.overflow.i64(i64 %v1, i64 2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %overflow, label %continue
|
|
|
|
overflow:
|
|
ret i1 false
|
|
|
|
continue:
|
|
ret i1 true
|
|
}
|
|
|
|
define zeroext i1 @uaddo.i64.constant(i64 %v1, ptr %res) {
|
|
; RV64-LABEL: uaddo.i64.constant:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addi a2, a0, 2
|
|
; RV64-NEXT: sltu a0, a2, a0
|
|
; RV64-NEXT: sd a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @uaddo.i64.constant_2048(i64 %v1, ptr %res) {
|
|
; RV64-LABEL: uaddo.i64.constant_2048:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addi a2, a0, 2047
|
|
; RV64-NEXT: addi a2, a2, 1
|
|
; RV64-NEXT: sltu a0, a2, a0
|
|
; RV64-NEXT: sd a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 2048)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define zeroext i1 @uaddo.i64.constant_2049(i64 %v1, ptr %res) {
|
|
; RV64-LABEL: uaddo.i64.constant_2049:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: addi a2, a0, 2047
|
|
; RV64-NEXT: addi a2, a2, 2
|
|
; RV64-NEXT: sltu a0, a2, a0
|
|
; RV64-NEXT: sd a2, 0(a1)
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 2049)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
store i64 %val, ptr %res
|
|
ret i1 %obit
|
|
}
|
|
|
|
define i64 @uaddo.i64.constant_setcc_on_overflow_flag(ptr %p) {
|
|
; RV64-LABEL: uaddo.i64.constant_setcc_on_overflow_flag:
|
|
; RV64: # %bb.0: # %entry
|
|
; RV64-NEXT: ld a1, 0(a0)
|
|
; RV64-NEXT: addi a0, a1, 2
|
|
; RV64-NEXT: bltu a0, a1, .LBB69_2
|
|
; RV64-NEXT: # %bb.1: # %IfOverflow
|
|
; RV64-NEXT: li a0, 0
|
|
; RV64-NEXT: .LBB69_2: # %IfNoOverflow
|
|
; RV64-NEXT: ret
|
|
entry:
|
|
%v1 = load i64, ptr %p
|
|
%t = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %v1, i64 2)
|
|
%val = extractvalue {i64, i1} %t, 0
|
|
%obit = extractvalue {i64, i1} %t, 1
|
|
br i1 %obit, label %IfNoOverflow, label %IfOverflow
|
|
IfOverflow:
|
|
ret i64 0
|
|
IfNoOverflow:
|
|
ret i64 %val
|
|
}
|
|
|
|
declare {i32, i1} @llvm.sadd.with.overflow.i32(i32, i32) nounwind readnone
|
|
declare {i64, i1} @llvm.sadd.with.overflow.i64(i64, i64) nounwind readnone
|
|
declare {i32, i1} @llvm.uadd.with.overflow.i32(i32, i32) nounwind readnone
|
|
declare {i64, i1} @llvm.uadd.with.overflow.i64(i64, i64) nounwind readnone
|
|
declare {i32, i1} @llvm.ssub.with.overflow.i32(i32, i32) nounwind readnone
|
|
declare {i64, i1} @llvm.ssub.with.overflow.i64(i64, i64) nounwind readnone
|
|
declare {i32, i1} @llvm.usub.with.overflow.i32(i32, i32) nounwind readnone
|
|
declare {i64, i1} @llvm.usub.with.overflow.i64(i64, i64) nounwind readnone
|
|
declare {i32, i1} @llvm.smul.with.overflow.i32(i32, i32) nounwind readnone
|
|
declare {i64, i1} @llvm.smul.with.overflow.i64(i64, i64) nounwind readnone
|
|
declare {i32, i1} @llvm.umul.with.overflow.i32(i32, i32) nounwind readnone
|
|
declare {i64, i1} @llvm.umul.with.overflow.i64(i64, i64) nounwind readnone
|