Skip to content

Commit

Permalink
add support for assume bundles
Browse files Browse the repository at this point in the history
  • Loading branch information
dtcxzyw committed Feb 17, 2025
1 parent ca5cc69 commit 994e4ac
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 41 deletions.
108 changes: 83 additions & 25 deletions csmith.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,56 @@
print("EMI-based mutation is enabled")
if inconsistent:
print("Inconsistency check is enabled")
csmith_command = csmith_dir +"/bin/csmith --max-funcs 3 --max-block-depth 5 --quiet --builtins --no-packed-struct --no-unions --no-bitfields --output "
csmith_command = (
csmith_dir
+ "/bin/csmith --max-funcs 3 --max-block-depth 5 --quiet --builtins --no-packed-struct --no-unions --no-bitfields --output "
)
compile_command = llvm_dir + "/bin/clang -DNDEBUG -g0 -w -I" + csmith_dir + "/include "
comp_timeout = 10.0
exec_timeout = 1.0
llubi_workarounds = [
# https://github.com/llvm/llvm-project/issues/115890
# https://github.com/llvm/llvm-project/issues/115976
'--ignore-param-attrs-intrinsic',
# https://github.com/llvm/llvm-project/issues/115890
"--ignore-param-attrs-intrinsic",
]
if not inconsistent:
# llubi_workarounds.append('--track-volatile-mem')
pass

cwd = "csmith"+datetime.datetime.now().strftime("%Y-%m-%d@%H:%M")
cwd = "csmith" + datetime.datetime.now().strftime("%Y-%m-%d@%H:%M")
os.makedirs(cwd)


def csmith_test(i):
basename = cwd+"/test"+str(i)
basename = cwd + "/test" + str(i)
file_c = basename + ".c"
try:
subprocess.check_call((csmith_command+file_c).split(' '))
subprocess.check_call((csmith_command + file_c).split(" "))
except subprocess.SubprocessError:
return None

file_out = basename + ".ll"
try:
comp_command = compile_command +" -o "+file_out+" "+file_c
subprocess.check_call(comp_command.split(' '), timeout=comp_timeout)
subprocess.check_call([file_out], timeout=exec_timeout,stderr=subprocess.DEVNULL,stdout=subprocess.DEVNULL)
subprocess.check_call((comp_command + " -O3 -emit-llvm -S" + (" -mllvm -opt-bisect-limit=" + str(random.randint(0, 1000)) if emi else "")).split(' '), timeout=comp_timeout,stderr=subprocess.DEVNULL)
comp_command = compile_command + " -o " + file_out + " " + file_c
subprocess.check_call(comp_command.split(" "), timeout=comp_timeout)
subprocess.check_call(
[file_out],
timeout=exec_timeout,
stderr=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
)
subprocess.check_call(
(
comp_command
+ " -O3 -emit-llvm -S"
+ (
" -mllvm -opt-bisect-limit=" + str(random.randint(0, 1000))
if emi
else ""
)
).split(" "),
timeout=comp_timeout,
stderr=subprocess.DEVNULL,
)
except Exception:
if os.path.exists(file_out):
os.remove(file_out)
Expand All @@ -62,7 +81,10 @@ def csmith_test(i):
if emi:
file_emi_out = basename + ".emi.ll"
try:
ref_out = subprocess.check_output([llubi_bin, file_out, '--emi', file_emi_out] + llubi_workarounds, timeout=exec_timeout)
ref_out = subprocess.check_output(
[llubi_bin, file_out, "--emi", file_emi_out] + llubi_workarounds,
timeout=exec_timeout,
)
except subprocess.TimeoutExpired:
# Ignore timeout
os.remove(file_c)
Expand All @@ -72,10 +94,21 @@ def csmith_test(i):
return None
except Exception:
return False

file_emi_opt_out = basename + ".emiopt.ll"
try:
subprocess.check_call([llvm_dir+"/bin/opt", '-O3', file_emi_out, '-S', '-o', file_emi_opt_out], timeout=comp_timeout,stderr=subprocess.DEVNULL)
subprocess.check_call(
[
llvm_dir + "/bin/opt",
"-O3",
file_emi_out,
"-S",
"-o",
file_emi_opt_out,
],
timeout=comp_timeout,
stderr=subprocess.DEVNULL,
)
except subprocess.TimeoutExpired:
# Ignore timeout
os.remove(file_c)
Expand All @@ -86,7 +119,10 @@ def csmith_test(i):
return False

try:
out = subprocess.check_output([llubi_bin, file_emi_opt_out] + llubi_workarounds, timeout=exec_timeout * 2)
out = subprocess.check_output(
[llubi_bin, file_emi_opt_out] + llubi_workarounds,
timeout=exec_timeout * 2,
)
except subprocess.TimeoutExpired:
# Ignore timeout
os.remove(file_c)
Expand All @@ -107,23 +143,41 @@ def csmith_test(i):
else:
if inconsistent:
try:
ref_out = subprocess.check_output([llvm_dir+"/bin/lli", file_out], timeout=exec_timeout,stderr=subprocess.DEVNULL)
ref_out = subprocess.check_output(
[llvm_dir + "/bin/lli", file_out],
timeout=exec_timeout,
stderr=subprocess.DEVNULL,
)
except Exception:
os.remove(file_c)
os.remove(file_out)
return None
else:
file_o0_output = basename + ".O0.ll"
try:
comp_command = compile_command +" -o "+file_o0_output+" "+file_c+ " -O0 -emit-llvm -S"
subprocess.check_call(comp_command.split(' '), timeout=comp_timeout,stderr=subprocess.DEVNULL)
comp_command = (
compile_command
+ " -o "
+ file_o0_output
+ " "
+ file_c
+ " -O0 -emit-llvm -S"
)
subprocess.check_call(
comp_command.split(" "),
timeout=comp_timeout,
stderr=subprocess.DEVNULL,
)
except Exception:
os.remove(file_out)
os.remove(file_c)
return None

try:
ref_out = subprocess.check_output([llubi_bin, file_o0_output] + llubi_workarounds, timeout=exec_timeout * 2)
ref_out = subprocess.check_output(
[llubi_bin, file_o0_output] + llubi_workarounds,
timeout=exec_timeout * 2,
)
except subprocess.TimeoutExpired:
# Ignore timeout
os.remove(file_c)
Expand All @@ -134,7 +188,10 @@ def csmith_test(i):
return False

try:
out = subprocess.check_output([llubi_bin, file_out] + llubi_workarounds + ['--verify-value-tracking'], timeout=exec_timeout * 2)
out = subprocess.check_output(
[llubi_bin, file_out] + llubi_workarounds + ["--verify-value-tracking"],
timeout=exec_timeout * 2,
)
except subprocess.TimeoutExpired:
# Ignore timeout
os.remove(file_c)
Expand All @@ -144,7 +201,7 @@ def csmith_test(i):
return True
except Exception:
return False

if out == ref_out:
os.remove(file_c)
os.remove(file_out)
Expand All @@ -166,8 +223,9 @@ def csmith_test(i):
else:
skipped_count += 1

pbar.set_description("Failed: {} Skipped: {}".format(
error_count, skipped_count), refresh=False)
pbar.set_description(
"Failed: {} Skipped: {}".format(error_count, skipped_count), refresh=False
)
pbar.update(1)
pbar.close()

Expand Down
61 changes: 49 additions & 12 deletions ubi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// See the LICENSE file for more information.

#include "ubi.h"
#include <llvm/Analysis/AssumeBundleQueries.h>
#include <llvm/Analysis/ValueTracking.h>
#include <llvm/IR/InlineAsm.h>
#include <cassert>
Expand Down Expand Up @@ -1962,7 +1963,7 @@ AnyValue UBAwareInterpreter::handleCall(CallBase &CB) {
else
ImmUBReporter(*this) << "Call with invalid callee";
}
auto RetVal = call(Callee, FMF, CB.getMemoryEffects(), Args);
auto RetVal = call(Callee, &CB, Args);
handleRangeMetadata(RetVal, CB);
postProcessAttr(*this, RetVal, CB.getRetAttributes());
if (auto *Val = CB.getReturnedArgOperand()) {
Expand Down Expand Up @@ -2055,10 +2056,12 @@ AnyValue UBAwareInterpreter::handleWithOverflow(
return std::vector<AnyValue>{std::move(K), std::move(V)};
}

AnyValue UBAwareInterpreter::callIntrinsic(Function *Func, FastMathFlags FMF,
AnyValue UBAwareInterpreter::callIntrinsic(IntrinsicInst &II,
SmallVectorImpl<AnyValue> &Args) {
auto IID = Func->getIntrinsicID();
Type *RetTy = Func->getReturnType();
auto IID = II.getIntrinsicID();
Type *RetTy = II.getType();
FastMathFlags FMF =
isa<FPMathOperator>(II) ? II.getFastMathFlags() : FastMathFlags();
switch (IID) {
case Intrinsic::donothing:
return none();
Expand Down Expand Up @@ -2192,15 +2195,46 @@ AnyValue UBAwareInterpreter::callIntrinsic(Function *Func, FastMathFlags FMF,
});
}
case Intrinsic::assume: {
// Assume bundles have not supported yet
switch (getBoolean(Args[0].getSingleValue())) {
case BooleanVal::Poison:
ImmUBReporter(*this) << "assumption violation (poison)";
case BooleanVal::False:
ImmUBReporter(*this) << "assumption violation (false)";
case BooleanVal::True:
case BooleanVal::True: {
if (II.hasOperandBundles()) {
for (auto &BOI : II.bundle_op_infos()) {
RetainedKnowledge RK =
llvm::getKnowledgeFromBundle(cast<AssumeInst>(II), BOI);
if (RK.AttrKind == Attribute::Alignment ||
RK.AttrKind == Attribute::NonNull ||
RK.AttrKind == Attribute::Dereferenceable) {
auto Val = getValue(RK.WasOn);
postProcess(Val, [&](SingleValue &SV) {
if (isPoison(SV))
ImmUBReporter(*this) << "Assumption on poison pointer";
switch (RK.AttrKind) {
case Attribute::Alignment:
handleAlign(SV, RK.ArgValue);
break;
case Attribute::NonNull:
handleNonNull(SV);
break;
case Attribute::Dereferenceable:
handleDereferenceable(*this, SV, RK.ArgValue, /*OrNull=*/false);
break;
default:
llvm_unreachable("Unexpected attribute kind");
}
if (isPoison(SV))
ImmUBReporter(*this) << "Assumption violated";
});
}
}
}

return none();
}
}
}
case Intrinsic::sadd_with_overflow:
case Intrinsic::ssub_with_overflow:
Expand All @@ -2209,7 +2243,7 @@ AnyValue UBAwareInterpreter::callIntrinsic(Function *Func, FastMathFlags FMF,
case Intrinsic::usub_with_overflow:
case Intrinsic::umul_with_overflow:
return handleWithOverflow(
Func->getArg(0)->getType(), Args[0], Args[1],
II.getArgOperand(0)->getType(), Args[0], Args[1],
[IID](const APInt &LHS, const APInt &RHS) -> std::pair<APInt, bool> {
APInt Res;
bool Overflow = false;
Expand Down Expand Up @@ -2506,7 +2540,8 @@ AnyValue UBAwareInterpreter::callIntrinsic(Function *Func, FastMathFlags FMF,
default:
break;
}
errs() << "Unsupported intrinsic: " << Func->getName() << '\n';
errs() << "Unsupported intrinsic: " << II.getCalledFunction()->getName()
<< '\n';
std::abort();
}
SingleValue UBAwareInterpreter::alloc(const APInt &AllocSize,
Expand Down Expand Up @@ -2598,18 +2633,20 @@ AnyValue UBAwareInterpreter::callLibFunc(LibFunc Func, Function *FuncDecl,
errs() << "Unsupported libcall: " << FuncDecl->getName() << '\n';
std::abort();
}
AnyValue UBAwareInterpreter::call(Function *Func, FastMathFlags FMF,
MemoryEffects ME,
AnyValue UBAwareInterpreter::call(Function *Func, CallBase *CB,
SmallVectorImpl<AnyValue> &Args) {
auto FnAttrs = Func->getAttributes();
for (const auto &[Idx, Param] : enumerate(Func->args()))
postProcessAttr(*this, Args[Idx], FnAttrs.getParamAttrs(Idx));

auto FMF = isa_and_present<FPMathOperator>(CB) ? CB->getFastMathFlags()
: FastMathFlags{};
auto ME = CB ? CB->getMemoryEffects() : MemoryEffects::unknown();
if (Func->isIntrinsic()) {
if ((CurrentFrame->MemEffects.getModRef() & ME.getModRef()) !=
ME.getModRef())
ImmUBReporter(*this) << "Illegal call due to invalid memory effects";
return callIntrinsic(Func, FMF, Args);
return callIntrinsic(*cast<IntrinsicInst>(CB), Args);
} else {
LibFunc F;
if (TLI.getLibFunc(*Func, F)) {
Expand Down Expand Up @@ -2705,7 +2742,7 @@ int32_t UBAwareInterpreter::runMain() {
Args.push_back(SingleValue{APInt::getZero(32)});
Args.push_back(SingleValue{*NullPtr});
}
auto RetVal = call(Entry, FastMathFlags{}, Entry->getMemoryEffects(), Args);
auto RetVal = call(Entry, nullptr, Args);
if (Entry->getReturnType()->isVoidTy())
return EXIT_SUCCESS;
if (isPoison(RetVal.getSingleValue()))
Expand Down
6 changes: 2 additions & 4 deletions ubi.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,10 @@ class UBAwareInterpreter : public InstVisitor<UBAwareInterpreter, bool> {
const function_ref<std::pair<APInt, bool>(const APInt &, const APInt &)>
&Fn);

AnyValue callIntrinsic(Function *Func, FastMathFlags FMF,
SmallVectorImpl<AnyValue> &Args);
AnyValue callIntrinsic(IntrinsicInst &II, SmallVectorImpl<AnyValue> &Args);
AnyValue callLibFunc(LibFunc Func, Function *FuncDecl,
SmallVectorImpl<AnyValue> &Args);
AnyValue call(Function *Func, FastMathFlags FMF, MemoryEffects ME,
SmallVectorImpl<AnyValue> &Args);
AnyValue call(Function *Func, CallBase *CB, SmallVectorImpl<AnyValue> &Args);
void dumpStackTrace();
int32_t runMain();
void mutate();
Expand Down

0 comments on commit 994e4ac

Please sign in to comment.