blob: a7c946eaffd03beda1f153527f1a157635355512 [file] [log] [blame]
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -Wno-unused-value -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -Wno-unused-value -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
unsigned up0() {
unsigned a = 1u;
return +a;
}
// CHECK: cir.func{{.*}} @_Z3up0v() -> !u32i
// CHECK: %[[A:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init]
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[OUTPUT:.*]] = cir.unary(plus, %[[INPUT]])
// LLVM: define{{.*}} i32 @_Z3up0v()
// LLVM: %[[RV:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[A:.*]] = alloca i32, i64 1, align 4
// LLVM: store i32 1, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// OGCG: define{{.*}} i32 @_Z3up0v()
// OGCG: %[[A:.*]] = alloca i32, align 4
// OGCG: store i32 1, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
unsigned um0() {
unsigned a = 1u;
return -a;
}
// CHECK: cir.func{{.*}} @_Z3um0v() -> !u32i
// CHECK: %[[A:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init]
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[OUTPUT:.*]] = cir.unary(minus, %[[INPUT]])
// LLVM: define{{.*}} i32 @_Z3um0v()
// LLVM: %[[RV:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[A:.*]] = alloca i32, i64 1, align 4
// LLVM: store i32 1, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = sub i32 0, %[[A_LOAD]]
// OGCG: define{{.*}} i32 @_Z3um0v()
// OGCG: %[[A:.*]] = alloca i32, align 4
// OGCG: store i32 1, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = sub i32 0, %[[A_LOAD]]
unsigned un0() {
unsigned a = 1u;
return ~a; // a ^ -1 , not
}
// CHECK: cir.func{{.*}} @_Z3un0v() -> !u32i
// CHECK: %[[A:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init]
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[OUTPUT:.*]] = cir.unary(not, %[[INPUT]])
// LLVM: define{{.*}} i32 @_Z3un0v()
// LLVM: %[[RV:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[A:.*]] = alloca i32, i64 1, align 4
// LLVM: store i32 1, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = xor i32 %[[A_LOAD]], -1
// OGCG: define{{.*}} i32 @_Z3un0v()
// OGCG: %[[A:.*]] = alloca i32, align 4
// OGCG: store i32 1, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = xor i32 %[[A_LOAD]], -1
int inc0() {
int a = 1;
++a;
return a;
}
// CHECK: cir.func{{.*}} @_Z4inc0v() -> !s32i
// CHECK: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !s32i
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]]) nsw
// CHECK: cir.store{{.*}} %[[INCREMENTED]], %[[A]]
// CHECK: %[[A_TO_OUTPUT:.*]] = cir.load{{.*}} %[[A]]
// LLVM: define{{.*}} i32 @_Z4inc0v()
// LLVM: %[[RV:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[A:.*]] = alloca i32, i64 1, align 4
// LLVM: store i32 1, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = add nsw i32 %[[A_LOAD]], 1
// OGCG: define{{.*}} i32 @_Z4inc0v()
// OGCG: %[[A:.*]] = alloca i32, align 4
// OGCG: store i32 1, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = add nsw i32 %[[A_LOAD]], 1
int dec0() {
int a = 1;
--a;
return a;
}
// CHECK: cir.func{{.*}} @_Z4dec0v() -> !s32i
// CHECK: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !s32i
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[DECREMENTED:.*]] = cir.unary(dec, %[[INPUT]]) nsw
// CHECK: cir.store{{.*}} %[[DECREMENTED]], %[[A]]
// CHECK: %[[A_TO_OUTPUT:.*]] = cir.load{{.*}} %[[A]]
// LLVM: define{{.*}} i32 @_Z4dec0v()
// LLVM: %[[RV:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[A:.*]] = alloca i32, i64 1, align 4
// LLVM: store i32 1, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = sub nsw i32 %[[A_LOAD]], 1
// OGCG: define{{.*}} i32 @_Z4dec0v()
// OGCG: %[[A:.*]] = alloca i32, align 4
// OGCG: store i32 1, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = add nsw i32 %[[A_LOAD]], -1
int inc1() {
int a = 1;
a++;
return a;
}
// CHECK: cir.func{{.*}} @_Z4inc1v() -> !s32i
// CHECK: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !s32i
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]]) nsw
// CHECK: cir.store{{.*}} %[[INCREMENTED]], %[[A]]
// CHECK: %[[A_TO_OUTPUT:.*]] = cir.load{{.*}} %[[A]]
// LLVM: define{{.*}} i32 @_Z4inc1v()
// LLVM: %[[RV:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[A:.*]] = alloca i32, i64 1, align 4
// LLVM: store i32 1, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = add nsw i32 %[[A_LOAD]], 1
// OGCG: define{{.*}} i32 @_Z4inc1v()
// OGCG: %[[A:.*]] = alloca i32, align 4
// OGCG: store i32 1, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = add nsw i32 %[[A_LOAD]], 1
int dec1() {
int a = 1;
a--;
return a;
}
// CHECK: cir.func{{.*}} @_Z4dec1v() -> !s32i
// CHECK: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !s32i
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[DECREMENTED:.*]] = cir.unary(dec, %[[INPUT]]) nsw
// CHECK: cir.store{{.*}} %[[DECREMENTED]], %[[A]]
// CHECK: %[[A_TO_OUTPUT:.*]] = cir.load{{.*}} %[[A]]
// LLVM: define{{.*}} i32 @_Z4dec1v()
// LLVM: %[[RV:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[A:.*]] = alloca i32, i64 1, align 4
// LLVM: store i32 1, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = sub nsw i32 %[[A_LOAD]], 1
// OGCG: define{{.*}} i32 @_Z4dec1v()
// OGCG: %[[A:.*]] = alloca i32, align 4
// OGCG: store i32 1, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = add nsw i32 %[[A_LOAD]], -1
// Ensure the increment is performed after the assignment to b.
int inc2() {
int a = 1;
int b = a++;
return b;
}
// CHECK: cir.func{{.*}} @_Z4inc2v() -> !s32i
// CHECK: %[[A:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
// CHECK: %[[B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !s32i
// CHECK: %[[ATOB:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[ATOB]]) nsw
// CHECK: cir.store{{.*}} %[[INCREMENTED]], %[[A]]
// CHECK: cir.store{{.*}} %[[ATOB]], %[[B]]
// CHECK: %[[B_TO_OUTPUT:.*]] = cir.load{{.*}} %[[B]]
// LLVM: define{{.*}} i32 @_Z4inc2v()
// LLVM: %[[RV:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[A:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[B:.*]] = alloca i32, i64 1, align 4
// LLVM: store i32 1, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// LLVM: %[[A_INC:.*]] = add nsw i32 %[[A_LOAD]], 1
// LLVM: store i32 %[[A_INC]], ptr %[[A]], align 4
// LLVM: store i32 %[[A_LOAD]], ptr %[[B]], align 4
// LLVM: %[[B_TO_OUTPUT:.*]] = load i32, ptr %[[B]], align 4
// OGCG: define{{.*}} i32 @_Z4inc2v()
// OGCG: %[[A:.*]] = alloca i32, align 4
// OGCG: %[[B:.*]] = alloca i32, align 4
// OGCG: store i32 1, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load i32, ptr %[[A]], align 4
// OGCG: %[[A_INC:.*]] = add nsw i32 %[[A_LOAD]], 1
// OGCG: store i32 %[[A_INC]], ptr %[[A]], align 4
// OGCG: store i32 %[[A_LOAD]], ptr %[[B]], align 4
// OGCG: %[[B_TO_OUTPUT:.*]] = load i32, ptr %[[B]], align 4
float fpPlus() {
float a = 1.0f;
return +a;
}
// CHECK: cir.func{{.*}} @_Z6fpPlusv() -> !cir.float
// CHECK: %[[A:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[OUTPUT:.*]] = cir.unary(plus, %[[INPUT]])
// LLVM: define{{.*}} float @_Z6fpPlusv()
// LLVM: %[[RV:.*]] = alloca float, i64 1, align 4
// LLVM: %[[A:.*]] = alloca float, i64 1, align 4
// LLVM: store float 1.000000e+00, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// OGCG: define{{.*}} float @_Z6fpPlusv()
// OGCG: %[[A:.*]] = alloca float, align 4
// OGCG: store float 1.000000e+00, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
float fpMinus() {
float a = 1.0f;
return -a;
}
// CHECK: cir.func{{.*}} @_Z7fpMinusv() -> !cir.float
// CHECK: %[[A:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[OUTPUT:.*]] = cir.unary(minus, %[[INPUT]])
// LLVM: define{{.*}} float @_Z7fpMinusv()
// LLVM: %[[RV:.*]] = alloca float, i64 1, align 4
// LLVM: %[[A:.*]] = alloca float, i64 1, align 4
// LLVM: store float 1.000000e+00, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = fneg float %[[A_LOAD]]
// OGCG: define{{.*}} float @_Z7fpMinusv()
// OGCG: %[[A:.*]] = alloca float, align 4
// OGCG: store float 1.000000e+00, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = fneg float %[[A_LOAD]]
float fpPreInc() {
float a = 1.0f;
return ++a;
}
// CHECK: cir.func{{.*}} @_Z8fpPreIncv() -> !cir.float
// CHECK: %[[A:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !cir.float
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]])
// LLVM: define{{.*}} float @_Z8fpPreIncv()
// LLVM: %[[RV:.*]] = alloca float, i64 1, align 4
// LLVM: %[[A:.*]] = alloca float, i64 1, align 4
// LLVM: store float 1.000000e+00, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = fadd float 1.000000e+00, %[[A_LOAD]]
// OGCG: define{{.*}} float @_Z8fpPreIncv()
// OGCG: %[[A:.*]] = alloca float, align 4
// OGCG: store float 1.000000e+00, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = fadd float %[[A_LOAD]], 1.000000e+00
float fpPreDec() {
float a = 1.0f;
return --a;
}
// CHECK: cir.func{{.*}} @_Z8fpPreDecv() -> !cir.float
// CHECK: %[[A:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !cir.float
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[DECREMENTED:.*]] = cir.unary(dec, %[[INPUT]])
// LLVM: define{{.*}} float @_Z8fpPreDecv()
// LLVM: %[[RV:.*]] = alloca float, i64 1, align 4
// LLVM: %[[A:.*]] = alloca float, i64 1, align 4
// LLVM: store float 1.000000e+00, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = fadd float -1.000000e+00, %[[A_LOAD]]
// OGCG: define{{.*}} float @_Z8fpPreDecv()
// OGCG: %[[A:.*]] = alloca float, align 4
// OGCG: store float 1.000000e+00, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = fadd float %[[A_LOAD]], -1.000000e+00
float fpPostInc() {
float a = 1.0f;
return a++;
}
// CHECK: cir.func{{.*}} @_Z9fpPostIncv() -> !cir.float
// CHECK: %[[A:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !cir.float
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]])
// LLVM: define{{.*}} float @_Z9fpPostIncv()
// LLVM: %[[RV:.*]] = alloca float, i64 1, align 4
// LLVM: %[[A:.*]] = alloca float, i64 1, align 4
// LLVM: store float 1.000000e+00, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = fadd float 1.000000e+00, %[[A_LOAD]]
// OGCG: define{{.*}} float @_Z9fpPostIncv()
// OGCG: %[[A:.*]] = alloca float, align 4
// OGCG: store float 1.000000e+00, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = fadd float %[[A_LOAD]], 1.000000e+00
float fpPostDec() {
float a = 1.0f;
return a--;
}
// CHECK: cir.func{{.*}} @_Z9fpPostDecv() -> !cir.float
// CHECK: %[[A:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !cir.float
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[DECREMENTED:.*]] = cir.unary(dec, %[[INPUT]])
// LLVM: define{{.*}} float @_Z9fpPostDecv()
// LLVM: %[[RV:.*]] = alloca float, i64 1, align 4
// LLVM: %[[A:.*]] = alloca float, i64 1, align 4
// LLVM: store float 1.000000e+00, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// LLVM: %[[RESULT:.*]] = fadd float -1.000000e+00, %[[A_LOAD]]
// OGCG: define{{.*}} float @_Z9fpPostDecv()
// OGCG: %[[A:.*]] = alloca float, align 4
// OGCG: store float 1.000000e+00, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// OGCG: %[[RESULT:.*]] = fadd float %[[A_LOAD]], -1.000000e+00
// Ensure the increment is performed after the assignment to b.
float fpPostInc2() {
float a = 1.0f;
float b = a++;
return b;
}
// CHECK: cir.func{{.*}} @_Z10fpPostInc2v() -> !cir.float
// CHECK: %[[A:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a", init]
// CHECK: %[[B:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init]
// CHECK: %[[ATMP:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float
// CHECK: cir.store{{.*}} %[[ATMP]], %[[A]] : !cir.float
// CHECK: %[[ATOB:.*]] = cir.load{{.*}} %[[A]]
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[ATOB]])
// CHECK: cir.store{{.*}} %[[INCREMENTED]], %[[A]]
// CHECK: cir.store{{.*}} %[[ATOB]], %[[B]]
// CHECK: %[[B_TO_OUTPUT:.*]] = cir.load{{.*}} %[[B]]
// LLVM: define{{.*}} float @_Z10fpPostInc2v()
// LLVM: %[[RV:.*]] = alloca float, i64 1, align 4
// LLVM: %[[A:.*]] = alloca float, i64 1, align 4
// LLVM: %[[B:.*]] = alloca float, i64 1, align 4
// LLVM: store float 1.000000e+00, ptr %[[A]], align 4
// LLVM: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// LLVM: %[[A_INC:.*]] = fadd float 1.000000e+00, %[[A_LOAD]]
// LLVM: store float %[[A_INC]], ptr %[[A]], align 4
// LLVM: store float %[[A_LOAD]], ptr %[[B]], align 4
// LLVM: %[[B_TO_OUTPUT:.*]] = load float, ptr %[[B]], align 4
// OGCG: define{{.*}} float @_Z10fpPostInc2v()
// OGCG: %[[A:.*]] = alloca float, align 4
// OGCG: %[[B:.*]] = alloca float, align 4
// OGCG: store float 1.000000e+00, ptr %[[A]], align 4
// OGCG: %[[A_LOAD:.*]] = load float, ptr %[[A]], align 4
// OGCG: %[[A_INC:.*]] = fadd float %[[A_LOAD]], 1.000000e+00
// OGCG: store float %[[A_INC]], ptr %[[A]], align 4
// OGCG: store float %[[A_LOAD]], ptr %[[B]], align 4
// OGCG: %[[B_TO_OUTPUT:.*]] = load float, ptr %[[B]], align 4
void chars(char c) {
// CHECK: cir.func{{.*}} @_Z5charsc
int c1 = +c;
// CHECK: %[[PROMO:.*]] = cir.cast(integral, %{{.+}} : !s8i), !s32i
// CHECK: cir.unary(plus, %[[PROMO]]) : !s32i, !s32i
int c2 = -c;
// CHECK: %[[PROMO:.*]] = cir.cast(integral, %{{.+}} : !s8i), !s32i
// CHECK: cir.unary(minus, %[[PROMO]]) nsw : !s32i, !s32i
// Chars can go through some integer promotion codegen paths even when not promoted.
// These should not have nsw attributes because the intermediate promotion makes the
// overflow defined behavior.
++c; // CHECK: cir.unary(inc, %{{.+}}) : !s8i, !s8i
--c; // CHECK: cir.unary(dec, %{{.+}}) : !s8i, !s8i
c++; // CHECK: cir.unary(inc, %{{.+}}) : !s8i, !s8i
c--; // CHECK: cir.unary(dec, %{{.+}}) : !s8i, !s8i
}
_Float16 fp16UPlus(_Float16 f) {
return +f;
}
// CHECK: cir.func{{.*}} @_Z9fp16UPlusDF16_({{.*}}) -> !cir.f16
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[F:.*]]
// CHECK: %[[PROMOTED:.*]] = cir.cast(floating, %[[INPUT]] : !cir.f16), !cir.float
// CHECK: %[[RESULT:.*]] = cir.unary(plus, %[[PROMOTED]])
// CHECK: %[[UNPROMOTED:.*]] = cir.cast(floating, %[[RESULT]] : !cir.float), !cir.f16
// LLVM: define{{.*}} half @_Z9fp16UPlusDF16_({{.*}})
// LLVM: %[[F_LOAD:.*]] = load half, ptr %{{.*}}, align 2
// LLVM: %[[PROMOTED:.*]] = fpext half %[[F_LOAD]] to float
// LLVM: %[[UNPROMOTED:.*]] = fptrunc float %[[PROMOTED]] to half
// OGCG: define{{.*}} half @_Z9fp16UPlusDF16_({{.*}})
// OGCG: %[[F_LOAD:.*]] = load half, ptr %{{.*}}, align 2
// OGCG: %[[PROMOTED:.*]] = fpext half %[[F_LOAD]] to float
// OGCG: %[[UNPROMOTED:.*]] = fptrunc float %[[PROMOTED]] to half
_Float16 fp16UMinus(_Float16 f) {
return -f;
}
// CHECK: cir.func{{.*}} @_Z10fp16UMinusDF16_({{.*}}) -> !cir.f16
// CHECK: %[[INPUT:.*]] = cir.load{{.*}} %[[F:.*]]
// CHECK: %[[PROMOTED:.*]] = cir.cast(floating, %[[INPUT]] : !cir.f16), !cir.float
// CHECK: %[[RESULT:.*]] = cir.unary(minus, %[[PROMOTED]])
// CHECK: %[[UNPROMOTED:.*]] = cir.cast(floating, %[[RESULT]] : !cir.float), !cir.f16
// LLVM: define{{.*}} half @_Z10fp16UMinusDF16_({{.*}})
// LLVM: %[[F_LOAD:.*]] = load half, ptr %{{.*}}, align 2
// LLVM: %[[PROMOTED:.*]] = fpext half %[[F_LOAD]] to float
// LLVM: %[[RESULT:.*]] = fneg float %[[PROMOTED]]
// LLVM: %[[UNPROMOTED:.*]] = fptrunc float %[[RESULT]] to half
// OGCG: define{{.*}} half @_Z10fp16UMinusDF16_({{.*}})
// OGCG: %[[F_LOAD:.*]] = load half, ptr %{{.*}}, align 2
// OGCG: %[[PROMOTED:.*]] = fpext half %[[F_LOAD]] to float
// OGCG: %[[RESULT:.*]] = fneg float %[[PROMOTED]]
// OGCG: %[[UNPROMOTED:.*]] = fptrunc float %[[RESULT]] to half
void test_logical_not() {
int a = 5;
a = !a;
bool b = false;
b = !b;
float c = 2.0f;
c = !c;
int *p = 0;
b = !p;
double d = 3.0;
b = !d;
}
// CHECK: cir.func{{.*}} @_Z16test_logical_notv()
// CHECK: %[[A:.*]] = cir.load{{.*}} %[[A_ADDR:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[A_BOOL:.*]] = cir.cast(int_to_bool, %[[A]] : !s32i), !cir.bool
// CHECK: %[[A_NOT:.*]] = cir.unary(not, %[[A_BOOL]]) : !cir.bool, !cir.bool
// CHECK: %[[A_CAST:.*]] = cir.cast(bool_to_int, %[[A_NOT]] : !cir.bool), !s32i
// CHECK: cir.store{{.*}} %[[A_CAST]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i>
// CHECK: %[[B:.*]] = cir.load{{.*}} %[[B_ADDR:.*]] : !cir.ptr<!cir.bool>, !cir.bool
// CHECK: %[[B_NOT:.*]] = cir.unary(not, %[[B]]) : !cir.bool, !cir.bool
// CHECK: cir.store{{.*}} %[[B_NOT]], %[[B_ADDR]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: %[[C:.*]] = cir.load{{.*}} %[[C_ADDR:.*]] : !cir.ptr<!cir.float>, !cir.float
// CHECK: %[[C_BOOL:.*]] = cir.cast(float_to_bool, %[[C]] : !cir.float), !cir.bool
// CHECK: %[[C_NOT:.*]] = cir.unary(not, %[[C_BOOL]]) : !cir.bool, !cir.bool
// CHECK: %[[C_CAST:.*]] = cir.cast(bool_to_float, %[[C_NOT]] : !cir.bool), !cir.float
// CHECK: cir.store{{.*}} %[[C_CAST]], %[[C_ADDR]] : !cir.float, !cir.ptr<!cir.float>
// CHECK: %[[P:.*]] = cir.load{{.*}} %[[P_ADDR:.*]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CHECK: %[[P_BOOL:.*]] = cir.cast(ptr_to_bool, %[[P]] : !cir.ptr<!s32i>), !cir.bool
// CHECK: %[[P_NOT:.*]] = cir.unary(not, %[[P_BOOL]]) : !cir.bool, !cir.bool
// CHECK: cir.store{{.*}} %[[P_NOT]], %[[B_ADDR]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: %[[D:.*]] = cir.load{{.*}} %[[D_ADDR:.*]] : !cir.ptr<!cir.double>, !cir.double
// CHECK: %[[D_BOOL:.*]] = cir.cast(float_to_bool, %[[D]] : !cir.double), !cir.bool
// CHECK: %[[D_NOT:.*]] = cir.unary(not, %[[D_BOOL]]) : !cir.bool, !cir.bool
// CHECK: cir.store{{.*}} %[[D_NOT]], %[[B_ADDR]] : !cir.bool, !cir.ptr<!cir.bool>
// LLVM: define{{.*}} void @_Z16test_logical_notv()
// LLVM: %[[A:.*]] = load i32, ptr %[[A_ADDR:.*]], align 4
// LLVM: %[[A_BOOL:.*]] = icmp ne i32 %[[A]], 0
// LLVM: %[[A_NOT:.*]] = xor i1 %[[A_BOOL]], true
// LLVM: %[[A_CAST:.*]] = zext i1 %[[A_NOT]] to i32
// LLVM: store i32 %[[A_CAST]], ptr %[[A_ADDR]], align 4
// LLVM: %[[B:.*]] = load i8, ptr %[[B_ADDR:.*]], align 1
// LLVM: %[[B_BOOL:.*]] = trunc i8 %[[B]] to i1
// LLVM: %[[B_NOT:.*]] = xor i1 %[[B_BOOL]], true
// LLVM: %[[B_CAST:.*]] = zext i1 %[[B_NOT]] to i8
// LLVM: store i8 %[[B_CAST]], ptr %[[B_ADDR]], align 1
// LLVM: %[[C:.*]] = load float, ptr %[[C_ADDR:.*]], align 4
// LLVM: %[[C_BOOL:.*]] = fcmp une float %[[C]], 0.000000e+00
// LLVM: %[[C_NOT:.*]] = xor i1 %[[C_BOOL]], true
// LLVM: %[[C_CAST:.*]] = uitofp i1 %[[C_NOT]] to float
// LLVM: store float %[[C_CAST]], ptr %[[C_ADDR]], align 4
// LLVM: %[[P:.*]] = load ptr, ptr %[[P_ADDR:.*]], align 8
// LLVM: %[[P_BOOL:.*]] = icmp ne ptr %[[P]], null
// LLVM: %[[P_NOT:.*]] = xor i1 %[[P_BOOL]], true
// LLVM: %[[P_CAST:.*]] = zext i1 %[[P_NOT]] to i8
// LLVM: store i8 %[[P_CAST]], ptr %[[B_ADDR]], align 1
// LLVM: %[[D:.*]] = load double, ptr %[[D_ADDR:.*]], align 8
// LLVM: %[[D_BOOL:.*]] = fcmp une double %[[D]], 0.000000e+00
// LLVM: %[[D_NOT:.*]] = xor i1 %[[D_BOOL]], true
// LLVM: %[[D_CAST:.*]] = zext i1 %[[D_NOT]] to i8
// LLVM: store i8 %[[D_CAST]], ptr %[[B_ADDR]], align 1
// OGCG: define{{.*}} void @_Z16test_logical_notv()
// OGCG: %[[A:.*]] = load i32, ptr %[[A_ADDR:.*]], align 4
// OGCG: %[[A_BOOL:.*]] = icmp ne i32 %[[A]], 0
// OGCG: %[[A_NOT:.*]] = xor i1 %[[A_BOOL]], true
// OGCG: %[[A_CAST:.*]] = zext i1 %[[A_NOT]] to i32
// OGCG: store i32 %[[A_CAST]], ptr %[[A_ADDR]], align 4
// OGCG: %[[B:.*]] = load i8, ptr %[[B_ADDR:.*]], align 1
// OGCG: %[[B_BOOL:.*]] = trunc i8 %[[B]] to i1
// OGCG: %[[B_NOT:.*]] = xor i1 %[[B_BOOL]], true
// OGCG: %[[B_CAST:.*]] = zext i1 %[[B_NOT]] to i8
// OGCG: store i8 %[[B_CAST]], ptr %[[B_ADDR]], align 1
// OGCG: %[[C:.*]] = load float, ptr %[[C_ADDR:.*]], align 4
// OGCG: %[[C_BOOL:.*]] = fcmp une float %[[C]], 0.000000e+00
// OGCG: %[[C_NOT:.*]] = xor i1 %[[C_BOOL]], true
// OGCG: %[[C_CAST:.*]] = uitofp i1 %[[C_NOT]] to float
// OGCG: store float %[[C_CAST]], ptr %[[C_ADDR]], align 4
// OGCG: %[[P:.*]] = load ptr, ptr %[[P_ADDR:.*]], align 8
// OGCG: %[[P_BOOL:.*]] = icmp ne ptr %[[P]], null
// OGCG: %[[P_NOT:.*]] = xor i1 %[[P_BOOL]], true
// OGCG: %[[P_CAST:.*]] = zext i1 %[[P_NOT]] to i8
// OGCG: store i8 %[[P_CAST]], ptr %[[B_ADDR]], align 1
// OGCG: %[[D:.*]] = load double, ptr %[[D_ADDR:.*]], align 8
// OGCG: %[[D_BOOL:.*]] = fcmp une double %[[D]], 0.000000e+00
// OGCG: %[[D_NOT:.*]] = xor i1 %[[D_BOOL]], true
// OGCG: %[[D_CAST:.*]] = zext i1 %[[D_NOT]] to i8
// OGCG: store i8 %[[D_CAST]], ptr %[[B_ADDR]], align 1