Skip to content

Missed moving load after if.end block in memory_grow () #150437

@BreadTom

Description

@BreadTom

Clang 20.1.0 computes new_m = *m at entry block even though this value isn't needed until after if condition.
C code

#include <stdint.h>
#include <string.h>
#include <stdlib.h>

uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {
    uint8_t *new_m = *m;
    uint32_t r = *p;
    uint32_t new_p = r + n;
    if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);
    uint32_t new_c = *c;
    if (new_c < new_p) {
        do new_c += new_c / 2 + 8; while (new_c < new_p);
        if (new_c > UINT32_C(0xFFFF)) new_c = UINT32_C(0xFFFF);
        new_m = realloc(new_m, new_c << 16);
        if (new_m == NULL) return UINT32_C(0xFFFFFFFF);
        *m = new_m;
        *c = new_c;
    }
    *p = new_p;
    memset(&new_m[r << 16], 0, n << 16);
    return r;
}

uint32_t memory_grow_new(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {
    uint32_t r = *p;
    uint32_t new_p = r + n;
    if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);
    uint8_t *new_m = *m;
    uint32_t new_c = *c;
    if (new_c < new_p) {
        do new_c += new_c / 2 + 8; while (new_c < new_p);
        if (new_c > UINT32_C(0xFFFF)) new_c = UINT32_C(0xFFFF);
        new_m = realloc(new_m, new_c << 16);
        if (new_m == NULL) return UINT32_C(0xFFFFFFFF);
        *m = new_m;
        *c = new_c;
    }
    *p = new_p;
    memset(&new_m[r << 16], 0, n << 16);
    return r;
}

LLVM IR

define dso_local i32 @memory_grow(ptr nocapture noundef %m, ptr nocapture noundef %p, ptr nocapture noundef %c, i32 noundef %n) local_unnamed_addr {
entry:
  %0 = load ptr, ptr %m, align 8
  %1 = load i32, ptr %p, align 4
  %add = add i32 %1, %n
  %cmp = icmp ugt i32 %add, 65535
  br i1 %cmp, label %cleanup17, label %if.end

if.end:
  %2 = load i32, ptr %c, align 4
  %cmp1 = icmp ult i32 %2, %add
  br i1 %cmp1, label %do.body, label %if.end13

do.body:
  %new_c.0 = phi i32 [ %add4, %do.body ], [ %2, %if.end ]
  %div38 = lshr i32 %new_c.0, 1
  %add3 = add i32 %new_c.0, 8
  %add4 = add i32 %add3, %div38
  %cmp5 = icmp ult i32 %add4, %add
  br i1 %cmp5, label %do.body, label %do.end

do.end:
  %spec.store.select = tail call i32 @llvm.umin.i32(i32 %add4, i32 65535)
  %shl = shl nuw i32 %spec.store.select, 16
  %conv = zext i32 %shl to i64
  %call = tail call ptr @realloc(ptr noundef %0, i64 noundef %conv) #4
  %cmp9 = icmp eq ptr %call, null
  br i1 %cmp9, label %cleanup17, label %if.end12

if.end12:
  store ptr %call, ptr %m, align 8
  store i32 %spec.store.select, ptr %c, align 4
  br label %if.end13

if.end13:
  %new_m.0 = phi ptr [ %call, %if.end12 ], [ %0, %if.end ]
  store i32 %add, ptr %p, align 4
  %shl14 = shl i32 %1, 16
  %idxprom = zext i32 %shl14 to i64
  %arrayidx = getelementptr inbounds nuw i8, ptr %new_m.0, i64 %idxprom
  %shl15 = shl i32 %n, 16
  %conv16 = zext i32 %shl15 to i64
  tail call void @llvm.memset.p0.i64(ptr align 1 %arrayidx, i8 0, i64 %conv16, i1 false)
  br label %cleanup17

cleanup17:
  %retval.1 = phi i32 [ -1, %entry ], [ %1, %if.end13 ], [ -1, %do.end ]
  ret i32 %retval.1
}

declare noalias noundef ptr @realloc(ptr allocptr nocapture noundef, i64 noundef) local_unnamed_addr #1

declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #2

define dso_local i32 @memory_grow_new(ptr nocapture noundef %m, ptr nocapture noundef %p, ptr nocapture noundef %c, i32 noundef %n) local_unnamed_addr {
entry:
  %0 = load i32, ptr %p, align 4
  %add = add i32 %0, %n
  %cmp = icmp ugt i32 %add, 65535
  br i1 %cmp, label %cleanup18, label %if.end

if.end:
  %1 = load ptr, ptr %m, align 8
  %2 = load i32, ptr %c, align 4
  %cmp1 = icmp ult i32 %2, %add
  br i1 %cmp1, label %do.body, label %if.end13

do.body:
  %new_c.0 = phi i32 [ %add4, %do.body ], [ %2, %if.end ]
  %div38 = lshr i32 %new_c.0, 1
  %add3 = add i32 %new_c.0, 8
  %add4 = add i32 %add3, %div38
  %cmp5 = icmp ult i32 %add4, %add
  br i1 %cmp5, label %do.body, label %do.end

do.end:
  %spec.store.select = tail call i32 @llvm.umin.i32(i32 %add4, i32 65535)
  %shl = shl nuw i32 %spec.store.select, 16
  %conv = zext i32 %shl to i64
  %call = tail call ptr @realloc(ptr noundef %1, i64 noundef %conv) #4
  %cmp9 = icmp eq ptr %call, null
  br i1 %cmp9, label %cleanup18, label %if.end12

if.end12:
  store ptr %call, ptr %m, align 8
  store i32 %spec.store.select, ptr %c, align 4
  br label %if.end13

if.end13:
  %new_m.0 = phi ptr [ %call, %if.end12 ], [ %1, %if.end ]
  store i32 %add, ptr %p, align 4
  %shl14 = shl i32 %0, 16
  %idxprom = zext i32 %shl14 to i64
  %arrayidx = getelementptr inbounds nuw i8, ptr %new_m.0, i64 %idxprom
  %shl15 = shl i32 %n, 16
  %conv16 = zext i32 %shl15 to i64
  tail call void @llvm.memset.p0.i64(ptr align 1 %arrayidx, i8 0, i64 %conv16, i1 false)
  br label %cleanup18

cleanup18:
  %retval.1 = phi i32 [ -1, %entry ], [ %0, %if.end13 ], [ -1, %do.end ]
  ret i32 %retval.1
}

declare i32 @llvm.umin.i32(i32, i32) #3

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions