Currently we emit an error in just about every case of conditionals with a 'non simple' branch if treated as an LValue. This patch adds support for the special case where this is an 'ignored' lvalue, which permits the side effects from happening. It also splits up the emit for conditional LValue in a way that should be usable to handle simple assignment expressions in similar situations. Differential Revision: https://reviews.llvm.org/D123680
148 lines
5.9 KiB
C++
148 lines
5.9 KiB
C++
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
|
|
|
struct S {
|
|
int field1 : 5;
|
|
int field2 : 6;
|
|
int field3 : 3;
|
|
};
|
|
|
|
void use(bool cond, struct S s1, struct S s2, int val1, int val2) {
|
|
// CHECK: define {{.*}}use{{.*}}(
|
|
// CHECK: %[[S1:.+]] = alloca %struct.S
|
|
// CHECK: %[[S2:.+]] = alloca %struct.S
|
|
// CHECK: %[[COND:.+]] = alloca i8
|
|
// CHECK: %[[VAL1:.+]] = alloca i32
|
|
// CHECK: %[[VAL2:.+]] = alloca i32
|
|
|
|
cond ? s1.field1 = val1 : s1.field2 = val2;
|
|
// Condition setup, branch.
|
|
// CHECK: %[[CONDLD:.+]] = load i8, ptr %[[COND]]
|
|
// CHECK: %[[TO_BOOL:.+]] = trunc i8 %[[CONDLD]] to i1
|
|
// CHECK: br i1 %[[TO_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
|
|
|
|
// 'True', branch set the BF, branch to 'end'.
|
|
// CHECK: [[TRUE]]:
|
|
// CHECK: %[[VAL1LD:.+]] = load i32, ptr %[[VAL1]]
|
|
// CHECK: %[[VAL1TRUNC:.+]] = trunc i32 %[[VAL1LD]] to i16
|
|
// CHECK: %[[BF_LOAD:.+]] = load i16, ptr %[[S1]]
|
|
// CHECK: %[[BF_VAL:.+]] = and i16 %[[VAL1TRUNC]], 31
|
|
// CHECK: %[[BF_CLEAR:.+]] = and i16 %[[BF_LOAD]], -32
|
|
// CHECK: %[[BF_SET:.+]] = or i16 %[[BF_CLEAR]], %[[BF_VAL]]
|
|
// CHECK: store i16 %[[BF_SET]], ptr %[[S1]]
|
|
// CHECK: br label %[[END:.+]]
|
|
|
|
// 'False', branch set the OTHER BF, branch to 'end'.
|
|
// CHECK: [[FALSE]]:
|
|
// CHECK: %[[VAL2LD:.+]] = load i32, ptr %[[VAL2]]
|
|
// CHECK: %[[VAL2TRUNC:.+]] = trunc i32 %[[VAL2LD]] to i16
|
|
// CHECK: %[[BF_LOAD:.+]] = load i16, ptr %[[S1]]
|
|
// CHECK: %[[BF_VAL:.+]] = and i16 %[[VAL2TRUNC]], 63
|
|
// CHECK: %[[BF_SHIFT:.+]] = shl i16 %[[BF_VAL]], 5
|
|
// CHECK: %[[BF_CLEAR:.+]] = and i16 %[[BF_LOAD]], -2017
|
|
// CHECK: %[[BF_SET:.+]] = or i16 %[[BF_CLEAR]], %[[BF_SHIFT]]
|
|
// CHECK: store i16 %[[BF_SET]], ptr %[[S1]]
|
|
// CHECK: br label %[[END:.+]]
|
|
|
|
// CHECK: [[END]]:
|
|
// There is nothing in the 'end' block associated with this, but it is the
|
|
// 'continuation' block for the rest of the function.
|
|
|
|
// Same test, has a no-op cast and parens.
|
|
(void)(cond ? s2.field1 = val1 : s2.field2 = val2);
|
|
// Condition setup, branch.
|
|
// CHECK: %[[CONDLD:.+]] = load i8, ptr %[[COND]]
|
|
// CHECK: %[[TO_BOOL:.+]] = trunc i8 %[[CONDLD]] to i1
|
|
// CHECK: br i1 %[[TO_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
|
|
|
|
// 'True', branch set the BF, branch to 'end'.
|
|
// CHECK: [[TRUE]]:
|
|
// CHECK: %[[VAL1LD:.+]] = load i32, ptr %[[VAL1]]
|
|
// CHECK: %[[VAL1TRUNC:.+]] = trunc i32 %[[VAL1LD]] to i16
|
|
// CHECK: %[[BF_LOAD:.+]] = load i16, ptr %[[S2]]
|
|
// CHECK: %[[BF_VAL:.+]] = and i16 %[[VAL1TRUNC]], 31
|
|
// CHECK: %[[BF_CLEAR:.+]] = and i16 %[[BF_LOAD]], -32
|
|
// CHECK: %[[BF_SET:.+]] = or i16 %[[BF_CLEAR]], %[[BF_VAL]]
|
|
// CHECK: store i16 %[[BF_SET]], ptr %[[S2]]
|
|
// CHECK: br label %[[END:.+]]
|
|
|
|
// 'False', branch set the OTHER BF, branch to 'end'.
|
|
// CHECK: [[FALSE]]:
|
|
// CHECK: %[[VAL2LD:.+]] = load i32, ptr %[[VAL2]]
|
|
// CHECK: %[[VAL2TRUNC:.+]] = trunc i32 %[[VAL2LD]] to i16
|
|
// CHECK: %[[BF_LOAD:.+]] = load i16, ptr %[[S2]]
|
|
// CHECK: %[[BF_VAL:.+]] = and i16 %[[VAL2TRUNC]], 63
|
|
// CHECK: %[[BF_SHIFT:.+]] = shl i16 %[[BF_VAL]], 5
|
|
// CHECK: %[[BF_CLEAR:.+]] = and i16 %[[BF_LOAD]], -2017
|
|
// CHECK: %[[BF_SET:.+]] = or i16 %[[BF_CLEAR]], %[[BF_SHIFT]]
|
|
// CHECK: store i16 %[[BF_SET]], ptr %[[S2]]
|
|
// CHECK: br label %[[END:.+]]
|
|
|
|
// CHECK: [[END]]:
|
|
// CHECK-NOT: phi
|
|
// There is nothing in the 'end' block associated with this, but it is the
|
|
// 'continuation' block for the rest of the function.
|
|
|
|
}
|
|
|
|
|
|
void use2(bool cond1, bool cond2, struct S s1, int val1, int val2, int val3) {
|
|
// CHECK: define {{.*}}use2{{.*}}(
|
|
// CHECK: %[[S1:.+]] = alloca %struct.S
|
|
// CHECK: %[[COND1:.+]] = alloca i8
|
|
// CHECK: %[[COND2:.+]] = alloca i8
|
|
// CHECK: %[[VAL1:.+]] = alloca i32
|
|
// CHECK: %[[VAL2:.+]] = alloca i32
|
|
// CHECK: %[[VAL3:.+]] = alloca i32
|
|
|
|
cond1 ? s1.field1 = val1 : cond2 ? s1.field2 = val2 : s1.field3 = val3;
|
|
// First Condition setup, branch.
|
|
// CHECK: %[[CONDLD:.+]] = load i8, ptr %[[COND1]]
|
|
// CHECK: %[[TO_BOOL:.+]] = trunc i8 %[[CONDLD]] to i1
|
|
// CHECK: br i1 %[[TO_BOOL]], label %[[TRUE:.+]], label %[[FALSE:.+]]
|
|
|
|
// First 'True' branch, sets field1 to val1.
|
|
// CHECK: [[TRUE]]:
|
|
// CHECK: %[[VAL1LD:.+]] = load i32, ptr %[[VAL1]]
|
|
// CHECK: %[[VAL1TRUNC:.+]] = trunc i32 %[[VAL1LD]] to i16
|
|
// CHECK: %[[BF_LOAD:.+]] = load i16, ptr %[[S1]]
|
|
// CHECK: %[[BF_VAL:.+]] = and i16 %[[VAL1TRUNC]], 31
|
|
// CHECK: %[[BF_CLEAR:.+]] = and i16 %[[BF_LOAD]], -32
|
|
// CHECK: %[[BF_SET:.+]] = or i16 %[[BF_CLEAR]], %[[BF_VAL]]
|
|
// CHECK: store i16 %[[BF_SET]], ptr %[[S1]]
|
|
// CHECK: br label %[[END:.+]]
|
|
|
|
// First 'False' branch, starts second ignored expression.
|
|
// CHECK: [[FALSE]]:
|
|
// CHECK: %[[CONDLD:.+]] = load i8, ptr %[[COND2]]
|
|
// CHECK: %[[TO_BOOL:.+]] = trunc i8 %[[CONDLD]] to i1
|
|
// CHECK: br i1 %[[TO_BOOL]], label %[[TRUE2:.+]], label %[[FALSE2:.+]]
|
|
|
|
// Second 'True' branch, sets field2 to val2.
|
|
// CHECK: [[TRUE2]]:
|
|
// CHECK: %[[VAL2LD:.+]] = load i32, ptr %[[VAL2]]
|
|
// CHECK: %[[VAL2TRUNC:.+]] = trunc i32 %[[VAL2LD]] to i16
|
|
// CHECK: %[[BF_LOAD:.+]] = load i16, ptr %[[S1]]
|
|
// CHECK: %[[BF_VAL:.+]] = and i16 %[[VAL2TRUNC]], 63
|
|
// CHECK: %[[BF_SHIFT:.+]] = shl i16 %[[BF_VAL]], 5
|
|
// CHECK: %[[BF_CLEAR:.+]] = and i16 %[[BF_LOAD]], -2017
|
|
// CHECK: %[[BF_SET:.+]] = or i16 %[[BF_CLEAR]], %[[BF_SHIFT]]
|
|
// CHECK: store i16 %[[BF_SET]], ptr %[[S1]]
|
|
// CHECK: br label %[[END:.+]]
|
|
|
|
// Second 'False' branch, sets field3 to val3.
|
|
// CHECK: [[FALSE2]]:
|
|
// CHECK: %[[VAL3LD:.+]] = load i32, ptr %[[VAL3]]
|
|
// CHECK: %[[VAL3TRUNC:.+]] = trunc i32 %[[VAL3LD]] to i16
|
|
// CHECK: %[[BF_LOAD:.+]] = load i16, ptr %[[S1]]
|
|
// CHECK: %[[BF_VAL:.+]] = and i16 %[[VAL3TRUNC]], 7
|
|
// CHECK: %[[BF_SHIFT:.+]] = shl i16 %[[BF_VAL]], 11
|
|
// CHECK: %[[BF_CLEAR:.+]] = and i16 %[[BF_LOAD]], -14337
|
|
// CHECK: %[[BF_SET:.+]] = or i16 %[[BF_CLEAR]], %[[BF_SHIFT]]
|
|
// CHECK: store i16 %[[BF_SET]], ptr %[[S1]]
|
|
// CHECK: br label %[[END:.+]]
|
|
|
|
// CHECK[[END]]:
|
|
// CHECK-NOT: phi
|
|
// Nothing left to do here.
|
|
}
|