[LLVMdev] RFC: change BoundsChecking.cpp to use address-based tests

Schoedel, Kevin P kevin.p.schoedel at intel.com
Mon Nov 26 07:56:09 PST 2012


I am investigating changing BoundsChecking to use address-based rather
than size- & offset-based tests.

To explain, here is a short code sample cribbed from one of the tests:

  %mem = tail call i8* @calloc(i64 1, i64 %elements)
  %memobj = bitcast i8* %mem to i64*
  %ptr = getelementptr inbounds i64* %memobj, i64 %index
  %4 = load i64* %ptr, align 8

Currently, the IR for bounds checking this load looks like this:

  %size = mul i64 8, %elements
  %offset = mul i64 %index, 8
  %objsize = sub i64 %size, %offset

  %cmp2 = icmp ult i64 %size, %offset
  %cmp3 = icmp ult i64 %objsize, 8
  %cmp1 = icmp slt i64 %offset, 0

  %9 = or i1 %cmp2, %cmp3
  %11 = or i1 %cmp1, %9
  br i1 %11, label %trap, label %12

                      ┆       ┆
                      │       │
    ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┢━━━━━━━┪╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶
    ↑                 ┃       ┃              ↑      ↑
    ·                 ┇       ┇              ·      ·
    ·                 ┃       ┃              ·      ·
    ·        ╴╴╴╴╴╴╴╴╴┣━━━━━━━┫╶╶╶╶╶╶╶╶    ObjSize  ·
    ·        ↑        ┃       ┃       ↑      ·      ·
    ·     data item   ┃       ┃  NeededSize  ·    Size
    ·        ↓        ┃       ┃       ↓      ↓      ·
    ·        ╴╴╴╴Ptr╴╴┣━━━━━━━┫╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶      ·
    ·                 ┃       ┃              ↑      ·
  memory object       ┇       ┇            Offset   ·
    ↓                 ┃       ┃              ↓      ↓
    ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┡━━━━━━━┩╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶
                      │       │
                      │       │  Cmp1: Offset ≥ 0 (unless constant)
                      │       │  Cmp2: Size ≥ Offset
                      ┆       ┆  Cmp3: ObjSize ≥ NeededSize


I am looking at generating IR like this:

  %upperbound = getelementptr inbounds i64* %memobj, i64 %elements
  %end = getelementptr inbounds i64* %ptr, i64 1

  %ilowerbound = ptrtoint i64* %memobj to i64
  %iupperbound = ptrtoint i64* %upperbound to i64
  %iptr = ptrtoint i64* %ptr to i64
  %iend = ptrtoint i64* %end to i64

  %cmpl = icmp ult %iptr, %ilowerbound
  %cmpu = icmp ult %iupperbound, %iend

  %9 = or i1 %cmpl, %cmpu
  br i1 %11, label %trap, label %12

                      ┆       ┆
                      │       │
    ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┢━━━━━━━┪╶╶╶╶╶UpperBound
    ↑                 ┃       ┃        
    ·                 ┇       ┇        
    ·                 ┃       ┃        
    ·        ╴╴╴╴╴╴╴╴╴┣━━━━━━━┫╶╶╶╶╶╶╶╶╶╶╶╶End
    ·        ↑        ┃       ┃           
    ·     data item   ┃       ┃           
    ·        ↓        ┃       ┃           
    ·        ╴╴╴╴Ptr╴╴┣━━━━━━━┫╶╶╶╶╶╶╶╶╶╶╶╶Ptr
    ·                 ┃       ┃
  memory object       ┇       ┇
    ↓                 ┃       ┃
    ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┡━━━━━━━┩╶╶╶╶╶LowerBound
                      │       │
                      │       │  Cmp1: Ptr ≥ LowerBound
                      ┆       ┆  Cmp2: UpperBound ≥ End

Potential advantages that I see for address-based tests: 
- Always performs two comparisons, rather than (sometimes) three;
- No need to recompute Offset and ObjSize for varying Ptr within the
  same memory object;
- getelementptr, for UpperBound and End, is typically very cheap on
  contemporary processors (and ptrtoint typically free).

I have prototyped address-based testing (with one wart that makes it
not production grade) but not done benchmarking and analysis. Before
I do that, I'm looking for any reasons that this method of bounds
checking would be a "no go".

-- 
Kevin Schoedel kevin.p.schoedel at intel.com +1-519-772-2580
SSG-DPD-ECDL-DMP - Intel Dynamic Mobility and Parallelism






More information about the llvm-dev mailing list