diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -813,6 +813,14 @@ return; // Propagate constant value markConstant(&I, C); + } else if (OpSt.isConstantRange()) { + + LatticeVal &LV = getValueState(&I); + ConstantRange OpRange = OpSt.getConstantRange(); + Type *DestTy = I.getDestTy(); + ConstantRange Res = + OpRange.castOp(I.getOpcode(), DL.getTypeSizeInBits(DestTy)); + mergeInValue(LV, &I, LatticeVal::getRange(Res)); } else if (!OpSt.isUnknown()) markOverdefined(&I); } diff --git a/llvm/test/Transforms/SCCP/ip-ranges-casts.ll b/llvm/test/Transforms/SCCP/ip-ranges-casts.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SCCP/ip-ranges-casts.ll @@ -0,0 +1,280 @@ +; RUN: opt < %s -ipsccp -S | FileCheck %s + +; x = [100, 301) +define internal i1 @f.trunc(i32 %x) { +; CHECK-LABEL: define internal i1 @f.trunc(i32 %x) { +; CHECK-NEXT: %t.1 = trunc i32 %x to i16 +; CHECK-NEXT: %c.2 = icmp sgt i16 %t.1, 299 +; CHECK-NEXT: %c.4 = icmp slt i16 %t.1, 101 +; CHECK-NEXT: %res.1 = add i1 false, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, false +; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4 +; CHECK-NEXT: %t.2 = trunc i32 %x to i8 +; CHECK-NEXT: %c.5 = icmp sgt i8 %t.2, 44 +; CHECK-NEXT: %c.6 = icmp sgt i8 %t.2, 43 +; CHECK-NEXT: %c.7 = icmp slt i8 %t.2, 100 +; CHECK-NEXT: %c.8 = icmp slt i8 %t.2, 101 +; CHECK-NEXT: %res.4 = add i1 %res.3, %c.5 +; CHECK-NEXT: %res.5 = add i1 %res.4, %c.6 +; CHECK-NEXT: %res.6 = add i1 %res.5, %c.7 +; CHECK-NEXT: %res.7 = add i1 %res.6, %c.8 +; CHECK-NEXT: ret i1 %res.7 + + %t.1 = trunc i32 %x to i16 + %c.1 = icmp sgt i16 %t.1, 300 + %c.2 = icmp sgt i16 %t.1, 299 + %c.3 = icmp slt i16 %t.1, 100 + %c.4 = icmp slt i16 %t.1, 101 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + %t.2 = trunc i32 %x to i8 + %c.5 = icmp sgt i8 %t.2, 300 + %c.6 = icmp sgt i8 %t.2, 299 + %c.7 = icmp slt i8 %t.2, 100 + %c.8 = icmp slt i8 %t.2, 101 + %res.4 = add i1 %res.3, %c.5 + %res.5 = add i1 %res.4, %c.6 + %res.6 = add i1 %res.5, %c.7 + %res.7 = add i1 %res.6, %c.8 + ret i1 %res.7 +} + +define i1 @caller1() { +; CHECK-LABEL: define i1 @caller1() { +; CHECK-NEXT: %call.1 = tail call i1 @f.trunc(i32 100) +; CHECK-NEXT: %call.2 = tail call i1 @f.trunc(i32 300) +; CHECK-NEXT: %res = and i1 %call.1, %call.2 +; CHECK-NEXT: ret i1 %res +; + %call.1 = tail call i1 @f.trunc(i32 100) + %call.2 = tail call i1 @f.trunc(i32 300) + %res = and i1 %call.1, %call.2 + ret i1 %res +} + + +; x = [100, 301) +define internal i1 @f.zext(i32 %x, i32 %y) { +; CHECK-LABEL: define internal i1 @f.zext(i32 %x, i32 %y) { +; CHECK-NEXT: %t.1 = zext i32 %x to i64 +; CHECK-NEXT: %c.2 = icmp sgt i64 %t.1, 299 +; CHECK-NEXT: %c.4 = icmp slt i64 %t.1, 101 +; CHECK-NEXT: %res.1 = add i1 false, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, false +; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4 +; CHECK-NEXT: %t.2 = zext i32 %y to i64 +; CHECK-NEXT: %c.5 = icmp sgt i64 %t.2, 300 +; CHECK-NEXT: %c.6 = icmp sgt i64 %t.2, 299 +; CHECK-NEXT: %c.8 = icmp slt i64 %t.2, 1 +; CHECK-NEXT: %res.4 = add i1 %res.3, %c.5 +; CHECK-NEXT: %res.5 = add i1 %res.4, %c.6 +; CHECK-NEXT: %res.6 = add i1 %res.5, false +; CHECK-NEXT: %res.7 = add i1 %res.6, %c.8 +; CHECK-NEXT: ret i1 %res.7 + + %t.1 = zext i32 %x to i64 + %c.1 = icmp sgt i64 %t.1, 300 + %c.2 = icmp sgt i64 %t.1, 299 + %c.3 = icmp slt i64 %t.1, 100 + %c.4 = icmp slt i64 %t.1, 101 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + %t.2 = zext i32 %y to i64 + %c.5 = icmp sgt i64 %t.2, 300 + %c.6 = icmp sgt i64 %t.2, 299 + %c.7 = icmp slt i64 %t.2, 0 + %c.8 = icmp slt i64 %t.2, 1 + %res.4 = add i1 %res.3, %c.5 + %res.5 = add i1 %res.4, %c.6 + %res.6 = add i1 %res.5, %c.7 + %res.7 = add i1 %res.6, %c.8 + ret i1 %res.7 +} + +define i1 @caller.zext() { +; CHECK-LABEL: define i1 @caller.zext() { +; CHECK-NEXT: %call.1 = tail call i1 @f.zext(i32 100, i32 -120) +; CHECK-NEXT: %call.2 = tail call i1 @f.zext(i32 300, i32 900) +; CHECK-NEXT: %res = and i1 %call.1, %call.2 +; CHECK-NEXT: ret i1 %res +; + %call.1 = tail call i1 @f.zext(i32 100, i32 -120) + %call.2 = tail call i1 @f.zext(i32 300, i32 900) + %res = and i1 %call.1, %call.2 + ret i1 %res +} + +; x = [100, 301) +define internal i1 @f.sext(i32 %x, i32 %y) { +; CHECK-LABEL: define internal i1 @f.sext(i32 %x, i32 %y) { +; CHECK-NEXT: %t.1 = sext i32 %x to i64 +; CHECK-NEXT: %c.2 = icmp sgt i64 %t.1, 299 +; CHECK-NEXT: %c.4 = icmp slt i64 %t.1, 101 +; CHECK-NEXT: %res.1 = add i1 false, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, false +; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4 +; CHECK-NEXT: %t.2 = sext i32 %y to i64 +; CHECK-NEXT: %c.6 = icmp sgt i64 %t.2, 899 +; CHECK-NEXT: %c.8 = icmp slt i64 %t.2, -119 +; CHECK-NEXT: %res.4 = add i1 %res.3, false +; CHECK-NEXT: %res.5 = add i1 %res.4, %c.6 +; CHECK-NEXT: %res.6 = add i1 %res.5, false +; CHECK-NEXT: %res.7 = add i1 %res.6, %c.8 +; CHECK-NEXT: ret i1 %res.7 +; + %t.1 = sext i32 %x to i64 + %c.1 = icmp sgt i64 %t.1, 300 + %c.2 = icmp sgt i64 %t.1, 299 + %c.3 = icmp slt i64 %t.1, 100 + %c.4 = icmp slt i64 %t.1, 101 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + %t.2 = sext i32 %y to i64 + %c.5 = icmp sgt i64 %t.2, 900 + %c.6 = icmp sgt i64 %t.2, 899 + %c.7 = icmp slt i64 %t.2, -120 + %c.8 = icmp slt i64 %t.2, -119 + %res.4 = add i1 %res.3, %c.5 + %res.5 = add i1 %res.4, %c.6 + %res.6 = add i1 %res.5, %c.7 + %res.7 = add i1 %res.6, %c.8 + ret i1 %res.7 +} + +define i1 @caller.sext() { +; CHECK-LABEL: define i1 @caller.sext() { +; CHECK-NEXT: %call.1 = tail call i1 @f.sext(i32 100, i32 -120) +; CHECK-NEXT: %call.2 = tail call i1 @f.sext(i32 300, i32 900) +; CHECK-NEXT: %res = and i1 %call.1, %call.2 +; CHECK-NEXT: ret i1 %res +; + %call.1 = tail call i1 @f.sext(i32 100, i32 -120) + %call.2 = tail call i1 @f.sext(i32 300, i32 900) + %res = and i1 %call.1, %call.2 + ret i1 %res +} + +; There's nothing we can do besides going to the full range or overdefined. +define internal i1 @f.fptosi(i32 %x) { +; CHECK-LABEL: define internal i1 @f.fptosi(i32 %x) { +; CHECK-NEXT: %to.double = sitofp i32 %x to double +; CHECK-NEXT: %add = fadd double 0.000000e+00, %to.double +; CHECK-NEXT: %to.i32 = fptosi double %add to i32 +; CHECK-NEXT: %c.1 = icmp sgt i32 %to.i32, 300 +; CHECK-NEXT: %c.2 = icmp sgt i32 %to.i32, 299 +; CHECK-NEXT: %c.3 = icmp slt i32 %to.i32, 100 +; CHECK-NEXT: %c.4 = icmp slt i32 %to.i32, 101 +; CHECK-NEXT: %res.1 = add i1 %c.1, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, %c.3 +; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4 +; CHECK-NEXT: ret i1 %res.3 +; + %to.double = sitofp i32 %x to double + %add = fadd double 0.000000e+00, %to.double + %to.i32 = fptosi double %add to i32 + %c.1 = icmp sgt i32 %to.i32, 300 + %c.2 = icmp sgt i32 %to.i32, 299 + %c.3 = icmp slt i32 %to.i32, 100 + %c.4 = icmp slt i32 %to.i32, 101 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + ret i1 %res.3 +} + +define i1 @caller.fptosi() { +; CHECK-LABEL: define i1 @caller.fptosi() { +; CHECK-NEXT: %call.1 = tail call i1 @f.fptosi(i32 100) +; CHECK-NEXT: %call.2 = tail call i1 @f.fptosi(i32 300) +; CHECK-NEXT: %res = and i1 %call.1, %call.2 +; CHECK-NEXT: ret i1 %res +; + %call.1 = tail call i1 @f.fptosi(i32 100) + %call.2 = tail call i1 @f.fptosi(i32 300) + %res = and i1 %call.1, %call.2 + ret i1 %res +} + +; There's nothing we can do besides going to the full range or overdefined. +define internal i1 @f.fpext(i16 %x) { +; CHECK-LABEL: define internal i1 @f.fpext(i16 %x) { +; CHECK-NEXT: %to.float = sitofp i16 %x to float +; CHECK-NEXT: %to.double = fpext float %to.float to double +; CHECK-NEXT: %to.i64 = fptoui float %to.float to i64 +; CHECK-NEXT: %c.1 = icmp sgt i64 %to.i64, 300 +; CHECK-NEXT: %c.2 = icmp sgt i64 %to.i64, 299 +; CHECK-NEXT: %c.3 = icmp slt i64 %to.i64, 100 +; CHECK-NEXT: %c.4 = icmp slt i64 %to.i64, 101 +; CHECK-NEXT: %res.1 = add i1 %c.1, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, %c.3 +; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4 +; CHECK-NEXT: ret i1 %res.3 +; + %to.float = sitofp i16 %x to float + %to.double = fpext float %to.float to double + %to.i64= fptoui float %to.float to i64 + %c.1 = icmp sgt i64 %to.i64, 300 + %c.2 = icmp sgt i64 %to.i64, 299 + %c.3 = icmp slt i64 %to.i64, 100 + %c.4 = icmp slt i64 %to.i64, 101 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + ret i1 %res.3 +} + +; There's nothing we can do besides going to the full range or overdefined. +define i1 @caller.fpext() { +; CHECK-LABEL: define i1 @caller.fpext() { +; CHECK-NEXT: %call.1 = tail call i1 @f.fpext(i16 100) +; CHECK-NEXT: %call.2 = tail call i1 @f.fpext(i16 300) +; CHECK-NEXT: %res = and i1 %call.1, %call.2 +; CHECK-NEXT: ret i1 %res +; + %call.1 = tail call i1 @f.fpext(i16 100) + %call.2 = tail call i1 @f.fpext(i16 300) + %res = and i1 %call.1, %call.2 + ret i1 %res +} + +; There's nothing we can do besides going to the full range or overdefined. +define internal i1 @f.inttoptr.ptrtoint(i64 %x) { +; CHECK-LABEL: define internal i1 @f.inttoptr.ptrtoint(i64 %x) { +; CHECK-NEXT: %to.ptr = inttoptr i64 %x to i8* +; CHECK-NEXT: %to.i64 = ptrtoint i8* %to.ptr to i64 +; CHECK-NEXT: %c.1 = icmp sgt i64 %to.i64, 300 +; CHECK-NEXT: %c.2 = icmp sgt i64 %to.i64, 299 +; CHECK-NEXT: %c.3 = icmp slt i64 %to.i64, 100 +; CHECK-NEXT: %c.4 = icmp slt i64 %to.i64, 101 +; CHECK-NEXT: %res.1 = add i1 %c.1, %c.2 +; CHECK-NEXT: %res.2 = add i1 %res.1, %c.3 +; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4 +; CHECK-NEXT: ret i1 %res.3 +; + %to.ptr = inttoptr i64 %x to i8* + %to.i64 = ptrtoint i8* %to.ptr to i64 + %c.1 = icmp sgt i64 %to.i64, 300 + %c.2 = icmp sgt i64 %to.i64, 299 + %c.3 = icmp slt i64 %to.i64, 100 + %c.4 = icmp slt i64 %to.i64, 101 + %res.1 = add i1 %c.1, %c.2 + %res.2 = add i1 %res.1, %c.3 + %res.3 = add i1 %res.2, %c.4 + ret i1 %res.3 +} + +define i1 @caller.inttoptr.ptrtoint() { +; CHECK-LABEL: define i1 @caller.inttoptr.ptrtoint() { +; CHECK-NEXT: %call.1 = tail call i1 @f.inttoptr.ptrtoint(i64 100) +; CHECK-NEXT: %call.2 = tail call i1 @f.inttoptr.ptrtoint(i64 300) +; CHECK-NEXT: %res = and i1 %call.1, %call.2 +; CHECK-NEXT: ret i1 %res +; + %call.1 = tail call i1 @f.inttoptr.ptrtoint(i64 100) + %call.2 = tail call i1 @f.inttoptr.ptrtoint(i64 300) + %res = and i1 %call.1, %call.2 + ret i1 %res +}