allow noread functions to access const globals
required by LLVM's switch lowering pass
fixes
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -2584,7 +2584,7 @@ static void check_can_load(State &s, const expr &p0) {
Pointer p(s.getMemory(), p0);
if (attrs.has(FnAttrs::NoRead))
- s.addUB(p.isLocal());
+ s.addUB(p.isLocal() || p.isConstGlobal());
else if (attrs.has(FnAttrs::ArgMemOnly))
s.addUB(p.isLocal() || ptr_only_args(s, p));
}

MODIFY
ir/pointer.cpp
ir/pointer.cpp
@@ -165,6 +165,15 @@ expr Pointer::isLocal(bool simplify) const {
return local == 1;
}
+expr Pointer::isConstGlobal() const {
+ auto bid = getShortBid();
+ auto generic = bid.uge(has_null_block) &&
+ bid.ule(num_consts_src + has_null_block - 1);
+ auto tgt = bid.uge(num_nonlocals_src + num_extra_nonconst_tgt) &&
+ bid.ule(num_nonlocals - 1);
+ return !isLocal() && (generic || tgt);
+}
+
expr Pointer::getBid() const {
return p.extract(totalBits() - 1, bits_for_offset + bits_for_ptrattrs);
}

MODIFY
ir/pointer.h
ir/pointer.h
@@ -56,6 +56,7 @@ public:
static bool hasLocalBit();
smt::expr isLocal(bool simplify = true) const;
+ smt::expr isConstGlobal() const;
smt::expr getBid() const;
smt::expr getShortBid() const; // same as getBid but ignoring is_local bit

ADD
tests/alive-tv/switch-to-table.srctgt.ll
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @src(i32 %c) readnone {
+entry:
+ switch i32 %c, label %default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+
+sw.bb1:
+ br label %return
+
+sw.bb2:
+ br label %return
+
+sw.bb3:
+ br label %return
+
+default:
+ br label %return
+
+return:
+ %retval.0 = phi i32 [ 33, %sw.bb0 ], [ 2, %sw.bb1 ], [ 5, %sw.bb2 ], [ 1, %sw.bb3 ], [ 0, %default ]
+ ret i32 %retval.0
+}
+
+
+@switch.table = hidden unnamed_addr constant [4 x i32] [i32 33, i32 2, i32 5, i32 1], align 4
+
+define i32 @tgt(i32 %c) readnone {
+entry:
+ %0 = icmp ule i32 %c, 3
+ br i1 %0, label %switch.lookup, label %default
+
+switch.lookup:
+ %switch.gep = getelementptr inbounds [4 x i32], [4 x i32]* @switch.table, i64 0, i32 %c
+ %switch.load = load i32, i32* %switch.gep, align 4
+ ret i32 %switch.load
+
+default:
+ ret i32 0
+}
+

allow noread functions to access const globals
required by LLVM's switch lowering pass
fixes #477