diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/Dartagnan.java b/dartagnan/src/main/java/com/dat3m/dartagnan/Dartagnan.java index db1e006485..e78a745b41 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/Dartagnan.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/Dartagnan.java @@ -144,7 +144,7 @@ public static void main(String[] args) throws Exception { final Program p = new ProgramParser().parse(f); if (o.overrideEntryFunction()) { p.setEntrypoint(new Entrypoint.Simple(p.getFunctionByName(o.getEntryFunction()).orElseThrow( - () -> new MalformedProgramException(String.format("Program has no function named %s. Select a different entry point.", o.getEntryFunction()))))); + () -> new MalformedProgramException(String.format("Program has no function named %s. Select a different entry point.", o.getEntryFunction()))))); } final Wmm mcm = new ParserCat(Path.of(o.getCatIncludePath())).parse(fileModel); final VerificationTaskBuilder builder = VerificationTask.builder() @@ -204,19 +204,19 @@ public static void main(String[] args) throws Exception { private static List getProgramFilesFromArgs(String[] args) { final List files = new ArrayList<>(); Stream.of(args) - .map(File::new) - .forEach(file -> { - if (file.exists()) { - final String path = file.getAbsolutePath(); - if (file.isDirectory()) { - logger.info("Programs path: {}", path); - files.addAll(getProgramFiles(path)); - } else if (file.isFile() && supportedFormats.stream().anyMatch(file.getName()::endsWith)) { - logger.info("Program path: {}", path); - files.add(file); + .map(File::new) + .forEach(file -> { + if (file.exists()) { + final String path = file.getAbsolutePath(); + if (file.isDirectory()) { + logger.info("Programs path: {}", path); + files.addAll(getProgramFiles(path)); + } else if (file.isFile() && supportedFormats.stream().anyMatch(file.getName()::endsWith)) { + logger.info("Program path: {}", path); + files.add(file); + } } - } - }); + }); if (files.isEmpty()) { throw new IllegalArgumentException("Path to input program(s) not given or format not recognized"); } @@ -227,10 +227,10 @@ private static List getProgramFiles(String dirPath) { List files = new ArrayList(); try (Stream stream = Files.walk(Paths.get(dirPath))) { files = stream.filter(Files::isRegularFile) - .filter(p -> supportedFormats.stream().anyMatch(p.toString()::endsWith)) - .map(Path::toFile) - .sorted(Comparator.comparing(File::toString)) - .toList(); + .filter(p -> supportedFormats.stream().anyMatch(p.toString()::endsWith)) + .map(Path::toFile) + .sorted(Comparator.comparing(File::toString)) + .toList(); } catch (IOException e) { logger.error("There was an I/O error when accessing path {}", dirPath); System.exit(UNKNOWN_ERROR.asInt()); @@ -246,7 +246,7 @@ public static File generateExecutionGraphFile(VerificationTask task, ModelChecke final String progName = task.getProgram().getName(); final int fileSuffixIndex = progName.lastIndexOf('.'); final String name = progName.isEmpty() ? "unnamed_program" : - (fileSuffixIndex == - 1) ? progName : progName.substring(0, fileSuffixIndex); + (fileSuffixIndex == -1) ? progName : progName.substring(0, fileSuffixIndex); final ExecutionModelNext model = modelChecker.getExecutionGraph(); // RF edges give both ordering and data flow information, thus even when the pair is in PO // we get some data flow information by observing the edge @@ -258,7 +258,7 @@ public static File generateExecutionGraphFile(VerificationTask task, ModelChecke } private static void generateWitnessIfAble(VerificationTask task, - ModelChecker modelChecker, String details) throws SolverException { + ModelChecker modelChecker, String details) throws SolverException { // ------------------ Generate Witness, if possible ------------------ final EnumSet properties = task.getProperty(); if (task.getProgram().getFormat().equals(SourceLanguage.LLVM) && modelChecker.hasModel() @@ -304,8 +304,8 @@ private static ResultSummary summaryFromResult(VerificationTask task, ModelCheck reason = ResultSummary.PROGRAM_SPEC_REASON; condition = getSpecificationString(p); List violations = p.getThreadEvents(Assert.class) - .stream().filter(model::assertionViolated) - .toList(); + .stream().filter(model::assertionViolated) + .toList(); for (Assert ass : violations) { appendTo(details, ass, synContext); } @@ -400,7 +400,7 @@ private static void appendTo(StringBuilder details, Event event, SyntacticContex } private static void increaseBoundAndDump(List boundEvents, Configuration config) throws IOException { - if(!config.hasProperty(BOUNDS_SAVE_PATH)) { + if (!config.hasProperty(BOUNDS_SAVE_PATH)) { return; } final File boundsFile = new File(config.getProperty(BOUNDS_SAVE_PATH)); @@ -440,8 +440,8 @@ private static void increaseBoundAndDump(List boundEvents, Configuration private static void printWarningIfThreadStartFailed(Program p, IREvaluator model) { p.getThreads().stream().filter(t -> t.getEntry().isSpawned() - && model.isExecuted(t.getEntry().getCreator()) - && !model.threadHasStarted(t) + && model.isExecuted(t.getEntry().getCreator()) + && !model.threadHasStarted(t) ).forEach(t -> System.out.printf( "[WARNING] The call to pthread_create of thread %s failed. To force thread creation to succeed use --%s=true%n", t, OptionNames.THREAD_CREATE_ALWAYS_SUCCEEDS diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java index 55768372ba..ff6f0462fb 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/EncodingContext.java @@ -1,5 +1,8 @@ package com.dat3m.dartagnan.encoding; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.type.IntegerType; import com.dat3m.dartagnan.expression.type.TypeFactory; @@ -41,6 +44,7 @@ import java.util.Map; import static com.dat3m.dartagnan.configuration.OptionNames.*; +import static com.dat3m.dartagnan.encoding.ExpressionEncoder.ConversionMode.MEMORY_ROUND_TRIP_RELAXED; import static com.dat3m.dartagnan.program.event.Tag.INIT; import static com.dat3m.dartagnan.program.event.Tag.WRITE; import static com.google.common.base.Preconditions.checkArgument; @@ -65,7 +69,7 @@ public final class EncodingContext { private final ExpressionFactory exprs = ExpressionFactory.getInstance(); @Option( - name=IDL_TO_SAT, + name = IDL_TO_SAT, description = "Use SAT-based encoding for totality and acyclicity.", secure = true) boolean useSATEncoding = false; @@ -219,19 +223,21 @@ public BooleanFormula sameResult(RegWriter first, RegWriter second) { return exprEncoder.equal(result(first), result(second)); } - public BooleanFormula sameValue(MemoryCoreEvent first, MemoryCoreEvent second, ExpressionEncoder.ConversionMode cmode) { - return exprEncoder.equal(value(first), value(second), cmode); + public BooleanFormula sameValue(MemoryCoreEvent first, MemoryCoreEvent second) { + return exprEncoder.equal(value(first), value(second)); } - public BooleanFormula sameValue(MemoryCoreEvent first, MemoryCoreEvent second) { - return sameValue(first, second, ExpressionEncoder.ConversionMode.NO); + public BooleanFormula assignValue(MemoryCoreEvent left, MemoryCoreEvent right) { + return exprEncoder.assignEqual(value(left), value(right), MEMORY_ROUND_TRIP_RELAXED); } public TypedFormula address(MemoryCoreEvent event) { return addresses.get(event); } - public TypedFormula address(MemoryObject memoryObject) { return objAddress.get(memoryObject); } + public TypedFormula address(MemoryObject memoryObject) { + return objAddress.get(memoryObject); + } // NOTE: This formula represents the size of successfully allocated memory objects. // For non-allocated memory objects, the size may be any non-negative value. diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/ExpressionEncoder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/ExpressionEncoder.java index 389ebf5f2a..204bbb725d 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/ExpressionEncoder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/ExpressionEncoder.java @@ -11,7 +11,9 @@ import com.dat3m.dartagnan.expression.booleans.BoolUnaryOp; import com.dat3m.dartagnan.expression.floats.*; import com.dat3m.dartagnan.expression.integers.*; +import com.dat3m.dartagnan.expression.memory.*; import com.dat3m.dartagnan.expression.misc.ITEExpr; +import com.dat3m.dartagnan.expression.pointers.*; import com.dat3m.dartagnan.expression.type.*; import com.dat3m.dartagnan.expression.utils.ExpressionHelper; import com.dat3m.dartagnan.program.Register; @@ -29,8 +31,6 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static java.util.Arrays.asList; @@ -104,6 +104,13 @@ public TypedFormula encodeBooleanFinal(Expression e : bitvectorFormulaManager().makeVariable(integerType.getBitWidth(), name); } else if (type instanceof FloatType floatType) { variable = floatingPointFormulaManager().makeVariable(name, getFloatFormulaType(floatType)); + } else if (type instanceof PointerType pointerType) { + variable = context.useIntegers + ? integerFormulaManager().makeVariable(name) + : bitvectorFormulaManager().makeVariable(pointerType.getBitWidth(), name); + } else if (type instanceof MemoryType memoryType) { + assert !context.useIntegers; + variable = bitvectorFormulaManager().makeVariable(memoryType.getBitWidth(), name); } else if (type instanceof AggregateType aggType) { final List fields = new ArrayList<>(aggType.getFields().size()); for (TypeOffset field : aggType.getFields()) { @@ -131,40 +138,54 @@ public TypedFormula wrap(BooleanFormula formula) { // ==================================================================================== // Utility - // TODO: For conversion operations, we might want to have an universal intermediate type T with the following properties: - // (1) every other type has a lossless conversion to T - // (2) T can be converted to every other type (possibly with loss) - // (3) A round-trip through T is always lossless. - // See comments on TypedFormula class for more details. + public BooleanFormula equal(Expression left, Expression right) { + Preconditions.checkArgument(left.getType().equals(right.getType())); + return encodeBooleanFinal(context.getExpressionFactory().makeEQ(left, right)).formula(); + } + + public BooleanFormula equalAt(Expression left, Event leftAt, Expression right, Event rightAt) { + return equal(encodeAt(left, leftAt), encodeAt(right, rightAt)); + } + public enum ConversionMode { - NO, - LEFT_TO_RIGHT, - RIGHT_TO_LEFT, + STRICT, // No conversion, types must match exactly + CAST, // Immediate cast + MEMORY_ROUND_TRIP_STRICT, // Round-trip over memory, but source/target type sizes must match + MEMORY_ROUND_TRIP_RELAXED, // Round-trip over memory, source/target can have mismatching sizes } - public BooleanFormula equal(Expression left, Expression right, ConversionMode cMode) { + // Encodes assignment equality "left := right" with a possible conversion applied to the rhs. + public BooleanFormula assignEqual(Expression left, Expression right, ConversionMode conversion) { final ExpressionFactory exprs = context.getExpressionFactory(); - switch (cMode) { - case NO -> {} - case LEFT_TO_RIGHT -> left = exprs.makeCast(left, right.getType()); - case RIGHT_TO_LEFT -> right = exprs.makeCast(right, left.getType()); - } - return encodeBooleanFinal(exprs.makeEQ(left, right)).formula(); - } + final Expression value = switch (conversion) { + case STRICT -> { + Preconditions.checkArgument(left.getType().equals(right.getType())); + yield right; + } + case CAST -> { + yield exprs.makeCast(right, left.getType()); + } + case MEMORY_ROUND_TRIP_STRICT, MEMORY_ROUND_TRIP_RELAXED -> { + final boolean signed = true; + final boolean strict = conversion == ConversionMode.MEMORY_ROUND_TRIP_STRICT; + yield exprs.makeCastOverMemory(right, left.getType(), strict, signed); + } + }; - public BooleanFormula equal(Expression left, Expression right) { - return equal(left, right, ConversionMode.NO); + return equal(left, value); } - public BooleanFormula equalAt(Expression left, Event leftAt, Expression right, Event rightAt, ConversionMode cMode) { - return equal(encodeAt(left, leftAt), encodeAt(right, rightAt), cMode); + + public BooleanFormula assignEqual(Expression left, Expression right) { + return assignEqual(left, right, ConversionMode.STRICT); } - public BooleanFormula equalAt(Expression left, Event leftAt, Expression right, Event rightAt) { - return equal(encodeAt(left, leftAt), encodeAt(right, rightAt)); + public BooleanFormula assignEqualAt(Expression left, Event leftAt, Expression right, Event rightAt) { + return assignEqual(encodeAt(left, leftAt), encodeAt(right, rightAt)); } + // ==================================================================================== // Private implementation @@ -173,6 +194,7 @@ public BooleanFormula equalAt(Expression left, Event leftAt, Expression right, E private class Visitor implements ExpressionVisitor> { private Event event; + public void setEvent(Event e) { this.event = e; } @@ -190,6 +212,24 @@ public void setEvent(Event e) { return (TypedFormula) typedFormula; } + @SuppressWarnings("unchecked") + public TypedFormula encodePointerExpr(Expression expression) { + Preconditions.checkArgument(expression.getType() instanceof PointerType); + final TypedFormula typedFormula = encode(expression); + assert typedFormula.type() == expression.getType(); + assert typedFormula.formula() instanceof IntegerFormula || typedFormula.formula() instanceof BitvectorFormula; + return (TypedFormula) typedFormula; + } + + @SuppressWarnings("unchecked") + public TypedFormula encodeMemoryExpr(Expression expression) { + Preconditions.checkArgument(expression.getType() instanceof MemoryType); + final TypedFormula typedFormula = encode(expression); + assert typedFormula.getType() == expression.getType(); + assert typedFormula.formula() instanceof IntegerFormula || typedFormula.formula() instanceof BitvectorFormula; + return (TypedFormula) typedFormula; + } + @SuppressWarnings("unchecked") public TypedFormula encodeFloatExpr(Expression expression) { Preconditions.checkArgument(expression.getType() instanceof FloatType); @@ -656,6 +696,158 @@ private BooleanFormula fromUnordToOrd(FloatingPointFormula l, FloatingPointFormu return new TypedFormula<>(expr.getTargetType(), enc); } + + // ==================================================================================== + // Pointers + + @Override + public TypedFormula visitPtrAddExpression(PtrAddExpr expr) { + final TypedFormula base = encodePointerExpr(expr.getBase()); + final TypedFormula offset = encodeIntegerExpr(expr.getOffset()); + + if (context.useIntegers) { + final IntegerFormula baseForm = (IntegerFormula) base.formula(); + final IntegerFormula offsetForm = (IntegerFormula) offset.formula(); + + return new TypedFormula<>(base.getType(), integerFormulaManager().add(baseForm, offsetForm)); + } else { + final BitvectorFormula baseForm = (BitvectorFormula) base.formula(); + final BitvectorFormula offsetForm = (BitvectorFormula) offset.formula(); + + return new TypedFormula<>(base.getType(), bitvectorFormulaManager().add(baseForm, offsetForm)); + } + } + + @Override + public TypedFormula visitPtrToIntCastExpression(PtrToIntCast expr) { + final TypedFormula inner = encodePointerExpr(expr.getOperand()); + final Formula enc; + if (context.useIntegers) { + if (expr.isShrinking()) { + final BigInteger highValue = BigInteger.TWO.pow(expr.getType().getBitWidth()); + final IntegerFormulaManager imgr = integerFormulaManager(); + enc = imgr.modulo((IntegerFormula) inner.formula(), imgr.makeNumber(highValue)); + } else { + enc = inner.formula(); + } + } else { + assert inner.formula() instanceof BitvectorFormula; + final BitvectorFormulaManager bvmgr = bitvectorFormulaManager(); + final BitvectorFormula innerBv = (BitvectorFormula) inner.formula(); + final int targetBitWidth = expr.getTargetType().getBitWidth(); + final int sourceBitWidth = expr.getSourceType().getBitWidth(); + assert (sourceBitWidth == bvmgr.getLength(innerBv)); + if (expr.sameWidth()) { + enc = innerBv; + } else { + enc = expr.isExtension() + ? bvmgr.extend(innerBv, targetBitWidth - sourceBitWidth, false) + : bvmgr.extract(innerBv, targetBitWidth - 1, 0); + } + } + return new TypedFormula<>(expr.getType(), enc); + } + + @Override + public TypedFormula visitIntToPtrCastExpression(IntToPtrCast expr) { + final TypedFormula address = encodeIntegerExpr(expr.getOperand()); + if (!context.useIntegers) { + int ibw = ((IntegerType) expr.getOperand().getType()).getBitWidth(); + int pbw = expr.getType().getBitWidth(); + if (ibw < pbw) { + return new TypedFormula<>(expr.getType(), fmgr.getBitvectorFormulaManager() + .extend(((BitvectorFormula) address.formula()), pbw - ibw, false)); + } + } + return new TypedFormula<>(expr.getType(), address.formula()); + } + + @Override + public TypedFormula visitPtrCmpExpression(PtrCmpExpr expr) { + if (context.useIntegers) { + final var left = (TypedFormula) encodePointerExpr(expr.getLeft()); + final var right = (TypedFormula) encodePointerExpr(expr.getRight()); + + final IntegerFormulaManager imgr = integerFormulaManager(); + final BooleanFormula result = switch (expr.getKind()) { + case EQ -> imgr.equal(left.formula(), right.formula()); + case NEQ -> bmgr.not(fmgr.equal(left.formula(), right.formula())); + }; + return new TypedFormula<>(types.getBooleanType(), result); + } else { + final int nullLocation = expr.getLeft() instanceof NullLiteral ? 1 : (expr.getRight() instanceof NullLiteral ? 2 : 0); // 0 means no nullpointer + final BitvectorFormula left = (BitvectorFormula) encodePointerExpr(expr.getLeft()).formula(); + final BitvectorFormula right = (BitvectorFormula) encodePointerExpr(expr.getRight()).formula(); + final BitvectorFormulaManager bvgr = bitvectorFormulaManager(); + final BooleanFormula result = switch (expr.getKind()) { + case EQ -> switch (nullLocation) { + case 0 -> bvgr.equal(left, right); + case 1 -> fmgr.isZeroBitVector(right); + case 2 -> fmgr.isZeroBitVector(left); + default -> throw new IllegalStateException(); + }; + case NEQ -> bmgr.not(switch (nullLocation) { + case 0 -> bvgr.equal(left, right); + case 1 -> fmgr.isZeroBitVector(right); + case 2 -> fmgr.isZeroBitVector(left); + default -> throw new IllegalStateException(); + }); + }; + return new TypedFormula<>(types.getBooleanType(), result); + } + } + + @Override + public TypedFormula visitNullLiteral(NullLiteral lit) { + final Formula zero = context.useIntegers + ? integerFormulaManager().makeNumber(0) + : bitvectorFormulaManager().makeBitvector(lit.getType().bitWidth, 0); + + return new TypedFormula<>(lit.getType(), zero); + } + + @Override + public TypedFormula visitPtrExtract(PtrExtract expr) { + final Formula operand = encodePointerExpr(expr.getOperand()).formula(); + final Formula enc; + if (context.useIntegers) { + final IntegerFormulaManager imgr = integerFormulaManager(); + final IntegerFormula highBitValue = imgr.makeNumber(BigInteger.TWO.pow(expr.getHighBit() + 1)); + final IntegerFormula lowBitValue = imgr.makeNumber(BigInteger.TWO.pow(expr.getLowBit())); + final IntegerFormula op = (IntegerFormula) operand; + final IntegerFormula extracted = expr.isExtractingHighBits() ? op : imgr.modulo(op, highBitValue); + enc = expr.isExtractingLowBits() ? extracted : imgr.divide(extracted, lowBitValue); + } else { + final BitvectorFormulaManager bvmgr = bitvectorFormulaManager(); + enc = bvmgr.extract((BitvectorFormula) operand, expr.getHighBit(), expr.getLowBit()); + } + return new TypedFormula<>(expr.getType(), enc); + } + + @Override + public TypedFormula visitPtrConcat(PtrConcat expr) { + Preconditions.checkArgument(!expr.getOperands().isEmpty()); + final List> operands = expr.getOperands().stream() + .map(this::encodePointerExpr) + .toList(); + Formula enc = operands.get(0).formula(); + if (context.useIntegers) { + final IntegerFormulaManager imgr = fmgr.getIntegerFormulaManager(); + int offset = operands.get(0).type().getBitWidth(); + for (TypedFormula op : operands.subList(1, operands.size())) { + final IntegerFormula offsetValue = imgr.makeNumber(BigInteger.TWO.pow(offset - 1)); + enc = imgr.add((IntegerFormula) enc, imgr.multiply((IntegerFormula) op.formula(), offsetValue)); + offset += op.type().getBitWidth(); + } + } else { + final BitvectorFormulaManager bvmgr = bitvectorFormulaManager(); + for (TypedFormula op : operands.subList(1, operands.size())) { + enc = bvmgr.concat((BitvectorFormula) op.formula(), (BitvectorFormula) enc); + } + } + return new TypedFormula<>(expr.getType(), enc); + } + // ==================================================================================== // Aggregates @@ -696,6 +888,114 @@ public TypedFormula visitInsertExpression(InsertExpr insert) { return new TypedFormula<>(insert.getType(), insertForm); } + // ==================================================================================== + // Memory type + + private void checkMemoryCastSupport(Type type) { + if (!(type instanceof IntegerType || type instanceof PointerType)) { + throw new UnsupportedOperationException("Cannot cast memory to type: " + type); + } + } + + @Override + public TypedFormula visitToMemoryCastExpression(ToMemoryCast expr) { + final TypedFormula inner = encode(expr.getOperand()); + final MemoryType targetType = types.getMemoryTypeFor(expr.getSourceType()); + + checkMemoryCastSupport(expr.getSourceType()); + + Formula enc = inner.formula(); + if (inner.formula() instanceof BitvectorFormula bvform) { + final BitvectorFormulaManager bvmgr = bitvectorFormulaManager(); + final int innerSize = bvmgr.getLength(bvform); + if (innerSize < targetType.getBitWidth()) { + enc = bvmgr.extend(bvform, targetType.getBitWidth() - innerSize, false); + } + } + // TODO: Do actual conversions + return new TypedFormula<>(targetType, enc); + } + + @Override + public TypedFormula visitFromMemoryCastExpression(FromMemoryCast expr) { + final TypedFormula inner = encodeMemoryExpr(expr.getOperand()); + final Type targetType = expr.getTargetType(); + + checkMemoryCastSupport(targetType); + + Formula enc = inner.formula(); + if (!context.useIntegers && targetType instanceof IntegerType bvType) { + final BitvectorFormulaManager bvmgr = bitvectorFormulaManager(); + final int targetSize = bvType.getBitWidth(); + if (targetSize < expr.getSourceType().getBitWidth()) { + enc = bvmgr.extract((BitvectorFormula) inner.formula(), targetSize - 1, 0); + } + } + + // TODO: Do actual conversions + return new TypedFormula<>(targetType, enc); + } + + @Override + public TypedFormula visitMemoryConcatExpression(MemoryConcat expr) { + Preconditions.checkArgument(!expr.getOperands().isEmpty()); + Preconditions.checkState(!context.useIntegers); + + // TODO: We just do normal bitvector concatenation for now + final List> operands = expr.getOperands().stream() + .map(this::encodeMemoryExpr) + .toList(); + Formula enc = operands.get(0).formula(); + final BitvectorFormulaManager bvmgr = bitvectorFormulaManager(); + for (TypedFormula op : operands.subList(1, operands.size())) { + enc = bvmgr.concat((BitvectorFormula) op.formula(), (BitvectorFormula) enc); + } + return new TypedFormula<>(expr.getType(), enc); + } + + @Override + public TypedFormula visitMemoryExtractExpression(MemoryExtract expr) { + // TODO: We just do normal bitvector extraction for now + // NOTE: We need to support mathematical integers for some unit tests, which is a bit awkward + final Formula operand = encodeMemoryExpr(expr.getOperand()).formula(); + final Formula enc; + if (context.useIntegers) { + final IntegerFormulaManager imgr = integerFormulaManager(); + final IntegerFormula highBitValue = imgr.makeNumber(BigInteger.TWO.pow(expr.getHighBit() + 1)); + final IntegerFormula lowBitValue = imgr.makeNumber(BigInteger.TWO.pow(expr.getLowBit())); + final IntegerFormula op = (IntegerFormula) operand; + final IntegerFormula extracted = expr.isExtractingHighBits() ? op : imgr.modulo(op, highBitValue); + enc = expr.isExtractingLowBits() ? extracted : imgr.divide(extracted, lowBitValue); + } else { + final BitvectorFormulaManager bvmgr = bitvectorFormulaManager(); + enc = bvmgr.extract((BitvectorFormula) operand, expr.getHighBit(), expr.getLowBit()); + } + return new TypedFormula<>(expr.getType(), enc); + } + + @Override + public TypedFormula visitMemoryExtend(MemoryExtend expr) { + final Formula operand = encodeMemoryExpr(expr.getOperand()).formula(); + final Formula enc; + if (context.useIntegers) { + enc = operand; // Maybe remove sign? + } else { + final BitvectorFormulaManager bvmgr = bitvectorFormulaManager(); + final int extendedBits = expr.getTargetType().getBitWidth() - expr.getSourceType().getBitWidth(); + enc = bvmgr.extend((BitvectorFormula) operand, extendedBits, false); + } + return new TypedFormula<>(expr.getType(), enc); + + } + + @Override + public TypedFormula visitMemoryEqualExpression(MemoryEqualExpr expr) { + final Formula left = expr.getLeft().accept(this).formula(); + final Formula right = expr.getRight().accept(this).formula(); + + return new TypedFormula<>(types.getBooleanType(), fmgr.equal(left, right)); + } + // ==================================================================================== // Misc @@ -734,7 +1034,7 @@ public TypedFormula visitInsertExpression(InsertExpr insert) { checkState(event == null, "Cannot evaluate final memory value of %s at event %s.", val, event); final MemoryObject base = val.getMemoryObject(); final int offset = val.getOffset(); - checkArgument(base.isInRange(offset), "Array index out of bounds"); + Preconditions.checkArgument(base.isInRange(offset), "Array index out of bounds"); final String name = String.format("last_val_at_%s_%d", base, offset); return makeVariable(name, val.getType()); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/NonTerminationEncoder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/NonTerminationEncoder.java index 2869ada9ec..4fe7d7b605 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/NonTerminationEncoder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/NonTerminationEncoder.java @@ -438,7 +438,8 @@ private BooleanFormula encodeInfixSuffixDecomposition() { totalEnc.add(bmgr.not(bmgr.and(isInSuffixVar(iter), isInInfixVar(iter)))); } - final Iteration last = iters.get(iters.size() - 1);; + final Iteration last = iters.get(iters.size() - 1); + ; final BooleanFormula loopIsNonterminating = loop.nontermCases.stream() .map(this::isNonterminating) .reduce(bmgr.makeFalse(), bmgr::or); @@ -677,7 +678,7 @@ private BooleanFormula encodeStrongSuffixExtension() { if (isPossiblySuffix(r)) { enc.add(bmgr.implication( bmgr.and(isInSuffix(r), context.edge(rf, w, r)), - isSuffixReadable((Store)w) + isSuffixReadable((Store) w) )); } }); @@ -745,8 +746,13 @@ public Loop(LoopAnalysis.LoopInfo loopInfo) { this.loopInfo = loopInfo; } - public List getIterations() { return Lists.transform(loopInfo.iterations(), iterInfo2Iter::get); } - public boolean isAlwaysTerminating() { return nontermCases.isEmpty(); } + public List getIterations() { + return Lists.transform(loopInfo.iterations(), iterInfo2Iter::get); + } + + public boolean isAlwaysTerminating() { + return nontermCases.isEmpty(); + } @Override public String toString() { @@ -763,16 +769,28 @@ public String toString() { containingFunc.getName(), containingFunc.getId()); } - public String getUniqueId() { return toString(); } - public boolean isLast() { return loopIterInfo.isLast(); } - public int getIterationNumber() { return loopIterInfo().getIterationNumber(); } + public String getUniqueId() { + return toString(); + } + + public boolean isLast() { + return loopIterInfo.isLast(); + } + + public int getIterationNumber() { + return loopIterInfo().getIterationNumber(); + } } private record NonterminationCase(CondJump nontermEvent, Iteration iteration) { - public boolean isSideEffectFree() { return nontermEvent.hasTag(Tag.SPINLOOP); } + public boolean isSideEffectFree() { + return nontermEvent.hasTag(Tag.SPINLOOP); + } - public Loop getLoop() { return iteration.loop; } + public Loop getLoop() { + return iteration.loop; + } @Override public String toString() { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/ProgramEncoder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/ProgramEncoder.java index 916b9f39cb..20bd35d176 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/ProgramEncoder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/ProgramEncoder.java @@ -198,7 +198,7 @@ public BooleanFormula encodeControlFlow() { final BooleanFormulaManager bmgr = context.getBooleanFormulaManager(); final ForwardProgressEncoder progressEncoder = new ForwardProgressEncoder(); List enc = new ArrayList<>(); - for(Thread t : program.getThreads()){ + for (Thread t : program.getThreads()) { enc.add(encodeConsistentThreadCF(t)); if (IRHelper.isInitThread(t)) { // Init threads are always progressing @@ -227,7 +227,7 @@ private BooleanFormula encodeConsistentThreadCF(Thread thread) { enc.add(bmgr.implication(threadHasStarted(thread), threadIsEnabled(thread))); enc.add(startEvent.encodeExec(context)); - for(final Event cur : startEvent.getSuccessor().getSuccessors()) { + for (final Event cur : startEvent.getSuccessor().getSuccessors()) { final Event pred = cur.getPredecessor(); // Immediate control flow BooleanFormula cfCond = context.controlFlow(pred); @@ -427,7 +427,7 @@ private BooleanFormula encodeMemoryLayout(Memory memory) { final List memoryObjects = ImmutableList.copyOf(memory.getObjects()); for (int i = 0; i < memoryObjects.size(); i++) { final MemoryObject cur = memoryObjects.get(i); - final Expression addrVar = context.address(cur); + final Expression addrVar = exprs.makePtrToIntCast(context.address(cur), archType); final Expression sizeVar = context.size(cur); final Expression size; @@ -448,29 +448,32 @@ private BooleanFormula encodeMemoryLayout(Memory memory) { alignment = cur.hasKnownAlignment() ? cur.alignment() : exprs.makeITE(exec, cur.alignment(), one); } - final BiFunction equate = (a, b) -> { + final BiFunction assign = (a, b) -> { final Event alloc = cur.getAllocationSite(); return cur.isStaticallyAllocated() - ? exprEnc.equal(a, b) - : exprEnc.equalAt(a, alloc, b, alloc); + ? exprEnc.assignEqual(a, b) + : exprEnc.assignEqualAt(a, alloc, b, alloc); }; // Encode size - enc.add(equate.apply(sizeVar, size)); + enc.add(assign.apply(sizeVar, size)); // Encode address (we even give non-allocated objects a proper, well-aligned address) final MemoryObject prev = i > 0 ? memoryObjects.get(i - 1) : null; if (prev == null) { // First object is placed at alignment - enc.add(equate.apply(addrVar, alignment)); + enc.add(assign.apply(addrVar, alignment)); } else { - final Expression nextAvailableAddr = exprs.makeAdd(context.address(prev), context.size(prev)); + final Expression nextAvailableAddr = exprs.makeAdd( + exprs.makePtrToIntCast(context.address(prev), archType), + context.size(prev) + ); final Expression nextAlignedAddr = exprs.makeAdd(nextAvailableAddr, - exprs.makeSub(alignment, exprs.makeRem(nextAvailableAddr, alignment, true)) + exprs.makeSub(alignment, exprs.makeRem(nextAvailableAddr, alignment, true)) ); // ... other objects are placed at the next well-aligned address that is available. - enc.add(equate.apply(addrVar, nextAlignedAddr)); + enc.add(assign.apply(addrVar, nextAlignedAddr)); } } @@ -480,8 +483,7 @@ private BooleanFormula encodeMemoryLayout(Memory memory) { // ====================================== Data flow ====================================== /** - * @return - * Describes that for each pair of events, if the reader uses the result of the writer, + * @return Describes that for each pair of events, if the reader uses the result of the writer, * then the value the reader gets from the register is exactly the value that the writer computed. * Also, the reader may only use the value of the latest writer that is executed. * Also, if no fitting writer is executed, the reader uses 0. @@ -515,15 +517,15 @@ public BooleanFormula encodeDependencies() { edge = context.dependency(writer, reader); enc.add(bmgr.equivalence(edge, bmgr.and(context.execution(writer), context.controlFlow(reader), bmgr.not(bmgr.or(overwrite))))); } - BooleanFormula equalValue = exprEncoder.equalAt(register, reader, context.result(writer), writer); + BooleanFormula equalValue = exprEncoder.assignEqualAt(register, reader, context.result(writer), writer); enc.add(bmgr.implication(edge, equalValue)); overwrite.add(context.execution(writer)); } - if(initializeRegisters && !reg.mustBeInitialized()) { + if (initializeRegisters && !reg.mustBeInitialized()) { final Expression zero = exprs.makeGeneralZero(register.getType()); overwrite.add(bmgr.not(context.controlFlow(reader))); - overwrite.add(exprEncoder.equalAt(register, reader, zero, reader)); + overwrite.add(exprEncoder.assignEqualAt(register, reader, zero, reader)); enc.add(bmgr.or(overwrite)); } } @@ -556,7 +558,7 @@ public BooleanFormula encodeFinalRegisterValues() { final List writers = registerWriters.getMayWriters(); if (initializeRegisters && !registerWriters.mustBeInitialized()) { List clause = new ArrayList<>(); - clause.add(exprEncoder.equal(register, exprs.makeGeneralZero(register.getType()))); + clause.add(exprEncoder.assignEqual(register, exprs.makeGeneralZero(register.getType()))); for (Event w : writers) { clause.add(context.execution(w)); } @@ -565,7 +567,7 @@ public BooleanFormula encodeFinalRegisterValues() { for (int i = 0; i < writers.size(); i++) { final RegWriter writer = writers.get(i); List clause = new ArrayList<>(); - clause.add(exprEncoder.equal(register, context.result(writer))); + clause.add(exprEncoder.assignEqual(register, context.result(writer))); clause.add(bmgr.not(context.execution(writer))); for (Event w : writers.subList(i + 1, writers.size())) { if (!exec.areMutuallyExclusive(writer, w)) { @@ -654,7 +656,7 @@ private BooleanFormula encodeForwardProgress(Program program, ProgressModel.Hier group.getChildren().stream() .map(c -> bmgr.and(hasForwardProgress(c), isSchedulable(c))) .reduce(bmgr.makeFalse(), bmgr::or) - )); + )); } // (2.3 Base cases for threads) @@ -726,7 +728,7 @@ private BooleanFormula encodeProgressForwarding(ThreadHierarchy group, ProgressM for (int i = 0; i < sortedChildren.size(); i++) { final ThreadHierarchy child = sortedChildren.get(i); final BooleanFormula sameOrHigherIDThreadWasScheduledOnce = - sortedChildren.subList(i , sortedChildren.size()).stream() + sortedChildren.subList(i, sortedChildren.size()).stream() .map(this::wasScheduledOnce) .reduce(bmgr.makeFalse(), bmgr::or); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/PropertyEncoder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/PropertyEncoder.java index 610c07864b..390b00edfe 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/PropertyEncoder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/PropertyEncoder.java @@ -1,10 +1,15 @@ package com.dat3m.dartagnan.encoding; + +import com.dat3m.dartagnan.expression.type.MemoryType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.dat3m.dartagnan.configuration.Arch; import com.dat3m.dartagnan.configuration.Property; import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.program.Program; import com.dat3m.dartagnan.program.Thread; @@ -39,7 +44,7 @@ import java.util.stream.Stream; import static com.dat3m.dartagnan.configuration.Property.*; -import static com.dat3m.dartagnan.encoding.ExpressionEncoder.ConversionMode.RIGHT_TO_LEFT; +import static com.dat3m.dartagnan.encoding.ExpressionEncoder.ConversionMode.MEMORY_ROUND_TRIP_RELAXED; import static com.dat3m.dartagnan.program.Program.SourceLanguage.LLVM; import static com.dat3m.dartagnan.program.Program.SpecificationType.ASSERT; import static com.dat3m.dartagnan.wmm.RelationNameRepository.CO; @@ -110,9 +115,9 @@ public BooleanFormula encodeProperties(EnumSet properties) { if (specType == Property.Type.MIXED) { final String warn = String.format( "The set of properties %s are of mixed type (safety and reachability properties). " + - "Cannot encode mixed properties into a single SMT-query. " + - "You can select a different set of properties with option --property. " + - "Defaulting to " + Property.PROGRAM_SPEC.asStringOption() + ".", + "Cannot encode mixed properties into a single SMT-query. " + + "You can select a different set of properties with option --property. " + + "Defaulting to " + Property.PROGRAM_SPEC.asStringOption() + ".", properties); logger.warn(warn); properties = EnumSet.of(Property.PROGRAM_SPEC); @@ -216,10 +221,10 @@ private BooleanFormula encodeLastCoConstraints() { continue; } BooleanFormula sameAddress = context.sameAddress(init, w1); - final BooleanFormula sameValue = exprEncoder.equal( + final BooleanFormula sameValue = exprEncoder.assignEqual( new FinalMemoryValue(null, init.getValue().getType(), init.getBase(), init.getOffset()), context.value(w1), - RIGHT_TO_LEFT + MEMORY_ROUND_TRIP_RELAXED ); enc.add(bmgr.implication(bmgr.and(lastCoExpr, sameAddress), sameValue)); } @@ -241,11 +246,11 @@ private BooleanFormula encodeLastCoConstraints() { } BooleanFormula isLast = context.lastCoVar(w); BooleanFormula sameAddr = context.sameAddress(init, w); - BooleanFormula sameValue = exprEncoder.equal(finalValue, context.value(w), RIGHT_TO_LEFT); + BooleanFormula sameValue = exprEncoder.assignEqual(finalValue, context.value(w), MEMORY_ROUND_TRIP_RELAXED); readLastStore = bmgr.or(readLastStore, bmgr.and(isLast, sameAddr, sameValue)); lastStoreExistsEnc = bmgr.or(lastStoreExistsEnc, bmgr.and(isLast, sameAddr)); } - BooleanFormula readInitValue = exprEncoder.equal(finalValue, context.value(init), RIGHT_TO_LEFT); + BooleanFormula readInitValue = exprEncoder.assignEqual(finalValue, context.value(init), MEMORY_ROUND_TRIP_RELAXED); enc.add(bmgr.ifThenElse(lastStoreExistsEnc, readLastStore, readInitValue)); } } @@ -362,25 +367,25 @@ public TrackableFormula encodeDataRaces() { }); BooleanFormula hasRace = bmgr.makeFalse(); - for(Thread t1 : program.getThreads()) { - for(Thread t2 : program.getThreads()) { - if(t1 == t2) { + for (Thread t1 : program.getThreads()) { + for (Thread t2 : program.getThreads()) { + if (t1 == t2) { continue; } for (Event e1 : t1.getEvents()) { if (!e1.hasTag(Tag.WRITE) || e1.hasTag(Tag.INIT)) { continue; } - MemoryCoreEvent w = (MemoryCoreEvent)e1; + MemoryCoreEvent w = (MemoryCoreEvent) e1; if (!canRace.test(w)) { continue; } - for(Event e2 : t2.getEvents()) { + for (Event e2 : t2.getEvents()) { if (!e2.hasTag(Tag.MEMORY) || e2.hasTag(Tag.INIT)) { continue; } - MemoryCoreEvent m = (MemoryCoreEvent)e2; - if((w.hasTag(Tag.RMW) && m.hasTag(Tag.RMW)) || !canRace.test(m) || !alias.mayAlias(m, w)) { + MemoryCoreEvent m = (MemoryCoreEvent) e2; + if ((w.hasTag(Tag.RMW) && m.hasTag(Tag.RMW)) || !canRace.test(m) || !alias.mayAlias(m, w)) { continue; } @@ -447,20 +452,28 @@ record Var(BooleanFormula leak, BooleanFormula track) {} // Object A is reachable from another object B, if a co-maximal store writes an address pointing to A into B. for (Store store : program.getThreadEvents(Store.class)) { final List stores = instructions.getOrDefault(store, List.of(store)); - if (!mayBeFinalAddressStore(store, stores)) { continue; } + if (!mayBeFinalAddressStore(store, stores)) { + continue; + } final Set communicableObjects = alias.communicableObjects(store).stream() .filter(variables::containsKey) .collect(Collectors.toSet()); - if (communicableObjects.isEmpty()) { continue; } + if (communicableObjects.isEmpty()) { + continue; + } final BooleanFormula isFinal = bmgr.and(stores.stream().map(context::lastCoVar).toList()); for (MemoryObject addressableObject : alias.addressableObjects(store)) { final Var addressVariable = variables.get(addressableObject); - if (addressVariable == null && !addressableObject.isStaticallyAllocated()) { continue; } + if (addressVariable == null && !addressableObject.isStaticallyAllocated()) { + continue; + } final BooleanFormula addressed = referencesObject(stores, false, addressableObject); final BooleanFormula addressTrack = addressVariable != null ? addressVariable.track : bmgr.makeTrue(); for (MemoryObject communicableObject : communicableObjects) { final Var valueVariable = variables.get(communicableObject); - if (valueVariable == null) { continue; } + if (valueVariable == null) { + continue; + } final BooleanFormula valueTrack = valueVariable.track; final BooleanFormula communicated = referencesObject(stores, true, communicableObject); enc.add(bmgr.not(bmgr.and(isFinal, addressed, addressTrack, communicated, bmgr.not(valueTrack)))); @@ -478,7 +491,8 @@ private boolean mayBeFinalAddressStore(Store store, List stores) { if (laterStores.stream().anyMatch(o -> exec.isImplied(store, o))) { return false; } - if (!stores.stream().allMatch(o -> o.getMemValue().getType() instanceof IntegerType)) { + if (!stores.stream().allMatch(o -> o.getMemValue().getType() instanceof IntegerType || + o.getMemValue().getType() instanceof PointerType || o.getMemValue().getType() instanceof MemoryType)) { return false; } final TypeFactory types = TypeFactory.getInstance(); @@ -492,15 +506,21 @@ private BooleanFormula referencesObject(List stores, boolean isValue, Mem Preconditions.checkArgument(!stores.isEmpty(), "Empty instruction cannot reference object '%s'.", object); //TODO Use provenance to omit some of these checks statically. final ExpressionFactory expressions = context.getExpressionFactory(); - final Expression pointer = isValue - ? expressions.makeIntConcat(stores.stream().map(Store::getMemValue).toList()) - : stores.get(0).getAddress(); + Expression pointer; + if (isValue) { + List memVals = stores.stream().map(Store::getMemValue).toList(); + // assert memVals.get(0) instanceof MemoryType; + pointer = expressions.makeFromMemoryCast(expressions.makeMemoryConcat(memVals), object.getType()); + } else { + pointer = stores.get(0).getAddress(); + } if (object.equals(pointer)) { return bmgr.makeTrue(); } - final Expression objectEnd = expressions.makeAdd(object, object.size()); - final Expression overLowerBound = expressions.makeLTE(object, pointer, false); - final Expression underUpperBound = expressions.makeLT(pointer, objectEnd, false); + final Expression objectEnd = expressions.makePtrAdd(object, object.size()); + final Expression ptrAddr = expressions.makePtrToIntCast(pointer); + final Expression overLowerBound = expressions.makeLTE(expressions.makePtrToIntCast(object), ptrAddr, false); + final Expression underUpperBound = expressions.makeLT(ptrAddr, expressions.makePtrToIntCast(objectEnd), false); final Expression withinBounds = expressions.makeAnd(overLowerBound, underUpperBound); return context.getExpressionEncoder().encodeBooleanAt(withinBounds, stores.get(0)).formula(); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/SymmetryEncoder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/SymmetryEncoder.java index a9529537c1..b1872ad3ab 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/SymmetryEncoder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/SymmetryEncoder.java @@ -91,7 +91,7 @@ public BooleanFormula encodeFullSymmetryBreaking() { final BooleanFormulaManager bmgr = context.getBooleanFormulaManager(); final EventGraph maySet; final EncodingContext.EdgeEncoder edgeEncoder; - switch(symmBreakTarget) { + switch (symmBreakTarget) { case "": return bmgr.makeTrue(); case "_cf": diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/TypedFormula.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/TypedFormula.java index e025ebb549..b38351d50b 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/TypedFormula.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/TypedFormula.java @@ -35,7 +35,7 @@ type of tuple formula. However, as in point (2), their bitwise representation is TODO: The above examples showcase that IR Types should have a unifying bitwise(?) representation which becomes relevant when communicating over memory. - We can give this representation an IR Type M = AbstractBytes parametric in the bitsize. + We can give this representation an IR Type M = AbstractBitsType parametric in the bitsize. Then this type should satisfy the following properties: - Every standard IR Type T should be convertable to an appropriately-sized M - M should be convertable to other IR types (not necessarily all?) @@ -57,7 +57,7 @@ metadata, i.e., they may be of shape (metadata, bvX). Metadata then needs to be preserved even over extract/concatenation operations. */ public record TypedFormula(TType type, TFormula formula) - implements LeafExpression { + implements LeafExpression { public TypedFormula { Preconditions.checkNotNull(type); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/WmmEncoder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/WmmEncoder.java index 8ac6d8fa00..617a9634a9 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/WmmEncoder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/encoding/WmmEncoder.java @@ -39,7 +39,6 @@ import java.util.stream.Collectors; import static com.dat3m.dartagnan.configuration.OptionNames.*; -import static com.dat3m.dartagnan.encoding.ExpressionEncoder.ConversionMode.LEFT_TO_RIGHT; import static com.dat3m.dartagnan.program.event.Tag.*; import static com.google.common.base.Verify.verify; @@ -609,7 +608,7 @@ public Void visitReadFrom(ReadFrom rfDef) { final BooleanFormula rfEdge = edge.encode(w, r); final BooleanFormula sameAddress = context.sameAddress(w, r); - final BooleanFormula sameValue = context.sameValue(w, r, LEFT_TO_RIGHT); + final BooleanFormula sameValue = context.assignValue(r, w); enc.add(bmgr.implication(rfEdge, bmgr.and(execution(w, r), sameAddress, sameValue))); read2RfEdges.computeIfAbsent(r, key -> new ArrayList<>()).add(rfEdge); }); @@ -619,7 +618,7 @@ public Void visitReadFrom(ReadFrom rfDef) { final BooleanFormula uninit = getUninitReadVar(r); if (memoryIsZeroed) { final Expression zero = context.getExpressionFactory().makeGeneralZero(r.getAccessType()); - enc.add(bmgr.implication(uninit, exprEncoder.equal(context.value(r), zero))); + enc.add(bmgr.implication(uninit, exprEncoder.assignEqual(context.value(r), zero))); } final List rfChoices = Lists.newArrayList(Iterables.concat( diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionFactory.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionFactory.java index 279b9c9d95..27aed456d2 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionFactory.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionFactory.java @@ -4,8 +4,11 @@ import com.dat3m.dartagnan.expression.booleans.*; import com.dat3m.dartagnan.expression.floats.*; import com.dat3m.dartagnan.expression.integers.*; +import com.dat3m.dartagnan.expression.memory.*; import com.dat3m.dartagnan.expression.misc.GEPExpr; import com.dat3m.dartagnan.expression.misc.ITEExpr; +import com.dat3m.dartagnan.expression.pointers.*; +import com.dat3m.dartagnan.expression.processing.ExprSimplifier; import com.dat3m.dartagnan.expression.type.*; import com.dat3m.dartagnan.expression.utils.ExpressionHelper; import com.dat3m.dartagnan.program.memory.MemoryObject; @@ -14,23 +17,37 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; +import java.util.Stack; + import java.math.BigDecimal; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import static com.dat3m.dartagnan.expression.type.TypeFactory.isStaticTypeOf; public final class ExpressionFactory { - private static final ExpressionFactory instance = new ExpressionFactory(); + private static final ExpressionFactory instance; + private static final ExprSimplifier simplifier; + + static { + // This is a bit awkward, but ExpressionFactory and ExprTransformer/Simplifier have + // cyclic dependencies, and so we need to ensure a specific initialization order. + // Maybe we should not use ExpressionSimplifier in this class or don't let ExpressionSimplifier + // cache a static instance of ExpressionFactory. + instance = new ExpressionFactory(); + simplifier = new ExprSimplifier(false); + } private final TypeFactory types = TypeFactory.getInstance(); + private final IntegerType archType = types.getArchType(); + private final PointerType pointerType = types.getPointerType(); private final BooleanType booleanType = types.getBooleanType(); private final BoolLiteral falseConstant = new BoolLiteral(booleanType, false); private final BoolLiteral trueConstant = new BoolLiteral(booleanType, true); - private ExpressionFactory() {} + private ExpressionFactory() { + } public static ExpressionFactory getInstance() { return instance; @@ -77,6 +94,8 @@ public Expression makeBooleanCast(Expression operand) { return operand; } else if (sourceType instanceof IntegerType intType) { return makeNEQ(operand, makeZero(intType)); + } else if (sourceType instanceof PointerType) { + return makeBooleanCast(makePtrToIntCast(operand, archType)); } throw new UnsupportedOperationException(String.format("Cannot cast %s to %s.", sourceType, booleanType)); } @@ -96,6 +115,14 @@ public IntLiteral parseValue(String text, IntegerType type) { return makeValue(new BigInteger(text), type); } + public IntLiteral makeValue(BigInteger value) { + return new IntLiteral(archType, value); + } + + public IntLiteral makeValue(BigInteger value, int bitwidth) { + return new IntLiteral(types.getIntegerType(bitwidth), value); + } + public IntLiteral makeValue(long value, IntegerType type) { return makeValue(BigInteger.valueOf(value), type); } @@ -104,6 +131,10 @@ public IntLiteral makeValue(BigInteger value, IntegerType type) { return new IntLiteral(type, value); } + public IntLiteral makeValue(int value, int bitwidth) { + return makeValue(BigInteger.valueOf(value), bitwidth); + } + public Expression makeLT(Expression leftOperand, Expression rightOperand, boolean signed) { return makeIntCmp(leftOperand, signed ? IntCmpOp.LT : IntCmpOp.ULT, rightOperand); } @@ -201,6 +232,8 @@ public Expression makeIntegerCast(Expression operand, IntegerType targetType, bo return sourceType.equals(targetType) ? operand : new IntSizeCast(targetType, operand, signed); } else if (sourceType instanceof FloatType) { return new FloatToIntCast(targetType, operand, signed); + } else if (sourceType instanceof PointerType) { + return makePtrToIntCast(operand, targetType); } throw new UnsupportedOperationException(String.format("Cannot cast %s to %s.", sourceType, targetType)); @@ -336,6 +369,34 @@ public Expression makeConstruct(Type type, List arguments) return new ConstructExpr(type, arguments); } + public Expression makeCompatibilityConstruct(Type type, List arguments) { + assert ExpressionHelper.isAggregateLike(type); + List types = new ArrayList<>(); + Stack stack = new Stack<>(); + stack.push(type); + while (!stack.isEmpty()) { + Type t = stack.pop(); + if (t instanceof AggregateType ag) { + for (TypeOffset f : ag.getFields()) { + stack.push(f.type()); + } + } else if (t instanceof ArrayType ar) { + for (int i = 0; i < ar.getNumElements(); i++) { + stack.push(ar.getElementType()); + } + } else { + types.add(t); + } + } + Collections.reverse(types); + List newArguments = new ArrayList<>(); + assert types.size() == arguments.size(); + for (int i = 0; i < types.size(); ++i) { + newArguments.add(makeCast(arguments.get(i), types.get(i))); + } + return new ConstructExpr(type, newArguments); + } + public Expression makeArray(ArrayType type, List items) { Preconditions.checkArgument(!type.hasKnownNumElements() || type.getNumElements() == items.size(), "The number of elements must match"); @@ -379,17 +440,19 @@ public Expression makeAggregateCmp(Expression x, AggregateCmpOp op, Expression y // Pointers public Expression makeGetElementPointer(Type indexingType, Expression base, List offsets) { - return makeGetElementPointer(indexingType, base, offsets, null); + Preconditions.checkArgument(base.getType() instanceof PointerType, + "Applying offsets to non-pointer expression."); + return new GEPExpr(indexingType, base, offsets, null); } public Expression makeGetElementPointer(Type indexingType, Expression base, List offsets, Integer stride) { // TODO: Stride should be a property of the pointer, not of a GEPExpr. // Refactor GEPExpr to only accept a (new) PointerType and a list of offsets. // A PointerType should have the referred type and the stride in its attributes. - Preconditions.checkArgument(base.getType().equals(types.getArchType()), + Preconditions.checkArgument(base.getType() instanceof PointerType, "Applying offsets to non-pointer expression."); Preconditions.checkArgument(stride == null || stride >= types.getMemorySizeInBytes(indexingType), - "Stride cannot be smaller than indexing type"); + "Stride cannot be smaller than indexing type"); return new GEPExpr(indexingType, base, offsets, stride); } @@ -401,8 +464,129 @@ public ScopedPointerVariable makeScopedPointerVariable(String id, ScopedPointerT return new ScopedPointerVariable(id, type, memObj); } + public Expression makePtrAdd(Expression base, Expression offset) { + return new PtrAddExpr(base, offset); + } + + public Expression makePtrCast(Expression base, PointerType type) { + if (base.getType() instanceof PointerType) { + if (base.getType().equals(type)) { + return base; + // pointers of different size than arch should not be used (store | load). Comparison is still possible in wmm. + } else { + // we use this because spirv has some weird casts between scoped pointers. + // not the most elegant solution, maybe a dedicated ptr size/type cast? + return makeIntToPtrCast(makePtrToIntCast(base, types.getIntegerType(type.bitWidth)), type); + } + } + if (base.getType() instanceof IntegerType) { + return makeIntToPtrCast(base, type); + } + if (base.getType() instanceof BooleanType) { + return makePtrCast(makeIntegerCast(base, archType, false), type); + } + throw new UnsupportedOperationException(String.format("Cast %s into pointer unsupported.", base)); + } + + + public Expression makePtrToIntCast(Expression pointer, IntegerType type) { + return new PtrToIntCast(type, pointer); + } + public Expression makePtrToIntCast(Expression pointer) { + return makePtrToIntCast(pointer, archType); + } + + + public Expression makeIntToPtrCast(Expression integer, PointerType pointerType) { + return new IntToPtrCast(pointerType, integer); + } + + public Expression makeIntToPtrCast(Expression operand) { + return makeIntToPtrCast(operand, pointerType); + } + + + public Expression makeNullLiteral(PointerType pointerType) { + return new NullLiteral(pointerType); + } + + public Expression makeNullLiteral() { + return makeNullLiteral(pointerType); + } + + public Expression makePtrCmp(Expression left, PtrCmpOp op, Expression right) { + return new PtrCmpExpr(types.getBooleanType(), left, op, right); + } + + public Expression makePtrExtract(Expression operand, int lowBit, int highBit) { + return new PtrExtract(operand, lowBit, highBit); + } + + public Expression makePtrConcat(List operands) { + return new PtrConcat(operands); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Memory + + public Expression makeToMemoryCast(Expression operand) { + if (operand.getType() instanceof MemoryType) { + return operand; + } + return new ToMemoryCast(types.getMemoryTypeFor(operand.getType()), operand); + } + + public Expression makeFromMemoryCast(Expression operand, Type type) { + Preconditions.checkArgument(types.getMemorySizeInBits(operand.getType()) == types.getMemorySizeInBits(type)); + if (operand.getType().equals(type)) { + return operand; + } + return new FromMemoryCast(type, operand); + } + + public Expression makeMemoryConcat(List operands) { + return new MemoryConcat(operands); + } + + public Expression makeMemoryExtract(Expression operand, int lowBit, int highBit) { + return new MemoryExtract(operand, lowBit, highBit); + } + + public Expression makeMemoryExtend(Expression operand, MemoryType targetType) { + return new MemoryExtend(targetType, operand); + } + // ----------------------------------------------------------------------------------------------------------------- - // Misc + + // Cast via a round-trip through memory: "fromMem(toMem()) to ". + // If is false, the memory sizes of the source type and the target type may mismatch: + // "source type < target type": a zero-extension is performed before converting to the target type + // "source type > target type": only the lowest bits of are used for the conversion. + public Expression makeCastOverMemory(Expression expr, Type targetType, boolean strict, boolean signed) { + final Type sourceType = expr.getType(); + if (sourceType.equals(targetType)) { + return expr; + } + + final int targetSize = types.getMemorySizeInBits(targetType); + final int sourceSize = types.getMemorySizeInBits(sourceType); + + if (strict && (targetSize != sourceSize)) { + final String error = String.format("Strict memory cast from %s to %s not possible: " + + "mismatching memory sizes.", sourceType, targetType); + throw new IllegalArgumentException(error); + } + + Expression exprMem = makeToMemoryCast(expr); + if (targetSize < sourceSize) { + exprMem = makeMemoryExtract(exprMem, 0, targetSize - 1); + } else if (targetSize > sourceSize) { + exprMem = makeMemoryExtend(exprMem, types.getMemoryTypeFor(targetType)); + } + exprMem = makeFromMemoryCast(exprMem, targetType); + + return exprMem.accept(simplifier); + } public Expression makeGeneralZero(Type type) { if (type instanceof ArrayType arrayType) { @@ -424,6 +608,10 @@ public Expression makeGeneralZero(Type type) { return makeFalse(); } else if (type instanceof FloatType floatType) { return makeZero(floatType); + } else if (type instanceof MemoryType memoryType) { + return makeToMemoryCast(makeZero(types.getIntegerType(memoryType.getBitWidth()))); + } else if (type instanceof PointerType pt) { + return makeNullLiteral(pt); } else { throw new UnsupportedOperationException("Cannot create zero of type " + type); } @@ -433,13 +621,14 @@ public Expression makeCast(Expression expression, Type type, boolean signed) { if (expression.getType().equals(type)) { return expression; } - if (type instanceof BooleanType) { return makeBooleanCast(expression); } else if (type instanceof IntegerType integerType) { return makeIntegerCast(expression, integerType, signed); } else if (type instanceof FloatType floatType) { return makeFloatCast(expression, floatType, signed); + } else if (type instanceof PointerType) { + return makePtrCast(expression, (PointerType) type); } throw new UnsupportedOperationException(String.format("Cast %s into %s unsupported.", expression, type)); } @@ -453,13 +642,20 @@ public Expression makeITE(Expression condition, Expression ifTrue, Expression if } public Expression makeEQ(Expression leftOperand, Expression rightOperand) { + assert leftOperand.getType().equals(rightOperand.getType()); final Type type = leftOperand.getType(); if (type instanceof BooleanType) { return makeBoolBinary(leftOperand, BoolBinaryOp.IFF, rightOperand); } else if (type instanceof IntegerType) { return makeIntCmp(leftOperand, IntCmpOp.EQ, rightOperand); + } + if (type instanceof PointerType) { + return makePtrCmp(leftOperand, PtrCmpOp.EQ, rightOperand); } else if (type instanceof FloatType) { - return makeFloatCmp(leftOperand, FloatCmpOp.EQ, rightOperand); + // TODO: Decide on a default semantics for float equality? + return makeFloatCmp(leftOperand, FloatCmpOp.OEQ, rightOperand); + } else if (type instanceof MemoryType) { + return new MemoryEqualExpr(booleanType, leftOperand, rightOperand); } else if (ExpressionHelper.isAggregateLike(type)) { return makeAggregateCmp(leftOperand, AggregateCmpOp.EQ, rightOperand); } @@ -471,11 +667,15 @@ public Expression makeFEQ(Expression leftOperand, Expression rightOperand, boole } public Expression makeNEQ(Expression leftOperand, Expression rightOperand) { + assert leftOperand.getType().equals(rightOperand.getType()); final Type type = leftOperand.getType(); if (type instanceof BooleanType) { return makeNot(makeBoolBinary(leftOperand, BoolBinaryOp.IFF, rightOperand)); } else if (type instanceof IntegerType) { return makeIntCmp(leftOperand, IntCmpOp.NEQ, rightOperand); + } + if (type instanceof PointerType) { + return makePtrCmp(leftOperand, PtrCmpOp.NEQ, rightOperand); } else if (type instanceof FloatType) { return makeFloatCmp(leftOperand, FloatCmpOp.NEQ, rightOperand); } else if (type instanceof AggregateType) { @@ -508,6 +708,8 @@ public Expression makeBinary(Expression x, ExpressionKind op, Expression y) { return makeFloatBinary(x, floatOp, y); } else if (op instanceof IntCmpOp cmpOp) { return makeCompare(x, cmpOp, y); + } else if (op instanceof PtrCmpOp cmpOp) { + return makeCompare(x, cmpOp, y); } throw new UnsupportedOperationException(String.format("Expression kind %s is no binary operator.", op)); } @@ -519,6 +721,8 @@ public Expression makeCompare(Expression x, ExpressionKind cmpOp, Expression y) return makeFloatCmp(x, floatOp, y); } else if (cmpOp instanceof AggregateCmpOp aggrCmpOp) { return makeAggregateCmp(x, aggrCmpOp, y); + } else if (cmpOp instanceof PtrCmpOp ptrCmpOp) { + return makePtrCmp(x, ptrCmpOp, y); } throw new UnsupportedOperationException(String.format("Expression kind %s is no comparison operator.", cmpOp)); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionPrinter.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionPrinter.java index ad586d43ee..95a017d009 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionPrinter.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionPrinter.java @@ -7,7 +7,9 @@ import com.dat3m.dartagnan.expression.booleans.BoolUnaryOp; import com.dat3m.dartagnan.expression.floats.FloatSizeCast; import com.dat3m.dartagnan.expression.floats.IntToFloatCast; +import com.dat3m.dartagnan.expression.pointers.*; import com.dat3m.dartagnan.expression.integers.*; +import com.dat3m.dartagnan.expression.memory.*; import com.dat3m.dartagnan.expression.misc.GEPExpr; import com.dat3m.dartagnan.expression.misc.ITEExpr; import com.dat3m.dartagnan.program.Register; @@ -124,6 +126,57 @@ public String visitGEPExpression(GEPExpr expr) { return expr.getOperands().stream().map(this::visit).collect(Collectors.joining(", ", "GEP(", ")")); } + @Override + public String visitToMemoryCastExpression(ToMemoryCast expr) { + return String.format("%s to %s", visit(expr.getOperand()), expr.getTargetType()); + } + + @Override + public String visitFromMemoryCastExpression(FromMemoryCast expr) { + return String.format("%s to %s", visit(expr.getOperand()), expr.getTargetType()); + } + + @Override + public String visitMemoryConcatExpression(MemoryConcat expr) { + return Lists.reverse(expr.getOperands()).stream().map(this::visit).collect(Collectors.joining("::")); + } + + @Override + public String visitMemoryExtractExpression(MemoryExtract expr) { + return String.format("%s[%d..%d]", visit(expr.getOperand()), expr.getLowBit(), expr.getHighBit()); + } + + @Override + public String visitMemoryEqualExpression(MemoryEqualExpr expr) { + return String.format("%s == %s", visit(expr.getLeft()), visit(expr.getRight())); + } + + @Override + public String visitIntToPtrCastExpression(IntToPtrCast expr) { + return String.format("%s to %s", visit(expr.getOperand()), expr.getTargetType()); + } + + @Override + public String visitPtrToIntCastExpression(PtrToIntCast expr) { + return String.format("%s to %s", visit(expr.getOperand()), expr.getTargetType()); + } + + @Override + public String visitPtrAddExpression(PtrAddExpr expr) { + return String.format("%s + %s", visit(expr.getBase()), visit(expr.getOffset())); + } + + @Override + public String visitPtrConcat(PtrConcat expr) { + return Lists.reverse(expr.getOperands()).stream().map(this::visit).collect(Collectors.joining("::")); + } + + @Override + public String visitPtrExtract(PtrExtract expr) { + return String.format("%s[%d..%d]", expr.getOperand().accept(this), expr.getLowBit(), expr.getHighBit()); + } + + @Override public String visitITEExpression(ITEExpr expr) { return visit(expr.getCondition()) + " ? " + visit(expr.getTrueCase()) + " : " + visit(expr.getFalseCase()); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionVisitor.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionVisitor.java index 3396f90063..01567196de 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionVisitor.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/ExpressionVisitor.java @@ -9,8 +9,10 @@ import com.dat3m.dartagnan.expression.booleans.BoolUnaryExpr; import com.dat3m.dartagnan.expression.floats.*; import com.dat3m.dartagnan.expression.integers.*; +import com.dat3m.dartagnan.expression.memory.*; import com.dat3m.dartagnan.expression.misc.GEPExpr; import com.dat3m.dartagnan.expression.misc.ITEExpr; +import com.dat3m.dartagnan.expression.pointers.*; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.memory.FinalMemoryValue; @@ -57,6 +59,13 @@ public interface ExpressionVisitor { // =================================== Pointer =================================== default TRet visitGEPExpression(GEPExpr expr) { return visitExpression(expr); } + default TRet visitPtrAddExpression(PtrAddExpr expr) { return visitExpression(expr); } + default TRet visitIntToPtrCastExpression(IntToPtrCast expr) { return visitCastExpression(expr); } + default TRet visitPtrToIntCastExpression(PtrToIntCast expr) { return visitCastExpression(expr); } + default TRet visitPtrCmpExpression(PtrCmpExpr expr) { return visitBinaryExpression(expr); } + default TRet visitNullLiteral(NullLiteral lit) { return visitLeafExpression(lit); } + default TRet visitPtrConcat(PtrConcat expr){ return visitExpression(expr); } + default TRet visitPtrExtract(PtrExtract expr){ return visitUnaryExpression(expr); } // =================================== Generic =================================== default TRet visitITEExpression(ITEExpr expr) { return visitExpression(expr); } @@ -68,6 +77,14 @@ public interface ExpressionVisitor { default TRet visitFinalMemoryValue(FinalMemoryValue val) { return visitLeafExpression(val); } default TRet visitNonDetValue(NonDetValue nonDet) { return visitLeafExpression(nonDet); } + // =================================== Memory =================================== + default TRet visitToMemoryCastExpression(ToMemoryCast expr) { return visitCastExpression(expr); } + default TRet visitFromMemoryCastExpression(FromMemoryCast expr) { return visitCastExpression(expr); } + default TRet visitMemoryConcatExpression(MemoryConcat expr) { return visitExpression(expr); } + default TRet visitMemoryExtractExpression(MemoryExtract expr) { return visitUnaryExpression(expr); } + default TRet visitMemoryEqualExpression(MemoryEqualExpr expr) { return visitBinaryExpression(expr); } + default TRet visitMemoryExtend(MemoryExtend expr) { return visitUnaryExpression(expr); } + private static UnsupportedOperationException unsupported(Expression expr, Class clazz) { final String error = String.format("Expression '%s' is unsupported by %s", diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/FromMemoryCast.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/FromMemoryCast.java new file mode 100644 index 0000000000..3eec74a64e --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/FromMemoryCast.java @@ -0,0 +1,21 @@ +package com.dat3m.dartagnan.expression.memory; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.Type; +import com.dat3m.dartagnan.expression.base.CastExpressionBase; +import com.dat3m.dartagnan.expression.type.MemoryType; +import com.google.common.base.Preconditions; + +public final class FromMemoryCast extends CastExpressionBase { + + public FromMemoryCast(Type type, Expression operand) { + super(type, operand); + Preconditions.checkArgument(operand.getType() instanceof MemoryType); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitFromMemoryCastExpression(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryConcat.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryConcat.java new file mode 100644 index 0000000000..3122081539 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryConcat.java @@ -0,0 +1,33 @@ +package com.dat3m.dartagnan.expression.memory; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionKind; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.NaryExpressionBase; +import com.dat3m.dartagnan.expression.type.MemoryType; +import com.dat3m.dartagnan.expression.type.TypeFactory; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +public class MemoryConcat extends NaryExpressionBase { + + public MemoryConcat(List operands) { + super(getConcatType(operands), () -> "MEM_CONCAT", ImmutableList.copyOf(operands)); + } + + private static MemoryType getConcatType(List operands) { + int size = 0; + for (Expression op : operands) { + ExpressionHelper.checkExpectedType(op, MemoryType.class); + size += ((MemoryType) op.getType()).getBitWidth(); + } + return TypeFactory.getInstance().getMemoryType(size); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitMemoryConcatExpression(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryEqualExpr.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryEqualExpr.java new file mode 100644 index 0000000000..f9d623e234 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryEqualExpr.java @@ -0,0 +1,22 @@ +package com.dat3m.dartagnan.expression.memory; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionKind; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.BinaryExpressionBase; +import com.dat3m.dartagnan.expression.type.BooleanType; +import com.dat3m.dartagnan.expression.type.MemoryType; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; + +public class MemoryEqualExpr extends BinaryExpressionBase { + + public MemoryEqualExpr(BooleanType type, Expression left, Expression right) { + super(type, () -> "EQ", left, right); + ExpressionHelper.checkSameExpectedType(left, right, MemoryType.class); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitMemoryEqualExpression(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryExtend.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryExtend.java new file mode 100644 index 0000000000..9ed5fb4738 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryExtend.java @@ -0,0 +1,35 @@ +package com.dat3m.dartagnan.expression.memory; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.CastExpressionBase; +import com.dat3m.dartagnan.expression.type.MemoryType; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; +import com.google.common.base.Preconditions; + +public final class MemoryExtend extends CastExpressionBase { + + public MemoryExtend(MemoryType targetType, Expression operand) { + super(targetType, operand); + ExpressionHelper.checkExpectedType(operand, MemoryType.class); + Preconditions.checkArgument(isExtension(getSourceType(), targetType)); + } + + + public boolean isExtension() { + return isExtension(getSourceType(), getTargetType()); + } + + public boolean isNoop() { + return getSourceType().equals(getTargetType()); + } + + private static boolean isExtension(MemoryType sourceType, MemoryType targetType) { + return sourceType.getBitWidth() < targetType.getBitWidth(); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitMemoryExtend(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryExtract.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryExtract.java new file mode 100644 index 0000000000..25d504c006 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/MemoryExtract.java @@ -0,0 +1,48 @@ +package com.dat3m.dartagnan.expression.memory; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionKind; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.UnaryExpressionBase; +import com.dat3m.dartagnan.expression.type.MemoryType; +import com.dat3m.dartagnan.expression.type.TypeFactory; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; +import com.google.common.base.Preconditions; + +public class MemoryExtract extends UnaryExpressionBase { + + private final int lowBit; + private final int highBit; + + public MemoryExtract(Expression operand, int lowBit, int highBit) { + super(TypeFactory.getInstance().getMemoryType(highBit - lowBit + 1), + () -> "MEM_EXTRACT", + operand); + ExpressionHelper.checkExpectedType(operand, MemoryType.class); + int originalWidth = ((MemoryType) operand.getType()).getBitWidth(); + Preconditions.checkArgument(0 <= lowBit && lowBit <= highBit && highBit < originalWidth); + this.lowBit = lowBit; + this.highBit = highBit; + } + + public boolean isExtractingLowBits() { + return lowBit == 0; + } + + public boolean isExtractingHighBits() { + return operand.getType() instanceof MemoryType t && highBit + 1 == t.getBitWidth(); + } + + public int getLowBit() { + return lowBit; + } + + public int getHighBit() { + return highBit; + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitMemoryExtractExpression(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/ToMemoryCast.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/ToMemoryCast.java new file mode 100644 index 0000000000..caa93272e2 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/memory/ToMemoryCast.java @@ -0,0 +1,19 @@ +package com.dat3m.dartagnan.expression.memory; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.Type; +import com.dat3m.dartagnan.expression.base.CastExpressionBase; +import com.dat3m.dartagnan.expression.type.MemoryType; + +public final class ToMemoryCast extends CastExpressionBase { + + public ToMemoryCast(MemoryType type, Expression operand) { + super(type, operand); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitToMemoryCastExpression(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/misc/GEPExpr.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/misc/GEPExpr.java index 81891dfa1c..28cb606422 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/misc/GEPExpr.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/misc/GEPExpr.java @@ -6,6 +6,7 @@ import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.base.NaryExpressionBase; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.utils.ExpressionHelper; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -21,7 +22,7 @@ public final class GEPExpr extends NaryExpressionBase offsets, Integer stride) { super(base.getType(), ExpressionKind.Other.GEP, concat(base, offsets)); - ExpressionHelper.checkExpectedType(base, IntegerType.class); + ExpressionHelper.checkExpectedType(base, PointerType.class); if (offsets.size() > 1) { Preconditions.checkArgument(isAggregateLike(indexType), "Indexing with multiple indices into non-aggregate type."); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/IntToPtrCast.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/IntToPtrCast.java new file mode 100644 index 0000000000..9fb7b1068d --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/IntToPtrCast.java @@ -0,0 +1,21 @@ +package com.dat3m.dartagnan.expression.pointers; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.CastExpressionBase; +import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; + +public final class IntToPtrCast extends CastExpressionBase { + + public IntToPtrCast(PointerType pointerType, Expression operand) { + super(pointerType, operand); + ExpressionHelper.checkExpectedType(operand, IntegerType.class); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitIntToPtrCastExpression(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/NullLiteral.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/NullLiteral.java new file mode 100644 index 0000000000..29bf3dba69 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/NullLiteral.java @@ -0,0 +1,28 @@ +package com.dat3m.dartagnan.expression.pointers; + +import com.dat3m.dartagnan.expression.ExpressionKind; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.LeafExpressionBase; +import com.dat3m.dartagnan.expression.type.PointerType; + +public class NullLiteral extends LeafExpressionBase { + + public NullLiteral(PointerType type) { + super(type); + } + + @Override + public ExpressionKind getKind() { + return () -> "NULL"; + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitNullLiteral(this); + } + + @Override + public String toString() { + return "nullptr"; + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrAddExpr.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrAddExpr.java new file mode 100644 index 0000000000..b983aeb683 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrAddExpr.java @@ -0,0 +1,49 @@ +package com.dat3m.dartagnan.expression.pointers; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionKind; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.ExpressionBase; +import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +/* This expression has only one operation and therefore does not need an operation class. + * Similar to the compare operation, ptrAdd expression is not recognised by the parsers. + * IntAddOp is transformed into the ptrAdd expression in the visitors if Ptr + Int or Int + Ptr. + */ +public class PtrAddExpr extends ExpressionBase { + + private final Expression base; + private final Expression offset; + + public PtrAddExpr(Expression base, Expression offset) { + super((PointerType) base.getType()); + Preconditions.checkArgument(offset.getType() instanceof IntegerType); + this.base = base; + this.offset = offset; + } + + public Expression getBase() { + return base; + } + + public Expression getOffset() { + return offset; + } + + @Override + public ImmutableList getOperands() { + return ImmutableList.of(base, offset); + } + + @Override + public ExpressionKind getKind() { + return () -> "ptradd"; + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitPtrAddExpression(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrCmpExpr.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrCmpExpr.java new file mode 100644 index 0000000000..f738f846a0 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrCmpExpr.java @@ -0,0 +1,21 @@ +package com.dat3m.dartagnan.expression.pointers; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.BinaryExpressionBase; +import com.dat3m.dartagnan.expression.type.BooleanType; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; + +public final class PtrCmpExpr extends BinaryExpressionBase { + + public PtrCmpExpr(BooleanType type, Expression left, PtrCmpOp kind, Expression right) { + super(type, kind, left, right); + ExpressionHelper.checkSameExpectedType(left, right, PointerType.class); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitPtrCmpExpression(this); + } +} \ No newline at end of file diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrCmpOp.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrCmpOp.java new file mode 100644 index 0000000000..d8df482fcc --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrCmpOp.java @@ -0,0 +1,66 @@ +package com.dat3m.dartagnan.expression.pointers; + +import com.dat3m.dartagnan.expression.ExpressionKind; +/* This operation is not recognised by the parsers. +* IntCmpOp is transformed into ptrCmpOp in the visitors if the two operands are pointers and the operators are either EQ or NEQ. +* If Operator is GTE, LTE, GT or LT, both operators are cast to integers and the operation remains IntCmpOp. +* Otherwise, when an integer and a pointer are compared, the pointer gets cast to integer. +*/ +public enum PtrCmpOp implements ExpressionKind { + EQ, NEQ + //, GTE, LTE, GT, LT + ; + + @Override + public String toString() { + return getSymbol(); + } + + @Override + public String getSymbol() { + return switch (this) { + case EQ -> "=="; + case NEQ -> "!="; +// case GTE -> ">="; +// case LTE -> "<="; +// case GT -> ">"; +// case LT -> "<"; + }; + } + + public PtrCmpOp inverted() { + return switch (this) { + case EQ -> NEQ; + case NEQ -> EQ; +// case GTE -> LT; +// case LTE -> GT; +// case GT -> LTE; +// case LT -> GTE; + }; + } + + public PtrCmpOp reverse() { + return switch (this) { + case EQ, NEQ -> this; +// case GTE -> LTE; +// case LTE -> GTE; +// case GT -> LT; +// case LT -> GT; + }; + } + + public boolean isStrict() { + return switch (this) { + case NEQ -> true; + case EQ -> false; + }; + } + +// public boolean isLessCategory() { +// return switch (this) { +// case LT, LTE-> true; +// default -> false; +// }; +// } +} + diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrConcat.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrConcat.java new file mode 100644 index 0000000000..4bd23ff07f --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrConcat.java @@ -0,0 +1,34 @@ +package com.dat3m.dartagnan.expression.pointers; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionKind; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.NaryExpressionBase; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.expression.type.TypeFactory; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/* Now that we have a memory type that supports tearing, this class is redundant */ +public class PtrConcat extends NaryExpressionBase { + + public PtrConcat(List operands) { + super(getConcatType(operands), ExpressionKind.Other.BV_CONCAT, ImmutableList.copyOf(operands)); + } + + private static PointerType getConcatType(List operands) { + int size = 0; + for (Expression op : operands) { + ExpressionHelper.checkExpectedType(op, PointerType.class); + size += ((PointerType) op.getType()).getBitWidth(); + } + return TypeFactory.getInstance().getPointerType(size); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitPtrConcat(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrExtract.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrExtract.java new file mode 100644 index 0000000000..21c9bd7d87 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrExtract.java @@ -0,0 +1,50 @@ +package com.dat3m.dartagnan.expression.pointers; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionKind; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.UnaryExpressionBase; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.expression.type.TypeFactory; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; +import com.google.common.base.Preconditions; + +/* Now that we have a memory type that supports tearing, this class is redundant */ + +public class PtrExtract extends UnaryExpressionBase { + + private final int lowBit; + private final int highBit; + + public PtrExtract(Expression operand, int lowBit, int highBit) { + super(TypeFactory.getInstance().getPointerType(highBit - lowBit + 1), + ExpressionKind.Other.BV_EXTRACT, + operand); + ExpressionHelper.checkExpectedType(operand, PointerType.class); + int originalWidth = ((PointerType) operand.getType()).getBitWidth(); + Preconditions.checkArgument(0 <= lowBit && lowBit <= highBit && highBit < originalWidth); + this.lowBit = lowBit; + this.highBit = highBit; + } + + public int getLowBit() { + return lowBit; + } + + public int getHighBit() { + return highBit; + } + + public boolean isExtractingLowBits() { + return lowBit == 0; + } + + public boolean isExtractingHighBits() { + return operand.getType() instanceof PointerType t && highBit + 1 == t.getBitWidth(); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitPtrExtract(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrToIntCast.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrToIntCast.java new file mode 100644 index 0000000000..60c4417532 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/pointers/PtrToIntCast.java @@ -0,0 +1,33 @@ +package com.dat3m.dartagnan.expression.pointers; + +import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.base.CastExpressionBase; +import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.expression.utils.ExpressionHelper; + +public final class PtrToIntCast extends CastExpressionBase { + + public PtrToIntCast(IntegerType integerType, Expression operand) { + super(integerType, operand); + ExpressionHelper.checkExpectedType(operand, PointerType.class); + } + + public boolean isExtension() { + return getSourceType().getBitWidth() < getTargetType().getBitWidth(); + } + + public boolean isShrinking() { + return getSourceType().getBitWidth() > getTargetType().getBitWidth(); + } + + public boolean sameWidth() { + return getSourceType().getBitWidth() == getTargetType().getBitWidth(); + } + + @Override + public T accept(ExpressionVisitor visitor) { + return visitor.visitPtrToIntCastExpression(this); + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/processing/ExprSimplifier.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/processing/ExprSimplifier.java index 39bcd500be..dd70f005ff 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/processing/ExprSimplifier.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/processing/ExprSimplifier.java @@ -10,7 +10,11 @@ import com.dat3m.dartagnan.expression.aggregates.ExtractExpr; import com.dat3m.dartagnan.expression.booleans.*; import com.dat3m.dartagnan.expression.integers.*; +import com.dat3m.dartagnan.expression.memory.FromMemoryCast; +import com.dat3m.dartagnan.expression.memory.MemoryEqualExpr; +import com.dat3m.dartagnan.expression.memory.ToMemoryCast; import com.dat3m.dartagnan.expression.misc.ITEExpr; +import com.dat3m.dartagnan.expression.pointers.*; import com.dat3m.dartagnan.expression.utils.IntegerHelper; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.memory.MemoryObject; @@ -19,6 +23,8 @@ import com.google.common.collect.Iterables; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; public class ExprSimplifier extends ExprTransformer { @@ -162,7 +168,7 @@ public Expression visitIntCmpExpression(IntCmpExpr cmp) { case ULT -> IntegerHelper.ucmp(l1.getValue(), l2.getValue(), bitWidth) < 0; case ULTE -> IntegerHelper.ucmp(l1.getValue(), l2.getValue(), bitWidth) <= 0; default -> - throw new VerifyException(String.format("Unexpected comparison operator '%s'. Missing normalization?", op)); + throw new VerifyException(String.format("Unexpected comparison operator '%s'. Missing normalization?", op)); }; return expressions.makeValue(cmpResult); } @@ -178,7 +184,7 @@ public Expression visitIntCmpExpression(IntCmpExpr cmp) { case LT, ULT -> sameObj ? false : null; case LTE, ULTE -> sameObj ? true : null; default -> - throw new VerifyException(String.format("Unexpected comparison operator '%s'. Missing normalization?", op)); + throw new VerifyException(String.format("Unexpected comparison operator '%s'. Missing normalization?", op)); }; if (cmpResult != null) { @@ -189,6 +195,49 @@ public Expression visitIntCmpExpression(IntCmpExpr cmp) { return expressions.makeIntCmp(left, op, right); } + @Override + public Expression visitPtrCmpExpression(PtrCmpExpr cmp) { + final Expression rewrite = tryGeneralRewrite(cmp); + if (rewrite != null) { + return rewrite; + } + + final Expression left = cmp.getLeft().accept(this); + final Expression right = cmp.getRight().accept(this); + final PtrCmpOp op = cmp.getKind(); + + // ------- Operations on same value ------- + if (aggressive && left.equals(right)) { + return expressions.makeValue(!op.isStrict()); + } + + // ------- Operations with constants ------- + if (left instanceof NullLiteral && right instanceof NullLiteral) { + final boolean cmpResult = switch (op) { + case EQ -> true; + case NEQ -> false; + }; + return expressions.makeValue(cmpResult); + } + + // ------- Operations on memory objects ------- + if (left instanceof MemoryObject && right instanceof MemoryObject + || left instanceof Function && right instanceof Function) { + final boolean sameObj = left.equals(right); + + final Boolean cmpResult = switch (op) { + case EQ -> sameObj; + case NEQ -> !sameObj; + }; + + if (cmpResult != null) { + return expressions.makeValue(cmpResult); + } + } + + return expressions.makePtrCmp(left, op, right); + } + @Override public Expression visitIntSizeCastExpression(IntSizeCast expr) { final Expression operand = expr.getOperand().accept(this); @@ -287,7 +336,62 @@ public Expression visitIntBinaryExpression(IntBinaryExpr expr) { return expressions.makeIntBinary(left, op, right); } - // TODO: Add simplifications for IntExtract and IntConcat expressions + // what about (base + offset) + offset -> base + (offset + offset)? + @Override + public Expression visitPtrAddExpression(PtrAddExpr expr) { + + final Expression base = expr.getBase().accept(this); + final Expression offset = expr.getOffset().accept(this); + + + // Optimizations for "x op constant" + if (offset instanceof IntLiteral lit) { + if (lit.isZero()) { + return base; + } + } + return expressions.makePtrAdd(base, offset); + } + + // TODO: Add simplifications for IntExtract and IntConcat expressions. + + // Simplifies (int(i) -> ptr(i)) -> int(i). + @Override + public Expression visitPtrToIntCastExpression(PtrToIntCast expr) { + final Expression sub = expr.getOperand().accept(this); + if (sub instanceof IntToPtrCast subT) { + final int originalBitWidth = subT.getSourceType().getBitWidth(); + final int inBetweenBitWidth = subT.getTargetType().getBitWidth(); + final int finalBitWidth = expr.getType().getBitWidth(); + + if (originalBitWidth == inBetweenBitWidth && finalBitWidth == originalBitWidth) { + return subT.getOperand(); + } + } + if (sub instanceof NullLiteral) { + return expressions.makeZero(expr.getType()); + } + return expressions.makePtrToIntCast(expr.getOperand(), expr.getType()); + } + + // Simplifies (ptr(i) -> int(i)) -> ptr(i). + @Override + public Expression visitIntToPtrCastExpression(IntToPtrCast expr) { + final Expression sub = expr.getOperand().accept(this); + if (sub instanceof PtrToIntCast subT) { + final int originalBitWidth = subT.getSourceType().getBitWidth(); + final int inBetweenBitWidth = subT.getTargetType().getBitWidth(); + final int finalBitWidth = expr.getType().getBitWidth(); + + if (originalBitWidth == inBetweenBitWidth && finalBitWidth == originalBitWidth) { + return subT.getOperand(); + } + } + if (sub instanceof IntLiteral && ((IntLiteral) sub).isZero()) { + return expressions.makeNullLiteral(expr.getType()); + } + return expressions.makeIntToPtrCast(expr.getOperand()); + } @Override public Expression visitITEExpression(ITEExpr expr) { @@ -339,7 +443,7 @@ public Expression visitExtractExpression(ExtractExpr expr) { final ImmutableList indices = expr.getIndices(); int indexCursor = 0; - while(indexCursor < indices.size() && (inner instanceof ConstructExpr construct)) { + while (indexCursor < indices.size() && (inner instanceof ConstructExpr construct)) { inner = construct.getOperands().get(indices.get(indexCursor)); indexCursor++; } @@ -378,8 +482,30 @@ public Expression visitAggregateCmpExpression(AggregateCmpExpr expr) { return expressions.makeAggregateCmp(left, expr.getKind(), right); } - // =================================== Helper methods =================================== + // =================================== Memory type =================================== + @Override + public Expression visitMemoryEqualExpression(MemoryEqualExpr expr) { + final Expression rewrite = tryGeneralRewrite(expr); + if (rewrite != null) { + return rewrite; + } + + return super.visitMemoryEqualExpression(expr); + } + + @Override + public Expression visitFromMemoryCastExpression(FromMemoryCast cast) { + final Expression inner = cast.getOperand().accept(this); + if (inner instanceof ToMemoryCast toMemoryCast && toMemoryCast.getSourceType().equals(cast.getTargetType())) { + return toMemoryCast.getOperand(); + } + + return expressions.makeFromMemoryCast(inner, cast.getTargetType()); + } + + + // =================================== Helper methods =================================== // An expression is potentially eliminable if it either carries no dependencies // or we are in aggressive mode. private boolean isPotentiallyEliminable(Expression expr) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/processing/ExprTransformer.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/processing/ExprTransformer.java index 30f18da27e..0060481930 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/processing/ExprTransformer.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/processing/ExprTransformer.java @@ -12,9 +12,12 @@ import com.dat3m.dartagnan.expression.booleans.BoolUnaryExpr; import com.dat3m.dartagnan.expression.floats.*; import com.dat3m.dartagnan.expression.integers.*; +import com.dat3m.dartagnan.expression.memory.*; import com.dat3m.dartagnan.expression.misc.GEPExpr; import com.dat3m.dartagnan.expression.misc.ITEExpr; import com.dat3m.dartagnan.expression.type.TypeFactory; +import com.dat3m.dartagnan.expression.pointers.*; + import java.util.ArrayList; @@ -130,6 +133,44 @@ public Expression visitAggregateCmpExpression(AggregateCmpExpr expr) { ); } + + @Override + public Expression visitPtrAddExpression(PtrAddExpr expr) { + return expressions.makePtrAdd( + expr.getBase().accept(this), + expr.getOffset().accept(this) + ); + } + + @Override + public Expression visitPtrCmpExpression(PtrCmpExpr expr) { + return expressions.makePtrCmp( + expr.getLeft().accept(this), + expr.getKind(), + expr.getRight().accept(this) + ); + } + + @Override + public Expression visitPtrToIntCastExpression(PtrToIntCast expr) { + return expressions.makePtrToIntCast(expr.getOperand().accept(this), expr.getType()); + } + + @Override + public Expression visitIntToPtrCastExpression(IntToPtrCast expr) { + return expressions.makeIntToPtrCast(expr.getOperand().accept(this)); + } + + @Override + public Expression visitPtrConcat(PtrConcat expr) { + return expressions.makePtrConcat(expr.getOperands().stream().map(e -> e.accept(this)).toList()); + } + + @Override + public Expression visitPtrExtract(PtrExtract expr) { + return expressions.makePtrExtract(expr.getOperand().accept(this), expr.getLowBit(), expr.getHighBit()); + } + @Override public Expression visitGEPExpression(GEPExpr gep) { Expression base = gep.getBase().accept(this); @@ -140,6 +181,36 @@ public Expression visitGEPExpression(GEPExpr gep) { return expressions.makeGetElementPointer(gep.getIndexingType(), base, offsets); } + @Override + public Expression visitToMemoryCastExpression(ToMemoryCast expr) { + return expressions.makeToMemoryCast(expr.getOperand().accept(this)); + } + + @Override + public Expression visitFromMemoryCastExpression(FromMemoryCast expr) { + return expressions.makeFromMemoryCast(expr.getOperand().accept(this), expr.getTargetType()); + } + + @Override + public Expression visitMemoryConcatExpression(MemoryConcat expr) { + return expressions.makeMemoryConcat(expr.getOperands().stream().map(e -> e.accept(this)).toList()); + } + + @Override + public Expression visitMemoryExtractExpression(MemoryExtract expr) { + return expressions.makeMemoryExtract(expr.getOperand().accept(this), expr.getLowBit(), expr.getHighBit()); + } + + @Override + public Expression visitMemoryEqualExpression(MemoryEqualExpr expr) { + return expressions.makeEQ(expr.getLeft().accept(this), expr.getRight().accept(this)); + } + + @Override + public Expression visitMemoryExtend(MemoryExtend expr) { + return expressions.makeMemoryExtend(expr.getOperand().accept(this), expr.getTargetType()); + } + @Override public Expression visitLeafExpression(LeafExpression expr) { return expr; diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/MemoryType.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/MemoryType.java new file mode 100644 index 0000000000..a6771729c8 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/MemoryType.java @@ -0,0 +1,59 @@ +package com.dat3m.dartagnan.expression.type; + +import com.dat3m.dartagnan.expression.Type; +import com.google.common.base.Preconditions; + +/* + This type represents an abstract value in memory, typically understood as a sequence of bits/bytes with + additional metadata. Value instances of this type are referred to as "memory values". + Properties: + - Any other type that can be stored to/loaded from memory should be convertible to a memory type of + appropriate size, i.e., the memory type that has size matching the memory size of the type. + - Conversely, memory values must be convertible back to (at least) the type they originated from without loss of + information: if o is of type T, then "o == toT(toMemory(o))" should hold. + - To guarantee the above lossless round-trip property, for every metadata that some type may track + (e.g., pointer provenance, address space, ...), the memory type must also be able to track it. + - Storing any object "T o" in memory conceptually stores "toMemory(o)" in memory. + Conversely, any load of type T from memory conceptually loads "toT(o)". + Due the lossless round-trip property "o = toT(toMemory(o))", loads froms stores of the same type + guarantee that the load sees exactly the stored value. + - To support mixed-size accesses, MemoryType supports extraction and concatenation operations, + which also have a lossless round-trip property: + extracting single bits/bytes and then sticking them together again in the correct order must produce the original value + including all metadata like pointer provenance. + Concatenating bits from different memory values may or may not produce valid values: + Generally, metadata like provenance will not be retained, however, for metadata-less types like + integers, the concatenation may be reasonable. + */ +public class MemoryType implements Type { + + private final int bitWidth; + + MemoryType(int bitWidth) { + Preconditions.checkArgument(bitWidth > 0, "Size for memory type must be positive: %s", bitWidth); + Preconditions.checkArgument((bitWidth & 7) == 0, "Size must be a multiple of 8: %s", bitWidth); + this.bitWidth = bitWidth; + } + + public int getBitWidth() { + return bitWidth; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + return obj instanceof MemoryType other && other.bitWidth == this.bitWidth; + } + + @Override + public int hashCode() { + return 31 * bitWidth + getClass().hashCode(); + } + + @Override + public String toString() { + return "membits" + bitWidth; + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/PointerType.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/PointerType.java new file mode 100644 index 0000000000..859cb117a8 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/PointerType.java @@ -0,0 +1,27 @@ +package com.dat3m.dartagnan.expression.type; + +import com.dat3m.dartagnan.expression.Type; + +public class PointerType implements Type { + + public int bitWidth; + + PointerType(int bitWidth) { + this.bitWidth = bitWidth; + } + + @Override + public String toString() { + return "ptr" + bitWidth; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof PointerType other + && other.bitWidth == this.bitWidth; + } + + public int getBitWidth() { + return bitWidth; + } +} diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/ScopedPointerType.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/ScopedPointerType.java index 87125ff27a..780d8c430e 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/ScopedPointerType.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/ScopedPointerType.java @@ -4,9 +4,9 @@ import java.util.Objects; -public class ScopedPointerType extends IntegerType { +public class ScopedPointerType extends PointerType { - private static final int ARCH_SIZE = TypeFactory.getInstance().getArchType().getBitWidth(); + private static final int ARCH_SIZE = TypeFactory.getInstance().getPointerType().getBitWidth(); private final String scopeId; private final Type pointedType; diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/TypeFactory.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/TypeFactory.java index ac68c53880..01b92ab062 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/TypeFactory.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/type/TypeFactory.java @@ -20,12 +20,13 @@ public final class TypeFactory { private final VoidType voidType = new VoidType(); private final BooleanType booleanType = new BooleanType(); - private final IntegerType pointerDifferenceType; - + private final IntegerType archType; + private final PointerType pointerType; private final Normalizer typeNormalizer = new Normalizer(); private TypeFactory() { - pointerDifferenceType = getIntegerType(64);//TODO insert proper pointer and difference types + archType = getIntegerType(64); + pointerType = getPointerType(64); } @@ -38,12 +39,22 @@ public BooleanType getBooleanType() { return booleanType; } - public VoidType getVoidType() { return voidType; } + public VoidType getVoidType() { + return voidType; + } - public Type getUnitType() { return getAggregateType(List.of()); } + public Type getUnitType() { + return getAggregateType(List.of()); + } + + public PointerType getPointerType() { + return pointerType; + } - public Type getPointerType() { - return pointerDifferenceType; + public PointerType getPointerType(int bitWidth) { + // to be used in tearing + checkArgument(bitWidth > 0, "Non-positive bit width %s.", bitWidth); + return typeNormalizer.normalize(new PointerType(bitWidth)); } public IntegerType getIntegerType(int bitWidth) { @@ -51,6 +62,18 @@ public IntegerType getIntegerType(int bitWidth) { return typeNormalizer.normalize(new IntegerType(bitWidth)); } + public MemoryType getMemoryType(int bitWidth) { + checkArgument(bitWidth > 0, "Non-positive bit width %s.", bitWidth); + return typeNormalizer.normalize(new MemoryType(bitWidth)); + } + + public MemoryType getMemoryTypeFor(Type other) { + if (other instanceof MemoryType memType) { + return memType; + } + return getMemoryType(getMemorySizeInBits(other)); + } + public ScopedPointerType getScopedPointerType(String scopeId, Type pointedType, Integer stride) { checkNotNull(scopeId); checkNotNull(pointedType); @@ -96,10 +119,10 @@ public AggregateType getAggregateType(List fields, List offsets) checkArgument(offsets.stream().noneMatch(o -> o < 0), "Offset cannot be negative"); checkArgument(offsets.isEmpty() || offsets.get(0) == 0, "The first offset must be zero"); checkArgument(IntStream.range(1, offsets.size()).allMatch( - i -> offsets.get(i) >= offsets.get(i - 1) + Integer.max(0, getMemorySizeInBytes(fields.get(i - 1), false))), + i -> offsets.get(i) >= offsets.get(i - 1) + Integer.max(0, getMemorySizeInBytes(fields.get(i - 1), false))), "Offset is too small"); checkArgument(IntStream.range(0, fields.size() - 1).allMatch( - i -> hasKnownSize(fields.get(i))), + i -> hasKnownSize(fields.get(i))), "Non-last element with unknown size"); return typeNormalizer.normalize(new AggregateType(fields, offsets)); } @@ -147,13 +170,24 @@ public ArrayType getArrayType(Type element, int size, Integer stride, Integer al } public IntegerType getArchType() { - return pointerDifferenceType; + return archType; } public IntegerType getByteType() { return getIntegerType(8); } + public Type getCompatibleTypeOfMemorySize(Type type, int memSizeInBits) { + if (type instanceof IntegerType) { + return getIntegerType(memSizeInBits); + } + if (type instanceof PointerType) { + return getPointerType(memSizeInBits); + } + + throw new UnsupportedOperationException(String.format("Type %s has no compatible type of size %s", type, memSizeInBits)); + } + public int getMemorySizeInBytes(Type type) { return getMemorySizeInBytes(type, true); } @@ -162,9 +196,15 @@ private int getMemorySizeInBytes(Type type, boolean padded) { if (type instanceof BooleanType) { return 1; } + if (type instanceof MemoryType memType) { + return IntMath.divide(memType.getBitWidth(), 8, RoundingMode.CEILING); + } if (type instanceof IntegerType integerType) { return IntMath.divide(integerType.getBitWidth(), 8, RoundingMode.CEILING); } + if (type instanceof PointerType pointerTypp) { + return IntMath.divide(pointerTypp.getBitWidth(), 8, RoundingMode.CEILING); + } if (type instanceof FloatType floatType) { return IntMath.divide(floatType.getBitWidth(), 8, RoundingMode.CEILING); } @@ -204,7 +244,7 @@ private int getMemorySizeInBytes(Type type, boolean padded) { } private int getAlignment(Type type) { - if (type instanceof BooleanType || type instanceof IntegerType || type instanceof FloatType) { + if (type instanceof BooleanType || type instanceof IntegerType || type instanceof FloatType || type instanceof PointerType) { return getMemorySizeInBytes(type); } if (type instanceof ArrayType arrayType) { @@ -228,7 +268,9 @@ public static int paddedSize(int size, int alignment) { return size; } - public boolean hasKnownSize(Type type) { return getMemorySizeInBytes(type) >= 0; } + public boolean hasKnownSize(Type type) { + return getMemorySizeInBytes(type) >= 0; + } public int getMemorySizeInBits(Type type) { return getMemorySizeInBytes(type) * 8; @@ -271,7 +313,7 @@ public Map decomposeIntoPrimitives(Type type) { } public static boolean isStaticType(Type type) { - if (type instanceof BooleanType || type instanceof IntegerType || type instanceof FloatType) { + if (type instanceof BooleanType || type instanceof IntegerType || type instanceof PointerType || type instanceof FloatType) { return true; } if (type instanceof ArrayType aType) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/utils/ExpressionHelper.java b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/utils/ExpressionHelper.java index e6f9bfe775..978ae5a42e 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/expression/utils/ExpressionHelper.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/expression/utils/ExpressionHelper.java @@ -9,7 +9,8 @@ public class ExpressionHelper { - private ExpressionHelper() {} + private ExpressionHelper() { + } public static void checkSameType(Expression x, Expression y) { Preconditions.checkArgument(x.getType().equals(y.getType()), @@ -48,7 +49,7 @@ public static void checkInbounds(Type aggregateType, int index) { } public static boolean isScalar(Type type) { - return type instanceof BooleanType || type instanceof IntegerType || type instanceof FloatType; + return type instanceof BooleanType || type instanceof IntegerType || type instanceof FloatType || type instanceof PointerType; } public static boolean isAggregateLike(Type type) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/cat/VisitorCat.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/cat/VisitorCat.java index b025afa1fc..ee1cea23e4 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/cat/VisitorCat.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/cat/VisitorCat.java @@ -31,6 +31,12 @@ import static com.dat3m.dartagnan.program.event.Tag.VISIBLE; import static com.dat3m.dartagnan.wmm.RelationNameRepository.ID; +import com.dat3m.dartagnan.parsers.CatParser.*; +import com.dat3m.dartagnan.wmm.definition.*; +import org.antlr.v4.runtime.*; + +import java.util.*; + class VisitorCat extends CatBaseVisitor { private static final Logger logger = LoggerFactory.getLogger(VisitorCat.class); @@ -138,7 +144,7 @@ private String createUniqueName(String name) { nameOccurrenceCounter.putIfAbsent(name, 1); } - final int occurrenceNumber = nameOccurrenceCounter.compute(name, (k, v) -> v == null ? 1 : v + 1); + final int occurrenceNumber = nameOccurrenceCounter.compute(name, (k, v) -> v == null ? 1 : v + 1); // If it is the first time we encounter this name, we return it as is. return occurrenceNumber == 1 ? name : name + "#" + occurrenceNumber; } @@ -254,7 +260,7 @@ public Object visitExprCall(ExprCallContext ctx) { final Map curNamespace = namespace; namespace = functionNamespace; final CatParser parser = getParser(CharStreams.fromString(funcDef.expression)); - Object result = parser.expression().accept(this); + Object result = parser.expression().accept(this); namespace = curNamespace; return result; } @@ -374,7 +380,7 @@ private Relation addDefinition(Definition definition) { } private void checkNoRecursion(ExpressionContext c) { - if(relationToBeDefined != null) { + if (relationToBeDefined != null) { throw new ParsingException("Unexpected recursive context at expression: " + c.getText()); } } @@ -414,7 +420,8 @@ private static CatParser getParser(CharStream input) { private final class ArityInspector extends CatBaseVisitor { - private ArityInspector() {} + private ArityInspector() { + } @Override public Relation.Arity visitExpr(ExprContext c) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/ProgramParser.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/ProgramParser.java index 60ac20ff35..b4cd341b6d 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/ProgramParser.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/ProgramParser.java @@ -94,7 +94,7 @@ private ParserInterface getConcreteParser(File file) throws IOException { return new ParserLlvm(); } if (name.endsWith(EXTENSION_SPV_DIS)) { - logger.warn(String.format("Extension %s is deprecated. Please rename your file to %s instead.", EXTENSION_SPV_DIS, EXTENSION_SPVASM)); + logger.warn(String.format("Extension %s is deprecated. Please rename your file to %s instead.", EXTENSION_SPV_DIS, EXTENSION_SPVASM)); return new ParserSpirv(); } if (name.endsWith(EXTENSION_SPVASM)) { @@ -119,7 +119,7 @@ private ParserInterface getConcreteLitmusParser(String programText) { return new ParserLitmusRISCV(); } else if (programText.indexOf(TYPE_LITMUS_PTX) == 0) { return new ParserLitmusPTX(); - } else if(programText.indexOf(TYPE_LITMUS_VULKAN) == 0) { + } else if (programText.indexOf(TYPE_LITMUS_VULKAN) == 0) { return new ParserLitmusVulkan(); } final int spaceIndex = programText.indexOf(" "); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/AsmUtils.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/AsmUtils.java index 66fbbde42d..b1db64d18b 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/AsmUtils.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/AsmUtils.java @@ -6,10 +6,7 @@ import com.dat3m.dartagnan.exception.ParsingException; import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.Type; -import com.dat3m.dartagnan.expression.type.AggregateType; -import com.dat3m.dartagnan.expression.type.BooleanType; -import com.dat3m.dartagnan.expression.type.IntegerType; -import com.dat3m.dartagnan.expression.type.VoidType; +import com.dat3m.dartagnan.expression.type.*; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.event.EventFactory; import com.dat3m.dartagnan.program.event.core.Label; @@ -28,7 +25,7 @@ public static int getNumASMReturnRegisters(Register returnRegister) { return 0; } Type returnType = returnRegister.getType(); - if (returnType instanceof IntegerType || returnType instanceof BooleanType) { + if (returnType instanceof IntegerType || returnType instanceof PointerType || returnType instanceof BooleanType) { return 1; } else if (isReturnRegisterAggregate(returnRegister)) { return ((AggregateType) returnType).getFields().size(); @@ -46,7 +43,7 @@ public static boolean isReturnRegisterAggregate(Register returnRegister) { } // Tells if the registerID is mapped to the returnRegister - public static boolean isPartOfReturnRegister(Register returnRegister,int registerID) { + public static boolean isPartOfReturnRegister(Register returnRegister, int registerID) { return registerID < getNumASMReturnRegisters(returnRegister); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/Compilation.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/Compilation.java index 6681399993..5026d50293 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/Compilation.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/Compilation.java @@ -50,8 +50,8 @@ private static void runCmd(ArrayList cmd) throws Exception { processBuilder.redirectOutput(log); Process proc = processBuilder.start(); proc.waitFor(); - if(proc.exitValue() != 0) { - String errorString = Files.asCharSource(log, Charsets.UTF_8).read(); + if (proc.exitValue() != 0) { + String errorString = Files.asCharSource(log, Charsets.UTF_8).read(); throw new IOException("'" + String.join("' '", cmd) + "': " + errorString); } } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/ProgramBuilder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/ProgramBuilder.java index 880eb08671..649446f21e 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/ProgramBuilder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/utils/ProgramBuilder.java @@ -5,8 +5,11 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.Type; +import com.dat3m.dartagnan.expression.integers.IntCmpExpr; +import com.dat3m.dartagnan.expression.integers.IntCmpOp; import com.dat3m.dartagnan.expression.integers.IntLiteral; import com.dat3m.dartagnan.expression.type.FunctionType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.program.*; import com.dat3m.dartagnan.program.Thread; @@ -137,7 +140,7 @@ public void setAssertFilter(Expression ass) { // This method creates a "default" thread that has no parameters, no return value, and runs unconditionally. // It is only useful for creating threads of Litmus code. public Thread newThread(String name, int tid) { - if(id2FunctionsMap.containsKey(tid)) { + if (id2FunctionsMap.containsKey(tid)) { throw new MalformedProgramException("Function or thread with id " + tid + " already exists."); } final Thread thread = new Thread(name, DEFAULT_THREAD_TYPE, List.of(), tid, EventFactory.newThreadStart(null)); @@ -147,7 +150,7 @@ public Thread newThread(String name, int tid) { } public Function newFunction(String name, int fid, FunctionType type, List parameterNames) { - if(id2FunctionsMap.containsKey(fid)) { + if (id2FunctionsMap.containsKey(fid)) { throw new MalformedProgramException("Function or thread with id " + fid + " already exists."); } final Function func = new Function(name, type, parameterNames, fid, null); @@ -234,26 +237,26 @@ public void initLocEqLocPtr(String leftName, String rightName) { initLocEqConst(leftName, getOrNewMemoryObject(rightName)); } - public void initLocEqLocVal(String leftName, String rightName){ - initLocEqConst(leftName,getInitialValue(rightName)); + public void initLocEqLocVal(String leftName, String rightName) { + initLocEqConst(leftName, getInitialValue(rightName)); } - public void initLocEqConst(String locName, Expression iValue){ + public void initLocEqConst(String locName, Expression iValue) { getOrNewMemoryObject(locName).setInitialValue(0, iValue); } - public void initRegEqLocPtr(int regThread, String regName, String locName, Type type) { + public void initRegEqLocPtr(int regThread, String regName, String locName) { MemoryObject object = getOrNewMemoryObject(locName); - Register reg = getOrNewRegister(regThread, regName, type); + Register reg = getOrNewRegister(regThread, regName, types.getPointerType()); addChild(regThread, EventFactory.newLocal(reg, object)); } public void initRegEqLocVal(int regThread, String regName, String locName, Type type) { Register reg = getOrNewRegister(regThread, regName, type); - addChild(regThread, EventFactory.newLocal(reg,getInitialValue(locName))); + addChild(regThread, EventFactory.newLocal(reg, getInitialValue(locName))); } - public void initRegEqConst(int regThread, String regName, Expression value){ + public void initRegEqConst(int regThread, String regName, Expression value) { Preconditions.checkArgument(value.getRegs().isEmpty()); addChild(regThread, EventFactory.newLocal(getOrNewRegister(regThread, regName, value.getType()), value)); } @@ -265,12 +268,12 @@ private Expression getInitialValue(String name) { // ---------------------------------------------------------------------------------------------------------------- // Utility - public Register getRegister(int fid, String name){ + public Register getRegister(int fid, String name) { return getFunctionOrError(fid).getRegister(name); } - public Register getOrNewRegister(int fid, String name) { - return getOrNewRegister(fid, name, types.getArchType()); + public Register getOrNewRegister(int fid, String name) { // use carefully + return getOrNewRegister(fid, name, types.getPointerType()); } public Register getOrNewRegister(int fid, String name, Type type) { @@ -287,7 +290,7 @@ public Register getOrErrorRegister(int fid, String name) { throw new IllegalStateException("Register " + fid + ":" + name + " is not initialised"); } - public Label getOrCreateLabel(int funcId, String name){ + public Label getOrCreateLabel(int funcId, String name) { return fid2LabelsMap .computeIfAbsent(funcId, k -> new HashMap<>()) .computeIfAbsent(name, EventFactory::newLabel); @@ -297,9 +300,10 @@ public Label getEndOfThreadLabel(int tid) { return getOrCreateLabel(tid, "END_OF_T" + tid); } + // ---------------------------------------------------------------------------------------------------------------- // GPU - public void newScopedThread(Arch arch, String name, int id, int ...scopeIds) { + public void newScopedThread(Arch arch, String name, int id, int... scopeIds) { ScopeHierarchy scopeHierarchy = switch (arch) { case PTX -> ScopeHierarchy.ScopeHierarchyForPTX(scopeIds[0], scopeIds[1]); case VULKAN -> ScopeHierarchy.ScopeHierarchyForVulkan(scopeIds[0], scopeIds[1], scopeIds[2]); @@ -307,7 +311,7 @@ public void newScopedThread(Arch arch, String name, int id, int ...scopeIds) { default -> throw new UnsupportedOperationException("Unsupported architecture: " + arch); }; - if(id2FunctionsMap.containsKey(id)) { + if (id2FunctionsMap.containsKey(id)) { throw new MalformedProgramException("Function or thread with id " + id + " already exists."); } // Litmus threads run unconditionally (have no creator) and have no parameters/return types. @@ -317,17 +321,17 @@ public void newScopedThread(Arch arch, String name, int id, int ...scopeIds) { program.addThread(scopedThread); } - public void newScopedThread(Arch arch, int id, int ...ids) { + public void newScopedThread(Arch arch, int id, int... ids) { newScopedThread(arch, String.valueOf(id), id, ids); } // ---------------------------------------------------------------------------------------------------------------- // PTX - public void initVirLocEqCon(String leftName, IntLiteral iValue){ + public void initVirLocEqCon(String leftName, IntLiteral iValue) { getOrNewVirtualMemoryObject(leftName, true, null).setInitialValue(0, iValue); } - public void initVirLocEqLoc(String leftName, String rightName){ + public void initVirLocEqLoc(String leftName, String rightName) { VirtualMemoryObject rightLocation = (VirtualMemoryObject) getMemoryObject(rightName); if (rightLocation == null) { throw new MalformedProgramException("Alias to non-exist location: " + rightName); @@ -335,7 +339,7 @@ public void initVirLocEqLoc(String leftName, String rightName){ getOrNewVirtualMemoryObject(leftName, true, null).setInitialValue(0, rightLocation.getInitialValue(0)); } - public void initVirLocEqLocAliasGen(String leftName, String rightName){ + public void initVirLocEqLocAliasGen(String leftName, String rightName) { VirtualMemoryObject rightLocation = (VirtualMemoryObject) getMemoryObject(rightName); if (rightLocation == null) { throw new MalformedProgramException("Alias to non-exist location: " + rightName); @@ -343,7 +347,7 @@ public void initVirLocEqLocAliasGen(String leftName, String rightName){ getOrNewVirtualMemoryObject(leftName, true, rightLocation).setInitialValue(0, rightLocation.getInitialValue(0)); } - public void initVirLocEqLocAliasProxy(String leftName, String rightName){ + public void initVirLocEqLocAliasProxy(String leftName, String rightName) { VirtualMemoryObject rightLocation = (VirtualMemoryObject) getMemoryObject(rightName); if (rightLocation == null) { throw new MalformedProgramException("Alias to non-exist location: " + rightName); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmArm.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmArm.java index f628fa6f45..789c7b7fd1 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmArm.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmArm.java @@ -11,6 +11,8 @@ import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.integers.IntCmpOp; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.parsers.AsmArmBaseVisitor; import com.dat3m.dartagnan.parsers.AsmArmParser; import com.dat3m.dartagnan.parsers.program.utils.AsmUtils; @@ -21,7 +23,7 @@ import com.dat3m.dartagnan.program.event.Tag; import com.dat3m.dartagnan.program.event.core.Label; import com.dat3m.dartagnan.program.event.core.Local; -import static com.google.common.base.Preconditions.checkState; + // The trickiest part of handling inline assembly is matching input and output registers on the LLVM side with the registers in the assembly. // The matching depends on what is specified in the constraints. @@ -90,7 +92,10 @@ // 3. the third asm register is related both to the return register (already above in r11[3] <- asm_3) and to an args register, i.e. asm_3 <- r8 public class VisitorAsmArm extends AsmArmBaseVisitor { - private record CmpInstruction(Expression left, Expression right) {}; + private record CmpInstruction(Expression left, Expression right) { + } + + ; private final List inputAssignments = new ArrayList<>(); private final List asmInstructions = new ArrayList<>(); @@ -109,6 +114,8 @@ private record CmpInstruction(Expression left, Expression right) {}; private Type expectedType; // map from RegisterID to the corresponding asm register private final HashMap asmRegisters = new HashMap<>(); + private final TypeFactory typeFactory = TypeFactory.getInstance(); + private final PointerType pointerType = typeFactory.getPointerType(); public VisitorAsmArm(Function llvmFunction, Register returnRegister, List llvmArguments) { this.llvmFunction = llvmFunction; @@ -134,6 +141,10 @@ public List visitAsm(AsmArmParser.AsmContext ctx) { return events; } + private Expression toPtr(Register r) { + return expressions.makeIntToPtrCast(r, pointerType); + } + // Tells if a constraint is a numeric one, e.g. '3' private boolean isConstraintNumeric(AsmArmParser.ConstraintContext constraint) { return constraint.overlapInOutRegister() != null; @@ -158,7 +169,7 @@ private boolean isConstraintInputConstraint(AsmArmParser.ConstraintContext const public Object visitLoad(AsmArmParser.LoadContext ctx) { Register register = (Register) ctx.register(0).accept(this); Register address = (Register) ctx.register(1).accept(this); - asmInstructions.add(EventFactory.newLoad(register, address)); + asmInstructions.add(EventFactory.newLoad(register, toPtr(address))); return null; } @@ -166,7 +177,7 @@ public Object visitLoad(AsmArmParser.LoadContext ctx) { public Object visitLoadAcquire(AsmArmParser.LoadAcquireContext ctx) { Register register = (Register) ctx.register(0).accept(this); Register address = (Register) ctx.register(1).accept(this); - asmInstructions.add(EventFactory.newLoadWithMo(register, address, Tag.ARMv8.MO_ACQ)); + asmInstructions.add(EventFactory.newLoadWithMo(register, toPtr(address), Tag.ARMv8.MO_ACQ)); return null; } @@ -174,7 +185,7 @@ public Object visitLoadAcquire(AsmArmParser.LoadAcquireContext ctx) { public Object visitLoadExclusive(AsmArmParser.LoadExclusiveContext ctx) { Register register = (Register) ctx.register(0).accept(this); Register address = (Register) ctx.register(1).accept(this); - asmInstructions.add(EventFactory.newRMWLoadExclusive(register, address)); + asmInstructions.add(EventFactory.newRMWLoadExclusive(register, toPtr(address))); return null; } @@ -182,7 +193,7 @@ public Object visitLoadExclusive(AsmArmParser.LoadExclusiveContext ctx) { public Object visitLoadAcquireExclusive(AsmArmParser.LoadAcquireExclusiveContext ctx) { Register register = (Register) ctx.register(0).accept(this); Register address = (Register) ctx.register(1).accept(this); - asmInstructions.add(EventFactory.newRMWLoadExclusiveWithMo(register, address, Tag.ARMv8.MO_ACQ)); + asmInstructions.add(EventFactory.newRMWLoadExclusiveWithMo(register, toPtr(address), Tag.ARMv8.MO_ACQ)); return null; } @@ -232,7 +243,7 @@ public Object visitAnd(AsmArmParser.AndContext ctx) { public Object visitStore(AsmArmParser.StoreContext ctx) { Register value = (Register) ctx.register(0).accept(this); Register address = (Register) ctx.register(1).accept(this); - asmInstructions.add(EventFactory.newStore(address, value)); + asmInstructions.add(EventFactory.newStore(toPtr(address), value)); return null; } @@ -240,7 +251,7 @@ public Object visitStore(AsmArmParser.StoreContext ctx) { public Object visitStoreRelease(AsmArmParser.StoreReleaseContext ctx) { Register value = (Register) ctx.register(0).accept(this); Register address = (Register) ctx.register(1).accept(this); - asmInstructions.add(EventFactory.newStoreWithMo(address, value, Tag.ARMv8.MO_REL)); + asmInstructions.add(EventFactory.newStoreWithMo(toPtr(address), value, Tag.ARMv8.MO_REL)); return null; } @@ -249,7 +260,7 @@ public Object visitStoreExclusive(AsmArmParser.StoreExclusiveContext ctx) { Register freshResultRegister = (Register) ctx.register(0).accept(this); Register value = (Register) ctx.register(1).accept(this); Register address = (Register) ctx.register(2).accept(this); - asmInstructions.add(EventFactory.Common.newExclusiveStore(freshResultRegister, address, value, "")); + asmInstructions.add(EventFactory.Common.newExclusiveStore(freshResultRegister, toPtr(address), value, "")); return null; } @@ -258,7 +269,7 @@ public Object visitStoreReleaseExclusive(AsmArmParser.StoreReleaseExclusiveConte Register freshResultRegister = (Register) ctx.register(0).accept(this); Register value = (Register) ctx.register(1).accept(this); Register address = (Register) ctx.register(2).accept(this); - asmInstructions.add(EventFactory.Common.newExclusiveStore(freshResultRegister, address, value, Tag.ARMv8.MO_REL)); + asmInstructions.add(EventFactory.Common.newExclusiveStore(freshResultRegister, toPtr(address), value, Tag.ARMv8.MO_REL)); return null; } @@ -326,7 +337,10 @@ public Object visitRegister(AsmArmParser.RegisterContext ctx) { return asmRegisters.get(registerID); } else { // Pick up the correct type and create the new Register - Type registerType = AsmUtils.getLlvmRegisterTypeGivenAsmRegisterID(this.argsRegisters,this.returnRegister,registerID); + Type registerType = AsmUtils.getLlvmRegisterTypeGivenAsmRegisterID(this.argsRegisters, this.returnRegister, registerID); + if (registerType instanceof PointerType pt) { + registerType = typeFactory.getIntegerType(pt.bitWidth); + } String newRegisterName = AsmUtils.makeRegisterName(registerID); Register newRegister = this.llvmFunction.getOrNewRegister(newRegisterName, registerType); if (AsmUtils.isPartOfReturnRegister(this.returnRegister, registerID) && AsmUtils.isReturnRegisterAggregate(this.returnRegister)) { @@ -363,10 +377,10 @@ public Object visitAsmMetadataEntries(AsmArmParser.AsmMetadataEntriesContext ctx if (!isOutputRegistersInitialized) { isOutputRegistersInitialized = true; if (i == 1) { - outputAssignments.add(EventFactory.newLocal(returnRegister, asmRegisters.get(0))); + outputAssignments.add(EventFactory.newLocal(returnRegister, expressions.makeCast(asmRegisters.get(0), returnRegister.getType()))); } else { Type aggregateType = returnRegister.getType(); - Expression finalAssignExpression = expressions.makeConstruct(aggregateType, this.pendingRegisters); + Expression finalAssignExpression = expressions.makeCompatibilityConstruct(aggregateType, this.pendingRegisters); outputAssignments.add(EventFactory.newLocal(this.returnRegister, finalAssignExpression)); } } @@ -376,11 +390,13 @@ public Object visitAsmMetadataEntries(AsmArmParser.AsmMetadataEntriesContext ctx continue; } Expression llvmRegister = argsRegisters.get(i - AsmUtils.getNumASMReturnRegisters(this.returnRegister)); - inputAssignments.add(EventFactory.newLocal(asmRegister, llvmRegister)); + inputAssignments.add(EventFactory.newLocal(asmRegister, expressions.makeCast(llvmRegister, asmRegister.getType()))); } if (isConstraintNumeric(constraint)) { int constraintValue = Integer.parseInt(constraint.getText()); - inputAssignments.add(EventFactory.newLocal(asmRegisters.get(constraintValue), argsRegisters.get(i - AsmUtils.getNumASMReturnRegisters(this.returnRegister)))); + inputAssignments.add(EventFactory.newLocal(asmRegisters.get(constraintValue), + expressions.makeCast(argsRegisters.get(i - AsmUtils.getNumASMReturnRegisters(this.returnRegister)), asmRegisters.get(constraintValue).getType()) + )); } } return null; @@ -388,10 +404,17 @@ public Object visitAsmMetadataEntries(AsmArmParser.AsmMetadataEntriesContext ctx @Override public Object visitValue(AsmArmParser.ValueContext ctx) { - checkState(expectedType instanceof IntegerType, "Expected type is not an integer type"); - String valueString = ctx.Numbers().getText(); - BigInteger value = new BigInteger(valueString); - return expressions.makeValue(value, (IntegerType) expectedType); + if (expectedType instanceof IntegerType t) { + String valueString = ctx.Numbers().getText(); + BigInteger value = new BigInteger(valueString); + return expressions.makeValue(value, t); + } + if (expectedType instanceof PointerType t) { + String valueString = ctx.Numbers().getText(); + BigInteger value = new BigInteger(valueString); + return expressions.makeValue(value, typeFactory.getIntegerType(t.bitWidth)); + } + throw new RuntimeException("Unexpected type " + expectedType + " visited"); } @Override @@ -401,26 +424,16 @@ public Object visitArmFence(AsmArmParser.ArmFenceContext ctx) { String option = ctx.FenceArmOpt().getText(); String barrier = type + " " + option; Event fence = switch (barrier) { - case "dmb ish" -> - EventFactory.AArch64.DMB.newISHBarrier(); - case "dmb ishld" -> - EventFactory.AArch64.DMB.newISHLDBarrier(); - case "dmb sy" -> - EventFactory.AArch64.DMB.newSYBarrier(); - case "dmb st" -> - EventFactory.AArch64.DMB.newSTBarrier(); - case "dmb ishst" -> - EventFactory.AArch64.DMB.newISHSTBarrier(); - case "dsb ish" -> - EventFactory.AArch64.DSB.newISHBarrier(); - case "dsb ishld" -> - EventFactory.AArch64.DSB.newISHLDBarrier(); - case "dsb sy" -> - EventFactory.AArch64.DSB.newSYBarrier(); - case "dsb ishst" -> - EventFactory.AArch64.DSB.newISHSTBarrier(); - default -> - throw new ParsingException("Barrier not implemented"); + case "dmb ish" -> EventFactory.AArch64.DMB.newISHBarrier(); + case "dmb ishld" -> EventFactory.AArch64.DMB.newISHLDBarrier(); + case "dmb sy" -> EventFactory.AArch64.DMB.newSYBarrier(); + case "dmb st" -> EventFactory.AArch64.DMB.newSTBarrier(); + case "dmb ishst" -> EventFactory.AArch64.DMB.newISHSTBarrier(); + case "dsb ish" -> EventFactory.AArch64.DSB.newISHBarrier(); + case "dsb ishld" -> EventFactory.AArch64.DSB.newISHLDBarrier(); + case "dsb sy" -> EventFactory.AArch64.DSB.newSYBarrier(); + case "dsb ishst" -> EventFactory.AArch64.DSB.newISHSTBarrier(); + default -> throw new ParsingException("Barrier not implemented"); }; asmInstructions.add(fence); return null; diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmPPC.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmPPC.java index 7b5dbd82bb..e85eae9508 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmPPC.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmPPC.java @@ -9,8 +9,9 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.Type; -import com.dat3m.dartagnan.expression.integers.IntCmpOp; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.parsers.AsmPPCBaseVisitor; import com.dat3m.dartagnan.parsers.AsmPPCParser; import com.dat3m.dartagnan.parsers.program.utils.AsmUtils; @@ -20,11 +21,15 @@ import com.dat3m.dartagnan.program.event.EventFactory; import com.dat3m.dartagnan.program.event.core.Label; import com.dat3m.dartagnan.program.event.core.Local; + import static com.google.common.base.Preconditions.checkState; public class VisitorAsmPPC extends AsmPPCBaseVisitor { - private record CmpInstruction(Expression left, Expression right) {}; + private record CmpInstruction(Expression left, Expression right) { + } + + ; private final List inputAssignments = new ArrayList<>(); private final List asmInstructions = new ArrayList<>(); @@ -32,6 +37,7 @@ private record CmpInstruction(Expression left, Expression right) {}; private final Function llvmFunction; private final Register returnRegister; private final ExpressionFactory expressions = ExpressionFactory.getInstance(); + private final IntegerType archType = TypeFactory.getInstance().getArchType(); private CmpInstruction comparator; // keeps track of all the labels defined in the the asm code private final HashMap labelsDefined = new HashMap<>(); @@ -41,6 +47,7 @@ private record CmpInstruction(Expression left, Expression right) {}; private final List argsRegisters; // expected type of RHS of a comparison. private Type expectedType; + // map from RegisterID to the corresponding asm register private final HashMap asmRegisters = new HashMap<>(); @@ -54,7 +61,7 @@ public VisitorAsmPPC(Function llvmFunction, Register returnRegister, List - EventFactory.Power.newSyncBarrier(); - case "isync" -> - EventFactory.Power.newISyncBarrier(); - case "lwsync" -> - EventFactory.Power.newLwSyncBarrier(); - default -> - throw new ParsingException("Barrier not implemented"); + case "sync" -> EventFactory.Power.newSyncBarrier(); + case "isync" -> EventFactory.Power.newISyncBarrier(); + case "lwsync" -> EventFactory.Power.newLwSyncBarrier(); + default -> throw new ParsingException("Barrier not implemented"); }; asmInstructions.add(fence); return null; diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmRISCV.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmRISCV.java index 01b238abe3..cf38830cba 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmRISCV.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorAsmRISCV.java @@ -12,6 +12,7 @@ import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.integers.IntCmpOp; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.parsers.AsmRISCVBaseVisitor; import com.dat3m.dartagnan.parsers.AsmRISCVParser; import com.dat3m.dartagnan.parsers.program.utils.AsmUtils; @@ -22,7 +23,7 @@ import com.dat3m.dartagnan.program.event.Tag; import com.dat3m.dartagnan.program.event.core.Label; import com.dat3m.dartagnan.program.event.core.Local; -import static com.google.common.base.Preconditions.checkState; + public class VisitorAsmRISCV extends AsmRISCVBaseVisitor { private final List inputAssignments = new ArrayList<>(); @@ -87,7 +88,7 @@ public Object visitLoad(AsmRISCVParser.LoadContext ctx) { Register address = (Register) ctx.register(1).accept(this); expectedType = address.getType(); Expression offset = (Expression) ctx.value().accept(this); - Expression newAddress = expressions.makeAdd(address,offset); + Expression newAddress = expressions.makePtrAdd(address, offset); asmInstructions.add(EventFactory.newLoad(register, newAddress)); return null; } @@ -143,7 +144,7 @@ public Object visitStore(AsmRISCVParser.StoreContext ctx) { Register address = (Register) ctx.register(1).accept(this); expectedType = address.getType(); Expression offset = (Expression) ctx.value().accept(this); - Expression newAddress = expressions.makeAdd(address,offset); + Expression newAddress = expressions.makePtrAdd(address, offset); asmInstructions.add(EventFactory.newStore(newAddress, value)); return null; } @@ -204,28 +205,28 @@ public Object visitLabelDefinition(AsmRISCVParser.LabelDefinitionContext ctx) { } @Override - public Object visitNegate(AsmRISCVParser.NegateContext ctx){ + public Object visitNegate(AsmRISCVParser.NegateContext ctx) { // neg $0 $1 -> sub $0, #0, $1 Register destinationRegister = (Register) ctx.register(0).accept(this); Register sourceRegister = (Register) ctx.register(1).accept(this); Expression zero = expressions.makeZero((IntegerType) sourceRegister.getType()); Expression exp = expressions.makeSub(zero, sourceRegister); - asmInstructions.add(EventFactory.newLocal(destinationRegister,exp)); + asmInstructions.add(EventFactory.newLocal(destinationRegister, exp)); return null; } @Override - public Object visitAtomicAdd(AsmRISCVParser.AtomicAddContext ctx){ + public Object visitAtomicAdd(AsmRISCVParser.AtomicAddContext ctx) { throw new UnsupportedOperationException(ctx.AtomicAdd().getText()); } - + @Override - public Object visitAtomicAddRelease(AsmRISCVParser.AtomicAddReleaseContext ctx){ + public Object visitAtomicAddRelease(AsmRISCVParser.AtomicAddReleaseContext ctx) { throw new UnsupportedOperationException(ctx.AtomicAddRelease().getText()); } @Override - public Object visitAtomicAddAcquireRelease(AsmRISCVParser.AtomicAddAcquireReleaseContext ctx){ + public Object visitAtomicAddAcquireRelease(AsmRISCVParser.AtomicAddAcquireReleaseContext ctx) { throw new UnsupportedOperationException(ctx.AtomicAddAcquireRelease().getText()); } @@ -242,7 +243,7 @@ public Object visitRegister(AsmRISCVParser.RegisterContext ctx) { return asmRegisters.get(registerID); } else { // Pick up the correct type and create the new Register - Type registerType = AsmUtils.getLlvmRegisterTypeGivenAsmRegisterID(this.argsRegisters,this.returnRegister,registerID); + Type registerType = AsmUtils.getLlvmRegisterTypeGivenAsmRegisterID(this.argsRegisters, this.returnRegister, registerID); String newRegisterName = AsmUtils.makeRegisterName(registerID); Register newRegister = this.llvmFunction.getOrNewRegister(newRegisterName, registerType); if (AsmUtils.isPartOfReturnRegister(this.returnRegister, registerID) && AsmUtils.isReturnRegisterAggregate(this.returnRegister)) { @@ -304,7 +305,7 @@ public Object visitAsmMetadataEntries(AsmRISCVParser.AsmMetadataEntriesContext c @Override public Object visitRiscvFence(AsmRISCVParser.RiscvFenceContext ctx) { String mo = ctx.fenceOptions().mode; - Event fence = switch(mo) { + Event fence = switch (mo) { case "r r" -> EventFactory.RISCV.newRRFence(); case "r w" -> EventFactory.RISCV.newRWFence(); case "r rw" -> EventFactory.RISCV.newRRWFence(); @@ -324,10 +325,16 @@ public Object visitRiscvFence(AsmRISCVParser.RiscvFenceContext ctx) { @Override public Object visitValue(AsmRISCVParser.ValueContext ctx) { - checkState(expectedType instanceof IntegerType, "Expected type is not an integer type"); - String valueString = ctx.Numbers().getText(); - BigInteger value = new BigInteger(valueString); - return expressions.makeValue(value, (IntegerType) expectedType); + if (expectedType instanceof IntegerType) { + String valueString = ctx.Numbers().getText(); + BigInteger value = new BigInteger(valueString); + return expressions.makeValue(value, (IntegerType) expectedType); + } else if (expectedType instanceof PointerType) { + String valueString = ctx.Numbers().getText(); + BigInteger value = new BigInteger(valueString); + return expressions.makeValue(value, ((PointerType) expectedType).getBitWidth()); + } + throw new RuntimeException("Unexpected type " + expectedType + " visited"); } } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusAArch64.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusAArch64.java index 3f743fee51..58ee74d41e 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusAArch64.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusAArch64.java @@ -6,6 +6,7 @@ import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.integers.IntLiteral; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.parsers.LitmusAArch64BaseVisitor; import com.dat3m.dartagnan.parsers.LitmusAArch64Parser.*; @@ -28,7 +29,8 @@ public class VisitorLitmusAArch64 extends LitmusAArch64BaseVisitor { - private record CmpInstruction(Expression left, Expression right) {} + private record CmpInstruction(Expression left, Expression right) { + } private final ProgramBuilder programBuilder = ProgramBuilder.forArch(Program.SourceLanguage.LITMUS, Arch.ARM8); private final TypeFactory types = programBuilder.getTypeFactory(); @@ -36,6 +38,7 @@ private record CmpInstruction(Expression left, Expression right) {} private final IntegerType i16 = types.getIntegerType(16); private final IntegerType i32 = types.getIntegerType(32); private final IntegerType i64 = types.getIntegerType(64); + private final PointerType pointerType = types.getPointerType(); private final ExpressionFactory expressions = programBuilder.getExpressionFactory(); private int mainThread; private int threadCount = 0; @@ -108,7 +111,7 @@ public Object visitTypedRegisterDeclarator(TypedRegisterDeclaratorContext ctx) { @Override public Object visitVariableDeclaratorRegisterLocation(VariableDeclaratorRegisterLocationContext ctx) { - programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register64().id, ctx.location().getText(), i64); + programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register64().id, ctx.location().getText()); return null; } @@ -123,7 +126,7 @@ public Object visitVariableDeclaratorLocationLocation(VariableDeclaratorLocation @Override public Object visitThreadDeclaratorList(ThreadDeclaratorListContext ctx) { - for(ThreadIdContext threadCtx : ctx.threadId()){ + for (ThreadIdContext threadCtx : ctx.threadId()) { programBuilder.newThread(threadCtx.id); threadCount++; } @@ -135,7 +138,7 @@ public Object visitThreadDeclaratorList(ThreadDeclaratorListContext ctx) { @Override public Object visitInstructionRow(InstructionRowContext ctx) { - for(int i = 0; i < threadCount; i++){ + for (int i = 0; i < threadCount; i++) { mainThread = i; visitInstruction(ctx.instruction(i)); } @@ -180,7 +183,7 @@ public Object visitLoad(LoadContext ctx) { final Register register = shrinkRegister(r64, ctx.rD32, inst.halfWordSize, inst.byteSize); final Expression address = parseAddress(ctx.address()); final String mo = inst.acquire ? MO_ACQ : ""; - add(EventFactory.newLoadWithMo(register, address, mo)); + add(EventFactory.newLoadWithMo(register, expressions.makeCast(address, pointerType), mo)); addRegister64Update(r64, register); return null; } @@ -193,7 +196,7 @@ public Object visitLoadPair(LoadPairContext ctx) { final Register value0 = extended ? r064 : shrinkRegister(r064, ctx.rD032, false, false); final Register value1 = extended ? r164 : shrinkRegister(r164, ctx.rD132, false, false); final Expression address0 = parseAddress(ctx.address()); - final Expression address1 = expressions.makeAdd(address0, expressions.makeValue(extended ? 8 : 4, i64)); + final Expression address1 = expressions.makePtrAdd(address0, expressions.makeValue(extended ? 8 : 4, i64)); add(EventFactory.newLoad(value0, address0)); add(EventFactory.newLoad(value1, address1)); addRegister64Update(r064, value0); @@ -233,7 +236,7 @@ public Object visitStorePair(StorePairContext ctx) { final Expression value0 = expressions.makeIntegerCast(r64, type, false); final Expression value1 = expressions.makeIntegerCast(s64, type, false); final Expression address0 = parseAddress(ctx.address()); - final Expression address1 = expressions.makeAdd(address0, expressions.makeValue(extended ? 8 : 4, i64)); + final Expression address1 = expressions.makePtrAdd(address0, expressions.makeValue(extended ? 8 : 4, i64)); add(EventFactory.newStore(address0, value0)); return add(EventFactory.newStore(address1, value1)); } @@ -297,11 +300,11 @@ public Object visitSwap(SwapContext ctx) { @Override public Object visitBranch(BranchContext ctx) { Label label = programBuilder.getOrCreateLabel(mainThread, ctx.label().getText()); - if(ctx.branchCondition() == null){ + if (ctx.branchCondition() == null) { return add(EventFactory.newGoto(label)); } CmpInstruction cmp = lastCmpInstructionPerThread.put(mainThread, null); - if(cmp == null){ + if (cmp == null) { throw new ParsingException("Invalid syntax near " + ctx.getText()); } Expression expr = expressions.makeIntCmp(cmp.left, ctx.branchCondition().op, cmp.right); @@ -339,7 +342,7 @@ public Object visitReturn(ReturnContext ctx) { @Override public Expression visitExpressionRegister64(ExpressionRegister64Context ctx) { Expression expr = programBuilder.getOrNewRegister(mainThread, ctx.register64().id, i64); - if(ctx.shift() != null){ + if (ctx.shift() != null) { IntLiteral val = parseValue(ctx.shift().immediate().constant(), i64); expr = expressions.makeIntBinary(expr, ctx.shift().shiftOperator().op, val); } @@ -360,7 +363,7 @@ public Expression visitExpressionRegister32(ExpressionRegister32Context ctx) { @Override public Expression visitExpressionImmediate(ExpressionImmediateContext ctx) { Expression expr = parseValue(ctx.immediate().constant(), i64); - if(ctx.shift() != null){ + if (ctx.shift() != null) { IntLiteral val = parseValue(ctx.shift().immediate().constant(), i64); expr = expressions.makeIntBinary(expr, ctx.shift().shiftOperator().op, val); } @@ -387,14 +390,14 @@ private Expression parseExpression(Expr32Context x32, Expr64Context x64) { private Expression parseAddress(AddressContext ctx) { final Register base = programBuilder.getOrErrorRegister(mainThread, ctx.register64().id); if (ctx.offset() == null) { - return base; + return expressions.makeCast(base, pointerType); } final ExpressionConversionContext conversion = ctx.offset().expressionConversion(); final Register32Context register32 = conversion == null ? null : conversion.register32(); final Register64Context register64 = ctx.offset().register64(); final ImmediateContext imm = ctx.offset().immediate(); final Expression offset = imm == null ? parseRegister64(register32, register64) : parseValue(imm.constant(), i64); - return expressions.makeAdd(base, offset); + return expressions.makePtrAdd(base, offset); } private Register parseRegister64(Register32Context w) { @@ -428,6 +431,7 @@ private IntLiteral parseValue(ConstantContext ctx, IntegerType type) { return expressions.parseValue(ctx.getText(), type); } + private Register shrinkRegister(Register other, Register32Context ctx, boolean halfWordSize, boolean byteSize) { checkArgument(other.getType().equals(i64), "Non-64-bit %s", other); checkArgument(!byteSize | !halfWordSize, "Inconclusive access size"); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusC.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusC.java index 1b9df82763..6c97c5c01e 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusC.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusC.java @@ -4,8 +4,14 @@ import com.dat3m.dartagnan.exception.ParsingException; import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionFactory; +import com.dat3m.dartagnan.expression.Type; +import com.dat3m.dartagnan.expression.integers.IntBinaryOp; +import com.dat3m.dartagnan.expression.integers.IntCmpOp; import com.dat3m.dartagnan.expression.integers.IntLiteral; +import com.dat3m.dartagnan.expression.pointers.PtrCmpOp; +import com.dat3m.dartagnan.expression.type.BooleanType; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.parsers.LitmusCBaseVisitor; import com.dat3m.dartagnan.parsers.LitmusCParser; @@ -18,6 +24,8 @@ import com.dat3m.dartagnan.program.event.core.*; import com.dat3m.dartagnan.program.event.lang.catomic.*; import com.dat3m.dartagnan.program.memory.MemoryObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.ArrayList; import java.util.List; @@ -25,10 +33,12 @@ import static com.dat3m.dartagnan.program.event.Tag.C11; public class VisitorLitmusC extends LitmusCBaseVisitor { + Logger logger = LogManager.getLogger(VisitorLitmusC.class); private final ProgramBuilder programBuilder = ProgramBuilder.forLanguage(Program.SourceLanguage.LITMUS); private final ExpressionFactory expressions = programBuilder.getExpressionFactory(); private final IntegerType archType = programBuilder.getTypeFactory().getArchType(); + private final PointerType pointerType = programBuilder.getTypeFactory().getPointerType(); private final int archSize = TypeFactory.getInstance().getMemorySizeInBytes(archType); private int currentThread; private int scope; @@ -38,7 +48,7 @@ public class VisitorLitmusC extends LitmusCBaseVisitor { private boolean isOpenCL = false; private final List threadIds = new ArrayList<>(); - public VisitorLitmusC(){ + public VisitorLitmusC() { } // ---------------------------------------------------------------------------------------------------------------- @@ -77,19 +87,19 @@ public Object visitGlobalDeclaratorLocation(LitmusCParser.GlobalDeclaratorLocati public Object visitGlobalDeclaratorRegister(LitmusCParser.GlobalDeclaratorRegisterContext ctx) { if (ctx.initConstantValue() != null) { IntLiteral value = expressions.parseValue(ctx.initConstantValue().constant().getText(), archType); - programBuilder.initRegEqConst(ctx.threadId().id,ctx.varName().getText(), value); + programBuilder.initRegEqConst(ctx.threadId().id, ctx.varName().getText(), value); } return null; } @Override public Object visitGlobalDeclaratorLocationLocation(LitmusCParser.GlobalDeclaratorLocationLocationContext ctx) { - if(ctx.Ast() == null) { + if (ctx.Ast() == null) { programBuilder.initLocEqLocPtr(ctx.varName(0).getText(), ctx.varName(1).getText()); } else { String rightName = ctx.varName(1).getText(); MemoryObject object = programBuilder.getMemoryObject(rightName); - if(object != null){ + if (object != null) { programBuilder.initLocEqConst(ctx.varName(0).getText(), object); } else { programBuilder.initLocEqLocVal(ctx.varName(0).getText(), ctx.varName(1).getText()); @@ -101,15 +111,15 @@ public Object visitGlobalDeclaratorLocationLocation(LitmusCParser.GlobalDeclarat @Override public Object visitGlobalDeclaratorRegisterLocation(LitmusCParser.GlobalDeclaratorRegisterLocationContext ctx) { // FIXME: We visit declarators before threads, so we need to create threads early - if(ctx.Ast() == null){ - programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.varName(0).getText(), ctx.varName(1).getText(), archType); + if (ctx.Ast() == null) { + programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.varName(0).getText(), ctx.varName(1).getText()); } else { String rightName = ctx.varName(1).getText(); MemoryObject object = programBuilder.getMemoryObject(rightName); - if(object != null){ + if (object != null) { programBuilder.initRegEqConst(ctx.threadId().id, ctx.varName(0).getText(), object); } else { - programBuilder.initRegEqLocVal(ctx.threadId().id, ctx.varName(0).getText(), ctx.varName(1).getText(), archType); + programBuilder.initRegEqLocVal(ctx.threadId().id, ctx.varName(0).getText(), ctx.varName(1).getText(), pointerType); } } return null; @@ -120,21 +130,21 @@ public Object visitGlobalDeclaratorArray(LitmusCParser.GlobalDeclaratorArrayCont String name = ctx.varName().getText(); Integer size = ctx.DigitSequence() != null ? Integer.parseInt(ctx.DigitSequence().getText()) : null; - if(ctx.initArray() == null && size != null && size > 0){ - programBuilder.newMemoryObject(name,size); + if (ctx.initArray() == null && size != null && size > 0) { + programBuilder.newMemoryObject(name, size); return null; } - if(ctx.initArray() != null){ - if(size == null || ctx.initArray().arrayElement().size() == size){ + if (ctx.initArray() != null) { + if (size == null || ctx.initArray().arrayElement().size() == size) { List values = new ArrayList<>(); - for(LitmusCParser.ArrayElementContext elCtx : ctx.initArray().arrayElement()){ - if(elCtx.constant() != null){ + for (LitmusCParser.ArrayElementContext elCtx : ctx.initArray().arrayElement()) { + if (elCtx.constant() != null) { values.add(expressions.parseValue(elCtx.constant().getText(), archType)); } else { String varName = elCtx.varName().getText(); //see test/resources/arrays/ok/C-array-ok-17.litmus MemoryObject object = programBuilder.getMemoryObject(varName); - if(object != null){ + if (object != null) { values.add(object); } else { object = programBuilder.getOrNewMemoryObject(varName); @@ -142,9 +152,9 @@ public Object visitGlobalDeclaratorArray(LitmusCParser.GlobalDeclaratorArrayCont } } } - MemoryObject object = programBuilder.newMemoryObject(name,values.size() * archSize); - for(int i = 0; i < values.size(); i++) { - object.setInitialValue(i,values.get(i)); + MemoryObject object = programBuilder.newMemoryObject(name, values.size() * archSize); + for (int i = 0; i < values.size(); i++) { + object.setInitialValue(i, values.get(i)); } return null; } @@ -175,15 +185,15 @@ public Object visitThreadDeclarator(LitmusCParser.ThreadDeclaratorContext ctx) { @Override public Object visitThreadContent(LitmusCParser.ThreadContentContext ctx) { visitThreadArguments(ctx.threadArguments()); - for(LitmusCParser.ExpressionContext expressionContext : ctx.expression()) + for (LitmusCParser.ExpressionContext expressionContext : ctx.expression()) expressionContext.accept(this); return null; } @Override - public Object visitThreadArguments(LitmusCParser.ThreadArgumentsContext ctx){ - if(ctx != null){ - for(LitmusCParser.ThreadArgumentContext threadArgumentContext : ctx.threadArgument()){ + public Object visitThreadArguments(LitmusCParser.ThreadArgumentsContext ctx) { + if (ctx != null) { + for (LitmusCParser.ThreadArgumentContext threadArgumentContext : ctx.threadArgument()) { threadArgumentContext.accept(this); } } @@ -195,8 +205,9 @@ public Object visitThreadArgument(LitmusCParser.ThreadArgumentContext ctx) { // TODO: Possibly parse attributes/type modifiers (const, ...) // For now, herd7 also seems to ignore most modifiers, in particular the atomic one. String name = ctx.varName().getText(); + Type type = ctx.pointerTypeSpecifier().Ast() == null ? archType : pointerType; // as far as i understand the archtype is meaningless here. MemoryObject object = programBuilder.getOrNewMemoryObject(name); - Register register = programBuilder.getOrNewRegister(scope, name, archType); + Register register = programBuilder.getOrNewRegister(scope, name, type); boolean atomicity = ctx.pointerTypeSpecifier().atomicTypeSpecifier() != null || ctx.pointerTypeSpecifier().basicTypeSpecifier().AtomicInt() != null; if (!atomicity) { @@ -218,37 +229,37 @@ public Object visitIfExpression(LitmusCParser.IfExpressionContext ctx) { Expression expr = (Expression) ctx.re().accept(this); ifId++; - Label elseL = programBuilder.getOrCreateLabel(currentThread,"else_" + ifId); - Label endL = programBuilder.getOrCreateLabel(currentThread,"end_" + ifId); + Label elseL = programBuilder.getOrCreateLabel(currentThread, "else_" + ifId); + Label endL = programBuilder.getOrCreateLabel(currentThread, "end_" + ifId); IfAsJump ifEvent = EventFactory.newIfJumpUnless(expressions.makeBooleanCast(expr), elseL, endL); programBuilder.addChild(currentThread, ifEvent); - for(LitmusCParser.ExpressionContext expressionContext : ctx.expression()) + for (LitmusCParser.ExpressionContext expressionContext : ctx.expression()) expressionContext.accept(this); CondJump jumpToEnd = EventFactory.newGoto(endL); programBuilder.addChild(currentThread, jumpToEnd); programBuilder.addChild(currentThread, elseL); - if(ctx.elseExpression() != null){ + if (ctx.elseExpression() != null) { ctx.elseExpression().accept(this); } programBuilder.addChild(currentThread, endL); return null; } - @Override + @Override public Object visitWhileExpression(LitmusCParser.WhileExpressionContext ctx) { whileId++; - Label headL = programBuilder.getOrCreateLabel(currentThread,"head_" + whileId); - Label endL = programBuilder.getOrCreateLabel(currentThread,"end_" + whileId); + Label headL = programBuilder.getOrCreateLabel(currentThread, "head_" + whileId); + Label endL = programBuilder.getOrCreateLabel(currentThread, "end_" + whileId); programBuilder.addChild(currentThread, headL); Expression expr = (Expression) ctx.re().accept(this); programBuilder.addChild(currentThread, EventFactory.newJumpUnless(expr, endL)); - for(LitmusCParser.ExpressionContext expressionContext : ctx.expression()) { + for (LitmusCParser.ExpressionContext expressionContext : ctx.expression()) { expressionContext.accept(this); } @@ -263,8 +274,8 @@ public Object visitWhileExpression(LitmusCParser.WhileExpressionContext ctx) { // Returns new value (the value after computation) @Override - public Expression visitReAtomicOpReturn(LitmusCParser.ReAtomicOpReturnContext ctx){ - Register register = getReturnRegister(true); + public Expression visitReAtomicOpReturn(LitmusCParser.ReAtomicOpReturnContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Expression value = returnExpressionOrOne(ctx.value); Event event = EventFactory.Linux.newRMWOpReturn(getAddress(ctx.address), register, value, ctx.op, ctx.mo); programBuilder.addChild(currentThread, event); @@ -273,8 +284,8 @@ public Expression visitReAtomicOpReturn(LitmusCParser.ReAtomicOpReturnContext ct // Returns old value (the value before computation) @Override - public Expression visitReAtomicFetchOp(LitmusCParser.ReAtomicFetchOpContext ctx){ - Register register = getReturnRegister(true); + public Expression visitReAtomicFetchOp(LitmusCParser.ReAtomicFetchOpContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Expression value = returnExpressionOrOne(ctx.value); Event event = EventFactory.Linux.newRMWFetchOp(getAddress(ctx.address), register, value, ctx.op, ctx.mo); programBuilder.addChild(currentThread, event); @@ -283,7 +294,7 @@ public Expression visitReAtomicFetchOp(LitmusCParser.ReAtomicFetchOpContext ctx) @Override public Expression visitC11AtomicOp(LitmusCParser.C11AtomicOpContext ctx) { - Register register = getReturnRegister(true); + Register register = getReReturnRegisterOrDefaultTo(archType); Expression value = returnExpressionOrOne(ctx.value); Expression address = getAddress(ctx.address); Event event = EventFactory.Atomic.newFetchOp(register, address, value, ctx.op, ctx.c11Mo().mo); @@ -294,8 +305,8 @@ public Expression visitC11AtomicOp(LitmusCParser.C11AtomicOpContext ctx) { @Override - public Expression visitReAtomicOpAndTest(LitmusCParser.ReAtomicOpAndTestContext ctx){ - Register register = getReturnRegister(true); + public Expression visitReAtomicOpAndTest(LitmusCParser.ReAtomicOpAndTestContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Expression value = returnExpressionOrOne(ctx.value); Event event = EventFactory.Linux.newRMWOpAndTest(getAddress(ctx.address), register, value, ctx.op); programBuilder.addChild(currentThread, event); @@ -304,8 +315,8 @@ public Expression visitReAtomicOpAndTest(LitmusCParser.ReAtomicOpAndTestContext // Returns non-zero if the addition was executed, zero otherwise @Override - public Expression visitReAtomicAddUnless(LitmusCParser.ReAtomicAddUnlessContext ctx){ - Register register = getReturnRegister(true); + public Expression visitReAtomicAddUnless(LitmusCParser.ReAtomicAddUnlessContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Expression value = (Expression) ctx.value.accept(this); Expression cmp = (Expression) ctx.cmp.accept(this); programBuilder.addChild(currentThread, EventFactory.Linux.newRMWAddUnless(getAddress(ctx.address), register, cmp, value)); @@ -314,7 +325,7 @@ public Expression visitReAtomicAddUnless(LitmusCParser.ReAtomicAddUnlessContext @Override public Expression visitReC11AtomicXchg(LitmusCParser.ReC11AtomicXchgContext ctx) { - Register register = getReturnRegister(true); + Register register = getReReturnRegisterOrDefaultTo(archType); Expression value = (Expression) ctx.value.accept(this); Expression address = getAddress(ctx.address); Event event = EventFactory.Atomic.newExchange(register, address, value, Tag.C11.MO_SC); @@ -325,7 +336,7 @@ public Expression visitReC11AtomicXchg(LitmusCParser.ReC11AtomicXchgContext ctx) @Override public Expression visitReC11AtomicXchgExplicit(LitmusCParser.ReC11AtomicXchgExplicitContext ctx) { - Register register = getReturnRegister(true); + Register register = getReReturnRegisterOrDefaultTo(archType); Expression value = (Expression) ctx.value.accept(this); Expression address = getAddress(ctx.address); Event event = EventFactory.Atomic.newExchange(register, address, value, ctx.c11Mo().mo); @@ -335,8 +346,8 @@ public Expression visitReC11AtomicXchgExplicit(LitmusCParser.ReC11AtomicXchgExpl } @Override - public Expression visitReXchg(LitmusCParser.ReXchgContext ctx){ - Register register = getReturnRegister(true); + public Expression visitReXchg(LitmusCParser.ReXchgContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Expression value = (Expression) ctx.value.accept(this); Event event = EventFactory.Linux.newRMWExchange(getAddress(ctx.address), register, value, ctx.mo); programBuilder.addChild(currentThread, event); @@ -345,8 +356,8 @@ public Expression visitReXchg(LitmusCParser.ReXchgContext ctx){ @Override public Expression visitReC11SCmpXchgExplicit(LitmusCParser.ReC11SCmpXchgExplicitContext ctx) { - Register register = getReturnRegister(true); - Expression value = (Expression)ctx.value.accept(this); + Register register = getReReturnRegisterOrDefaultTo(archType); + Expression value = (Expression) ctx.value.accept(this); Expression address = getAddress(ctx.address); Expression expectedAdd = getAddress(ctx.expectedAdd); String mo = ctx.c11Mo(0).mo; @@ -358,8 +369,8 @@ public Expression visitReC11SCmpXchgExplicit(LitmusCParser.ReC11SCmpXchgExplicit @Override public Expression visitReC11SCmpXchg(LitmusCParser.ReC11SCmpXchgContext ctx) { - Register register = getReturnRegister(true); - Expression value = (Expression)ctx.value.accept(this); + Register register = getReReturnRegisterOrDefaultTo(archType); + Expression value = (Expression) ctx.value.accept(this); Expression address = getAddress(ctx.address); Expression expectedAdd = getAddress(ctx.expectedAdd); Event event = EventFactory.Atomic.newCompareExchange(register, address, expectedAdd, value, @@ -371,8 +382,8 @@ public Expression visitReC11SCmpXchg(LitmusCParser.ReC11SCmpXchgContext ctx) { @Override public Expression visitReC11WCmpXchgExplicit(LitmusCParser.ReC11WCmpXchgExplicitContext ctx) { - Register register = getReturnRegister(true); - Expression value = (Expression)ctx.value.accept(this); + Register register = getReReturnRegisterOrDefaultTo(archType); + Expression value = (Expression) ctx.value.accept(this); Expression address = getAddress(ctx.address); Expression expectedAdd = getAddress(ctx.expectedAdd); String mo = ctx.c11Mo(0).mo; @@ -384,8 +395,8 @@ public Expression visitReC11WCmpXchgExplicit(LitmusCParser.ReC11WCmpXchgExplicit @Override public Expression visitReC11WCmpXchg(LitmusCParser.ReC11WCmpXchgContext ctx) { - Register register = getReturnRegister(true); - Expression value = (Expression)ctx.value.accept(this); + Register register = getReReturnRegisterOrDefaultTo(archType); + Expression value = (Expression) ctx.value.accept(this); Expression address = getAddress(ctx.address); Expression expectedAdd = getAddress(ctx.expectedAdd); Event event = EventFactory.Atomic.newCompareExchange(register, address, expectedAdd, value, @@ -396,17 +407,18 @@ public Expression visitReC11WCmpXchg(LitmusCParser.ReC11WCmpXchgContext ctx) { } @Override - public Expression visitReCmpXchg(LitmusCParser.ReCmpXchgContext ctx){ - Register register = getReturnRegister(true); - Expression cmp = (Expression)ctx.cmp.accept(this); - Expression value = (Expression)ctx.value.accept(this); + public Expression visitReCmpXchg(LitmusCParser.ReCmpXchgContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); + Expression cmp = (Expression) ctx.cmp.accept(this); + Expression value = (Expression) ctx.value.accept(this); Event event = EventFactory.Linux.newRMWCompareExchange(getAddress(ctx.address), register, cmp, value, ctx.mo); programBuilder.addChild(currentThread, event); return register; } - @Override public Expression visitReC11LoadExplicit(LitmusCParser.ReC11LoadExplicitContext ctx) { - Register register = getReturnRegister(true); + @Override + public Expression visitReC11LoadExplicit(LitmusCParser.ReC11LoadExplicitContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Expression address = getAddress(ctx.address); AtomicLoad event = EventFactory.Atomic.newLoad(register, address, ctx.c11Mo().mo); addScopeTag(event, ctx.openCLScope()); @@ -414,8 +426,9 @@ public Expression visitReCmpXchg(LitmusCParser.ReCmpXchgContext ctx){ return register; } - @Override public Expression visitReC11Load(LitmusCParser.ReC11LoadContext ctx) { - Register register = getReturnRegister(true); + @Override + public Expression visitReC11Load(LitmusCParser.ReC11LoadContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Expression address = getAddress(ctx.address); AtomicLoad event = EventFactory.Atomic.newLoad(register, address, C11.DEFAULT_MO); addScopeTag(event, null); @@ -424,24 +437,24 @@ public Expression visitReCmpXchg(LitmusCParser.ReCmpXchgContext ctx){ } @Override - public Expression visitReLoad(LitmusCParser.ReLoadContext ctx){ - Register register = getReturnRegister(true); + public Expression visitReLoad(LitmusCParser.ReLoadContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Event event = EventFactory.Linux.newLKMMLoad(register, getAddress(ctx.address), ctx.mo); programBuilder.addChild(currentThread, event); return register; } @Override - public Expression visitReReadOnce(LitmusCParser.ReReadOnceContext ctx){ - Register register = getReturnRegister(true); + public Expression visitReReadOnce(LitmusCParser.ReReadOnceContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Event event = EventFactory.Linux.newLKMMLoad(register, getAddress(ctx.address), ctx.mo); programBuilder.addChild(currentThread, event); return register; } @Override - public Expression visitReReadNa(LitmusCParser.ReReadNaContext ctx){ - Register register = getReturnRegister(true); + public Expression visitReReadNa(LitmusCParser.ReReadNaContext ctx) { + Register register = getReReturnRegisterOrDefaultTo(archType); Expression address = getAddress(ctx.address); Load event = EventFactory.newLoadWithMo(register, address, C11.NONATOMIC); programBuilder.addChild(currentThread, event); @@ -452,28 +465,44 @@ public Expression visitReReadNa(LitmusCParser.ReReadNaContext ctx){ // Return expressions (register for return value is optional) @Override - public Expression visitReOpCompare(LitmusCParser.ReOpCompareContext ctx){ - Register register = getReturnRegister(false); - Expression v1 = (Expression)ctx.re(0).accept(this); - Expression v2 = (Expression)ctx.re(1).accept(this); - Expression result = expressions.makeIntCmp(v1, ctx.opCompare().op, v2); + public Expression visitReOpCompare(LitmusCParser.ReOpCompareContext ctx) { + Register register = getOptionalReturnRegister(); + Expression v1 = (Expression) ctx.re(0).accept(this); + Expression v2 = (Expression) ctx.re(1).accept(this); + Expression result; + if (v1.getType() instanceof PointerType && v2.getType() instanceof PointerType && (ctx.opCompare().op == IntCmpOp.EQ || ctx.opCompare().op == IntCmpOp.NEQ) ) { + var op = ctx.opCompare().op == IntCmpOp.EQ ? PtrCmpOp.EQ:PtrCmpOp.NEQ; + result = expressions.makeCompare(v1,op,v2); + }else if(!(v1.getType().equals(v2.getType()))){ + result = expressions.makeCompare(expressions.makeCast(v1, archType), ctx.opCompare().op, expressions.makeCast(v2, archType)); + }else{ + result = expressions.makeCompare(v1, ctx.opCompare().op, v2); + } return assignToReturnRegister(register, result); } @Override - public Expression visitReOpArith(LitmusCParser.ReOpArithContext ctx){ - Register register = getReturnRegister(false); - Expression v1 = (Expression)ctx.re(0).accept(this); - Expression v2 = (Expression)ctx.re(1).accept(this); - Expression result = expressions.makeIntBinary(v1, ctx.opArith().op, v2); + public Expression visitReOpArith(LitmusCParser.ReOpArithContext ctx) { + Register register = getOptionalReturnRegister(); + Expression v1 = (Expression) ctx.re(0).accept(this); + Expression v2 = (Expression) ctx.re(1).accept(this); + Expression result; + assert v2.getType() instanceof IntegerType || v1.getType() instanceof IntegerType; + if (ctx.opArith().op == IntBinaryOp.ADD && v1.getType() instanceof PointerType && v2.getType() instanceof IntegerType) { + result = expressions.makePtrAdd(v1, v2); + } else if (ctx.opArith().op == IntBinaryOp.ADD && v2.getType() instanceof PointerType && v1.getType() instanceof IntegerType) { + result = expressions.makePtrAdd(v2, v1); + } else { + result = expressions.makeIntBinary(v1, ctx.opArith().op, v2); + } return assignToReturnRegister(register, result); } @Override - public Expression visitReOpBool(LitmusCParser.ReOpBoolContext ctx){ - Register register = getReturnRegister(false); - Expression v1 = (Expression)ctx.re(0).accept(this); - Expression v2 = (Expression)ctx.re(1).accept(this); + public Expression visitReOpBool(LitmusCParser.ReOpBoolContext ctx) { + Register register = getOptionalReturnRegister(); + Expression v1 = (Expression) ctx.re(0).accept(this); + Expression v2 = (Expression) ctx.re(1).accept(this); v1 = expressions.makeBooleanCast(v1); v2 = expressions.makeBooleanCast(v2); Expression result = expressions.makeBoolBinary(v1, ctx.opBool().op, v2); @@ -481,34 +510,34 @@ public Expression visitReOpBool(LitmusCParser.ReOpBoolContext ctx){ } @Override - public Expression visitReOpBoolNot(LitmusCParser.ReOpBoolNotContext ctx){ - Register register = getReturnRegister(false); - Expression v = (Expression)ctx.re().accept(this); + public Expression visitReOpBoolNot(LitmusCParser.ReOpBoolNotContext ctx) { + Register register = getOptionalReturnRegister(); + Expression v = (Expression) ctx.re().accept(this); v = expressions.makeBooleanCast(v); Expression result = expressions.makeNot(v); return assignToReturnRegister(register, result); } @Override - public Expression visitReBoolConst(LitmusCParser.ReBoolConstContext ctx){ + public Expression visitReBoolConst(LitmusCParser.ReBoolConstContext ctx) { return expressions.makeValue(ctx.boolConst().value); } @Override - public Expression visitReParenthesis(LitmusCParser.ReParenthesisContext ctx){ - return (Expression)ctx.re().accept(this); + public Expression visitReParenthesis(LitmusCParser.ReParenthesisContext ctx) { + return (Expression) ctx.re().accept(this); } @Override - public Expression visitReCast(LitmusCParser.ReCastContext ctx){ - Register register = getReturnRegister(false); - Expression result = (Expression)ctx.re().accept(this); + public Expression visitReCast(LitmusCParser.ReCastContext ctx) { + Register register = getOptionalReturnRegister(); + Expression result = (Expression) ctx.re().accept(this); return assignToReturnRegister(register, result); } @Override - public Expression visitReVarName(LitmusCParser.ReVarNameContext ctx){ - Register register = getReturnRegister(false); + public Expression visitReVarName(LitmusCParser.ReVarNameContext ctx) { + Register register = getOptionalReturnRegister(); Expression variable = visitVarName(ctx.varName()); if (variable instanceof Register result) { return assignToReturnRegister(register, result); @@ -517,8 +546,8 @@ public Expression visitReVarName(LitmusCParser.ReVarNameContext ctx){ } @Override - public Expression visitReConst(LitmusCParser.ReConstContext ctx){ - Register register = getReturnRegister(false); + public Expression visitReConst(LitmusCParser.ReConstContext ctx) { + Register register = getOptionalReturnRegister(); IntLiteral result = expressions.parseValue(ctx.getText(), archType); return assignToReturnRegister(register, result); } @@ -528,16 +557,16 @@ public Expression visitReConst(LitmusCParser.ReConstContext ctx){ // NonReturn expressions (all other return expressions are reduced to these ones) @Override - public Object visitNreAtomicOp(LitmusCParser.NreAtomicOpContext ctx){ + public Object visitNreAtomicOp(LitmusCParser.NreAtomicOpContext ctx) { Expression value = returnExpressionOrOne(ctx.value); Event event = EventFactory.Linux.newRMWOp(getAddress(ctx.address), value, ctx.op); return programBuilder.addChild(currentThread, event); } @Override - public Object visitNreStore(LitmusCParser.NreStoreContext ctx){ - Expression value = (Expression)ctx.value.accept(this); - if(ctx.mo.equals(Tag.Linux.MO_MB)){ + public Object visitNreStore(LitmusCParser.NreStoreContext ctx) { + Expression value = (Expression) ctx.value.accept(this); + if (ctx.mo.equals(Tag.Linux.MO_MB)) { Event event = EventFactory.Linux.newLKMMStore(getAddress(ctx.address), value, Tag.Linux.MO_ONCE); programBuilder.addChild(currentThread, event); return programBuilder.addChild(currentThread, EventFactory.Linux.newMemoryBarrier()); @@ -547,15 +576,15 @@ public Object visitNreStore(LitmusCParser.NreStoreContext ctx){ } @Override - public Object visitNreWriteOnce(LitmusCParser.NreWriteOnceContext ctx){ - Expression value = (Expression)ctx.value.accept(this); + public Object visitNreWriteOnce(LitmusCParser.NreWriteOnceContext ctx) { + Expression value = (Expression) ctx.value.accept(this); Event event = EventFactory.Linux.newLKMMStore(getAddress(ctx.address), value, ctx.mo); return programBuilder.addChild(currentThread, event); } @Override public Object visitNreC11StoreExplicit(LitmusCParser.NreC11StoreExplicitContext ctx) { - Expression value = (Expression)ctx.value.accept(this); + Expression value = (Expression) ctx.value.accept(this); Expression address = getAddress(ctx.address); AtomicStore event = EventFactory.Atomic.newStore(address, value, ctx.c11Mo().mo); addScopeTag(event, ctx.openCLScope()); @@ -564,7 +593,7 @@ public Object visitNreC11StoreExplicit(LitmusCParser.NreC11StoreExplicitContext @Override public Object visitNreC11Store(LitmusCParser.NreC11StoreContext ctx) { - Expression value = (Expression)ctx.value.accept(this); + Expression value = (Expression) ctx.value.accept(this); Expression address = getAddress(ctx.address); AtomicStore event = EventFactory.Atomic.newStore(address, value, C11.DEFAULT_MO); addScopeTag(event, null); @@ -572,20 +601,19 @@ public Object visitNreC11Store(LitmusCParser.NreC11StoreContext ctx) { } @Override - public Object visitNreAssignment(LitmusCParser.NreAssignmentContext ctx){ - Expression variable = (Expression)ctx.varName().accept(this); - if(ctx.Ast() == null){ - if(variable instanceof Register reg){ + public Object visitNreAssignment(LitmusCParser.NreAssignmentContext ctx) { + Expression variable = (Expression) ctx.varName().accept(this); + if (ctx.Ast() == null) { + if (variable instanceof Register reg) { returnRegister = reg; ctx.re().accept(this); return null; } throw new ParsingException("Invalid syntax near " + ctx.getText()); } - - Expression value = (Expression)ctx.re().accept(this); - if(variable instanceof MemoryObject || variable instanceof Register){ - Event event = EventFactory.newStoreWithMo(variable, value, C11.NONATOMIC); + Expression value = (Expression) ctx.re().accept(this); + if (variable instanceof MemoryObject || variable instanceof Register) { + Event event = EventFactory.newStoreWithMo(expressions.makeCast(variable, pointerType), value, C11.NONATOMIC); if (isOpenCL) { event.addTags(Tag.OpenCL.DEFAULT_WEAK_SCOPE); } @@ -595,11 +623,10 @@ public Object visitNreAssignment(LitmusCParser.NreAssignmentContext ctx){ } @Override - public Object visitNreRegDeclaration(LitmusCParser.NreRegDeclarationContext ctx){ - Register register = programBuilder.getRegister(scope, ctx.varName().getText()); - if(register == null){ - register = programBuilder.getOrNewRegister(scope, ctx.varName().getText(), archType); - if(ctx.re() != null){ + public Object visitNreRegDeclaration(LitmusCParser.NreRegDeclarationContext ctx) { + if (programBuilder.getRegister(scope, ctx.varName().getText()) == null) { + Register register = programBuilder.getOrNewRegister(scope, ctx.varName().getText(), parseNreDeclarationType(ctx)); + if (ctx.re() != null) { returnRegister = register; ctx.re().accept(this); } @@ -608,6 +635,15 @@ public Object visitNreRegDeclaration(LitmusCParser.NreRegDeclarationContext ctx) throw new ParsingException("Register " + ctx.varName().getText() + " is already initialised"); } + // helper + private Type parseNreDeclarationType(LitmusCParser.NreRegDeclarationContext ctx) { + if (ctx.typeSpecifier().Ast().isEmpty()) { + return archType; + } else { + return pointerType; + } + } + @Override public Object visitNreC11Fence(LitmusCParser.NreC11FenceContext ctx) { AtomicThreadFence fence = EventFactory.Atomic.newFence(ctx.c11Mo().mo); @@ -615,12 +651,12 @@ public Object visitNreC11Fence(LitmusCParser.NreC11FenceContext ctx) { } @Override - public Object visitNreFence(LitmusCParser.NreFenceContext ctx){ + public Object visitNreFence(LitmusCParser.NreFenceContext ctx) { return programBuilder.addChild(currentThread, EventFactory.Linux.newLKMMFence(ctx.name)); } @Override - public Object visitNreOpenCLFence(LitmusCParser.NreOpenCLFenceContext ctx){ + public Object visitNreOpenCLFence(LitmusCParser.NreOpenCLFenceContext ctx) { AtomicThreadFence fence = EventFactory.Atomic.newFence(ctx.c11Mo().mo); if (ctx.openCLScope() != null) { fence.addTags(ctx.openCLScope().scope); @@ -634,7 +670,7 @@ public Object visitNreOpenCLFence(LitmusCParser.NreOpenCLFenceContext ctx){ } @Override - public Object visitNreOpenCLBarrier(LitmusCParser.NreOpenCLBarrierContext ctx){ + public Object visitNreOpenCLBarrier(LitmusCParser.NreOpenCLBarrierContext ctx) { List flags = ctx.openCLFenceFlags().openCLFenceFlag().stream().map(f -> f.flag).toList(); String barrierScope = ctx.openCLScope() != null ? ctx.openCLScope().scope : Tag.OpenCL.WORK_GROUP; String name = String.format("barrier(%s.%s)", ctx.openCLFenceFlags().getText(), barrierScope).toLowerCase(); @@ -665,15 +701,17 @@ public Object visitNreSrcuSync(LitmusCParser.NreSrcuSyncContext ctx) { // ---------------------------------------------------------------------------------------------------------------- // Utils + + // problem here @Override - public Expression visitVarName(LitmusCParser.VarNameContext ctx){ - if(scope > -1){ + public Expression visitVarName(LitmusCParser.VarNameContext ctx) { + if (scope > -1) { Register register = programBuilder.getRegister(scope, ctx.getText()); - if(register != null){ + if (register != null) { return register; } MemoryObject object = programBuilder.getMemoryObject(ctx.getText()); - if(object != null){ + if (object != null) { register = programBuilder.getOrNewRegister(scope, null, archType); programBuilder.addChild(currentThread, EventFactory.newLoadWithMo(register, object, C11.NONATOMIC)); return register; @@ -681,27 +719,40 @@ public Expression visitVarName(LitmusCParser.VarNameContext ctx){ return programBuilder.getOrNewRegister(scope, ctx.getText(), archType); } MemoryObject object = programBuilder.newMemoryObject(ctx.getText(), archSize); - Register register = programBuilder.getOrNewRegister(scope, null, archType); + Register register = programBuilder.getOrNewRegister(scope, null, pointerType); programBuilder.addChild(currentThread, EventFactory.newLoadWithMo(register, object, C11.NONATOMIC)); return register; } - private Expression getAddress(LitmusCParser.ReContext ctx){ - Expression address = (Expression)ctx.accept(this); - if(address.getType() instanceof IntegerType){ - return address; + private Expression getAddress(LitmusCParser.ReContext ctx) { + Expression address = (Expression) ctx.accept(this); + if (address.getType() instanceof IntegerType) { + // todo reg default type is sometimes wrong ==> cast for now + logger.warn("Integer used as address."); + return expressions.makeIntToPtrCast(address); + } + if (address.getType() instanceof PointerType) { + return address; } throw new ParsingException("Invalid syntax near " + ctx.getText()); } + private Expression returnExpressionOrOne(LitmusCParser.ReContext ctx) { return ctx != null ? (Expression) ctx.accept(this) : expressions.makeOne(archType); } - private Register getReturnRegister(boolean createOnNull){ + private Register getOptionalReturnRegister() { + Register register = returnRegister; + returnRegister = null; + return register; + } + + private Register getReReturnRegisterOrDefaultTo(Type defaultType) { Register register = returnRegister; - if(register == null && createOnNull){ - return programBuilder.getOrNewRegister(scope, null, archType); + if (register == null) { + logger.warn("Default register type used in a returning expression."); + return programBuilder.getOrNewRegister(scope, null, defaultType); } returnRegister = null; return register; @@ -709,7 +760,7 @@ private Register getReturnRegister(boolean createOnNull){ private Expression assignToReturnRegister(Register register, Expression value) { if (register != null) { - Expression cast = expressions.makeCast(value, register.getType()); + Expression cast = expressions.makeCast(value, register.getType()); // !! programBuilder.addChild(currentThread, EventFactory.newLocal(register, cast)); } return value; diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusPPC.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusPPC.java index 2fe6be4258..abb751ee40 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusPPC.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusPPC.java @@ -16,15 +16,20 @@ import com.dat3m.dartagnan.program.Program; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.event.EventFactory; + import static com.dat3m.dartagnan.program.event.FenceNameRepository.ISYNC; import static com.dat3m.dartagnan.program.event.FenceNameRepository.LWSYNC; import static com.dat3m.dartagnan.program.event.FenceNameRepository.SYNC; + import com.dat3m.dartagnan.program.event.core.Label; import com.google.common.collect.ImmutableSet; public class VisitorLitmusPPC extends LitmusPPCBaseVisitor { - private record CmpInstruction(Expression left, Expression right) {}; + private record CmpInstruction(Expression left, Expression right) { + } + + ; private final static ImmutableSet fences = ImmutableSet.of(SYNC, LWSYNC, ISYNC); private final ProgramBuilder programBuilder = ProgramBuilder.forArch(Program.SourceLanguage.LITMUS, Arch.POWER); @@ -70,7 +75,7 @@ public Object visitVariableDeclaratorRegister(LitmusPPCParser.VariableDeclarator @Override public Object visitVariableDeclaratorRegisterLocation(LitmusPPCParser.VariableDeclaratorRegisterLocationContext ctx) { - programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText(), archType); + programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText()); return null; } @@ -86,7 +91,7 @@ public Object visitVariableDeclaratorLocationLocation(LitmusPPCParser.VariableDe @Override public Object visitThreadDeclaratorList(LitmusPPCParser.ThreadDeclaratorListContext ctx) { - for(LitmusPPCParser.ThreadIdContext threadCtx : ctx.threadId()){ + for (LitmusPPCParser.ThreadIdContext threadCtx : ctx.threadId()) { programBuilder.newThread(threadCtx.id); threadCount++; } @@ -99,7 +104,7 @@ public Object visitThreadDeclaratorList(LitmusPPCParser.ThreadDeclaratorListCont @Override public Object visitInstructionRow(LitmusPPCParser.InstructionRowContext ctx) { - for(int i = 0; i < threadCount; i++){ + for (int i = 0; i < threadCount; i++) { mainThread = i; visitInstruction(ctx.instruction(i)); } @@ -131,7 +136,7 @@ public Object visitLwarx(LitmusPPCParser.LwarxContext ctx) { Register r1 = (Register) ctx.register(0).accept(this); Register ra = (Register) ctx.register(1).accept(this); Register rb = (Register) ctx.register(2).accept(this); - return programBuilder.addChild(mainThread, EventFactory.newRMWLoadExclusive(r1, expressions.makeAdd(ra, rb))); + return programBuilder.addChild(mainThread, EventFactory.newRMWLoadExclusive(r1, expressions.makePtrAdd(rb, ra))); } @Override @@ -156,7 +161,7 @@ public Object visitStwcx(LitmusPPCParser.StwcxContext ctx) { Register r1 = (Register) ctx.register(0).accept(this); Register ra = (Register) ctx.register(1).accept(this); Register rb = (Register) ctx.register(2).accept(this); - return programBuilder.addChild(mainThread, EventFactory.Common.newExclusiveStore(rs, expressions.makeAdd(ra, rb), r1, "")); + return programBuilder.addChild(mainThread, EventFactory.Common.newExclusiveStore(rs, expressions.makePtrAdd(rb, ra), r1, "")); } @Override @@ -195,10 +200,10 @@ public Object visitBranchCond(LitmusPPCParser.BranchCondContext ctx) { Label label = programBuilder.getOrCreateLabel(mainThread, ctx.Label().getText()); CmpInstruction cmp = lastCmpInstructionPerThread.put(mainThread, null); Expression expr = cmp == null ? - // In PPC, when there is no previous comparison instruction, - // the value of r0 is used as the branching condition - expressions.makeBooleanCast(programBuilder.getOrNewRegister(mainThread, "r0")) : - expressions.makeIntCmp(cmp.left, ctx.cond().op, cmp.right); + // In PPC, when there is no previous comparison instruction, + // the value of r0 is used as the branching condition + expressions.makeBooleanCast(programBuilder.getOrNewRegister(mainThread, "r0", archType)) : + expressions.makeIntCmp(cmp.left, ctx.cond().op, cmp.right); return programBuilder.addChild(mainThread, EventFactory.newJump(expr, label)); } @@ -210,7 +215,7 @@ public Object visitLabel(LitmusPPCParser.LabelContext ctx) { @Override public Object visitFence(LitmusPPCParser.FenceContext ctx) { String name = ctx.getText().toLowerCase(); - if(fences.contains(name)){ + if (fences.contains(name)) { return programBuilder.addChild(mainThread, EventFactory.newFence(name)); } throw new ParsingException("Unrecognised fence " + name); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusPTX.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusPTX.java index 2f7da8d178..8bf1810158 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusPTX.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusPTX.java @@ -67,8 +67,7 @@ public Object visitVariableDeclaratorRegister(LitmusPTXParser.VariableDeclarator @Override public Object visitVariableDeclaratorRegisterLocation(LitmusPTXParser.VariableDeclaratorRegisterLocationContext ctx) { - programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText(), - archType); + programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText()); return null; } @@ -240,7 +239,7 @@ public Object visitAtomCAS(LitmusPTXParser.AtomCASContext ctx) { return programBuilder.addChild(mainThread, atom); } - @Override + @Override public Object visitAtomExchange(LitmusPTXParser.AtomExchangeContext ctx) { Register register_destination = programBuilder.getOrNewRegister(mainThread, ctx.register().getText(), archType); MemoryObject object = programBuilder.getOrNewVirtualMemoryObject(ctx.location().getText()); @@ -311,7 +310,7 @@ public Object visitBarrier(LitmusPTXParser.BarrierContext ctx) { } barrier = EventFactory.newNamedBarrier(name, instanceId, Tag.PTX.CTA, id, quorum); } - if(ctx.barrierMode().Arrive() != null) { + if (ctx.barrierMode().Arrive() != null) { barrier.addTags(Tag.PTX.ARRIVE); } return programBuilder.addChild(mainThread, barrier); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusRISCV.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusRISCV.java index 92568decfd..6cda71e7ea 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusRISCV.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusRISCV.java @@ -1,12 +1,14 @@ package com.dat3m.dartagnan.parsers.program.visitors; import java.util.Arrays; + import com.dat3m.dartagnan.configuration.Arch; import com.dat3m.dartagnan.exception.ParsingException; import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.integers.IntLiteral; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.parsers.LitmusRISCVBaseVisitor; import com.dat3m.dartagnan.parsers.LitmusRISCVParser; @@ -26,15 +28,15 @@ public class VisitorLitmusRISCV extends LitmusRISCVBaseVisitor { private final TypeFactory types = programBuilder.getTypeFactory(); private final ExpressionFactory expressions = programBuilder.getExpressionFactory(); private final IntegerType archType = types.getArchType(); + private final PointerType pointerType = types.getPointerType(); private int mainThread; private int threadCount = 0; - public VisitorLitmusRISCV(){ + public VisitorLitmusRISCV() { } // ---------------------------------------------------------------------------------------------------------------- // Entry point - @Override public Object visitMain(LitmusRISCVParser.MainContext ctx) { visitThreadDeclaratorList(ctx.program().threadDeclaratorList()); @@ -48,7 +50,6 @@ public Object visitMain(LitmusRISCVParser.MainContext ctx) { // ---------------------------------------------------------------------------------------------------------------- // Variable declarator list - @Override public Object visitVariableDeclaratorLocation(LitmusRISCVParser.VariableDeclaratorLocationContext ctx) { IntLiteral value = expressions.parseValue(ctx.constant().getText(), archType); @@ -65,7 +66,7 @@ public Object visitVariableDeclaratorRegister(LitmusRISCVParser.VariableDeclarat @Override public Object visitVariableDeclaratorRegisterLocation(LitmusRISCVParser.VariableDeclaratorRegisterLocationContext ctx) { - programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText(), archType); + programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText()); return null; } @@ -75,154 +76,156 @@ public Object visitVariableDeclaratorLocationLocation(LitmusRISCVParser.Variable return null; } - // ---------------------------------------------------------------------------------------------------------------- // Thread declarator list (on top of instructions), e.g. " P0 | P1 | P2 ;" - @Override public Object visitThreadDeclaratorList(LitmusRISCVParser.ThreadDeclaratorListContext ctx) { - for(LitmusRISCVParser.ThreadIdContext threadCtx : ctx.threadId()){ + for (LitmusRISCVParser.ThreadIdContext threadCtx : ctx.threadId()) { programBuilder.newThread(threadCtx.id); threadCount++; } return null; } - // ---------------------------------------------------------------------------------------------------------------- // Instruction list (the program itself) - @Override public Object visitInstructionRow(LitmusRISCVParser.InstructionRowContext ctx) { - for(int i = 0; i < threadCount; i++){ + for (int i = 0; i < threadCount; i++) { mainThread = i; visitInstruction(ctx.instruction(i)); } return null; } - @Override - public Object visitLi(LitmusRISCVParser.LiContext ctx) { + @Override + public Object visitLi(LitmusRISCVParser.LiContext ctx) { Register register = programBuilder.getOrNewRegister(mainThread, ctx.register().getText(), archType); IntLiteral constant = expressions.parseValue(ctx.constant().getText(), archType); return programBuilder.addChild(mainThread, EventFactory.newLocal(register, constant)); - } + } - @Override - public Object visitXor(LitmusRISCVParser.XorContext ctx) { + @Override + public Object visitXor(LitmusRISCVParser.XorContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); Register r3 = programBuilder.getOrErrorRegister(mainThread, ctx.register(2).getText()); return programBuilder.addChild(mainThread, EventFactory.newLocal(r1, expressions.makeIntXor(r2, r3))); - } + } - @Override - public Object visitAnd(LitmusRISCVParser.AndContext ctx) { + @Override + public Object visitAnd(LitmusRISCVParser.AndContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); Register r3 = programBuilder.getOrErrorRegister(mainThread, ctx.register(2).getText()); return programBuilder.addChild(mainThread, EventFactory.newLocal(r1, expressions.makeIntAnd(r2, r3))); - } + } - @Override - public Object visitOr(LitmusRISCVParser.OrContext ctx) { + @Override + public Object visitOr(LitmusRISCVParser.OrContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); Register r3 = programBuilder.getOrErrorRegister(mainThread, ctx.register(2).getText()); return programBuilder.addChild(mainThread, EventFactory.newLocal(r1, expressions.makeIntOr(r2, r3))); - } + } - @Override - public Object visitAdd(LitmusRISCVParser.AddContext ctx) { + @Override + public Object visitAdd(LitmusRISCVParser.AddContext ctx) { + // todo the problem here is pointer addition saved to int reg Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); Register r3 = programBuilder.getOrErrorRegister(mainThread, ctx.register(2).getText()); - return programBuilder.addChild(mainThread, EventFactory.newLocal(r1, expressions.makeAdd(r2, r3))); - } + return programBuilder.addChild( + mainThread, EventFactory.newLocal(r1, expressions.makeCast( + expressions.makeAdd(expressions.makeIntegerCast(r2, archType, false), + expressions.makeIntegerCast(r3, archType, false)), r1.getType()))); + + + } - @Override - public Object visitXori(LitmusRISCVParser.XoriContext ctx) { + @Override + public Object visitXori(LitmusRISCVParser.XoriContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); IntLiteral constant = expressions.parseValue(ctx.constant().getText(), archType); return programBuilder.addChild(mainThread, EventFactory.newLocal(r1, expressions.makeIntXor(r2, constant))); - } + } - @Override - public Object visitAndi(LitmusRISCVParser.AndiContext ctx) { + @Override + public Object visitAndi(LitmusRISCVParser.AndiContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); IntLiteral constant = expressions.parseValue(ctx.constant().getText(), archType); return programBuilder.addChild(mainThread, EventFactory.newLocal(r1, expressions.makeIntAnd(r2, constant))); - } + } - @Override - public Object visitOri(LitmusRISCVParser.OriContext ctx) { + @Override + public Object visitOri(LitmusRISCVParser.OriContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrNewRegister(mainThread, ctx.register(1).getText(), archType); IntLiteral constant = expressions.parseValue(ctx.constant().getText(), archType); return programBuilder.addChild(mainThread, EventFactory.newLocal(r1, expressions.makeIntOr(r2, constant))); - } + } - @Override - public Object visitAddi(LitmusRISCVParser.AddiContext ctx) { + @Override + public Object visitAddi(LitmusRISCVParser.AddiContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrNewRegister(mainThread, ctx.register(1).getText(), archType); IntLiteral constant = expressions.parseValue(ctx.constant().getText(), archType); return programBuilder.addChild(mainThread, EventFactory.newLocal(r1, expressions.makeAdd(r2, constant))); - } + } - @Override - public Object visitLw(LitmusRISCVParser.LwContext ctx) { + @Override + public Object visitLw(LitmusRISCVParser.LwContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register ra = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); - return programBuilder.addChild(mainThread, EventFactory.newLoadWithMo(r1, ra, getMo(ctx.moRISCV(0), ctx.moRISCV(1)))); - } + return programBuilder.addChild(mainThread, EventFactory.newLoadWithMo(r1, expressions.makePtrCast(ra, pointerType), getMo(ctx.moRISCV(0), ctx.moRISCV(1)))); + } - @Override - public Object visitSw(LitmusRISCVParser.SwContext ctx) { + @Override + public Object visitSw(LitmusRISCVParser.SwContext ctx) { Register r1 = programBuilder.getOrErrorRegister(mainThread, ctx.register(0).getText()); Register ra = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); - return programBuilder.addChild(mainThread, EventFactory.newStoreWithMo(ra, r1, getMo(ctx.moRISCV(0), ctx.moRISCV(1)))); - } + return programBuilder.addChild(mainThread, EventFactory.newStoreWithMo(expressions.makePtrCast(ra, pointerType), r1, getMo(ctx.moRISCV(0), ctx.moRISCV(1)))); + } - @Override - public Object visitLr(LitmusRISCVParser.LrContext ctx) { + @Override + public Object visitLr(LitmusRISCVParser.LrContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register ra = programBuilder.getOrErrorRegister(mainThread, ctx.register(1).getText()); - return programBuilder.addChild(mainThread, EventFactory.newRMWLoadExclusiveWithMo(r1, ra, getMo(ctx.moRISCV(0), ctx.moRISCV(1)))); - } + return programBuilder.addChild(mainThread, EventFactory.newRMWLoadExclusiveWithMo(r1, expressions.makePtrCast(ra, pointerType), getMo(ctx.moRISCV(0), ctx.moRISCV(1)))); + } - @Override - public Object visitSc(LitmusRISCVParser.ScContext ctx) { + @Override + public Object visitSc(LitmusRISCVParser.ScContext ctx) { Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrNewRegister(mainThread, ctx.register(1).getText(), archType); Register ra = programBuilder.getOrErrorRegister(mainThread, ctx.register(2).getText()); - return programBuilder.addChild(mainThread, EventFactory.Common.newExclusiveStore(r1, ra, r2, getMo(ctx.moRISCV(0), ctx.moRISCV(1)))); - } + return programBuilder.addChild(mainThread, EventFactory.Common.newExclusiveStore(r1, expressions.makePtrCast(ra, pointerType), r2, getMo(ctx.moRISCV(0), ctx.moRISCV(1)))); + } - @Override - public Object visitLabel(LitmusRISCVParser.LabelContext ctx) { - return programBuilder.addChild(mainThread, programBuilder.getOrCreateLabel(mainThread, ctx.Label().getText())); - } + @Override + public Object visitLabel(LitmusRISCVParser.LabelContext ctx) { + return programBuilder.addChild(mainThread, programBuilder.getOrCreateLabel(mainThread, ctx.Label().getText())); + } - @Override - public Object visitBranchCond(LitmusRISCVParser.BranchCondContext ctx) { + @Override + public Object visitBranchCond(LitmusRISCVParser.BranchCondContext ctx) { Label label = programBuilder.getOrCreateLabel(mainThread, ctx.Label().getText()); Register r1 = programBuilder.getOrNewRegister(mainThread, ctx.register(0).getText(), archType); Register r2 = programBuilder.getOrNewRegister(mainThread, ctx.register(1).getText(), archType); Expression expr = expressions.makeIntCmp(r1, ctx.cond().op, r2); return programBuilder.addChild(mainThread, EventFactory.newJump(expr, label)); - } + } - @Override - public Object visitFence(LitmusRISCVParser.FenceContext ctx) { + @Override + public Object visitFence(LitmusRISCVParser.FenceContext ctx) { String mo = ctx.fenceMode().mode; - Event fence = switch(mo) { + Event fence = switch (mo) { case "r.r" -> EventFactory.RISCV.newRRFence(); case "r.w" -> EventFactory.RISCV.newRWFence(); case "r.rw" -> EventFactory.RISCV.newRRWFence(); @@ -236,30 +239,30 @@ public Object visitFence(LitmusRISCVParser.FenceContext ctx) { case "i" -> EventFactory.RISCV.newSynchronizeFence(); default -> throw new ParsingException("Invalid fence mode " + mo); }; - return programBuilder.addChild(mainThread, fence); - } - - @Override - public Object visitAmoadd(LitmusRISCVParser.AmoaddContext ctx) { - throw new ParsingException("No support for amoadd instructions"); + return programBuilder.addChild(mainThread, fence); } - @Override - public Object visitAmoor(LitmusRISCVParser.AmoorContext ctx) { - throw new ParsingException("No support for amoor instructions"); } + @Override + public Object visitAmoadd(LitmusRISCVParser.AmoaddContext ctx) { + throw new ParsingException("No support for amoadd instructions"); + } - @Override - public Object visitAmoswap(LitmusRISCVParser.AmoswapContext ctx) { - throw new ParsingException("No support for amoswap instructions"); - } + @Override + public Object visitAmoor(LitmusRISCVParser.AmoorContext ctx) { + throw new ParsingException("No support for amoor instructions"); + } - // ======================================= - // ================ Utils ================ - // ======================================= + @Override + public Object visitAmoswap(LitmusRISCVParser.AmoswapContext ctx) { + throw new ParsingException("No support for amoswap instructions"); + } - private String getMo(LitmusRISCVParser.MoRISCVContext mo1, LitmusRISCVParser.MoRISCVContext mo2) { - String moR = mo1 != null ? mo1.mo : ""; - String moW = mo2 != null ? mo2.mo : ""; - return !moR.isEmpty() ? (!moW.isEmpty() ? Tag.RISCV.MO_ACQ_REL : moR) : moW; - } + // ======================================= + // ================ Utils ================ + // ======================================= + private String getMo(LitmusRISCVParser.MoRISCVContext mo1, LitmusRISCVParser.MoRISCVContext mo2) { + String moR = mo1 != null ? mo1.mo : ""; + String moW = mo2 != null ? mo2.mo : ""; + return !moR.isEmpty() ? (!moW.isEmpty() ? Tag.RISCV.MO_ACQ_REL : moR) : moW; + } } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusVulkan.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusVulkan.java index b26aa5bdd9..1e3df09ccd 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusVulkan.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusVulkan.java @@ -69,7 +69,7 @@ public Object visitVariableDeclaratorRegister(LitmusVulkanParser.VariableDeclara @Override public Object visitVariableDeclaratorRegisterLocation(LitmusVulkanParser.VariableDeclaratorRegisterLocationContext ctx) { - programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText(), archType); + programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText()); return null; } @@ -332,7 +332,7 @@ private String getMemoryOrderOrDefault(ParserRuleContext ctx, String defaultMo) if (ctx.getRuleContext(LitmusVulkanParser.MoAcqContext.class, 0) != null) { return Tag.Vulkan.ACQUIRE; } - if(ctx.getRuleContext(LitmusVulkanParser.MoRelContext.class, 0) != null) { + if (ctx.getRuleContext(LitmusVulkanParser.MoRelContext.class, 0) != null) { return Tag.Vulkan.RELEASE; } if (ctx.getRuleContext(LitmusVulkanParser.MoAcqRelContext.class, 0) != null) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusX86.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusX86.java index dfd674dbfb..6d476c4415 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusX86.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLitmusX86.java @@ -28,7 +28,7 @@ public class VisitorLitmusX86 extends LitmusX86BaseVisitor { private int mainThread; private int threadCount = 0; - public VisitorLitmusX86(){ + public VisitorLitmusX86() { } // ---------------------------------------------------------------------------------------------------------------- @@ -63,7 +63,7 @@ public Object visitVariableDeclaratorRegister(LitmusX86Parser.VariableDeclarator @Override public Object visitVariableDeclaratorRegisterLocation(LitmusX86Parser.VariableDeclaratorRegisterLocationContext ctx) { - programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText(), archType); + programBuilder.initRegEqLocPtr(ctx.threadId().id, ctx.register().getText(), ctx.location().getText()); return null; } @@ -79,7 +79,7 @@ public Object visitVariableDeclaratorLocationLocation(LitmusX86Parser.VariableDe @Override public Object visitThreadDeclaratorList(LitmusX86Parser.ThreadDeclaratorListContext ctx) { - for(LitmusX86Parser.ThreadIdContext threadCtx : ctx.threadId()){ + for (LitmusX86Parser.ThreadIdContext threadCtx : ctx.threadId()) { programBuilder.newThread(threadCtx.id); threadCount++; } @@ -92,7 +92,7 @@ public Object visitThreadDeclaratorList(LitmusX86Parser.ThreadDeclaratorListCont @Override public Object visitInstructionRow(LitmusX86Parser.InstructionRowContext ctx) { - for(int i = 0; i < threadCount; i++){ + for (int i = 0; i < threadCount; i++) { mainThread = i; visitInstruction(ctx.instruction(i)); } @@ -167,7 +167,7 @@ public Object visitAddRegisterValue(LitmusX86Parser.AddRegisterValueContext ctx) @Override public Object visitFence(LitmusX86Parser.FenceContext ctx) { String name = ctx.getText().toLowerCase(); - if(fences.contains(name)) { + if (fences.contains(name)) { return programBuilder.addChild(mainThread, EventFactory.newFence(name)); } throw new ParsingException("Unrecognised fence " + name); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLlvm.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLlvm.java index a39bd22630..a066696de0 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLlvm.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/VisitorLlvm.java @@ -51,7 +51,7 @@ public class VisitorLlvm extends LLVMIRBaseVisitor { private final Program program; private final TypeFactory types = TypeFactory.getInstance(); private final ExpressionFactory expressions = ExpressionFactory.getInstance(); - private final Type pointerType = types.getPointerType(); + private final PointerType pointerType = types.getPointerType(); private final IntegerType integerType = types.getArchType(); private final Map constantMap = new HashMap<>(); private final Map typeDefinitionMap = new HashMap<>(); @@ -272,8 +272,8 @@ public Expression visitGlobalDef(GlobalDefContext ctx) { final boolean isExternal = ctx.externalLinkage() != null; final boolean hasInitializer = ctx.constant() != null; - check (!(isExternal && hasInitializer), "External global cannot have initializer: %s", ctx); - check (isExternal || hasInitializer, "Global without initializer; %s", ctx); + check(!(isExternal && hasInitializer), "External global cannot have initializer: %s", ctx); + check(isExternal || hasInitializer, "Global without initializer; %s", ctx); final Expression value; value = hasInitializer ? checkExpression(type, ctx.constant()) : program.newConstant(type); @@ -298,7 +298,7 @@ private List parseMetadataAttachment(List m final List metadata = new ArrayList<>(); //FIXME: This code only looks for DILocation metadata, // and it only extracts the information needed to construct SourceLocation metadata - for (MetadataAttachmentContext metadataCtx: metadataAttachmentContexts) { + for (MetadataAttachmentContext metadataCtx : metadataAttachmentContexts) { MdNode mdNode = (MdNode) metadataCtx.accept(this); assert mdNode instanceof MdReference; mdNode = metadataSymbolTable.get(((MdReference) mdNode).mdName()); @@ -389,18 +389,18 @@ public Expression visitCallInst(CallInstContext ctx) { ); Optional> events = Optional.empty(); boolean unsupportedEncountered = false; - for(ParserAsm parser : parsers){ + for (ParserAsm parser : parsers) { // we have to generate the stream each time as the parser consumes it CharStream charStream = CharStreams.fromString(asmCode); try { - events = tryParse(parser,charStream); - if(events.isPresent()){ + events = tryParse(parser, charStream); + if (events.isPresent()) { block.events.addAll(events.get()); break; } } catch (UnsupportedOperationException e) { logger.warn("Support for inline assembly instruction '{}' is not available for parser '{}'. Setting non deterministic value ", e.getMessage(), parser.getClass().getSimpleName()); - if(resultRegister != null){ + if (resultRegister != null) { Event nonDeterministicValue = EventFactory.Svcomp.newNonDetChoice(resultRegister); events = Optional.of(List.of(nonDeterministicValue)); } @@ -408,9 +408,9 @@ public Expression visitCallInst(CallInstContext ctx) { break; } } - if(!unsupportedEncountered && events.isEmpty()){ + if (!unsupportedEncountered && events.isEmpty()) { String msg = "Ignoring call."; - if(resultRegister != null){ + if (resultRegister != null) { block.events.add(EventFactory.Svcomp.newNonDetChoice(resultRegister)); msg = "Setting non deterministic value."; } @@ -538,7 +538,7 @@ public Expression visitAllocaInst(AllocaInstContext ctx) { sizeExpression = checkExpression(sizeType, ctx.typeValue().value()); } final Event alloc; - if(ctx.align() != null) { + if (ctx.align() != null) { final Expression alignmentExpression = expressions.makeValue(parseBigInteger(ctx.align().IntLit()), types.getArchType()); alloc = EventFactory.newAlignedAlloc(register, elementType, sizeExpression, alignmentExpression, false, false); } else { @@ -581,9 +581,14 @@ public Expression visitPhiInst(PhiInstContext ctx) { @Override public Expression visitICmpInst(ICmpInstContext ctx) { - final Expression left = visitTypeValue(ctx.typeValue()); - final Expression right = checkExpression(left.getType(), ctx.value()); + Expression left = visitTypeValue(ctx.typeValue()); + Expression right = checkExpression(left.getType(), ctx.value()); final String operator = ctx.iPred().getText(); + assert left.getType() == right.getType(); // llvm requires this + if (left.getType() instanceof PointerType p) { + left = expressions.makeCast(left,types.getIntegerType(p.getBitWidth())); + right = expressions.makeCast(right,types.getIntegerType(p.getBitWidth())); + } final Expression compared = switch (operator) { case "eq" -> expressions.makeEQ(left, right); case "ne" -> expressions.makeNEQ(left, right); @@ -923,8 +928,7 @@ public Expression visitAddrSpaceCastInst(AddrSpaceCastInstContext ctx) { private Register conversionInstruction(TypeValueContext operand, TypeContext target, boolean signed) { final Expression operandExpression = visitTypeValue(operand); final Type targetType = parseType(target); - checkSupport(targetType instanceof IntegerType, "Non-integer in %s.", target); - // checkSupport(targetType instanceof IntegerType || targetType instanceof FloatType, "Neither integer nor float in %s.", target); // TODO we can enable this once we have proper support for bitcats, see #957 + // checkSupport(targetType instanceof IntegerType, "Non-integer in %s.", target); final Expression result = expressions.makeCast(operandExpression, targetType, signed); return assignToRegister(result); } @@ -944,7 +948,8 @@ public Expression visitConstant(ConstantContext ctx) { @Override public Expression visitNullConst(NullConstContext ctx) { - return expressions.makeZero((IntegerType) pointerType); + // return expressions.makeZero((IntegerType) pointerType); + return expressions.makeNullLiteral(); } @Override @@ -1185,8 +1190,8 @@ private Expression checkExpression(Type type, ParserRuleContext context) { private Expression castExpression(TypeConstContext operand, TypeContext target, boolean signed) { final Expression operandExpression = visitTypeConst(operand); final Type targetType = parseType(target); - checkSupport(targetType instanceof IntegerType, "Non-integer type %s.", target); - return expressions.makeIntegerCast(operandExpression, (IntegerType) targetType, signed); + checkSupport(targetType instanceof IntegerType || targetType instanceof PointerType, "Non integer or pointer type %s.", target); + return expressions.makeCast(operandExpression, targetType, signed); } // ---------------------------------------------------------------------------------------------------------------- diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsAtomic.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsAtomic.java index 77aaebc188..d47d703b40 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsAtomic.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsAtomic.java @@ -7,6 +7,8 @@ import com.dat3m.dartagnan.expression.integers.IntBinaryOp; import com.dat3m.dartagnan.expression.integers.IntCmpOp; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.expression.type.ScopedPointerType; import com.dat3m.dartagnan.parsers.SpirvBaseVisitor; import com.dat3m.dartagnan.parsers.SpirvParser; import com.dat3m.dartagnan.parsers.program.visitors.spirv.helpers.HelperTags; @@ -143,8 +145,8 @@ private Event visitOpAtomicExtremum( String scope = getScopeTag(scopeCtx.getText()); Set tags = getMemorySemanticsTags(tagsCtx.getText()); tags.add(builder.getPointerStorageClass(ptrCtx.getText())); - if (!(ptr.getType() instanceof IntegerType) || !(value.getType() instanceof IntegerType)) { - throw new ParsingException("Unexpected type at '%s' or '%s', expected integer but received '%s' and '%s'", + if (!(ptr.getType() instanceof ScopedPointerType) || !(value.getType() instanceof IntegerType)) { + throw new ParsingException("Unexpected type at '%s' or '%s', expected pointer or integer but received '%s' and '%s'", ptrCtx.getText(), valCtx.getText(), ptr.getType(), value.getType()); } SpirvRmwExtremum event = newSpirvRmwExtremum(register, ptr, kind, value, scope, tags); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsConstant.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsConstant.java index 465e09b29f..57d199d67d 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsConstant.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsConstant.java @@ -143,6 +143,9 @@ private Expression getConstantNullExpression(String typeId, Type type) { if (type instanceof IntegerType iType) { return expressions.makeZero(iType); } + if (type instanceof PointerType pType) { + return expressions.makeNullLiteral(pType); + } throw new ParsingException("Unsupported NULL constant type '%s'", typeId); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsConversion.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsConversion.java index 730ee74816..327bb2a675 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsConversion.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/VisitorOpsConversion.java @@ -6,6 +6,7 @@ import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.type.ArrayType; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.ScopedPointerType; import com.dat3m.dartagnan.parsers.SpirvBaseVisitor; import com.dat3m.dartagnan.parsers.SpirvParser; @@ -40,9 +41,9 @@ public Event visitOpBitcast(SpirvParser.OpBitcastContext ctx) { throw new ParsingException("Bitcast between arrays is not supported for id '%s'", id); } - if (resultType instanceof ScopedPointerType pointerType1 && operandType instanceof ScopedPointerType pointerType2 - && !(pointerType1.getScopeId().equals(pointerType2.getScopeId()))) { - throw new ParsingException("Storage class mismatch in OpBitcast between '%s' and '%s' for id '%s'", typeId, operand, id); + if (resultType instanceof ScopedPointerType scpPointerType1 && operandType instanceof ScopedPointerType scpPointerType2 + && !(scpPointerType1.getScopeId().equals(scpPointerType2.getScopeId()))) { + throw new ParsingException("Storage class mismatch in OpBitcast between '%s' and '%s' for id '%s'", typeId, operand, id); } Expression convertedExpr = expressions.makeCast(operandExpr, resultType); @@ -55,7 +56,7 @@ public Event visitOpConvertPtrToU(SpirvParser.OpConvertPtrToUContext ctx) { String id = ctx.idResult().getText(); Type type = builder.getType(ctx.idResultType().getText()); Expression pointer = builder.getExpression(ctx.pointer().getText()); - if (type instanceof ScopedPointerType || !(type instanceof IntegerType)) { + if (!(type instanceof IntegerType)) { throw new ParsingException("Illegal OpConvertPtrToU for '%s', " + "attempt to convent into a non-integer type", id); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/builders/ProgramBuilder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/builders/ProgramBuilder.java index 10f4db6083..19d1ee5110 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/builders/ProgramBuilder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/builders/ProgramBuilder.java @@ -199,8 +199,8 @@ public ScopedPointerVariable allocateMemory(String id, ScopedPointerType type, E public String getPointerStorageClass(String id) { Expression expression = getExpression(id); - if (expression.getType() instanceof ScopedPointerType pointerType) { - return pointerType.getScopeId(); + if (expression.getType() instanceof ScopedPointerType scpPointerType) { + return scpPointerType.getScopeId(); } throw new ParsingException("Reference to undefined pointer '%s'", id); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/witness/ParserWitness.java b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/witness/ParserWitness.java index e185866535..3f9d02af10 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/witness/ParserWitness.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/parsers/witness/ParserWitness.java @@ -16,10 +16,10 @@ public class ParserWitness { - private static final Logger logger = LoggerFactory.getLogger(ParserWitness.class); + private static final Logger logger = LoggerFactory.getLogger(ParserWitness.class); public WitnessGraph parse(CharStream charStream) { - XMLLexer lexer = new XMLLexer(charStream); + XMLLexer lexer = new XMLLexer(charStream); lexer.addErrorListener(new AbortErrorListener()); lexer.addErrorListener(new DiagnosticErrorListener(true)); CommonTokenStream tokenStream = new CommonTokenStream(lexer); @@ -31,19 +31,19 @@ public WitnessGraph parse(CharStream charStream) { VisitorXML visitor = new VisitorXML(); WitnessGraph graph = (WitnessGraph) parserEntryPoint.accept(visitor); - if(graph.hasAttributed("producer")) { - logger.info("Witness graph produced by " + graph.getAttributed("producer")); - } - logger.info("Witness graph stats: #Nodes " + graph.getNodes().size()); - logger.info("Witness graph stats: #Edges " + graph.getEdges().size()); + if (graph.hasAttributed("producer")) { + logger.info("Witness graph produced by " + graph.getAttributed("producer")); + } + logger.info("Witness graph stats: #Nodes " + graph.getNodes().size()); + logger.info("Witness graph stats: #Edges " + graph.getEdges().size()); return graph; } - + public WitnessGraph parse(String raw) { - return parse(CharStreams.fromString(raw)); + return parse(CharStreams.fromString(raw)); } - + public WitnessGraph parse(File file) throws IOException { CharStream charStream; try (FileInputStream stream = new FileInputStream(file)) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/Function.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/Function.java index bf51489cf2..4935f0713d 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/Function.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/Function.java @@ -62,7 +62,7 @@ public Function(String name, FunctionType type, List parameterNames, int @Override public Type getType() { - return TypeFactory.getInstance().getArchType(); + return TypeFactory.getInstance().getPointerType(); } @Override diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/Dependency.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/Dependency.java index d4b03e027b..c805223ba6 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/Dependency.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/Dependency.java @@ -66,7 +66,7 @@ public static Dependency fromConfig(Program program, Context analysisContext, Co /** * Queries the collection of providers for a variable, given a certain state of the program. * - * @param reader Event containing some computation over values of the register space. + * @param reader Event containing some computation over values of the register space. * @return Local result of this analysis. */ @Override @@ -109,7 +109,7 @@ private void process(Thread thread, ExecutionAnalysis exec) { //collecting all register dependencies Set registers = new HashSet<>(); if (event instanceof RegReader regReader) { - regReader.getRegisterReads().forEach( read -> registers.add(read.register())); + regReader.getRegisterReads().forEach(read -> registers.add(read.register())); } if (!registers.isEmpty()) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/SyntacticContextAnalysis.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/SyntacticContextAnalysis.java index 38b1f4a63f..ea16db0a3c 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/SyntacticContextAnalysis.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/SyntacticContextAnalysis.java @@ -170,7 +170,7 @@ private void run(Thread thread, LoopAnalysis loops) { // FIXME: DCE can sometimes delete the end marker of functions if those never return // (e.g., "reach_error() { abort(0); }"). // Here we try to also pop those calls that have missing markers. - if(curContextStack.peek() instanceof CallContext) { + if (curContextStack.peek() instanceof CallContext) { topCallCtx = (CallContext) curContextStack.pop(); } else { logger.warn("Found a FunCallMarker without a matching FunReturnMarker. Giving up the analysis"); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/AliasAnalysis.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/AliasAnalysis.java index e488b7fb9f..0bf1cfd5a9 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/AliasAnalysis.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/AliasAnalysis.java @@ -54,7 +54,7 @@ public interface AliasAnalysis { List mayMixedSizeAccesses(MemoryCoreEvent event); static AliasAnalysis fromConfig(Program program, Context analysisContext, Configuration config, - boolean detectMixedSizeAccesses) throws InvalidConfigurationException { + boolean detectMixedSizeAccesses) throws InvalidConfigurationException { Config c = new Config(config, detectMixedSizeAccesses); logger.info("Selected alias analysis: {}", c.method); long t0 = System.currentTimeMillis(); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/AndersenAliasAnalysis.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/AndersenAliasAnalysis.java index 47005083ff..c1c4b88125 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/AndersenAliasAnalysis.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/AndersenAliasAnalysis.java @@ -1,8 +1,13 @@ package com.dat3m.dartagnan.program.analysis.alias; import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.base.CastExpressionBase; import com.dat3m.dartagnan.expression.integers.IntBinaryExpr; import com.dat3m.dartagnan.expression.integers.IntLiteral; +import com.dat3m.dartagnan.expression.pointers.IntToPtrCast; +import com.dat3m.dartagnan.expression.pointers.NullLiteral; +import com.dat3m.dartagnan.expression.pointers.PtrAddExpr; +import com.dat3m.dartagnan.expression.pointers.PtrToIntCast; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.program.Program; import com.dat3m.dartagnan.program.Register; @@ -49,9 +54,9 @@ public class AndersenAliasAnalysis implements AliasAnalysis { // For providing helpful error messages, this analysis prints call-stack and loop information for events. private final Supplier synContext; - ///When a pointer set gains new content, it is added to this queue + /// When a pointer set gains new content, it is added to this queue private final Queue variables = new ArrayDeque<>(); - ///Super set of all pointer sets in this analysis + /// Super set of all pointer sets in this analysis private final ImmutableSet maxAddressSet; private final Map> edges = new HashMap<>(); private final Map> addresses = new HashMap<>(); @@ -72,7 +77,7 @@ private AndersenAliasAnalysis(Program program, Config c) { for (MemoryObject a : program.getMemory().getObjects()) { if (!a.hasKnownSize()) { throw new UnsupportedOperationException(String.format("%s alias analysis does not support memory objects of unknown size. " + - "You can try the %s alias analysis", FIELD_INSENSITIVE, FULL)); + "You can try the %s alias analysis", FIELD_INSENSITIVE, FULL)); } for (int i = 0; i < a.getKnownSize(); i++) { builder.add(new Location(a, i)); @@ -215,7 +220,7 @@ private void processLocs(MemoryCoreEvent e) { //event is a store operation Verify.verify(e instanceof Store, "Encountered memory event that is neither store nor load: {}", e); - Expression value = ((Store)e).getMemValue(); + Expression value = ((Store) e).getMemValue(); if (value instanceof Register) { addEdge(value, location); return; @@ -238,6 +243,9 @@ private void processRegs(Local e) { } else if (expr instanceof IntBinaryExpr iBin && iBin.getLeft() instanceof Register) { addAllAddresses(register, maxAddressSet); variables.add(register); + } else if (expr instanceof PtrAddExpr pAdd && pAdd.getBase() instanceof Register) { + addAllAddresses(register, maxAddressSet); + variables.add(register); } else if (expr instanceof MemoryObject mem) { // r = &a addAddress(register, new Location(mem, 0)); @@ -284,16 +292,23 @@ private void algorithm() { private void processResults(Local e) { Expression exp = e.getExpr(); Register reg = e.getResultRegister(); + if (exp instanceof IntToPtrCast || exp instanceof PtrToIntCast) { + exp = ((CastExpressionBase) exp).getOperand(); + } if (exp instanceof MemoryObject mem) { addTarget(reg, new Location(mem, 0)); return; } - if (!(exp instanceof IntBinaryExpr iBin)) { + if (!(exp instanceof IntBinaryExpr || exp instanceof PtrAddExpr)) { return; } - Expression base = iBin.getLeft(); + Expression base = exp instanceof IntBinaryExpr ? ((IntBinaryExpr) exp).getLeft() : ((PtrAddExpr) exp).getBase(); + // fixme: this is a temp solution. + if (base instanceof IntToPtrCast || base instanceof PtrToIntCast) { + base = ((CastExpressionBase) base).getOperand(); + } + Expression rhs = exp instanceof IntBinaryExpr ? ((IntBinaryExpr) exp).getRight() : ((PtrAddExpr) exp).getOffset(); if (base instanceof MemoryObject mem) { - Expression rhs = iBin.getRight(); if (rhs instanceof IntLiteral ic) { addTarget(reg, new Location(mem, ic.getValueAsInt())); } else { @@ -306,7 +321,6 @@ private void processResults(Local e) { } //accept register2 = register1 + constant for (Location target : targets.getOrDefault(base, Set.of())) { - Expression rhs = iBin.getRight(); if (rhs instanceof IntLiteral ic) { int o = target.offset + ic.getValueAsInt(); if (o < target.base.getKnownSize()) { @@ -360,6 +374,11 @@ private static final class Constant { failed = false; return; } + if (x instanceof NullLiteral) { + location = null; + failed = false; + return; + } if (x instanceof IntBinaryExpr iBin && iBin.getKind() == ADD) { Expression lhs = iBin.getLeft(); Expression rhs = iBin.getRight(); @@ -369,6 +388,15 @@ private static final class Constant { return; } } + if (x instanceof PtrAddExpr pAdd) { + Expression lhs = pAdd.getBase(); + Expression rhs = pAdd.getOffset(); + if (lhs instanceof MemoryObject mem && rhs instanceof IntLiteral ic) { + location = new Location(mem, ic.getValueAsInt()); + failed = false; + return; + } + } location = null; failed = true; } @@ -379,7 +407,8 @@ public String toString() { } } - private record Location(MemoryObject base, int offset) {} + private record Location(MemoryObject base, int offset) { + } private boolean addEdge(Object v1, Object v2) { return edges.computeIfAbsent(v1, key -> new HashSet<>()).add(v2); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/FieldSensitiveAndersen.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/FieldSensitiveAndersen.java index 38777be16e..174c80a4fa 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/FieldSensitiveAndersen.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/FieldSensitiveAndersen.java @@ -7,6 +7,9 @@ import com.dat3m.dartagnan.expression.integers.IntSizeCast; import com.dat3m.dartagnan.expression.integers.IntUnaryExpr; import com.dat3m.dartagnan.expression.misc.ITEExpr; +import com.dat3m.dartagnan.expression.pointers.IntToPtrCast; +import com.dat3m.dartagnan.expression.pointers.PtrAddExpr; +import com.dat3m.dartagnan.expression.pointers.PtrToIntCast; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.program.Program; import com.dat3m.dartagnan.program.Register; @@ -57,17 +60,17 @@ public class FieldSensitiveAndersen implements AliasAnalysis { // For providing helpful error messages, this analysis prints call-stack and loop information for events. private final Supplier synContext; - ///When a pointer set gains new content, it is added to this queue + /// When a pointer set gains new content, it is added to this queue private final LinkedHashSet variables = new LinkedHashSet<>(); private final Map>> edges = new HashMap<>(); private final Map> addresses = new HashMap<>(); - ///Maps registers to result registers of loads that use the register in their address + /// Maps registers to result registers of loads that use the register in their address private final Map>> loads = new HashMap<>(); - ///Maps registers to matched value expressions of stores that use the register in their address + /// Maps registers to matched value expressions of stores that use the register in their address private final Map>> stores = new HashMap<>(); - ///Result sets + /// Result sets private final Map> eventAddressSpaceMap = new HashMap<>(); // Maps memory events to additional offsets inside their byte range, which may match other accesses' bounds. @@ -276,16 +279,18 @@ protected void processResults(MemoryCoreEvent e) { eventAddressSpaceMap.put(e, addresses.build()); } - private record Offset(Base base, int offset, int alignment) {} + private record Offset(Base base, int offset, int alignment) { + } - private record Location(MemoryObject base, int offset) {} + private record Location(MemoryObject base, int offset) { + } private static List fields(Collection v, int offset, int alignment) { final List result = new ArrayList<>(); for (Location l : v) { if (!l.base.hasKnownSize()) { throw new UnsupportedOperationException(String.format("%s alias analysis does not support memory objects of unknown size. " + - "You can try the %s alias analysis", FIELD_SENSITIVE, FULL)); + "You can try the %s alias analysis", FIELD_SENSITIVE, FULL)); } for (int i = 0; i < div(l.base.getKnownSize(), alignment); i++) { int mapped = l.offset + offset + i * alignment; @@ -389,6 +394,39 @@ public Result visitIntBinaryExpression(IntBinaryExpr x) { return null; } + @Override + public Result visitPtrAddExpression(PtrAddExpr x) { + Result l = x.getBase().accept(this); + Result r = x.getOffset().accept(this); + + if (l.address != null && r.address != null) { + return null; + } + MemoryObject base = l.address != null ? l.address : r.address; + BigInteger offset = l.offset.add(r.offset); + if (base != null) { + return new Result(base, + null, + offset, + min(min(l.alignment, l.register), min(r.alignment, r.register))); + } + if (l.register != null) { + return new Result(null, l.register, offset, min(l.alignment, min(r.alignment, r.register))); + } + return new Result(null, r.register, offset, min(l.alignment, r.alignment)); + + } + + @Override + public Result visitIntToPtrCastExpression(IntToPtrCast expr) { + return expr.getOperand().accept(this); + } + + @Override + public Result visitPtrToIntCastExpression(PtrToIntCast expr) { + return expr.getOperand().accept(this); + } + @Override public Result visitIntUnaryExpression(IntUnaryExpr x) { Result i = x.getOperand().accept(this); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/InclusionBasedPointerAnalysis.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/InclusionBasedPointerAnalysis.java index ac067c01d8..31b7d93485 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/InclusionBasedPointerAnalysis.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/analysis/alias/InclusionBasedPointerAnalysis.java @@ -5,6 +5,7 @@ import com.dat3m.dartagnan.expression.aggregates.ConstructExpr; import com.dat3m.dartagnan.expression.aggregates.ExtractExpr; import com.dat3m.dartagnan.expression.integers.*; +import com.dat3m.dartagnan.expression.pointers.*; import com.dat3m.dartagnan.expression.misc.ITEExpr; import com.dat3m.dartagnan.expression.processing.ExpressionInspector; import com.dat3m.dartagnan.expression.type.TypeFactory; @@ -110,7 +111,10 @@ public class InclusionBasedPointerAnalysis implements AliasAnalysis { // ================================ Debugging ================================ private record IntPair(int x, int y) { - @Override public String toString() {return x + "," + y;} + @Override + public String toString() { + return x + "," + y; + } } // Count inclusion tests grouped by complexity. @@ -268,7 +272,7 @@ private List toIncludeSet(Variable address) { } private void fetchAllMixedOffsets(Set xSet, Modifier xModifier, int xBytes, - Set ySet, Modifier yModifier, int yBytes) { + Set ySet, Modifier yModifier, int yBytes) { fetchMixedOffsets(xSet, xModifier, xBytes, yModifier, yBytes); fetchMixedOffsets(ySet, yModifier, yBytes, xModifier, xBytes); } @@ -330,7 +334,7 @@ private void run(Program program, AliasAnalysis.Config configuration) { private void processWriter(RegWriter event) { logger.trace("{}", event); final Expression expr = event instanceof Local local ? local.getExpr() : - event instanceof ThreadArgument arg ? arg.getCreator().getArguments().get(arg.getIndex()) : + event instanceof ThreadArgument arg ? arg.getCreator().getArguments().get(arg.getIndex()) : event instanceof Alloc alloc ? alloc.getAllocatedObject() : null; final DerivedVariable value; if (expr != null) { @@ -536,23 +540,33 @@ private static final class Variable { private final DerivedVariable[] aggregate; // For visualization. private final String name; + private Variable(MemoryObject o, DerivedVariable[] a, String n) { object = o; aggregate = a; name = n; } - @Override public String toString() { return name; } + + @Override + public String toString() { + return name; + } } - private record IncludeEdge(Variable source, Modifier modifier) {} + private record IncludeEdge(Variable source, Modifier modifier) { + } - private record LoadEdge(Variable result, Modifier addressModifier) {} + private record LoadEdge(Variable result, Modifier addressModifier) { + } - private record StoreEdge(DerivedVariable value, Modifier addressModifier) {} + private record StoreEdge(DerivedVariable value, Modifier addressModifier) { + } - private record Modifier(int offset, List alignment) {} + private record Modifier(int offset, List alignment) { + } - private record DerivedVariable(Variable base, Modifier modifier) {} + private record DerivedVariable(Variable base, Modifier modifier) { + } private static boolean isConstant(Modifier modifier) { return modifier.alignment.isEmpty(); @@ -828,18 +842,18 @@ private boolean includes(Modifier left, Modifier right) { mem[0] = true; for (int j = 1; j < mem.length; j++) { for (final Integer i : left.alignment) { - if (j - i/gcd >= 0 && mem[j - i/gcd]) { + if (j - i / gcd >= 0 && mem[j - i / gcd]) { mem[j] = true; break; } } } for (final Integer j : right.alignment) { - if (!mem[j/gcd]) { + if (!mem[j / gcd]) { return false; } } - return mem[Math.abs(offset)/gcd]; + return mem[Math.abs(offset) / gcd]; } // Checks if there may be some common value in both sets. @@ -1014,6 +1028,7 @@ public Expression visitRegister(Register register) { edges.add(new IncludeEdge(getPhiNodeVariable(register, reader).base, RELAXED_MODIFIER)); return register; } + @Override public Expression visitMemoryObject(MemoryObject object) { edges.add(new IncludeEdge(objectVariables.get(object), RELAXED_MODIFIER)); @@ -1023,22 +1038,67 @@ public Expression visitMemoryObject(MemoryObject object) { return edges; } - record ExprFlip(Expression x, int factor) {} + record ExprFlip(Expression expr, int factor) { + } + + @Override + public List visitPtrAddExpression(PtrAddExpr expr) { + return visitByteExpression(expr); + } + + private boolean matchPtrAddExpression(ExprFlip operand, Stack stack) { + if (!(operand.expr instanceof PtrAddExpr xp)) return false; + else { + final Expression left = xp.getBase(); + final Expression right = xp.getOffset(); + stack.push(new ExprFlip(right, operand.factor)); + stack.push(new ExprFlip(left, operand.factor)); + return true; + } + } @Override public List visitIntBinaryExpression(IntBinaryExpr x) { + return visitByteExpression(x); + } + + private boolean matchLinearExpression(ExprFlip operand, Stack stack) { + final Expression left = operand.expr instanceof IntBinaryExpr x ? x.getLeft() : null; + final Expression right = operand.expr instanceof IntBinaryExpr x ? x.getRight() : null; + final boolean add = operand.expr.getKind().equals(IntBinaryOp.ADD); + final boolean sub = operand.expr.getKind().equals(IntBinaryOp.SUB); + final boolean mul = operand.expr.getKind().equals(IntBinaryOp.MUL); + if (add || sub) { + stack.push(new ExprFlip(right, operand.factor * (add ? 1 : -1))); + stack.push(new ExprFlip(left, operand.factor)); + return true; + } else if (mul) { + final IntLiteral leftLiteral = left instanceof IntLiteral l ? l : null; + final IntLiteral rightLiteral = right instanceof IntLiteral l ? l : null; + if (leftLiteral != null || rightLiteral != null) { + final int factor = (leftLiteral != null ? leftLiteral : rightLiteral).getValueAsInt(); + stack.push(new ExprFlip(leftLiteral != null ? right : left, operand.factor * factor)); + return true; + } + } + return false; + } + + + public List visitByteExpression(Expression x) { + assert x instanceof IntBinaryExpr || x instanceof PtrAddExpr; BigInteger offset = BigInteger.ZERO; final List operands = new ArrayList<>(); final Stack stack = new Stack<>(); - if (!matchLinearExpression(new ExprFlip(x, 1), stack)) { + if (!matchByteExpression(new ExprFlip(x, 1), stack)) { return visitExpression(x); } while (!stack.isEmpty()) { final ExprFlip operand = stack.pop(); - if (matchLinearExpression(operand, stack)) { + if (matchByteExpression(operand, stack)) { continue; } - if (operand.x instanceof IntLiteral literal) { + if (operand.expr instanceof IntLiteral literal) { offset = offset.add(literal.getValue().multiply(BigInteger.valueOf(operand.factor))); } else { operands.add(operand); @@ -1049,42 +1109,41 @@ public List visitIntBinaryExpression(IntBinaryExpr x) { for (int i = 0; i < operands.size(); i++) { final ExprFlip operand = operands.get(i); if (operand.factor != 1) { - result.addAll(visitExpression(operand.x)); + result.addAll(visitExpression(operand.expr)); continue; } List alignment = List.of(); for (int j = 0; j < operands.size(); j++) { alignment = j == i ? alignment : compose(alignment, operands.get(j).factor); } - for (IncludeEdge subResult : operand.x.accept(this)) { + for (IncludeEdge subResult : operand.expr.accept(this)) { addInto(result, compose(subResult, modifier(o, alignment)), false); } } return result; } - private boolean matchLinearExpression(ExprFlip operand, Stack stack) { - final Expression left = operand.x instanceof IntBinaryExpr x ? x.getLeft() : null; - final Expression right = operand.x instanceof IntBinaryExpr x ? x.getRight() : null; - final boolean add = operand.x.getKind().equals(IntBinaryOp.ADD); - final boolean sub = operand.x.getKind().equals(IntBinaryOp.SUB); - final boolean mul = operand.x.getKind().equals(IntBinaryOp.MUL); - if (add || sub) { - stack.push(new ExprFlip(right, operand.factor * (add ? 1 : -1))); - stack.push(new ExprFlip(left, operand.factor)); - return true; - } else if (mul) { - final IntLiteral leftLiteral = left instanceof IntLiteral l ? l : null; - final IntLiteral rightLiteral = right instanceof IntLiteral l ? l : null; - if (leftLiteral != null || rightLiteral != null) { - final int factor = (leftLiteral != null ? leftLiteral : rightLiteral).getValueAsInt(); - stack.push(new ExprFlip(leftLiteral != null ? right : left, operand.factor * factor)); - return true; - } + private boolean matchByteExpression(ExprFlip operand, Stack stack) { + if (operand.expr instanceof IntBinaryExpr) { + return matchLinearExpression(operand, stack); + } + if (operand.expr instanceof PtrAddExpr) { + return matchPtrAddExpression(operand, stack); } return false; } + @Override + public List visitIntToPtrCastExpression(IntToPtrCast expr) { + return expr.getOperand().accept(this); + } + + @Override + public List visitPtrToIntCastExpression(PtrToIntCast expr) { + return expr.getOperand().accept(this); + } + + @Override public List visitIntSizeCastExpression(IntSizeCast expr) { // We assume type casts do not affect the value of pointers. @@ -1159,7 +1218,7 @@ public List visitConstructExpression(ConstructExpr construct) { // Red-labeled nodes are address variables that do not include any memory objects (probably a bug). private void generateGraph() { final Set seen = new HashSet<>(objectVariables.values()); - for (Set news = seen; !news.isEmpty();) { + for (Set news = seen; !news.isEmpty(); ) { final var next = new HashSet(); for (final Variable v : news) { next.addAll(v.seeAlso); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/EventFactory.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/EventFactory.java index 76407a9a82..bed1205fc5 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/EventFactory.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/EventFactory.java @@ -116,8 +116,8 @@ public static Alloc newAlloc(Register register, Type allocType, Expression array } public static Alloc newAlignedAlloc(Register register, Type allocType, Expression arraySize, Expression alignment, - boolean isHeapAlloc, boolean doesZeroOutMemory) { - arraySize = expressions.makeCast(arraySize, types.getArchType(), false); + boolean isHeapAlloc, boolean doesZeroOutMemory) { + arraySize = expressions.makeCast(arraySize, types.getArchType(), false); // why cast? alignment = expressions.makeCast(alignment, types.getArchType(), false); return new Alloc(register, allocType, arraySize, alignment, isHeapAlloc, doesZeroOutMemory); } @@ -169,7 +169,7 @@ public static Init newInit(MemoryObject base, int offset) { //TODO: We simplify here because virtual aliasing currently fails when pointer arithmetic is involved // meaning that and are treated differently. final Expression address = offset == 0 ? base : - expressions.makeAdd(base, expressions.makeValue(offset, (IntegerType) base.getType())); + expressions.makePtrAdd(base, expressions.makeValue(offset, types.getArchType())); final Init init = new Init(base, offset, address); init.addTags(base.getFeatureTags()); return init; @@ -187,6 +187,7 @@ public static ValueFunctionCall newValueFunctionCall(Register resultRegister, Fu public static VoidFunctionCall newVoidFunctionCall(Function function, List arguments) { return new VoidFunctionCall(function.getFunctionType(), function, arguments); } + public static VoidFunctionCall newVoidFunctionCall(FunctionType funcType, Expression funcPtr, List arguments) { return new VoidFunctionCall(funcType, funcPtr, arguments); } @@ -781,7 +782,8 @@ public static GenericVisibleEvent newLwSyncBarrier() { // ============================================ PTX ============================================ // ============================================================================================= public static class PTX { - private PTX() {} + private PTX() { + } public static PTXAtomOp newAtomOp(Expression address, Register register, Expression value, IntBinaryOp op, String mo, String scope) { @@ -792,14 +794,14 @@ public static PTXAtomOp newAtomOp(Expression address, Register register, Express } public static PTXAtomCAS newAtomCAS(Expression address, Register register, Expression expected, - Expression value, String mo, String scope) { + Expression value, String mo, String scope) { PTXAtomCAS atom = new PTXAtomCAS(register, address, expected, value, mo); atom.addTags(scope); return atom; } public static PTXAtomExch newAtomExch(Expression address, Register register, - Expression value, String mo, String scope) { + Expression value, String mo, String scope) { PTXAtomExch atom = new PTXAtomExch(register, address, value, mo); atom.addTags(scope); return atom; @@ -818,10 +820,11 @@ public static PTXRedOp newRedOp(Expression address, Expression value, // =========================================== Vulkan ========================================== // ============================================================================================= public static class Vulkan { - private Vulkan() {} + private Vulkan() { + } public static VulkanRMW newRMW(Expression address, Register register, Expression value, - String mo, String scope) { + String mo, String scope) { return new VulkanRMW(register, address, value, mo, scope); } @@ -854,7 +857,8 @@ public static GenericVisibleEvent newVisDevice() { // ============================================================================================= public static class Spirv { - private Spirv() {} + private Spirv() { + } public static SpirvLoad newSpirvLoad(Register register, Expression address, String scope, Set tags) { @@ -872,7 +876,7 @@ public static SpirvXchg newSpirvXchg(Register register, Expression address, Expr } public static SpirvRmw newSpirvRmw(Register register, Expression address, IntBinaryOp op, Expression value, - String scope, Set tags) { + String scope, Set tags) { return new SpirvRmw(register, address, op, value, scope, tags); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/common/SingleAccessMemoryEvent.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/common/SingleAccessMemoryEvent.java index 5ebb7129f5..3f5138270f 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/common/SingleAccessMemoryEvent.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/common/SingleAccessMemoryEvent.java @@ -3,6 +3,7 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionVisitor; import com.dat3m.dartagnan.expression.Type; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.program.event.AbstractEvent; import com.dat3m.dartagnan.program.event.MemoryAccess; import com.dat3m.dartagnan.program.event.MemoryEvent; @@ -32,6 +33,7 @@ public abstract class SingleAccessMemoryEvent extends AbstractEvent implements M // The empty string means no memory order public SingleAccessMemoryEvent(Expression address, Type accessType, String mo) { Preconditions.checkNotNull(mo, "The memory ordering cannot be null"); + // Preconditions.checkArgument(address.getType() instanceof PointerType); this.address = address; this.mo = mo; this.accessType = accessType; @@ -48,11 +50,21 @@ protected SingleAccessMemoryEvent(SingleAccessMemoryEvent other) { this.accessType = other.accessType; } - public Expression getAddress() { return address; } - public void setAddress(Expression address) { this.address = address; } + public Expression getAddress() { + return address; + } + + public void setAddress(Expression address) { + this.address = address; + } - public Type getAccessType() { return accessType; } - public void setAccessType(Type type) { this.accessType = type; } + public Type getAccessType() { + return accessType; + } + + public void setAccessType(Type type) { + this.accessType = type; + } public String getMo() { return mo; diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/AbstractMemoryCoreEvent.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/AbstractMemoryCoreEvent.java index a9eeb7a068..fb6dfd1677 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/AbstractMemoryCoreEvent.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/AbstractMemoryCoreEvent.java @@ -3,9 +3,13 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionVisitor; import com.dat3m.dartagnan.expression.Type; +import com.dat3m.dartagnan.expression.type.PointerType; +import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.event.AbstractEvent; + import static com.dat3m.dartagnan.program.event.Tag.MEMORY; import static com.dat3m.dartagnan.program.event.Tag.VISIBLE; + import com.dat3m.dartagnan.program.event.common.NoInterface; import com.google.common.base.Preconditions; @@ -19,6 +23,7 @@ public abstract class AbstractMemoryCoreEvent extends AbstractEvent implements M protected Type accessType; public AbstractMemoryCoreEvent(Expression address, Type accessType) { + //Preconditions.checkArgument(address.getType() instanceof PointerType); this.address = Preconditions.checkNotNull(address); this.accessType = accessType; addTags(VISIBLE, MEMORY); @@ -30,11 +35,21 @@ protected AbstractMemoryCoreEvent(AbstractMemoryCoreEvent other) { this.accessType = other.accessType; } - public Expression getAddress() { return address; } - public void setAddress(Expression address) { this.address = address; } + public Expression getAddress() { + return address; + } + + public void setAddress(Expression address) { + this.address = address; + } + + public Type getAccessType() { + return accessType; + } - public Type getAccessType() { return accessType; } - public void setAccessType(Type type) { this.accessType = type; } + public void setAccessType(Type type) { + this.accessType = type; + } @Override public void transformExpressions(ExpressionVisitor exprTransformer) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/Alloc.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/Alloc.java index cd15dff390..36f80e5e3c 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/Alloc.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/Alloc.java @@ -62,20 +62,47 @@ private Alloc(Alloc other) { } @Override - public Register getResultRegister() { return resultRegister; } + public Register getResultRegister() { + return resultRegister; + } + @Override - public void setResultRegister(Register reg) { this.resultRegister = reg; } + public void setResultRegister(Register reg) { + this.resultRegister = reg; + } + + public Type getAllocationType() { + return allocationType; + } + + public Expression getArraySize() { + return arraySize; + } + + public Expression getAlignment() { + return alignment; + } - public Type getAllocationType() { return allocationType; } - public Expression getArraySize() { return arraySize; } - public Expression getAlignment() { return alignment; } - public boolean isHeapAllocation() { return isHeapAllocation; } - public boolean doesZeroOutMemory() { return doesZeroOutMemory; } + public boolean isHeapAllocation() { + return isHeapAllocation; + } - public boolean isSimpleAllocation() { return (arraySize instanceof IntLiteral size && size.isOne()); } - public boolean isArrayAllocation() { return !isSimpleAllocation(); } + public boolean doesZeroOutMemory() { + return doesZeroOutMemory; + } + + public boolean isSimpleAllocation() { + return (arraySize instanceof IntLiteral size && size.isOne()); + } + + public boolean isArrayAllocation() { + return !isSimpleAllocation(); + } + + public void setAllocatedObject(MemoryObject obj) { + this.allocatedObject = obj; + } - public void setAllocatedObject(MemoryObject obj) { this.allocatedObject = obj; } // WARNING: This should only be accessed after program processing. public MemoryObject getAllocatedObject() { Preconditions.checkState(allocatedObject != null, @@ -122,7 +149,9 @@ protected String defaultString() { } @Override - public Alloc getCopy() { return new Alloc(this); } + public Alloc getCopy() { + return new Alloc(this); + } @Override public T accept(EventVisitor visitor) { @@ -133,7 +162,7 @@ public T accept(EventVisitor visitor) { public BooleanFormula encodeExec(EncodingContext ctx) { return ctx.getBooleanFormulaManager().and( super.encodeExec(ctx), - ctx.getExpressionEncoder().equalAt(ctx.result(this), this, getAllocatedObject(), this) + ctx.getExpressionEncoder().assignEqualAt(ctx.result(this), this, getAllocatedObject(), this) ); } } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/ExecutionStatus.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/ExecutionStatus.java index cf1de94589..3ff33e093e 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/ExecutionStatus.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/ExecutionStatus.java @@ -11,7 +11,7 @@ import java.util.Map; import java.util.Set; -import static com.dat3m.dartagnan.encoding.ExpressionEncoder.ConversionMode.RIGHT_TO_LEFT; +import static com.dat3m.dartagnan.encoding.ExpressionEncoder.ConversionMode.CAST; public class ExecutionStatus extends AbstractEvent implements RegWriter, EventUser { @@ -20,6 +20,7 @@ public class ExecutionStatus extends AbstractEvent implements RegWriter, EventUs private final boolean trackDep; public ExecutionStatus(Register register, Event event, boolean trackDep) { + // assert !(register.getType() instanceof PointerType); this.register = register; this.event = event; this.trackDep = trackDep; @@ -71,7 +72,7 @@ public BooleanFormula encodeExec(EncodingContext context) { final Expression notExec = exprEncoder.wrap(bmgr.not(context.execution(event))); return bmgr.and( super.encodeExec(context), - context.getExpressionEncoder().equal(context.result(this), notExec, RIGHT_TO_LEFT) + context.getExpressionEncoder().assignEqual(context.result(this), notExec, CAST) ); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/Local.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/Local.java index 30df6848ef..3a76a30420 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/Local.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/core/Local.java @@ -63,7 +63,7 @@ public String defaultString() { public BooleanFormula encodeExec(EncodingContext ctx) { return ctx.getBooleanFormulaManager().and( super.encodeExec(ctx), - ctx.getExpressionEncoder().equalAt(ctx.result(this), this, expr, this) + ctx.getExpressionEncoder().assignEqualAt(ctx.result(this), this, expr, this) ); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/lang/linux/LKMMAddUnless.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/lang/linux/LKMMAddUnless.java index d5fbb15cd7..c1f0378df3 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/lang/linux/LKMMAddUnless.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/event/lang/linux/LKMMAddUnless.java @@ -2,6 +2,7 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionVisitor; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.event.EventVisitor; import com.dat3m.dartagnan.program.event.MemoryAccess; diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/Memory.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/Memory.java index dbd2bfa730..3a32cb023e 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/Memory.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/Memory.java @@ -4,6 +4,7 @@ import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.program.event.core.Alloc; import com.google.common.base.Preconditions; @@ -14,7 +15,7 @@ public class Memory { private final ArrayList objects = new ArrayList<>(); - private final Type ptrType = TypeFactory.getInstance().getPointerType(); + private final PointerType ptrType = TypeFactory.getInstance().getPointerType(); private final IntegerType archType = TypeFactory.getInstance().getArchType(); private final Expression defaultAlignment = ExpressionFactory.getInstance().makeValue(8, archType); private final boolean bigEndian; diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/MemoryObject.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/MemoryObject.java index 8d11fc0d43..f2618e38ec 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/MemoryObject.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/MemoryObject.java @@ -19,7 +19,7 @@ /** * Associated with an array of memory locations. */ -public class MemoryObject extends LeafExpressionBase { +public class MemoryObject extends LeafExpressionBase { // TODO: (TH) I think is mostly useless. // Its only benefit is that we can have different memory objects with the same name (but why would we?) @@ -34,7 +34,7 @@ public class MemoryObject extends LeafExpressionBase { private final Map initialValues = new TreeMap<>(); - MemoryObject(int id, Expression size, Expression alignment, Alloc allocationSite, Type ptrType) { + MemoryObject(int id, Expression size, Expression alignment, Alloc allocationSite, PointerType ptrType) { super(ptrType); final TypeFactory types = TypeFactory.getInstance(); Preconditions.checkArgument(size.getType() instanceof IntegerType, "Size %s must be of integer type.", size); @@ -80,7 +80,7 @@ public int getKnownSize() { public boolean hasKnownAlignment() { return alignment instanceof IntLiteral; } public int getKnownAlignment() { Preconditions.checkState(hasKnownAlignment()); - return ((IntLiteral)alignment).getValueAsInt(); + return ((IntLiteral) alignment).getValueAsInt(); } public boolean isInRange(int offset) { @@ -118,8 +118,10 @@ public void setInitialValue(int offset, Expression value) { setInitialValue(offset + innerOffset, structElements.get(i)); } } else if (value.getType() instanceof IntegerType - || value.getType() instanceof FloatType - || value.getType() instanceof BooleanType) { + || value.getType() instanceof BooleanType + || value.getType() instanceof MemoryType + || value.getType() instanceof PointerType + || value.getType() instanceof FloatType) { checkArgument(isInRange(offset), "array index out of bounds"); initialValues.put(offset, value); } else { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/ScopedPointerVariable.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/ScopedPointerVariable.java index 6d7ac5158d..58fb998682 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/ScopedPointerVariable.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/ScopedPointerVariable.java @@ -4,8 +4,8 @@ import com.dat3m.dartagnan.expression.type.ScopedPointerType; public class ScopedPointerVariable extends ScopedPointer { - public ScopedPointerVariable(String id, ScopedPointerType pointerType, MemoryObject address) { - super(id, pointerType, address); + public ScopedPointerVariable(String id, ScopedPointerType spt, MemoryObject address) { + super(id, spt, address); } @Override diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/VirtualMemoryObject.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/VirtualMemoryObject.java index a3848c70b7..e155c07a64 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/VirtualMemoryObject.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/memory/VirtualMemoryObject.java @@ -2,6 +2,7 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.Type; +import com.dat3m.dartagnan.expression.type.PointerType; import static com.google.common.base.Preconditions.checkArgument; @@ -14,7 +15,7 @@ public class VirtualMemoryObject extends MemoryObject { // the generic address of this virtual address private final VirtualMemoryObject genericAddress; - VirtualMemoryObject(int index, Expression size, Expression alignment, boolean generic, VirtualMemoryObject alias, Type ptrType) { + VirtualMemoryObject(int index, Expression size, Expression alignment, boolean generic, VirtualMemoryObject alias, PointerType ptrType) { super(index, size, alignment, null, ptrType); checkArgument(generic || alias != null, "Non-generic VirtualMemoryObject must have alias target."); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/DynamicSpinLoopDetection.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/DynamicSpinLoopDetection.java index 88374088eb..ac8436fefe 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/DynamicSpinLoopDetection.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/DynamicSpinLoopDetection.java @@ -67,7 +67,7 @@ public void run(Program program) { AnalysisStats stats = new AnalysisStats(0); for (Function func : Iterables.concat(program.getFunctions(), program.getThreads())) { final List loops = computeLoopData(func, loopAnalysis); - final LiveRegistersAnalysis liveRegsAna = LiveRegistersAnalysis.forFunction(func); + final LiveRegistersAnalysis liveRegsAna = LiveRegistersAnalysis.forFunction(func); loops.forEach(loop -> this.collectSideEffects(loop, liveRegsAna)); loops.forEach(this::instrumentLoop); stats = stats.add(collectStats(loops)); @@ -212,8 +212,13 @@ private LoopData(LoopAnalysis.LoopInfo loopInfo) { this.loopInfo = loopInfo; } - private Event getStart() { return loopInfo.iterations().get(0).getIterationStart(); } - private Event getEnd() { return loopInfo.iterations().get(0).getIterationEnd(); } + private Event getStart() { + return loopInfo.iterations().get(0).getIterationStart(); + } + + private Event getEnd() { + return loopInfo.iterations().get(0).getIterationEnd(); + } @Override public String toString() { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/GEPToAddition.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/GEPToAddition.java index 9e7924dfd0..24f7c1ed7a 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/GEPToAddition.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/GEPToAddition.java @@ -40,7 +40,8 @@ */ public class GEPToAddition implements ProgramProcessor { - private GEPToAddition() {} + private GEPToAddition() { + } public static GEPToAddition newInstance() { return new GEPToAddition(); @@ -75,7 +76,7 @@ public Expression visitGEPExpression(GEPExpr gep) { Expression totalOffset = expressions.makeMul(expressions.makeValue(baseSize, offsetType), indices.get(0).accept(this)); for (Expression index : indices.subList(1, indices.size())) { - index = index.accept(this); + index = index.accept(this); Expression offset; if (indexingType instanceof AggregateType aggType && index instanceof IntLiteral lit) { final int intIndex = lit.getValueAsInt(); @@ -97,8 +98,8 @@ public Expression visitGEPExpression(GEPExpr gep) { } final Expression base = gep.getBase().accept(this); - final Expression castOffset = expressions.makeCast(totalOffset, base.getType(), true); - return expressions.makeAdd(base, castOffset); + final Expression castOffset = expressions.makeCast(totalOffset, types.getArchType(), true); + return expressions.makePtrAdd(base, castOffset); } } } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Inlining.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Inlining.java index 14ef8c4142..ff70348830 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Inlining.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Inlining.java @@ -2,10 +2,14 @@ import com.dat3m.dartagnan.exception.MalformedProgramException; import com.dat3m.dartagnan.expression.Expression; +import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.program.Thread; import com.dat3m.dartagnan.program.*; import com.dat3m.dartagnan.program.event.Event; import com.dat3m.dartagnan.program.event.EventFactory; +import com.dat3m.dartagnan.expression.ExpressionFactory; + import com.dat3m.dartagnan.program.event.Tag; import com.dat3m.dartagnan.program.event.core.ControlBarrier; import com.dat3m.dartagnan.program.event.core.Label; @@ -37,7 +41,10 @@ public class Inlining implements ProgramProcessor { secure = true) private int bound = 1; - private Inlining() {} + private static final ExpressionFactory expressions = ExpressionFactory.getInstance(); + + private Inlining() { + } public static Inlining fromConfig(Configuration config) throws InvalidConfigurationException { Inlining process = new Inlining(); @@ -64,7 +71,9 @@ public void run(Program program) { } } - private record Snapshot(String name, List parameters, List events, List registers, boolean isVarArgs) {} + private record Snapshot(String name, List parameters, List events, List registers, + boolean isVarArgs) { + } private boolean canInline(FunctionCall call) { return call.isDirectCall() && call.getCalledFunction().hasBody(); @@ -103,10 +112,13 @@ private int getScopeCount(Function function) { // Advance scope counter. for (Register r : function.getRegisters()) { final int i = r.getName().indexOf(":"); - if (i == -1) { continue; } + if (i == -1) { + continue; + } try { scope = Integer.max(scope, Integer.parseInt(r.getName().substring(0, i))); - } catch (NumberFormatException ignore) {} + } catch (NumberFormatException ignore) { + } } return scope; } @@ -142,7 +154,14 @@ private static Event inlineBody(FunctionCall call, Snapshot callTarget, int scop final ArrayList parameterAssignments = new ArrayList<>(); for (int j = 0; j < callTarget.parameters.size(); j++) { final Register register = registerMap.get(callTarget.parameters.get(j)); - parameterAssignments.add(newLocal(register, arguments.get(j))); + if (register.getType() instanceof PointerType) { + Expression v = expressions.makeCast(arguments.get(j), (PointerType) register.getType()); + parameterAssignments.add(newLocal(register, v)); + } else { + Expression v = arguments.get(j); + parameterAssignments.add(newLocal(register, v)); + } + // todo check } // --------- Inline call --------- diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Intrinsics.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Intrinsics.java index 070cce30e4..843827392b 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Intrinsics.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Intrinsics.java @@ -6,8 +6,10 @@ import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.integers.IntBinaryOp; import com.dat3m.dartagnan.expression.integers.IntLiteral; +import com.dat3m.dartagnan.expression.pointers.NullLiteral; import com.dat3m.dartagnan.expression.type.FunctionType; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.IRHelper; @@ -55,13 +57,14 @@ public class Intrinsics { @Option(name = REMOVE_ASSERTION_OF_TYPE, description = "Remove assertions of type [user, overflow, invalidderef, unknown_function].", - toUppercase=true, + toUppercase = true, secure = true) private EnumSet notToInline = EnumSet.noneOf(AssertionType.class); - private enum AssertionType { USER, OVERFLOW, INVALIDDEREF, UNKNOWN_FUNCTION } + private enum AssertionType {USER, OVERFLOW, INVALIDDEREF, UNKNOWN_FUNCTION} private final boolean detectMixedSizeAccesses; + private final IntegerType archType = types.getArchType(); private static final TypeFactory types = TypeFactory.getInstance(); private static final ExpressionFactory expressions = ExpressionFactory.getInstance(); @@ -76,7 +79,7 @@ private Intrinsics(boolean msa) { public static Intrinsics newInstance() { return new Intrinsics(false); } - + public static Intrinsics fromConfig(Configuration config, boolean detectMixedSizeAccesses) throws InvalidConfigurationException { Intrinsics instance = new Intrinsics(detectMixedSizeAccesses); @@ -236,10 +239,10 @@ public enum Info { STD_SLEEP("sleep", false, false, true, true, Intrinsics::inlineAsZero), STD_FFS(List.of("ffs", "ffsl", "ffsll"), false, false, true, true, Intrinsics::inlineFfs), // --------------------------- UBSAN --------------------------- - UBSAN_OVERFLOW(List.of("__ubsan_handle_add_overflow", "__ubsan_handle_sub_overflow", + UBSAN_OVERFLOW(List.of("__ubsan_handle_add_overflow", "__ubsan_handle_sub_overflow", "__ubsan_handle_divrem_overflow", "__ubsan_handle_mul_overflow", "__ubsan_handle_negate_overflow", "__ubsan_handle_shift_out_of_bounds"), false, false, false, true, Intrinsics::inlineIntegerOverflow), - UBSAN_TYPE_MISSMATCH(List.of("__ubsan_handle_type_mismatch_v1"), + UBSAN_TYPE_MISSMATCH(List.of("__ubsan_handle_type_mismatch_v1"), false, false, false, true, Intrinsics::inlineInvalidDereference), // ------------------------- Unknown function --------------------------- MISSING(List.of(), false, false, false, true, Intrinsics::inlineUnknownFunction), @@ -253,7 +256,7 @@ public enum Info { private final Replacer replacer; Info(List variants, boolean writesMemory, boolean readsMemory, boolean alwaysReturns, boolean isEarly, - Replacer replacer) { + Replacer replacer) { this.variants = variants; this.writesMemory = writesMemory; this.readsMemory = readsMemory; @@ -263,7 +266,7 @@ public enum Info { } Info(String name, boolean writesMemory, boolean readsMemory, boolean alwaysReturns, boolean isEarly, - Replacer replacer) { + Replacer replacer) { this(List.of(name), writesMemory, readsMemory, alwaysReturns, isEarly, replacer); } @@ -288,7 +291,7 @@ public boolean isEarly() { } private boolean matches(String funcName) { - boolean isPrefix = switch(this) { + boolean isPrefix = switch (this) { case LLVM, LLVM_ASSUME, LLVM_META, LLVM_MEMCPY, LLVM_MEMSET, LLVM_EXPECT, LLVM_OBJECTSIZE -> true; default -> false; }; @@ -313,12 +316,13 @@ private void markIntrinsics(Program program) { .findFirst() .ifPresentOrElse(func::setIntrinsicInfo, () -> { missingSymbols.add(funcName); - func.setIntrinsicInfo(Info.MISSING);}); + func.setIntrinsicInfo(Info.MISSING); + }); } } if (!missingSymbols.isEmpty()) { logger.warn(missingSymbols.stream().collect(Collectors.joining(", ", "Unknown intrinsics ", "")) + - ". Detecting calls to unknown functions requires --property=program_spec."); + ". Detecting calls to unknown functions requires --property=program_spec."); } } @@ -426,7 +430,7 @@ private List inlinePthreadCreate(FunctionCall call) { final Register resultRegister = getResultRegister(call); assert resultRegister.getType() instanceof IntegerType; - final Register tidReg = call.getFunction().newUniqueRegister("__tid", types.getArchType()); + final Register tidReg = call.getFunction().newUniqueRegister("__tid", archType); final Event createEvent = newDynamicThreadCreate(tidReg, PTHREAD_THREAD_TYPE, targetFunction, List.of(argument)); final Label skipAttrLabel = newLabel("__pthread_create_skip_attr"); final Label skipDetachLabel = newLabel("__pthread_create_skip_detach"); @@ -454,7 +458,9 @@ private List inlinePthreadJoin(FunctionCall call) { assert arguments.size() == 2; final Expression tidExpr = arguments.get(0); final Expression returnAddr = arguments.get(1); - final boolean hasReturnAddr = !(returnAddr instanceof IntLiteral lit && lit.isZero()); + // final boolean hasReturnAddr = !(returnAddr instanceof IntLiteral lit && lit.isZero()); + assert returnAddr.getType() instanceof PointerType; + final boolean hasReturnAddr = !(returnAddr instanceof NullLiteral); // is this enough? final Register statusRegister = getResultRegister(call); final IntegerType statusType = (IntegerType) statusRegister.getType(); @@ -583,10 +589,11 @@ private IntegerType getPthreadAttrType() { return types.getIntegerType(2); } - private record PthreadAttrImplementation(Expression out, List errorChecks) {} + private record PthreadAttrImplementation(Expression out, List errorChecks) { + } private PthreadAttrImplementation inlinePthreadAttrDetachState(Expression oldValue, Expression detachstate, - Label returnEINVAL) { + Label returnEINVAL) { // POSIX defines these two named constants of type int. // see https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/pthread.h.html //TODO values may vary by platform @@ -904,7 +911,7 @@ private List inlinePthreadRwlockDestroy(FunctionCall call) { final Register errorRegister = getResultRegisterAndCheckArguments(1, call); //TODO store a value such that later uses of the lock fail //final Expression lock = call.getArguments().get(0); - //final Expression finalizedValue = expressions.makeZero(types.getArchType()); + //final Expression finalizedValue = expressions.makeZero(archType); return List.of( //EventFactory.newStore(lock, finalizedValue) assignSuccess(errorRegister) @@ -1030,7 +1037,7 @@ private List inlinePthreadRwlockUnlock(FunctionCall call) { } private IntegerType getRwlockDatatype() { - return types.getArchType(); + return archType; } private IntLiteral getRwlockUnlockedValue() { @@ -1107,7 +1114,7 @@ private List inlineAssert(FunctionCall call, AssertionType skip, String e } private List inlineVerifierAssert(FunctionCall call, AssertionType skip, String errorMsg) { - if(notToInline.contains(skip)) { + if (notToInline.contains(skip)) { return List.of(); } assert call.getArguments().size() == 1; @@ -1138,7 +1145,7 @@ private List inlineUnknownFunction(FunctionCall call) { replacement.addAll(inlineCallAsNonDet(call)); } replacement.addAll(inlineAssert(call, AssertionType.UNKNOWN_FUNCTION, - "Calling unknown function " + call.getCalledFunction().getName())); + "Calling unknown function " + call.getCalledFunction().getName())); return replacement; } @@ -1621,7 +1628,7 @@ private List inlineNonDet(FunctionCall call) { private List inlineMemCpy(FunctionCall call) { final Function caller = call.getFunction(); final Expression dest = call.getArguments().get(0); - final Expression src = call.getArguments().get(1); + final Expression src = call.getArguments().get(1); // null ptr !! final Expression countExpr = call.getArguments().get(2); // final Expression isVolatile = call.getArguments.get(3) // LLVM's memcpy has an extra argument @@ -1632,13 +1639,13 @@ private List inlineMemCpy(FunctionCall call) { final int count = countValue.getValueAsInt(); final List replacement = new ArrayList<>(2 * count + 1); - //FIXME without MSA detection, each byte is treated as a 64-bit value. - final IntegerType type = detectMixedSizeAccesses ? types.getIntegerType(8 * count) : types.getArchType(); + // FIXME without MSA detection, each byte is treated as a 64-bit value. + final IntegerType type = detectMixedSizeAccesses ? types.getIntegerType(8 * count) : archType; final int typeSize = detectMixedSizeAccesses ? count : 1; for (int i = 0; i < count; i += typeSize) { - final Expression offset = expressions.makeValue(i, types.getArchType()); - final Expression srcAddr = expressions.makeAdd(src, offset); - final Expression destAddr = expressions.makeAdd(dest, offset); + final Expression offset = expressions.makeValue(i, archType); + final Expression srcAddr = expressions.makePtrAdd(src, offset); + final Expression destAddr = expressions.makePtrAdd(dest, offset); final Register reg = caller.getOrNewRegister("__memcpy_" + i, type); final Event load = EventFactory.newLoad(reg, srcAddr); @@ -1661,7 +1668,7 @@ private List inlineMemCpy(FunctionCall call) { // https://en.cppreference.com/w/c/string/byte/memcpy private List inlineMemCpyS(FunctionCall call) { // Cast guaranteed to success by the return type of memcpy_s - final Register resultRegister = ((ValueFunctionCall)call).getResultRegister(); + final Register resultRegister = ((ValueFunctionCall) call).getResultRegister(); final Function caller = call.getFunction(); final Expression dest = call.getArguments().get(0); final Expression destszExpr = call.getArguments().get(1); @@ -1681,33 +1688,38 @@ private List inlineMemCpyS(FunctionCall call) { final int destsz = destszValue.getValueAsInt(); // Runtime checks - final Expression nullExpr = expressions.makeZero(types.getArchType()); + final Expression nullExpr = expressions.makeNullLiteral(); final Expression destIsNull = expressions.makeEQ(dest, nullExpr); final Expression srcIsNull = expressions.makeEQ(src, nullExpr); // We assume RSIZE_MAX = 2^64-1 - final Expression rsize_max = expressions.makeValue(BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE), types.getArchType()); - // These parameters have type rsize_t/size_t which we model as types.getArchType(), thus the cast - final Expression castDestszExpr = expressions.makeCast(destszExpr, types.getArchType()); - final Expression castCountExpr = expressions.makeCast(countExpr, types.getArchType()); + final Expression rsize_max = expressions.makeValue(BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE), archType); + // These parameters have type rsize_t/size_t which we model as archType, thus the cast + final Expression castDestszExpr = expressions.makeCast(destszExpr, archType); + final Expression castCountExpr = expressions.makeCast(countExpr, archType); final Expression invalidDestsz = expressions.makeGT(castDestszExpr, rsize_max, false); final Expression countGtMax = expressions.makeGT(castCountExpr, rsize_max, false); final Expression countGtdestszExpr = expressions.makeGT(castCountExpr, castDestszExpr, false); final Expression invalidCount = expressions.makeOr(countGtMax, countGtdestszExpr); final Expression overlap = expressions.makeAnd( - expressions.makeGT(expressions.makeAdd(src, castCountExpr), dest, false), - expressions.makeGT(expressions.makeAdd(dest, castCountExpr), src, false)); + expressions.makeGT( + expressions.makeCast(expressions.makePtrAdd(src, castCountExpr), archType) + , expressions.makeCast(dest, archType), false), + expressions.makeGT( + expressions.makeCast(expressions.makePtrAdd(dest, castCountExpr), archType) + , expressions.makeCast(src, archType), false)); + final List replacement = new ArrayList<>(); - + Label check1 = EventFactory.newLabel("__memcpy_s_check_1"); Label check2 = EventFactory.newLabel("__memcpy_s_check_2"); Label success = EventFactory.newLabel("__memcpy_s_success"); Label end = EventFactory.newLabel("__memcpy_s_end"); - Expression errorCodeFail = expressions.makeOne((IntegerType)resultRegister.getType()); - Expression errorCodeSuccess = expressions.makeZero((IntegerType)resultRegister.getType()); + Expression errorCodeFail = expressions.makeOne((IntegerType) resultRegister.getType()); + Expression errorCodeSuccess = expressions.makeZero((IntegerType) resultRegister.getType()); // Condition 1: dest == NULL or destsz > RSIZE_MAX ----> return error > 0 final Expression cond1 = expressions.makeOr(destIsNull, invalidDestsz); @@ -1715,10 +1727,10 @@ private List inlineMemCpyS(FunctionCall call) { CondJump skipRest1 = EventFactory.newGoto(end); Local retError1 = EventFactory.newLocal(resultRegister, errorCodeFail); replacement.addAll(List.of( - check1, - skipE1, - retError1, - skipRest1 + check1, + skipE1, + retError1, + skipRest1 )); // Condition 2: dest != NULL && destsz <= RSIZE_MAX && (src == NULL || count > destsz || overlap(src, dest)) @@ -1729,31 +1741,31 @@ private List inlineMemCpyS(FunctionCall call) { CondJump skipRest2 = EventFactory.newGoto(end); Local retError2 = EventFactory.newLocal(resultRegister, errorCodeFail); replacement.addAll(List.of( - check2, - skipE2 + check2, + skipE2 )); for (int i = 0; i < destsz; i++) { - final Expression offset = expressions.makeValue(i, types.getArchType()); - final Expression destAddr = expressions.makeAdd(dest, offset); - final Expression zero = expressions.makeZero(types.getArchType()); + final Expression offset = expressions.makeValue(i, archType); + final Expression destAddr = expressions.makePtrAdd(dest, offset); + final Expression zero = expressions.makeZero(archType); replacement.add( - newStore(destAddr, zero) + newStore(destAddr, zero) ); } replacement.addAll(List.of( - retError2, - skipRest2 + retError2, + skipRest2 )); // Else ----> return error = 0 and do the actual copy Local retSuccess = EventFactory.newLocal(resultRegister, errorCodeSuccess); - replacement.add(success); + replacement.add(success); for (int i = 0; i < count; i++) { - final Expression offset = expressions.makeValue(i, types.getArchType()); - final Expression srcAddr = expressions.makeAdd(src, offset); - final Expression destAddr = expressions.makeAdd(dest, offset); + final Expression offset = expressions.makeValue(i, archType); + final Expression srcAddr = expressions.makePtrAdd(src, offset); + final Expression destAddr = expressions.makePtrAdd(dest, offset); // FIXME: We have no other choice but to load ptr-sized chunks for now - final Register reg = caller.getOrNewRegister("__memcpy_" + i, types.getArchType()); + final Register reg = caller.getOrNewRegister("__memcpy_" + i, archType); replacement.addAll(List.of( EventFactory.newLoad(reg, srcAddr), @@ -1761,8 +1773,8 @@ private List inlineMemCpyS(FunctionCall call) { )); } replacement.addAll(List.of( - retSuccess, - end + retSuccess, + end )); return replacement; @@ -1773,7 +1785,7 @@ private List inlineMemCmp(FunctionCall call) { final Expression src1 = call.getArguments().get(0); final Expression src2 = call.getArguments().get(1); final Expression numExpr = call.getArguments().get(2); - final Register returnReg = ((ValueFunctionCall)call).getResultRegister(); + final Register returnReg = ((ValueFunctionCall) call).getResultRegister(); if (!(numExpr instanceof IntLiteral numValue)) { final String error = "Cannot handle memcmp with dynamic num argument: " + call; @@ -1784,7 +1796,7 @@ private List inlineMemCmp(FunctionCall call) { final List replacement = new ArrayList<>(4 * count + 1); final Label endCmp = EventFactory.newLabel("__memcmp_end"); for (int i = 0; i < count; i++) { - final Expression offset = expressions.makeValue(i, types.getArchType()); + final Expression offset = expressions.makeValue(i, archType); final Expression src1Addr = expressions.makeAdd(src1, offset); final Expression src2Addr = expressions.makeAdd(src2, offset); //FIXME: This method should properly load byte chunks and compare them (unsigned). @@ -1834,10 +1846,10 @@ private List inlineMemSet(FunctionCall call) { assert fill == 0; final Expression zero = expressions.makeValue(fill, types.getByteType()); - final List replacement = new ArrayList<>( count + 1); + final List replacement = new ArrayList<>(count + 1); for (int i = 0; i < count; i++) { - final Expression offset = expressions.makeValue(i, types.getArchType()); - final Expression destAddr = expressions.makeAdd(dest, offset); + final Expression offset = expressions.makeValue(i, archType); + final Expression destAddr = expressions.makePtrAdd(dest, offset); replacement.add(newStore(destAddr, zero)); } @@ -1854,7 +1866,7 @@ private List inlineLLVMThreadLocal(FunctionCall call) { final Expression exp = call.getArguments().get(0); checkArgument(exp instanceof MemoryObject object && object.isThreadLocal(), "Calling thread-local intrinsic on a non-thread-local object \"%s\"", call); return List.of( - EventFactory.newLocal(resultReg, exp) + EventFactory.newLocal(resultReg, exp) ); } @@ -1868,7 +1880,7 @@ private List inlineFfs(FunctionCall call) { final Type outputType = resultReg.getType(); checkArgument(outputType instanceof IntegerType, "Non-integer %s type for \"%s\".", name, outputType); - final IntegerType inputType = (IntegerType)input.getType(); + final IntegerType inputType = (IntegerType) input.getType(); final Expression cttz = expressions.makeCTTZ(input); final Expression widthExpr = expressions.makeValue(BigInteger.valueOf(inputType.getBitWidth()), inputType); final Expression count = expressions.makeAdd(cttz, expressions.makeOne(inputType)); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/LogThreadStatistics.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/LogThreadStatistics.java index 3573ee0062..6864664a44 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/LogThreadStatistics.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/LogThreadStatistics.java @@ -19,9 +19,12 @@ public class LogThreadStatistics implements ProgramProcessor { private static final Logger logger = LoggerFactory.getLogger(LogThreadStatistics.class); - private LogThreadStatistics() { } + private LogThreadStatistics() { + } - public static LogThreadStatistics newInstance() { return new LogThreadStatistics(); } + public static LogThreadStatistics newInstance() { + return new LogThreadStatistics(); + } @Override public void run(Program program) { @@ -53,7 +56,7 @@ public void run(Program program) { } } - int numNonInitThreads = (int)threads.stream().filter(t -> !(t.getEntry().getSuccessor() instanceof Init)).count(); + int numNonInitThreads = (int) threads.stream().filter(t -> !(t.getEntry().getSuccessor() instanceof Init)).count(); int staticAddressSpaceSize = program.getMemory().getObjects().stream() .filter(m -> m.isStaticallyAllocated() && m.hasKnownSize()).mapToInt(MemoryObject::getKnownSize).sum(); int dynamicAddressSpaceSize = program.getMemory().getObjects().stream() diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/LoopUnrolling.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/LoopUnrolling.java index 7f12c348de..fb62175d67 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/LoopUnrolling.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/LoopUnrolling.java @@ -158,7 +158,7 @@ private Map computeLoopBoundsMap(Function func, int defaultBo } // Merge with loaded bounds if those exist. - if(globalLoopBoundsMap.containsKey(func)) { + if (globalLoopBoundsMap.containsKey(func)) { final Map loopBoundsMapFromFile = globalLoopBoundsMap.get(func); loopBoundsMapFromFile.forEach((key, value) -> loopBoundsMap.merge(key, value, Math::max)); } @@ -213,7 +213,7 @@ private void unrollLoop(CondJump loopBackJump, int bound) { } // Rename label of iteration. - final Label loopBeginCopy = ((Label)copyCtx.get(loopBegin)); + final Label loopBeginCopy = ((Label) copyCtx.get(loopBegin)); loopBeginCopy.setName(loopId); loopBeginCopy.addTags(Tag.NOOPT); } @@ -282,7 +282,7 @@ private void dumpLoopBoundsMapToFile(Program program, Map loopBoundsMap : loopBounds.values()) { for (Map.Entry entry : loopBoundsMap.entrySet()) { final CondJump loopJump = entry.getKey(); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/MemToReg.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/MemToReg.java index fba0f5a177..4298bbe8e4 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/MemToReg.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/MemToReg.java @@ -6,6 +6,7 @@ import com.dat3m.dartagnan.expression.integers.IntBinaryExpr; import com.dat3m.dartagnan.expression.integers.IntBinaryOp; import com.dat3m.dartagnan.expression.integers.IntLiteral; +import com.dat3m.dartagnan.expression.pointers.PtrAddExpr; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.IRHelper; @@ -147,7 +148,7 @@ private Register newRegister(Alloc allocation, Field field) { } private List promoteAccess(MemoryCoreEvent event, AddressOffset access, - Map promotableObjects) { + Map promotableObjects) { final Promotable object = access == null ? null : promotableObjects.get(access.base); final Type accessType = event.getAccessType(); final int accessSize = types.getMemorySizeInBytes(accessType); @@ -227,7 +228,8 @@ private boolean overlaps(Field other) { } } - private sealed interface AddressOffsets {} + private sealed interface AddressOffsets { + } // Invariant: base != null private record AddressOffset(RegWriter base, long offset) implements AddressOffsets { @@ -237,7 +239,8 @@ private AddressOffset increase(long o) { } // Invariant: hint != null && !hint.isEmpty() - private record AddressOffsetSet(Set hint) implements AddressOffsets {} + private record AddressOffsetSet(Set hint) implements AddressOffsets { + } // Checks if mixed-size accesses to a promotable object were collected. private static boolean hasMixedAccesses(Set registerTypes) { @@ -419,7 +422,8 @@ private void publishRegisters(Set registers) { } } - private record RegisterOffset(Register register, long offset) {} + private record RegisterOffset(Register register, long offset) { + } private AddressOffset computeAddressOffsetFromState(Expression expression) { final RegisterOffset gep = matchGEP(expression); @@ -431,13 +435,19 @@ private AddressOffset computeAddressOffsetFromState(Expression expression) { private static RegisterOffset matchGEP(Expression expression) { long sum = 0; while (!(expression instanceof Register register)) { - if (!(expression instanceof IntBinaryExpr bin) || - bin.getKind() != IntBinaryOp.ADD || - !(bin.getRight() instanceof IntLiteral offset)) { - return null; + if (expression instanceof IntBinaryExpr bin && + bin.getKind() == IntBinaryOp.ADD && + bin.getRight() instanceof IntLiteral offset) { + sum += offset.getValueAsLong(); + expression = bin.getLeft(); + continue; } - sum += offset.getValueAsLong(); - expression = bin.getLeft(); + if (expression instanceof PtrAddExpr ptr && ptr.getOffset() instanceof IntLiteral offset) { + sum += offset.getValueAsLong(); + expression = ptr.getBase(); + continue; + } + return null; } return new RegisterOffset(register, sum); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NaiveDevirtualisation.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NaiveDevirtualisation.java index 83f8fce04b..dba6de7ee9 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NaiveDevirtualisation.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NaiveDevirtualisation.java @@ -37,7 +37,9 @@ public class NaiveDevirtualisation implements ProgramProcessor { private NaiveDevirtualisation() { } - public static NaiveDevirtualisation newInstance() { return new NaiveDevirtualisation(); } + public static NaiveDevirtualisation newInstance() { + return new NaiveDevirtualisation(); + } @Override public void run(Program program) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NaiveLoopBoundAnnotation.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NaiveLoopBoundAnnotation.java index 703ebeb7f8..cb238282d5 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NaiveLoopBoundAnnotation.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NaiveLoopBoundAnnotation.java @@ -4,6 +4,7 @@ import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.integers.*; import com.dat3m.dartagnan.expression.misc.ITEExpr; +import com.dat3m.dartagnan.expression.pointers.PtrAddExpr; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.analysis.DominatorAnalysis; @@ -108,6 +109,7 @@ public void run(Function function) { continue; } final Expression negatedGuard = jump.getGuard(); + // Now we check for the guard shape "r != 0" (i.e., we exit when r == 0 due to the inversion). if (!(negatedGuard instanceof IntCmpExpr cond && cond.getLeft() instanceof Register r @@ -137,15 +139,21 @@ private Event findUniqueIncrement(List events, Register register, } // We found the non-trivial source. Check that this is indeed the desired increment: // (1) It is an addition operation - if (!(source instanceof Local local && local.getExpr() instanceof IntBinaryExpr add && add.getKind() == IntBinaryOp.ADD)) { - return null; + if (source instanceof Local local && local.getExpr() instanceof IntBinaryExpr add && add.getKind() == IntBinaryOp.ADD) { + // (2) The addition is a positive increment of the register. + if (add.getLeft().equals(register) && add.getRight() instanceof IntLiteral c && c.getValue().signum() > 0) { + return local; + } } - // (2) The addition is a positive increment of the register. - if (!(add.getLeft().equals(register) && add.getRight() instanceof IntLiteral c && c.getValue().signum() > 0)) { - return null; + // same as above + if (source instanceof Local local && local.getExpr() instanceof PtrAddExpr add) { + if (add.getBase().equals(register) && add.getOffset() instanceof IntLiteral c && c.getValue().signum() > 0) { + return local; + } } + return null; // TODO: return also the increment - return local; + } private Expression computeLoopBound(List events, Register exitReg, Register counterReg, int counterRegInitVal, diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NonterminationDetection.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NonterminationDetection.java index 9f8c9c04df..5ce1df8d72 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NonterminationDetection.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/NonterminationDetection.java @@ -43,7 +43,7 @@ number of times (incomplete) */ @Options public class NonterminationDetection implements ProgramProcessor { - + private static final Logger logger = LoggerFactory.getLogger(NonterminationDetection.class); public enum Mode { @@ -57,7 +57,8 @@ public enum Mode { secure = true) private Mode mode = Mode.FULL; - private NonterminationDetection() { } + private NonterminationDetection() { + } public static NonterminationDetection newInstance() { return new NonterminationDetection(); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/ProcessingManager.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/ProcessingManager.java index 8532a28fed..d3d06c4834 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/ProcessingManager.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/ProcessingManager.java @@ -80,7 +80,7 @@ public class ProcessingManager implements ProgramProcessor { secure = true) private boolean printAfterProcessing = false; -// ====================================================================== + // ====================================================================== private ProcessingManager(Configuration config) throws InvalidConfigurationException { config.inject(this); final Intrinsics intrinsics = Intrinsics.fromConfig(config, detectMixedSizeAccesses); @@ -130,6 +130,7 @@ private ProcessingManager(Configuration config) throws InvalidConfigurationExcep simplifyFunction ), Target.FUNCTIONS, true ), + ThreadCreation.fromConfig(config), ResolveNonDetChoices.newInstance(), reduceSymmetry ? SymmetryReduction.fromConfig(config) : null, diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadCondJumps.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadCondJumps.java index 0f38f48349..7db51ee119 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadCondJumps.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadCondJumps.java @@ -2,6 +2,7 @@ import com.dat3m.dartagnan.expression.booleans.BoolUnaryExpr; import com.dat3m.dartagnan.expression.integers.IntCmpExpr; +import com.dat3m.dartagnan.expression.pointers.PtrCmpExpr; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.event.Event; import com.dat3m.dartagnan.program.event.Tag; @@ -127,6 +128,9 @@ private boolean mutuallyExclusiveIfs(CondJump jump, Event e) { if (jump.getGuard() instanceof IntCmpExpr a1 && other.getGuard() instanceof IntCmpExpr a2) { return a1.getKind().inverted() == a2.getKind() && a1.getLeft().equals(a2.getLeft()) && a1.getRight().equals(a2.getRight()); } + if (jump.getGuard() instanceof PtrCmpExpr a1 && other.getGuard() instanceof PtrCmpExpr a2) { + return a1.getKind().inverted() == a2.getKind() && a1.getLeft().equals(a2.getLeft()) && a1.getRight().equals(a2.getRight()); + } return false; } } \ No newline at end of file diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadFunctions.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadFunctions.java index 7066eb8e02..6448e380a9 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadFunctions.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadFunctions.java @@ -31,7 +31,8 @@ public class RemoveDeadFunctions implements ProgramProcessor { private static final Logger logger = LoggerFactory.getLogger(RemoveDeadFunctions.class); - private RemoveDeadFunctions() { } + private RemoveDeadFunctions() { + } public static RemoveDeadFunctions newInstance() { return new RemoveDeadFunctions(); @@ -89,7 +90,9 @@ private void liveFunctions(Function function, FunctionCollector liveFunctions) { final List> jumps = events.stream().map(e -> new HashSet()).toList(); for (int i = events.size() - 1; i >= 0; i--) { Event event = events.get(i); - if (IRHelper.isAlwaysBranching(event)) { liveRegisters.clear(); } + if (IRHelper.isAlwaysBranching(event)) { + liveRegisters.clear(); + } liveRegisters.addAll(jumps.get(i)); if (event instanceof Label label) { for (CondJump jump : label.getJumpSet()) { @@ -131,7 +134,9 @@ private static class FunctionCollector implements ExpressionInspector { private final Set collectedFunctions = new HashSet<>(); - public void reset() { collectedFunctions.clear(); } + public void reset() { + collectedFunctions.clear(); + } @Override public Expression visitFunction(Function function) { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadNullChecks.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadNullChecks.java index 677e7fd50c..dcedf9727d 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadNullChecks.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/RemoveDeadNullChecks.java @@ -5,6 +5,8 @@ import com.dat3m.dartagnan.expression.ExpressionVisitor; import com.dat3m.dartagnan.expression.integers.*; import com.dat3m.dartagnan.expression.misc.ITEExpr; +import com.dat3m.dartagnan.expression.pointers.NullLiteral; +import com.dat3m.dartagnan.expression.pointers.PtrAddExpr; import com.dat3m.dartagnan.expression.processing.ExprTransformer; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.Register; @@ -42,11 +44,14 @@ */ public class RemoveDeadNullChecks implements FunctionProcessor { - private final static Logger logger = LoggerFactory.getLogger(RemoveDeadNullChecks.class) -; - private RemoveDeadNullChecks() { } + private final static Logger logger = LoggerFactory.getLogger(RemoveDeadNullChecks.class); - public static RemoveDeadNullChecks newInstance() { return new RemoveDeadNullChecks(); } + private RemoveDeadNullChecks() { + } + + public static RemoveDeadNullChecks newInstance() { + return new RemoveDeadNullChecks(); + } private enum Sign { UNKNOWN, @@ -156,6 +161,11 @@ public Sign visitIntLiteral(IntLiteral lit) { return cmpRes > 0 ? Sign.POS : cmpRes == 0 ? Sign.NON_NEG : Sign.UNKNOWN; } + @Override + public Sign visitNullLiteral(NullLiteral lit) { + return Sign.NON_NEG; + } + @Override public Sign visitIntBinaryExpression(IntBinaryExpr expr) { final Sign leftSign = expr.getLeft().accept(this); @@ -175,6 +185,19 @@ public Sign visitIntBinaryExpression(IntBinaryExpr expr) { return Sign.UNKNOWN; } + @Override + public Sign visitPtrAddExpression(PtrAddExpr expr) { + final Sign leftSign = expr.getBase().accept(this); + final Sign rightSign = expr.getOffset().accept(this); + if (leftSign == Sign.UNKNOWN || rightSign == Sign.UNKNOWN) { + return Sign.UNKNOWN; + } + if (leftSign == Sign.POS || rightSign == Sign.POS) { + return Sign.POS; + } + return Sign.UNKNOWN; + } + @Override public Sign visitITEExpression(ITEExpr expr) { return Sign.meet(expr.getTrueCase().accept(this), expr.getFalseCase().accept(this)); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/SparseConditionalConstantPropagation.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/SparseConditionalConstantPropagation.java index 10751d6f4b..fc83dcc542 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/SparseConditionalConstantPropagation.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/SparseConditionalConstantPropagation.java @@ -3,6 +3,7 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.booleans.BoolLiteral; import com.dat3m.dartagnan.expression.integers.IntLiteral; +import com.dat3m.dartagnan.expression.pointers.NullLiteral; import com.dat3m.dartagnan.expression.processing.ExprSimplifier; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.IRHelper; @@ -71,8 +72,8 @@ public void run(Function func) { return; } final Predicate checkDoPropagate = propagateCopyAssignments - ? (expr -> expr instanceof MemoryObject || expr instanceof Function || expr instanceof IntLiteral || expr instanceof BoolLiteral || expr instanceof Register) - : (expr -> expr instanceof MemoryObject || expr instanceof Function || expr instanceof IntLiteral || expr instanceof BoolLiteral); + ? (expr -> expr instanceof MemoryObject || expr instanceof NullLiteral || expr instanceof Function || expr instanceof IntLiteral || expr instanceof BoolLiteral || expr instanceof Register) + : (expr -> expr instanceof MemoryObject || expr instanceof NullLiteral || expr instanceof Function || expr instanceof IntLiteral || expr instanceof BoolLiteral); Set reachableEvents = new HashSet<>(); Map> inflowMap = new HashMap<>(); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/SymmetryReduction.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/SymmetryReduction.java index 632c4665cd..5a2f58f5b5 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/SymmetryReduction.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/SymmetryReduction.java @@ -29,7 +29,8 @@ public class SymmetryReduction implements ProgramProcessor { private static final Logger logger = LoggerFactory.getLogger(SymmetryReduction.class); - private SymmetryReduction() { } + private SymmetryReduction() { + } public static SymmetryReduction newInstance() { return new SymmetryReduction(); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Tearing.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Tearing.java index 9350cb4ddc..3eacb41659 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Tearing.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/Tearing.java @@ -6,6 +6,7 @@ import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.processing.ExprTransformer; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.program.Function; import com.dat3m.dartagnan.program.IRHelper; @@ -130,18 +131,19 @@ private int tearInits(Program program, AliasAnalysis alias, boolean bigEndian) { final int bytes = checkBytes(init, offsets); final MemoryObject base = init.getBase(); final int initOffset = init.getOffset(); - final Expression value = init.getValue(); + final Expression value = expressions.makeToMemoryCast(init.getValue()); // Tear initial values final int frontBegin = bigEndian ? bytes - offsets.get(0) : 0; final int frontEnd = bigEndian ? bytes : offsets.get(0); - final Expression frontValue = expressions.makeIntExtract(value, 8 * frontBegin, 8 * frontEnd - 1); + + final Expression frontValue = expressions.makeMemoryExtract(value, 8 * frontBegin, 8 * frontEnd - 1); base.setInitialValue(initOffset, frontValue); for (int i = 0; i < offsets.size(); i++) { final int offset = offsets.get(i); final int next = i + 1 < offsets.size() ? offsets.get(i + 1) : bytes; final int begin = bigEndian ? bytes - next : offset; final int end = bigEndian ? bytes - offset : next; - final Expression tearedValue = expressions.makeIntExtract(value, 8 * begin, 8 * end - 1); + final Expression tearedValue = expressions.makeMemoryExtract(value, 8 * begin, 8 * end - 1); base.setInitialValue(initOffset + offset, tearedValue); } // Tear init event @@ -174,9 +176,9 @@ private void tearExpressions(Program program) { private List createTransaction(Load load, List offsets) { final int bytes = checkBytes(load, offsets); final List replacement = new ArrayList<>(); - final IntegerType addressType = checkIntegerType(load.getAddress().getType(), - "Non-integer address in '%s'", load); - checkIntegerType(load.getAccessType(), "Non-integer mixed-size access in '%s'", load); + final PointerType addressType = checkPointerType(load.getAddress().getType(), + "Non-pointer address in '%s'", load); + checkType(load.getAccessType(), "Non-integer and non-pointer mixed-size access in '%s'", load); final Function function = load.getFunction(); final Register addressRegister = toRegister(load.getAddress(), function, replacement); final List smallerRegisters = new ArrayList<>(); @@ -184,7 +186,8 @@ private List createTransaction(Load load, List offsets) { int start = i < 0 ? 0 : offsets.get(i); int end = i + 1 < offsets.size() ? offsets.get(i + 1) : bytes; assert start < end; - smallerRegisters.add(newRegister(function, types.getIntegerType(8 * (end - start)))); + smallerRegisters.add(newRegister(function, + types.getMemoryType(8 * (end - start)))); } assert bytes == smallerRegisters.stream().mapToInt(t -> types.getMemorySizeInBytes(t.getType())).sum(); final InstructionBoundary begin = load.hasTag(Tag.NO_INSTRUCTION) ? null : EventFactory.newInstructionBegin(); @@ -193,8 +196,8 @@ private List createTransaction(Load load, List offsets) { } for (int i = -1; i < offsets.size(); i++) { final int start = i < 0 ? 0 : offsets.get(i); - final Expression offset = expressions.makeValue(start, addressType); - final Expression address = expressions.makeAdd(addressRegister, offset); + final Expression offset = expressions.makeValue(start, addressType.getBitWidth()); + final Expression address = expressions.makePtrAdd(addressRegister, offset); final Load byteLoad = load.getCopy(); final Register result = smallerRegisters.get(i + 1); byteLoad.setResultRegister(result); @@ -206,8 +209,8 @@ private List createTransaction(Load load, List offsets) { final Event end = EventFactory.newInstructionEnd(begin); replacement.add(end); } - final Expression combination = expressions.makeIntConcat(smallerRegisters); - final Event computeResult = EventFactory.newLocal(load.getResultRegister(), combination); + final Expression combination = expressions.makeMemoryConcat(smallerRegisters); + final Event computeResult = EventFactory.newLocal(load.getResultRegister(), expressions.makeFromMemoryCast(combination, load.getAccessType())); replacement.add(computeResult); return replacement; } @@ -215,9 +218,9 @@ private List createTransaction(Load load, List offsets) { private List createTransaction(Store store, List offsets, Map> map, boolean bigEndian) { final int bytes = checkBytes(store, offsets); final List replacement = new ArrayList<>(); - final IntegerType addressType = checkIntegerType(store.getAddress().getType(), + final PointerType addressType = checkPointerType(store.getAddress().getType(), "Non-integer address in '%s'", store); - checkIntegerType(store.getAccessType(), "Non-integer mixed-size access in '%s'", store); + checkType(store.getAccessType(), "Non-integer mixed-size access in '%s'", store); final Function function = store.getFunction(); final Register addressRegister = toRegister(store.getAddress(), function, replacement); final Register valueRegister = toRegister(store.getMemValue(), function, replacement); @@ -227,13 +230,15 @@ private List createTransaction(Store store, List offsets, Map createTransaction(Store store, List offsets, Map result = new ArrayList<>(); - for (int offset = begin; offset < end;) { + for (int offset = begin; offset < end; ) { final Type t = typesByOffset.get(offset); result.add(new FinalMemoryValue(value.getName(), t, value.getMemoryObject(), offset)); offset += types.getMemorySizeInBytes(t); } - final Expression combined = result.size() == 1 ? result.get(0) : expressions.makeIntConcat(result); - return expressions.makeCast(combined, value.getType()); + final Expression combined = result.size() == 1 ? result.get(0) : expressions.makeMemoryConcat(result); + return expressions.makeFromMemoryCast(combined, value.getType()); } } } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/ThreadCreation.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/ThreadCreation.java index 7fdf9ef5fc..bb94fa743a 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/ThreadCreation.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/ThreadCreation.java @@ -7,10 +7,7 @@ import com.dat3m.dartagnan.expression.integers.IntBinaryOp; import com.dat3m.dartagnan.expression.integers.IntLiteral; import com.dat3m.dartagnan.expression.processing.ExprTransformer; -import com.dat3m.dartagnan.expression.type.AggregateType; -import com.dat3m.dartagnan.expression.type.FunctionType; -import com.dat3m.dartagnan.expression.type.IntegerType; -import com.dat3m.dartagnan.expression.type.TypeFactory; +import com.dat3m.dartagnan.expression.type.*; import com.dat3m.dartagnan.program.*; import com.dat3m.dartagnan.program.Thread; import com.dat3m.dartagnan.program.event.*; @@ -84,6 +81,7 @@ public class ThreadCreation implements ProgramProcessor { private final IntegerType archType = types.getArchType(); // The thread state consists of two flags: ALIVE and JOINABLE. private final IntegerType threadStateType = types.getIntegerType(2); + private final PointerType pointerType = types.getPointerType(); private ThreadCreation(Configuration config) throws InvalidConfigurationException { config.inject(this); @@ -167,7 +165,7 @@ private List createThreads(Entrypoint.Simple entrypoint) { final List replacement = eventSequence( newReleaseStore(spawnedThread.comAddress(), threadState(ALIVE | JOINABLE)), createEvent, - newLocal(tidRegister, new TIdExpr(archType, spawnedThread.thread())) + newLocal(tidRegister, new TIdExpr((IntegerType) tidRegister.getType(), spawnedThread.thread())) ); IRHelper.replaceWithMetadata(create, replacement); @@ -188,11 +186,13 @@ private void resolveDynamicThreadJoin(Program program, List threadDa for (DynamicThreadJoin join : program.getThreadEvents(DynamicThreadJoin.class)) { final Thread caller = join.getThread(); - final Expression tidExpr = join.getTid(); + final Expression tidExpr_ = join.getTid(); + // todo check if this makes sense + final Expression tidExpr = tidExpr_.getType() instanceof PointerType ? expressions.makePtrToIntCast(tidExpr_, archType) : tidExpr_; final Register joinRegister = join.getResultRegister(); - final IntegerType statusType = (IntegerType) ((AggregateType)joinRegister.getType()).getFields().get(0).type(); - final Type retValType = ((AggregateType)joinRegister.getType()).getFields().get(1).type(); + final IntegerType statusType = (IntegerType) ((AggregateType) joinRegister.getType()).getFields().get(0).type(); + final Type retValType = ((AggregateType) joinRegister.getType()).getFields().get(1).type(); final Expression successValue = expressions.makeValue(SUCCESS.getErrorCode(), statusType); final Expression invalidTidValue = expressions.makeValue(INVALID_TID.getErrorCode(), statusType); @@ -252,7 +252,7 @@ private void resolveDynamicThreadJoin(Program program, List threadDa final List switchJumpTable = new ArrayList<>(); for (Expression tid : tid2joinCases.keySet()) { switchJumpTable.add(EventFactory.newJump( - expressions.makeEQ(tidExpr, tid), (Label)tid2joinCases.get(tid).get(0)) + expressions.makeEQ(tidExpr, tid), (Label) tid2joinCases.get(tid).get(0)) ); } // In the case where no tid matches, we return an error status. @@ -341,11 +341,18 @@ private void resolvePthreadSelf(Program program) { } if (call.getCalledFunction().getIntrinsicInfo() == Intrinsics.Info.P_THREAD_SELF) { final Register resultRegister = getResultRegister(call); - assert resultRegister.getType() instanceof IntegerType; + Type regType = resultRegister.getType(); + assert regType instanceof PointerType || regType instanceof IntegerType; assert call.getArguments().isEmpty(); - final Expression tidExpr = new TIdExpr((IntegerType) resultRegister.getType(), call.getThread()); - final Local tidAssignment = newLocal(resultRegister, tidExpr); - IRHelper.replaceWithMetadata(call, tidAssignment); + if (regType instanceof PointerType) { + final Expression tidExpr = new TIdExpr(archType, call.getThread()); + final Local tidAssignment = newLocal(resultRegister, expressions.makeIntToPtrCast(tidExpr)); + IRHelper.replaceWithMetadata(call, tidAssignment); + } else { + final Expression tidExpr = new TIdExpr((IntegerType) regType, call.getThread()); + final Local tidAssignment = newLocal(resultRegister, tidExpr); + IRHelper.replaceWithMetadata(call, tidAssignment); + } } } } @@ -382,7 +389,7 @@ private ThreadData createLLVMThreadFromFunction(Function function, int tid, Thre if (e instanceof Return || e instanceof ThreadReturn) { // NOTE: We also replace ThreadReturn but generate a single new one (normalization) afterward. final Expression retVal = (e instanceof Return ret) ? ret.getValue().orElse(null) - : ((ThreadReturn)e).getValue().orElse(null); + : ((ThreadReturn) e).getValue().orElse(null); final List replacement = eventSequence( returnRegister != null ? EventFactory.newLocal(returnRegister, retVal) : null, EventFactory.newGoto(threadReturnLabel) @@ -429,8 +436,10 @@ private ThreadData createLLVMThreadFromFunction(Function function, int tid, Thre return new ThreadData(thread, null, threadReturnLabel); } - private void replaceThreadLocalsWithStackalloc(Memory memory, Thread thread) { + final TypeFactory types = TypeFactory.getInstance(); + final ExpressionFactory exprs = ExpressionFactory.getInstance(); + // Translate thread-local memory object to local stack allocation Map toLocalRegister = new HashMap<>(); for (MemoryObject memoryObject : memory.getObjects()) { @@ -449,9 +458,9 @@ private void replaceThreadLocalsWithStackalloc(Memory memory, Thread thread) { final Type memoryType = types.getAggregateType(contentTypes, offsets); // Allocate single object of memory type - final Register reg = thread.newUniqueRegister("__threadLocal_" + memoryObject, types.getPointerType()); + final Register reg = thread.newUniqueRegister("__threadLocal_" + memoryObject, pointerType); final Event localAlloc = EventFactory.newAlloc( - reg, memoryType, expressions.makeOne(types.getArchType()), + reg, memoryType, expressions.makeOne(archType), false, true ); @@ -459,7 +468,7 @@ private void replaceThreadLocalsWithStackalloc(Memory memory, Thread thread) { final List initialization = new ArrayList<>(); for (Integer initOffset : memoryObject.getInitializedFields()) { initialization.add(EventFactory.newStore( - expressions.makeAdd(reg, expressions.makeValue(initOffset, types.getArchType())), + exprs.makePtrAdd(reg, exprs.makeValue(initOffset, archType)),// null pointer store here!! memoryObject.getInitialValue(initOffset) )); } @@ -487,6 +496,7 @@ public Expression visitMemoryObject(MemoryObject memObj) { private void resolveTidExpressions(Program program) { final ExprTransformer transformer = new ExprTransformer() { final ExpressionFactory expressions = ExpressionFactory.getInstance(); + @Override public Expression visitLeafExpression(LeafExpression expr) { if (expr instanceof TIdExpr tid) { @@ -501,9 +511,14 @@ public Expression visitLeafExpression(LeafExpression expr) { } private void resolveDynamicThreadLocals(Program program, List threads) { - record Storage(int id, MemoryObject data, MemoryObject destructor) {} - interface StorageField { MemoryObject get(Storage s); } - interface Match { Expression compute(StorageField f, Expression k); } + record Storage(int id, MemoryObject data, MemoryObject destructor) { + } + interface StorageField { + MemoryObject get(Storage s); + } + interface Match { + Expression compute(StorageField f, Expression k); + } final List storage = new ArrayList<>(); final Type type = types.getPointerType(); final int size = types.getMemorySizeInBytes(type); @@ -714,11 +729,19 @@ private void copyThreadEvents(Function function, Thread thread, MemoryTransforme // Helper classes private record ThreadData(Thread thread, MemoryObject comAddress, Label returnLabel) { - public boolean isDynamic() { return comAddress != null; } + public boolean isDynamic() { + return comAddress != null; + } + // We assume all dynamically created threads are joinable. // This is not true for pthread_join in general. - public boolean isJoinable() { return isDynamic(); } - public boolean isDetachable() { return isDynamic(); } + public boolean isJoinable() { + return isDynamic(); + } + + public boolean isDetachable() { + return isDynamic(); + } } // We use this class to refer to thread ids before we have (re)assigned proper ids for all threads. @@ -747,5 +770,4 @@ public T accept(ExpressionVisitor visitor) { } } - -} +} \ No newline at end of file diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/Compilation.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/Compilation.java index 8ebfb0e741..920eaa3dbc 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/Compilation.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/Compilation.java @@ -37,7 +37,10 @@ public class Compilation implements ProgramProcessor { toUppercase = true) private Arch target = Arch.C11; - public Arch getTarget() { return target; } + public Arch getTarget() { + return target; + } + public void setTarget(Arch target) { this.target = target; compiler = getCompiler(); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorArm8.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorArm8.java index f1603c7fd0..8822ed5211 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorArm8.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorArm8.java @@ -4,6 +4,7 @@ import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.type.BooleanType; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.event.Event; import com.dat3m.dartagnan.program.event.Tag; @@ -103,7 +104,7 @@ public List visitLlvmRMW(LlvmRMW e) { String mo = e.getMo(); Register dummyReg = e.getFunction().newRegister(resultRegister.getType()); - Local localOp = newLocal(dummyReg, expressions.makeIntBinary(resultRegister, e.getOperator(), e.getOperand())); + Local localOp = newLocal(dummyReg, expressions.makeCast(expressions.makeIntBinary(resultRegister, e.getOperator(), e.getOperand()), dummyReg.getType())); Load load = newRMWLoadExclusiveWithMo(resultRegister, address, ARMv8.extractLoadMoFromCMo(mo)); Store store = newRMWStoreExclusiveWithMo(address, dummyReg, true, ARMv8.extractStoreMoFromCMo(mo)); @@ -515,7 +516,15 @@ public List visitLKMMAddUnless(LKMMAddUnless e) { Register regValue = e.getFunction().newRegister(type); Load load = newRMWLoadExclusiveWithMo(regValue, address, ARMv8.extractLoadMoFromLKMo(mo)); - Store store = newRMWStoreExclusiveWithMo(address, expressions.makeAdd(regValue, e.getOperand()), true, ARMv8.extractStoreMoFromLKMo(mo)); + Expression expr; + if (regValue.getType() instanceof PointerType && e.getOperand().getType() instanceof IntegerType) { + expr = expressions.makePtrAdd(regValue, e.getOperand()); + } else if (regValue.getType() instanceof IntegerType) { + expr = expressions.makeAdd(regValue, e.getOperand()); + } else { + throw new IllegalArgumentException("Non int or ptr as lkmmAddUnless argument"); + } + Store store = newRMWStoreExclusiveWithMo(address, expr, true, ARMv8.extractStoreMoFromLKMo(mo)); Label label = newLabel("FakeDep"); Event fakeCtrlDep = newFakeCtrlDep(regValue, label); @@ -592,7 +601,7 @@ public List visitLKMMLock(LKMMLock e) { @Override public List visitLKMMUnlock(LKMMUnlock e) { - Expression zero = expressions.makeZero((IntegerType)e.getAccessType()); + Expression zero = expressions.makeZero((IntegerType) e.getAccessType()); return eventSequence( newStoreWithMo(e.getAddress(), zero, ARMv8.MO_REL) ); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorC11.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorC11.java index 49f39097d5..f49a8a83b0 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorC11.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorC11.java @@ -4,6 +4,7 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.type.BooleanType; +import com.dat3m.dartagnan.expression.type.IntegerType; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.event.Event; import com.dat3m.dartagnan.program.event.EventFactory; @@ -43,7 +44,7 @@ public List visitAtomicCmpXchg(AtomicCmpXchg e) { Expression address = e.getAddress(); String mo = e.getMo(); Expression expectedAddr = e.getAddressOfExpected(); - Type type = resultRegister.getType(); + Type type = resultRegister.getType(); // todo how can this be a pointer ? Register booleanResultRegister = type instanceof BooleanType ? resultRegister : e.getFunction().newRegister(types.getBooleanType()); Local castResult = type instanceof BooleanType ? null : @@ -82,7 +83,8 @@ public List visitAtomicFetchOp(AtomicFetchOp e) { Register dummyReg = e.getFunction().newRegister(resultRegister.getType()); Load load = newRMWLoadWithMo(resultRegister, address, Tag.C11.loadMO(mo)); - Local localOp = newLocal(dummyReg, expressions.makeIntBinary(resultRegister, e.getOperator(), e.getOperand())); + Expression temp = expressions.makeIntBinary(resultRegister, e.getOperator(), e.getOperand()); + Local localOp = newLocal(dummyReg, dummyReg.getType() instanceof IntegerType ? temp : expressions.makeIntToPtrCast(temp)); RMWStore store = newRMWStoreWithMo(load, address, dummyReg, Tag.C11.storeMO(mo)); return tagList(e, eventSequence( diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorPower.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorPower.java index aaff241615..298cafdd37 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorPower.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorPower.java @@ -2,8 +2,10 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.Type; +import com.dat3m.dartagnan.expression.pointers.PtrCmpOp; import com.dat3m.dartagnan.expression.type.BooleanType; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.event.Event; import com.dat3m.dartagnan.program.event.Tag; @@ -177,7 +179,7 @@ public List visitLlvmRMW(LlvmRMW e) { String mo = e.getMo(); Register dummyReg = e.getFunction().newRegister(resultRegister.getType()); - Local localOp = newLocal(dummyReg, expressions.makeIntBinary(resultRegister, e.getOperator(), e.getOperand())); + Local localOp = newLocal(dummyReg, expressions.makeCast(expressions.makeIntBinary(resultRegister, e.getOperator(), e.getOperand()), dummyReg.getType())); // Power does not have mo tags, thus we use null Load load = newRMWLoadExclusive(resultRegister, address); @@ -658,7 +660,7 @@ public List visitLKMMCmpXchg(LKMMCmpXchg e) { Register dummy = e.getFunction().newRegister(e.getResultRegister().getType()); Label casEnd = newLabel("CAS_end"); - CondJump branchOnCasCmpResult = newJump(expressions.makeNEQ(dummy, e.getExpectedValue()), casEnd); + CondJump branchOnCasCmpResult = newJump(expressions.makeNEQ(dummy, expressions.makeCast(e.getExpectedValue(), dummy.getType())), casEnd); Load load = newRMWLoadExclusive(dummy, address); Store store = Power.newRMWStoreConditional(address, e.getStoreValue(), true); @@ -717,7 +719,7 @@ public List visitLKMMOpNoReturn(LKMMOpNoReturn e) { String mo = e.getMo(); Register dummy = e.getFunction().newRegister(e.getAccessType()); - Expression storeValue = expressions.makeIntBinary(dummy, e.getOperator(), e.getOperand()); + Expression storeValue = expressions.makeCast(expressions.makeIntBinary(dummy, e.getOperator(), e.getOperand()), dummy.getType()); // Power does not have mo tags, thus we use the empty string Load load = newRMWLoadExclusive(dummy, address); Store store = Power.newRMWStoreConditional(address, storeValue, true); @@ -817,7 +819,15 @@ public List visitLKMMAddUnless(LKMMAddUnless e) { Register regValue = e.getFunction().newRegister(type); // Power does not have mo tags, thus we use the empty string Load load = newRMWLoadExclusive(regValue, address); - Store store = Power.newRMWStoreConditional(address, expressions.makeAdd(regValue, e.getOperand()), true); + Expression expr; + if (regValue.getType() instanceof PointerType && e.getOperand().getType() instanceof IntegerType) { + expr = expressions.makePtrAdd(regValue, e.getOperand()); + } else if (regValue.getType() instanceof IntegerType) { + expr = expressions.makeAdd(regValue, e.getOperand()); + } else { + throw new IllegalArgumentException("Non int or ptr as lkmmAddUnless operand"); + } + Store store = Power.newRMWStoreConditional(address, expr, true); Label label = newLabel("FakeDep"); Event fakeCtrlDep = newFakeCtrlDep(regValue, label); @@ -888,7 +898,7 @@ public List visitLKMMOpAndTest(LKMMOpAndTest e) { @Override public List visitLKMMLock(LKMMLock e) { - IntegerType type = (IntegerType)e.getAccessType(); + IntegerType type = (IntegerType) e.getAccessType(); Expression zero = expressions.makeZero(type); Expression one = expressions.makeOne(type); Register dummy = e.getFunction().newRegister(type); @@ -909,7 +919,7 @@ public List visitLKMMLock(LKMMLock e) { public List visitLKMMUnlock(LKMMUnlock e) { return eventSequence( Power.newLwSyncBarrier(), - newStore(e.getAddress(), expressions.makeZero((IntegerType)e.getAccessType())) + newStore(e.getAddress(), expressions.makeZero((IntegerType) e.getAccessType())) ); } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorRISCV.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorRISCV.java index c58379dbae..e5ea678fa1 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorRISCV.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/compilation/VisitorRISCV.java @@ -4,6 +4,7 @@ import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.type.BooleanType; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.program.Register; import com.dat3m.dartagnan.program.event.Event; import com.dat3m.dartagnan.program.event.Tag; @@ -458,7 +459,7 @@ public List visitLKMMXchg(LKMMXchg e) { public List visitLKMMOpNoReturn(LKMMOpNoReturn e) { Expression address = e.getAddress(); String mo = e.getMo(); - IntegerType type = (IntegerType)e.getAccessType(); + IntegerType type = (IntegerType) e.getAccessType(); Register dummy = e.getFunction().newRegister(type); Register statusReg = e.getFunction().newRegister(types.getBooleanType()); @@ -571,7 +572,15 @@ public List visitLKMMAddUnless(LKMMAddUnless e) { Register regValue = e.getFunction().newRegister(type); Load load = newRMWLoadExclusive(regValue, address); // TODO: No mo on the load? - Store store = RISCV.newRMWStoreConditional(address, expressions.makeAdd(regValue, e.getOperand()), mo.equals(Tag.Linux.MO_MB) ? Tag.RISCV.MO_REL : "", true); + Expression expr; + if (regValue.getType() instanceof PointerType && e.getOperand().getType() instanceof IntegerType) { + expr = expressions.makePtrAdd(regValue, e.getOperand()); + } else if (regValue.getType() instanceof IntegerType) { + expr = expressions.makeAdd(regValue, e.getOperand()); + } else { + throw new IllegalArgumentException("Non int or ptr as lkmmAddUnless argument"); + } + Store store = RISCV.newRMWStoreConditional(address, expr, mo.equals(Tag.Linux.MO_MB) ? Tag.RISCV.MO_REL : "", true); // TODO: Why does this use a different fake dep (from the load) than the other RMW events (from the store)? Label label = newLabel("FakeDep"); @@ -582,7 +591,6 @@ public List visitLKMMAddUnless(LKMMAddUnless e) { Label cauEnd = newLabel("CAddU_end"); CondJump branchOnCauCmpResult = newJumpUnless(dummy, cauEnd); Event optionalMemoryBarrierAfter = mo.equals(Tag.Linux.MO_MB) ? RISCV.newRWRWFence() : mo.equals(Tag.Linux.MO_ACQUIRE) ? RISCV.newRRWFence() : null; - return eventSequence( load, newLocal(dummy, expressions.makeNEQ(regValue, unless)), @@ -633,7 +641,7 @@ public List visitLKMMOpAndTest(LKMMOpAndTest e) { @Override public List visitLKMMLock(LKMMLock e) { - IntegerType type = (IntegerType)e.getAccessType(); + IntegerType type = (IntegerType) e.getAccessType(); Expression one = expressions.makeOne(type); Expression zero = expressions.makeZero(type); Register dummy = e.getFunction().newRegister(type); @@ -652,7 +660,7 @@ public List visitLKMMLock(LKMMLock e) { public List visitLKMMUnlock(LKMMUnlock e) { return eventSequence( RISCV.newRWWFence(), - newStore(e.getAddress(), expressions.makeZero((IntegerType)e.getAccessType())) + newStore(e.getAddress(), expressions.makeZero((IntegerType) e.getAccessType())) ); } } \ No newline at end of file diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/transformers/MemoryTransformer.java b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/transformers/MemoryTransformer.java index 9b39db624e..146b0067f2 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/transformers/MemoryTransformer.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/program/processing/transformers/MemoryTransformer.java @@ -3,6 +3,7 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.Type; import com.dat3m.dartagnan.expression.processing.ExprTransformer; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.ScopedPointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.parsers.program.visitors.spirv.decorations.BuiltIn; @@ -26,6 +27,7 @@ public class MemoryTransformer extends ExprTransformer { // Thread / Subgroup / Workgroup / QueueFamily / Device private static final List namePrefixes = List.of("T", "S", "W", "Q", "D"); private static final Type archType = TypeFactory.getInstance().getArchType(); + private static final Type pointerType = TypeFactory.getInstance().getPointerType(); private final Program program; private final Function function; @@ -66,10 +68,7 @@ public void setThread(Thread thread) { tid = newTid; builtIn.setThreadId(tid); registerMapping = function.getRegisters().stream().collect( - toMap(r -> r, r -> { - Type type = r.getType() instanceof ScopedPointerType ? archType : r.getType(); - return thread.getOrNewRegister(r.getName(), type); - })); + toMap(r -> r, r -> thread.getOrNewRegister(r.getName(), r.getType()))); nonDetMapping = new HashMap<>(); } @@ -99,18 +98,18 @@ public Expression visitMemoryObject(MemoryObject memObj) { return switch (storageClass) { // Device-level memory (keep the same instance) case Tag.Spirv.SC_UNIFORM_CONSTANT, - Tag.Spirv.SC_UNIFORM, - Tag.Spirv.SC_OUTPUT, - Tag.Spirv.SC_CROSS_WORKGROUP, - Tag.Spirv.SC_PUSH_CONSTANT, - Tag.Spirv.SC_ATOMIC_COUNTER, - Tag.Spirv.SC_IMAGE, - Tag.Spirv.SC_STORAGE_BUFFER, - Tag.Spirv.SC_PHYS_STORAGE_BUFFER -> memObj; + Tag.Spirv.SC_UNIFORM, + Tag.Spirv.SC_OUTPUT, + Tag.Spirv.SC_CROSS_WORKGROUP, + Tag.Spirv.SC_PUSH_CONSTANT, + Tag.Spirv.SC_ATOMIC_COUNTER, + Tag.Spirv.SC_IMAGE, + Tag.Spirv.SC_STORAGE_BUFFER, + Tag.Spirv.SC_PHYS_STORAGE_BUFFER -> memObj; // Private memory (copy for each new thread) case Tag.Spirv.SC_INPUT, - Tag.Spirv.SC_PRIVATE, - Tag.Spirv.SC_FUNCTION -> applyMapping(memObj, 0); + Tag.Spirv.SC_PRIVATE, + Tag.Spirv.SC_FUNCTION -> applyMapping(memObj, 0); // Workgroup-level memory (copy for each new workgroup) case Tag.Spirv.SC_WORKGROUP -> applyMapping(memObj, 2); default -> throw new UnsupportedOperationException( diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/smt/FormulaManagerExt.java b/dartagnan/src/main/java/com/dat3m/dartagnan/smt/FormulaManagerExt.java index d93628684e..71a54f7042 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/smt/FormulaManagerExt.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/smt/FormulaManagerExt.java @@ -63,6 +63,11 @@ public boolean hasSameType(Formula left, Formula right) { return false; } + public BooleanFormula isZeroBitVector(BitvectorFormula formula) { + BitvectorFormulaManager bvfm = fmgr.getBitvectorFormulaManager(); + return bvfm.equal(bvfm.makeBitvector(bvfm.getLength(formula),0), formula); + } + public BooleanFormula equal(Formula left, Formula right) { Preconditions.checkArgument(hasSameType(left, right)); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/solving/ModelChecker.java b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/solving/ModelChecker.java index cb664161c5..4ebe67fcb8 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/solving/ModelChecker.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/solving/ModelChecker.java @@ -211,7 +211,7 @@ public static void preprocessProgram(VerificationTask task, Configuration config ProcessingManager.fromConfig(config).run(program); } - public static void preprocessMemoryModel(VerificationTask task, Configuration config) throws InvalidConfigurationException{ + public static void preprocessMemoryModel(VerificationTask task, Configuration config) throws InvalidConfigurationException { final Wmm memoryModel = task.getMemoryModel(); WmmProcessingManager.fromConfig(config).run(memoryModel); } @@ -227,8 +227,8 @@ public static void performStaticProgramAnalyses(VerificationTask task, Context a analysisContext.register(AliasAnalysis.class, alias); analysisContext.register(ThreadSymmetry.class, ThreadSymmetry.fromConfig(program, config)); - for(Thread thread : program.getThreads()) { - for(Event e : thread.getEvents()) { + for (Thread thread : program.getThreads()) { + for (Event e : thread.getEvents()) { // Some events perform static analyses by themselves (e.g. Svcomp's EndAtomic) // which may rely on previous "global" analyses e.runLocalAnalysis(program, analysisContext); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/solving/RefinementSolver.java b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/solving/RefinementSolver.java index c5454abb32..0f4ada4c84 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/verification/solving/RefinementSolver.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/verification/solving/RefinementSolver.java @@ -1,5 +1,6 @@ package com.dat3m.dartagnan.verification.solving; + import com.dat3m.dartagnan.configuration.Baseline; import com.dat3m.dartagnan.configuration.Property; import com.dat3m.dartagnan.encoding.*; @@ -85,20 +86,20 @@ public class RefinementSolver extends ModelChecker { // ================================================================================================================ // Configuration - @Option(name=BASELINE, - description="Refinement starts from this baseline WMM.", - secure=true, - toUppercase=true) + @Option(name = BASELINE, + description = "Refinement starts from this baseline WMM.", + secure = true, + toUppercase = true) private EnumSet baselines = EnumSet.noneOf(Baseline.class); - @Option(name=COVERAGE, - description="Prints the coverage report (this option requires --method=caat).", - secure=true, - toUppercase=true) + @Option(name = COVERAGE, + description = "Prints the coverage report (this option requires --method=caat).", + secure = true, + toUppercase = true) private boolean printCovReport = false; - @Option(name=GRAPHVIZ_DEBUG_FILES, - description="This option causes Refinement to generate many .dot and .png files that describe EACH iteration." + + @Option(name = GRAPHVIZ_DEBUG_FILES, + description = "This option causes Refinement to generate many .dot and .png files that describe EACH iteration." + " It is very expensive and should only be used for debugging purposes.") private boolean generateGraphvizDebugFiles = false; @@ -167,7 +168,7 @@ private RefinementSolver(VerificationTask task) throws InvalidConfigurationExcep task.getConfig().inject(this); } - public static RefinementSolver create(VerificationTask task) throws InvalidConfigurationException { + public static RefinementSolver create(VerificationTask task) throws InvalidConfigurationException { return new RefinementSolver(task); } @@ -811,14 +812,14 @@ private static CharSequence generateCoverageReport(Set coveredEvents, Pro // TODO: Can we have events with source information but without oid? .filter(e -> e.hasMetadata(SourceLocation.class) && e.hasMetadata(OriginalId.class)) .collect(Collectors.toSet()); - + // Track (covered) events and branches via oId final Set branches = new HashSet<>(); final Set coveredBranches = new HashSet<>(); // Events not executed in any violating execution final Set messageSet = new TreeSet<>(); // TreeSet to keep strings in order - + final SyntacticContextAnalysis synContext = SyntacticContextAnalysis.newInstance(program); for (Event e : programEvents) { @@ -827,13 +828,13 @@ private static CharSequence generateCoverageReport(Set coveredEvents, Pro OriginalId branchRepId = cf.getRepresentative(symmRep).getMetadata(OriginalId.class); assert branchRepId != null; - if(coveredEvents.contains(e)) { + if (coveredEvents.contains(e)) { coveredBranches.add(branchRepId); } else { final String threads = clazz.stream().map(t -> "T" + t.getId()) .collect(Collectors.joining(" / ")); final String callStack = makeContextString( - synContext.getContextInfo(e).getContextOfType(CallContext.class), " -> "); + synContext.getContextInfo(e).getContextOfType(CallContext.class), " -> "); messageSet.add(String.format("%s: %s%s", threads, callStack.isEmpty() ? callStack : callStack + " -> ", getSourceLocationString(symmRep))); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/witness/graphml/WitnessBuilder.java b/dartagnan/src/main/java/com/dat3m/dartagnan/witness/graphml/WitnessBuilder.java index 3bb8f6b3c2..20f05ac7fe 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/witness/graphml/WitnessBuilder.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/witness/graphml/WitnessBuilder.java @@ -46,9 +46,9 @@ public class WitnessBuilder { // =========================== Configurables =========================== @Option( - name=WITNESS_ORIGINAL_PROGRAM_PATH, - description="Path to the original C file (for which to create a witness).", - secure=true) + name = WITNESS_ORIGINAL_PROGRAM_PATH, + description = "Path to the original C file (for which to create a witness).", + secure = true) private String originalProgramFilePath; public boolean canBeBuilt() { diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/witness/graphviz/ExecutionGraphVisualizer.java b/dartagnan/src/main/java/com/dat3m/dartagnan/witness/graphviz/ExecutionGraphVisualizer.java index 463f47c24f..9673d4c730 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/witness/graphviz/ExecutionGraphVisualizer.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/witness/graphviz/ExecutionGraphVisualizer.java @@ -45,9 +45,9 @@ public class ExecutionGraphVisualizer { private final List sortedMemoryObjects = new ArrayList<>(); private List relsToShow; - @Option(name=WITNESS_SHOW, - description="Names of relations to show in the witness graph.", - secure=true) + @Option(name = WITNESS_SHOW, + description = "Names of relations to show in the witness graph.", + secure = true) private String relsToShowStr = String.format("%s,%s,%s,%s", PO, SI, CO, RF); public ExecutionGraphVisualizer() { @@ -86,8 +86,8 @@ private BiPredicate getFilter(String relationName) { private void computeAddressMap(ExecutionModelNext model) { model.getMemoryLayoutMap().entrySet().stream() - .sorted(Comparator.comparing(entry -> (BigInteger) entry.getValue().address().value())) - .forEach(entry -> sortedMemoryObjects.add(entry.getValue())); + .sorted(Comparator.comparing(entry -> (BigInteger) entry.getValue().address().value())) + .forEach(entry -> sortedMemoryObjects.add(entry.getValue())); } private List> getEventModelsToShow(ThreadModel tm) { @@ -155,8 +155,8 @@ private Optional tryParseInt(String s) { private RelationModel getRelationModelByName(ExecutionModelNext model, String name) { return model.getRelationModels().stream() - .filter(rm -> rm.getRelation().hasName(name)) - .findFirst().orElse(null); + .filter(rm -> rm.getRelation().hasName(name)) + .findFirst().orElse(null); } // Getting the correct relation to show is tricky. @@ -175,13 +175,15 @@ private RelationModel getRelationModel(ExecutionModelNext model, String name) { for (String n : rm.getRelation().getNames()) { if (n.startsWith(name + "#")) { defIndex = tryParseInt(n).orElse(-1); - if (defIndex > -1) { break; } + if (defIndex > -1) { + break; + } } } maxId = Math.max(maxId, defIndex); } return maxId != -1 ? getRelationModelByName(model, name + "#" + maxId) - : getRelationModelByName(model, name); + : getRelationModelByName(model, name); } private void addRelations(ExecutionModelNext model) { @@ -220,7 +222,9 @@ private void addProgramOrder(ExecutionModelNext model, String name) { final BiPredicate filter = getFilter(PO); for (ThreadModel tm : model.getThreadModels()) { final List> instructions = getEventModelsToShow(tm); - if (instructions.size() <= 1) { continue; } + if (instructions.size() <= 1) { + continue; + } for (int i = 1; i < instructions.size(); i++) { final List fromList = instructions.get(i - 1); final List toList = instructions.get(i); @@ -271,7 +275,9 @@ private void addSameInstruction(ExecutionModelNext model, String name) { final BiPredicate filter = getFilter(name); for (ThreadModel tm : model.getThreadModels()) { final List> instructions = getEventModelsToShow(tm); - if (instructions.size() <= 1) { continue; } + if (instructions.size() <= 1) { + continue; + } for (List instruction : instructions) { int end = instruction.size() - 1; for (int i = 0; i < end; i++) { @@ -320,25 +326,25 @@ private String nodeLabel(EventModel e) { String.format("%s = R(%s%s)", value, address, moString); } else if (e instanceof LocalModel lm) { tag = String.format("%s(%s) <- %s", - lm.getEvent().getResultRegister(), - lm.getValue(), - lm.getEvent().getExpr() + lm.getEvent().getResultRegister(), + lm.getValue(), + lm.getEvent().getExpr() ); } else if (e instanceof AssertModel am) { tag = String.format("Assertion(%s)", am.getResult()); } final Thread thread = e.getThreadModel().getThread(); final String callStack = makeContextString( - synContext.getContextInfo(e.getEvent()).getContextOfType(CallContext.class), " -> \\n"); + synContext.getContextInfo(e.getEvent()).getContextOfType(CallContext.class), " -> \\n"); final String scope = thread.hasScope() ? "@" + thread.getScopeHierarchy() : ""; final String nodeString = String.format("%s:T%s%s\\nE%s %s%s\\n%s", - e.getThreadModel().getName(), - e.getThreadModel().getId(), - scope, - e.getEvent().getGlobalId(), - callStack.isEmpty() ? callStack : callStack + " -> \\n", - getSourceLocationString(e.getEvent()), - tag) + e.getThreadModel().getName(), + e.getThreadModel().getId(), + scope, + e.getEvent().getGlobalId(), + callStack.isEmpty() ? callStack : callStack + " -> \\n", + getSourceLocationString(e.getEvent()), + tag) .replace("%", "\\%") .replace("\"", "\\\""); // We need to escape quotes inside the string return "label=\"" + nodeString + "\""; @@ -368,11 +374,13 @@ public static File generateGraphvizFile(ExecutionModelNext model, try (FileWriter writer = new FileWriter(fileVio)) { // Create .dot file ExecutionGraphVisualizer visualizer = new ExecutionGraphVisualizer(); - if (config != null) { visualizer.setRelationsToShow(config); } + if (config != null) { + visualizer.setRelationsToShow(config); + } visualizer.setSyntacticContext(synContext) - .setFilter(RF, rfFilter) - .setFilter(CO, coFilter) - .generateGraphOfExecutionModel(writer, "Iteration " + iterationCount, model); + .setFilter(RF, rfFilter) + .setFilter(CO, coFilter) + .generateGraphOfExecutionModel(writer, "Iteration " + iterationCount, model); writer.flush(); if (convert) { @@ -395,13 +403,13 @@ public static void generateGraphvizFile(ExecutionModelNext model, String fileNameBase, SyntacticContextAnalysis synContext) { generateGraphvizFile(model, - iterationCount, - rfFilter, - coFilter, - directoryName, - fileNameBase, - synContext, - true, - null); + iterationCount, + rfFilter, + coFilter, + directoryName, + fileNameBase, + synContext, + true, + null); } } diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/Wmm.java b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/Wmm.java index 7eae078a51..e6458e65b2 100755 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/Wmm.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/Wmm.java @@ -33,7 +33,9 @@ public static class Config { secure = true) private boolean reduceAcyclicityEncoding = true; - public boolean isReduceAcyclicityEncoding() { return reduceAcyclicityEncoding; } + public boolean isReduceAcyclicityEncoding() { + return reduceAcyclicityEncoding; + } } private static final Logger logger = LoggerFactory.getLogger(Wmm.class); @@ -53,7 +55,9 @@ public Wmm() { ANARCHIC_CORE_RELATIONS.forEach(this::getOrCreatePredefinedRelation); } - public Config getConfig() { return this.config; } + public Config getConfig() { + return this.config; + } public List getConstraints() { return Stream.concat(constraints.stream(), relations.stream().map(Relation::getDefinition)).toList(); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/analysis/NativeRelationAnalysis.java b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/analysis/NativeRelationAnalysis.java index 8571813874..7daf95eeab 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/analysis/NativeRelationAnalysis.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/analysis/NativeRelationAnalysis.java @@ -774,7 +774,7 @@ public MutableKnowledge visitLXSXPairs(LXSXPairs lxsx) { } private void addLXSX(MutableEventGraph may, MutableEventGraph must, List loads, List stores, - boolean noIntermediaries, boolean requiresMatchingAddresses) { + boolean noIntermediaries, boolean requiresMatchingAddresses) { final boolean sameType = sameType(loads, stores); for (int i = 0; i < loads.size(); i++) { final MemoryCoreEvent ld = (MemoryCoreEvent) loads.get(i); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/axiom/Acyclicity.java b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/axiom/Acyclicity.java index 71514b787f..389b2518a8 100755 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/axiom/Acyclicity.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/axiom/Acyclicity.java @@ -232,10 +232,10 @@ private List inconsistentSAT(EventGraph toBeEncoded, EncodingCon // edge and at least one outgoing edge that are also in the cycle. enc.add(bmgr.implication(cycleVar(e, fmgr), bmgr.and(bmgr.or(inMap.get(e)), bmgr.or(outMap.get(e))))); toBeEncoded.apply((e1, e2) -> - // If an edge is guessed to be in a cycle, the edge must belong to relation, - // and both events must also be guessed to be on the cycle. - enc.add(bmgr.implication(getSMTCycleVar(e1, e2, fmgr), - bmgr.and(edge.encode(e1, e2), cycleVar(e1, fmgr), cycleVar(e2, fmgr))))); + // If an edge is guessed to be in a cycle, the edge must belong to relation, + // and both events must also be guessed to be on the cycle. + enc.add(bmgr.implication(getSMTCycleVar(e1, e2, fmgr), + bmgr.and(edge.encode(e1, e2), cycleVar(e1, fmgr), cycleVar(e2, fmgr))))); } // A cycle exists if there is an event in the cycle. enc.add(bmgr.or(eventsInCycle)); @@ -250,10 +250,10 @@ private List consistentIDL(EventGraph toBeEncoded, EncodingConte List enc = new ArrayList<>(); final EncodingContext.EdgeEncoder edge = context.edge(rel); toBeEncoded.apply((e1, e2) -> - enc.add(bmgr.implication(edge.encode(e1, e2), - imgr.lessThan( - context.clockVariable(clockVarName, e1), - context.clockVariable(clockVarName,e2)))) + enc.add(bmgr.implication(edge.encode(e1, e2), + imgr.lessThan( + context.clockVariable(clockVarName, e1), + context.clockVariable(clockVarName, e2)))) ); return enc; } @@ -356,7 +356,7 @@ private List consistentSAT(EventGraph toBeEncoded, EncodingConte for (int i = 0; i < varOrderings.size(); i++) { Event e1 = varOrderings.get(i); Set out = vertEleOutEdges.get(e1); - for (Event e2: out) { + for (Event e2 : out) { if (varOrderings.indexOf(e2) > i && vertEleInEdges.get(e2).contains(e1)) { BooleanFormula cond = minSet.contains(e1, e2) ? bmgr.makeTrue() : getSMTCycleVar(e1, e2, fmgr); enc.add(bmgr.implication(cond, bmgr.not(getSMTCycleVar(e2, e1, fmgr)))); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/processing/MergeEquivalentRelations.java b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/processing/MergeEquivalentRelations.java index 1000755ef1..4cfb3fbb58 100644 --- a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/processing/MergeEquivalentRelations.java +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/processing/MergeEquivalentRelations.java @@ -59,7 +59,7 @@ private Map computeEquivalenceClasses(Wmm wmm) { } private boolean areEquivalent(Relation r1, Relation r2) { - if (r1 == r2) { + if (r1 == r2) { return true; } final Definition def1 = r1.getDefinition(); diff --git a/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/utils/Cut.java b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/utils/Cut.java new file mode 100644 index 0000000000..2d63b95fd5 --- /dev/null +++ b/dartagnan/src/main/java/com/dat3m/dartagnan/wmm/utils/Cut.java @@ -0,0 +1,104 @@ +package com.dat3m.dartagnan.wmm.utils; + +import com.dat3m.dartagnan.wmm.Constraint; +import com.dat3m.dartagnan.wmm.Definition; +import com.dat3m.dartagnan.wmm.Relation; +import com.dat3m.dartagnan.wmm.Wmm; +import com.google.common.base.Preconditions; +import com.google.common.collect.Sets; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +/* + A cut C of a memory model is a partition (L, U) of the relations and constraints such that: + (1) For every relation r: r in L => defConstraint(r) in L + (2) For every constraint c: c in L => constrainedRels(c) \subset L. + + NOTE 1: For recursively defined relations, if one of them is in L then all are in L. + NOTE 2: A cut can be represented by just a partition of the constraints since the relation partition can be + computed from the defining constraints. + + PROPOSITION 1: For every set of relations and constraints RC of a memory model, there is a unique cut C + such that RC \subset L(C) and L(C) is minimal. + PROOF: We saturate the set RC to RC' using the left-to-right implications from conditions (1) and (2). + Claim: The partition (RC', MM \ RC) is a cut C. + By construction, it must satisfy properties (1)/(2) and L(C) contains RC. + Furthermore, L(C) it is also minimal by construction via saturation (least-fixed point). + + PROPOSITION 2: For every cut C = (L, U) and every non-defining constraint c with constrainedRels(c) \subset L, + C' = (L + c, U - c) and C'' = (L - c, U + c) are also cuts. + PROOF: Trivial. + + COROLLARY: For every cut C with lower relations R, there are constraint-minimal/maximal cuts C'/C'' with the + same lower relations R. + + DEF: The boundary B(C) of a cut C consists of the relations in L(C) that are constrained by some constraint + in U(C). + */ +// WARNING: A cut stays only valid as long as the memory model is not modified! +public class Cut { + private final Wmm memoryModel; + private final Set lower; + private final Set upper; + + private Cut(Wmm memoryModel, Set lower, Set upper) { + this.memoryModel = memoryModel; + this.lower = lower; + this.upper = upper; + } + + public Wmm getMemoryModel() { + return memoryModel; + } + + public Set getLower() { + return lower; + } + + public Set getUpper() { + return upper; + } + + public Set getLowerRelations() { + return lower.stream().flatMap(c -> c.getConstrainedRelations().stream()).collect(Collectors.toSet()); + } + + public Set getUpperRelations() { + return upper.stream() + .filter(Definition.class::isInstance) + .map(c -> ((Definition) c).getDefinedRelation()) + .collect(Collectors.toSet()); + } + + public Set getBoundaryRelations() { + final Set lowerRels = getLowerRelations(); + return upper.stream() + .flatMap(c -> c.getConstrainedRelations().stream()) + .filter(lowerRels::contains) + .collect(Collectors.toSet()); + } + + // ========================================================================================================= + + public static Cut computeInducedCut(Wmm memoryModel, Collection rootConstraints) { + final Set constraints = new HashSet<>(memoryModel.getConstraints()); + Preconditions.checkArgument(constraints.containsAll(rootConstraints)); + // Precondition: All constraints are from the same memory model. + final Set lower = new HashSet<>(); + rootConstraints.forEach(c -> collectLowerConstraints(c, lower)); + final Set upper = new HashSet<>(Sets.difference(constraints, lower)); + + return new Cut(memoryModel, lower, upper); + } + + private static void collectLowerConstraints(Constraint c, Set collector) { + if (collector.add(c)) { + for (Relation r : c.getConstrainedRelations()) { + collectLowerConstraints(r.getDefinition(), collector); + } + } + } +} diff --git a/dartagnan/src/test/java/com/dat3m/dartagnan/asm/armv7/libvsync/AsmLibvsyncArmv7Test.java b/dartagnan/src/test/java/com/dat3m/dartagnan/asm/armv7/libvsync/AsmLibvsyncArmv7Test.java index c8193f660c..6d9aeb8da3 100644 --- a/dartagnan/src/test/java/com/dat3m/dartagnan/asm/armv7/libvsync/AsmLibvsyncArmv7Test.java +++ b/dartagnan/src/test/java/com/dat3m/dartagnan/asm/armv7/libvsync/AsmLibvsyncArmv7Test.java @@ -46,8 +46,6 @@ public static Iterable data() throws IOException { //bounded_queue {"bounded_spsc", 1, PASS}, {"bounded_mpmc_check_full", 3, PASS}, - {"bounded_mpmc_check_empty", 4, PASS}, - //spinlocks // {"caslock", 4, PASS}, // passes Refinement but takes ~10 minutes {"clhlock", 3, PASS}, @@ -68,7 +66,8 @@ public static Iterable data() throws IOException { {"mutex_musl", 3, PASS}, {"mutex_slim", 2, PASS}, {"mutex_waiters", 2, PASS}, - {"once", 2, PASS} + {"once", 2, PASS}, + {"bounded_mpmc_check_empty", 4, PASS} }); } diff --git a/dartagnan/src/test/java/com/dat3m/dartagnan/asm/armv8/ck/AsmCkArmv8Test.java b/dartagnan/src/test/java/com/dat3m/dartagnan/asm/armv8/ck/AsmCkArmv8Test.java index 3b280c5042..ed2bb3f721 100644 --- a/dartagnan/src/test/java/com/dat3m/dartagnan/asm/armv8/ck/AsmCkArmv8Test.java +++ b/dartagnan/src/test/java/com/dat3m/dartagnan/asm/armv8/ck/AsmCkArmv8Test.java @@ -52,6 +52,7 @@ public static Iterable data() throws IOException { {"ticketlock", 1, Result.PASS}, {"spsc_queue", 1, Result.PASS}, {"stack_empty", 2, Result.UNKNOWN}, + }); } diff --git a/dartagnan/src/test/java/com/dat3m/dartagnan/llvm/AbstractCTest.java b/dartagnan/src/test/java/com/dat3m/dartagnan/llvm/AbstractCTest.java index 09ce0ff5f2..c02bf66299 100644 --- a/dartagnan/src/test/java/com/dat3m/dartagnan/llvm/AbstractCTest.java +++ b/dartagnan/src/test/java/com/dat3m/dartagnan/llvm/AbstractCTest.java @@ -50,7 +50,7 @@ protected final Configuration getBaseConfiguration() throws InvalidConfiguration } protected ConfigurationBuilder additionalConfig(ConfigurationBuilder builder) { - return builder.setOption(OptionNames.USE_INTEGERS, "true"); + return builder.setOption(OptionNames.USE_INTEGERS, "false"); } protected Provider getProgramPathProvider() { diff --git a/dartagnan/src/test/java/com/dat3m/dartagnan/others/miscellaneous/AnalysisTest.java b/dartagnan/src/test/java/com/dat3m/dartagnan/others/miscellaneous/AnalysisTest.java index 28c654bd66..446d940f91 100644 --- a/dartagnan/src/test/java/com/dat3m/dartagnan/others/miscellaneous/AnalysisTest.java +++ b/dartagnan/src/test/java/com/dat3m/dartagnan/others/miscellaneous/AnalysisTest.java @@ -6,6 +6,7 @@ import com.dat3m.dartagnan.expression.Expression; import com.dat3m.dartagnan.expression.ExpressionFactory; import com.dat3m.dartagnan.expression.type.IntegerType; +import com.dat3m.dartagnan.expression.type.PointerType; import com.dat3m.dartagnan.expression.type.TypeFactory; import com.dat3m.dartagnan.parsers.cat.ParserCat; import com.dat3m.dartagnan.parsers.program.ProgramParser; @@ -68,6 +69,15 @@ private enum Result {NONE, MAY, MUST} private static final TypeFactory types = TypeFactory.getInstance(); private static final ExpressionFactory expressions = ExpressionFactory.getInstance(); + private Expression toPtr(Expression expr) { + return expressions.makePtrCast(expr, types.getPointerType()); + } + private Expression toInt(Expression expr) { + return expressions.makeIntegerCast(expr, types.getArchType(),true); + } + + + @Test public void reachingDefinitionMustOverride() throws InvalidConfigurationException { reachingDefinitionMustOverride(ReachingDefinitionsAnalysis.Method.BACKWARD); @@ -77,9 +87,9 @@ public void reachingDefinitionMustOverride() throws InvalidConfigurationExceptio private void reachingDefinitionMustOverride(ReachingDefinitionsAnalysis.Method method) throws InvalidConfigurationException { ProgramBuilder b = ProgramBuilder.forLanguage(SourceLanguage.LITMUS); b.newThread(0); - Register r0 = b.getOrNewRegister(0, "r0"); - Register r1 = b.getOrNewRegister(0, "r1"); - Register r2 = b.getOrNewRegister(0, "r2"); + Register r0 = b.getOrNewRegister(0, "r0", types.getArchType()); + Register r1 = b.getOrNewRegister(0, "r1", types.getArchType()); + Register r2 = b.getOrNewRegister(0, "r2", types.getArchType()); Label alt = b.getOrCreateLabel(0, "alt"); b.addChild(0, newJump(b.newConstant(types.getBooleanType()), alt)); Local e0 = newLocal(r0, value(1)); @@ -128,8 +138,6 @@ private void reachingDefinitionMustOverride(ReachingDefinitionsAnalysis.Method m assertList(rd.getWriters(me5).ofRegister(r2).getMustWriters(), me4); } - - @Test public void reachingDefinitionSupportsLoops() throws InvalidConfigurationException { ProgramBuilder b = ProgramBuilder.forLanguage(SourceLanguage.LITMUS); @@ -153,7 +161,7 @@ public void reachingDefinitionSupportsLoops() throws InvalidConfigurationExcepti Local r20 = newLocal(r2, r0); b.addChild(0, r20); // r3 = 0 - Local r30 = newLocal(r3, expressions.makeZero(types.getArchType())); + Local r30 = newLocal(r3, expressions.makeNullLiteral()); b.addChild(0, r30); // do { Label begin = b.getOrCreateLabel(0, "begin"); @@ -201,7 +209,10 @@ public void reachingDefinitionSupportsLoops() throws InvalidConfigurationExcepti b.addChild(0, skip3); // return (r0 + r1) ^ (r2 | r3) Return ret = newFunctionReturn( - expressions.makeIntXor(expressions.makeAdd(r0, r1), expressions.makeIntOr(r2, r3))); + expressions.makeIntXor(expressions.makeAdd(expressions.makeIntegerCast(r0, types.getArchType(),false), + expressions.makeIntegerCast(r1, types.getArchType(),false)), + expressions.makeIntOr(expressions.makeIntegerCast(r2, types.getArchType(),false), + expressions.makeIntegerCast(r3, types.getArchType(),false)))); b.addChild(0, ret); Program program = b.build(); @@ -266,9 +277,9 @@ private void program0(Alias method, Result... expect) throws InvalidConfiguratio MemoryObject y = b.newMemoryObject("y", 8); b.newThread(0); - Register r0 = b.getOrNewRegister(0, "r0"); + Register r0 = b.getOrNewRegister(0, "r0", types.getPointerType()); //In C11, this is well-defined: ((uint64_t*) ((uintptr_t) x * 1)) - b.addChild(0, newLocal(r0, mult(x, 1))); + b.addChild(0, newLocal(r0, toPtr(mult(toInt(x), 1)))); Store e0 = newStore(r0); b.addChild(0, e0); Store e1 = newStore(plus(r0, 8)); @@ -356,27 +367,25 @@ public void full2() throws InvalidConfigurationException { private void program2(Alias method, Result... expect) throws InvalidConfigurationException { ProgramBuilder b = ProgramBuilder.forLanguage(SourceLanguage.LITMUS); - IntegerType type = types.getArchType(); + IntegerType itype = types.getArchType(); MemoryObject x = b.newMemoryObject("x", 24); b.newThread(0); - Register r0 = b.getOrNewRegister(0, "r0"); - b.addChild(0, newLocal(r0, b.newConstant(type))); + Register r0 = b.getOrNewRegister(0, "r0", itype); + b.addChild(0, newLocal(r0, b.newConstant(itype))); Label l0 = b.getOrCreateLabel(0,"l0"); b.addChild(0, newJump(expressions.makeOr( - expressions.makeGT(r0, expressions.makeOne(type), true), - expressions.makeLT(r0, expressions.makeZero(type), true)), l0)); + expressions.makeGT(r0, expressions.makeOne(itype), true), + expressions.makeLT(r0, expressions.makeZero(itype), true)), l0)); Store e0 = newStore(x); b.addChild(0, e0); Store e1 = newStore(plus(x, 8)); b.addChild(0, e1); Store e2 = newStore(plus(x, 16)); b.addChild(0, e2); - Register r1 = b.getOrNewRegister(0, "r1"); - b.addChild(0, newLocal(r1, expressions.makeZero(type))); - Store e3 = newStore(expressions.makeAdd( - expressions.makeAdd(x, mult(r0, 16)), - mult(r1, 32))); + Register r1 = b.getOrNewRegister(0, "r1", itype); + b.addChild(0, newLocal(r1, expressions.makeZero(itype))); + Store e3 = newStore(add(add(x, mult(r0, 16)), mult(r1, 32))); b.addChild(0, e3); b.addChild(0, l0); @@ -464,7 +473,7 @@ private void program4(Alias method, Result... expect) throws InvalidConfiguratio b.newThread(0); Register r0 = b.getOrNewRegister(0, "r0"); - b.addChild(0, newLocal(r0, mult(x, 0))); + b.addChild(0, newLocal(r0, expressions.makePtrCast(mult(expressions.makeIntegerCast(x, types.getArchType(),false), 0), types.getPointerType()))); b.addChild(0, newLocal(r0, y)); Store e0 = newStore(r0); b.addChild(0, e0); @@ -516,7 +525,7 @@ private void program5(Alias method, Result... expect) throws InvalidConfiguratio b.addChild(0, newLocal(r0, y)); Store e0 = newStore(r0); b.addChild(0, e0); - b.addChild(0, newLocal(r0, mult(x, 0))); + b.addChild(0, newLocal(r0, toPtr(mult(toInt(x), 0)))); Store e1 = newStore(x); b.addChild(0, e1); Store e2 = newStore(y); @@ -639,8 +648,18 @@ private Store newStore(Expression address, Expression value) { private Expression value(long v) { return expressions.makeValue(v, types.getArchType()); } + private Expression add(Expression lhs, Expression rhs) { + assert rhs.getType() instanceof IntegerType; + if (lhs.getType() instanceof PointerType){ + return expressions.makePtrAdd(lhs,rhs); + } + return expressions.makeAdd(lhs, rhs); + } private Expression plus(Expression lhs, long rhs) { + if (lhs.getType() instanceof PointerType){ + return expressions.makePtrAdd(lhs,value(rhs)); + } return expressions.makeAdd(lhs, value(rhs)); } @@ -724,7 +743,7 @@ private Event findMatchingEventAfterProcessing(Program p, Event orig) { public void allKindsOfMixedSizeAccesses() throws Exception { TypeFactory types = TypeFactory.getInstance(); ExpressionFactory expressions = ExpressionFactory.getInstance(); - IntegerType pointerType = types.getArchType(); + IntegerType archType = types.getArchType(); ProgramBuilder b = ProgramBuilder.forLanguage(Program.SourceLanguage.LITMUS); b.newThread(0); Register r8 = b.getOrNewRegister(0, "r8", types.getIntegerType(8)); @@ -741,7 +760,7 @@ public void allKindsOfMixedSizeAccesses() throws Exception { final StringBuilder exp = new StringBuilder(); for (int offset = 0; offset < 9; offset++) { final MemoryObject x = b.getOrNewMemoryObject(String.format("x%d:%d", i, offset), OBJECT_SIZE); - final Expression address = expressions.makeAdd(x, expressions.makeValue(offset, pointerType)); + final Expression address = expressions.makePtrAdd(x, expressions.makeValue(offset, archType)); b.addChild(0, newLoad(r, x)); b.addChild(0, newLoad(s, address)); if (0 < offset && offset < rBytes) { diff --git a/dartagnan/src/test/java/com/dat3m/dartagnan/others/miscellaneous/ProcessingTest.java b/dartagnan/src/test/java/com/dat3m/dartagnan/others/miscellaneous/ProcessingTest.java index cc58012d03..32a58556aa 100644 --- a/dartagnan/src/test/java/com/dat3m/dartagnan/others/miscellaneous/ProcessingTest.java +++ b/dartagnan/src/test/java/com/dat3m/dartagnan/others/miscellaneous/ProcessingTest.java @@ -31,7 +31,7 @@ public void memToReg0() throws InvalidConfigurationException { final Program program = new Program(new Memory(), Program.SourceLanguage.LLVM); final Function f = new Function("f", types.getFunctionType(types.getVoidType(), List.of()), List.of(), 0, null); program.addFunction(f); - final Register r0 = f.newRegister("r0", types.getArchType()); + final Register r0 = f.newRegister("r0", types.getPointerType()); final Register r1 = f.newRegister("r1", types.getBooleanType()); final Event alloc = newAlloc(r0, types.getBooleanType(), 1); final Event storeFalse = EventFactory.newStore(r0, expressions.makeFalse()); @@ -56,8 +56,8 @@ public void memToReg1() throws InvalidConfigurationException { final Program program = new Program(new Memory(), Program.SourceLanguage.LLVM); final Function f = new Function("f", types.getFunctionType(types.getVoidType(), List.of()), List.of(), 0, null); program.addFunction(f); - final Register r0 = f.newRegister("r0", types.getArchType()); - final Register r1 = f.newRegister("r1", types.getArchType()); + final Register r0 = f.newRegister("r0", types.getPointerType()); + final Register r1 = f.newRegister("r1", types.getPointerType()); final Register r2 = f.newRegister("r2", types.getArchType()); final Register r3 = f.newRegister("r3", types.getBooleanType()); final Event allocX = newAlloc(r0, types.getBooleanType(), 2); @@ -68,8 +68,8 @@ public void memToReg1() throws InvalidConfigurationException { expressions.makeValue(1, types.getArchType()), expressions.makeValue(0, types.getArchType()))); final Event loadIndex = EventFactory.newLoad(r2, r1); - final Event storeTrue = EventFactory.newStore(expressions.makeAdd(r0, r2), expressions.makeTrue()); - final Event loadTrue = EventFactory.newLoad(r3, expressions.makeAdd(r0, r2)); + final Event storeTrue = EventFactory.newStore(expressions.makePtrAdd(r0, r2), expressions.makeTrue()); + final Event loadTrue = EventFactory.newLoad(r3, expressions.makePtrAdd(r0, r2)); final Event assertTrue = EventFactory.newAssert(r3, "assert true"); f.append(List.of(allocX, allocY, storeIndex, loadIndex, storeTrue, loadTrue, assertTrue)); final Configuration config = Configuration.builder().build(); @@ -89,8 +89,8 @@ public void memToReg2() throws InvalidConfigurationException { final Program program = new Program(new Memory(), Program.SourceLanguage.LLVM); final Function f = new Function("f", types.getFunctionType(types.getVoidType(), List.of()), List.of(), 0, null); program.addFunction(f); - final Register r0 = f.newRegister("r0", types.getArchType()); - final Register r1 = f.newRegister("r1", types.getArchType()); + final Register r0 = f.newRegister("r0", types.getPointerType()); + final Register r1 = f.newRegister("r1", types.getPointerType()); final Register r2 = f.newRegister("r2", types.getArchType()); final Register r3 = f.newRegister("r3", types.getBooleanType()); final Event allocX = newAlloc(r0, types.getBooleanType(), 2); @@ -102,8 +102,8 @@ public void memToReg2() throws InvalidConfigurationException { final Event store0 = EventFactory.newStore(r1, expressions.makeValue(0, types.getArchType())); final Event store1 = EventFactory.newStore(r1, expressions.makeValue(1, types.getArchType())); final Event loadIndex = EventFactory.newLoad(r2, r1); - final Event storeTrue = EventFactory.newStore(expressions.makeAdd(r0, r2), expressions.makeTrue()); - final Event loadTrue = EventFactory.newLoad(r3, expressions.makeAdd(r0, r2)); + final Event storeTrue = EventFactory.newStore(expressions.makePtrAdd(r0, r2), expressions.makeTrue()); + final Event loadTrue = EventFactory.newLoad(r3, expressions.makePtrAdd(r0, r2)); final Event assertTrue = EventFactory.newAssert(r3, "assert true"); f.append(List.of(allocX, allocY, jumpNondet, store0, gotoEndIf, labelThen, store1, labelEndIf, @@ -130,9 +130,9 @@ public void memToReg3() throws InvalidConfigurationException { final Program program = new Program(new Memory(), Program.SourceLanguage.LLVM); final Function f = new Function("f", types.getFunctionType(types.getVoidType(), List.of()), List.of(), 0, null); program.addFunction(f); - final Register r0 = f.newRegister("r0", types.getArchType()); - final Register r1 = f.newRegister("r1", types.getArchType()); - final Register r2 = f.newRegister("r2", types.getArchType()); + final Register r0 = f.newRegister("r0", types.getPointerType()); + final Register r1 = f.newRegister("r1", types.getPointerType()); + final Register r2 = f.newRegister("r2", types.getPointerType()); final Register r3 = f.newRegister("r3", types.getBooleanType()); final Event allocX = newAlloc(r0, types.getBooleanType(), 2); final Event allocY = newAlloc(r1, types.getArchType(), 1); @@ -141,7 +141,7 @@ public void memToReg3() throws InvalidConfigurationException { final Event jumpNondet = EventFactory.newJump(program.newConstant(types.getBooleanType()), labelThen); final Event gotoEndIf = EventFactory.newGoto(labelEndIf); final Event store0 = EventFactory.newStore(r1, r0); - final Event store1 = EventFactory.newStore(r1, expressions.makeAdd(r0, expressions.makeValue(1, types.getArchType()))); + final Event store1 = EventFactory.newStore(r1, expressions.makePtrAdd(r0, expressions.makeValue(1, types.getArchType()))); final Event loadIndex = EventFactory.newLoad(r2, r1); final Event storeTrue = EventFactory.newStore(r2, expressions.makeTrue()); final Event loadTrue = EventFactory.newLoad(r3, r2); diff --git a/dartagnan/src/test/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/mocks/MockProgramBuilder.java b/dartagnan/src/test/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/mocks/MockProgramBuilder.java index 5261757872..f53b64012a 100644 --- a/dartagnan/src/test/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/mocks/MockProgramBuilder.java +++ b/dartagnan/src/test/java/com/dat3m/dartagnan/parsers/program/visitors/spirv/mocks/MockProgramBuilder.java @@ -17,6 +17,7 @@ import com.dat3m.dartagnan.program.memory.MemoryObject; import com.dat3m.dartagnan.program.memory.ScopedPointerVariable; +import java.math.BigInteger; import java.util.*; import java.util.stream.Collectors; @@ -89,6 +90,9 @@ public Expression mockConstant(String id, String typeId, Object value) { } else if (type instanceof IntegerType iType) { IntLiteral iValue = exprFactory.makeValue((int) value, iType); return addExpression(id, iValue); + }else if (type instanceof PointerType pType) { + IntLiteral pValue = exprFactory.makeValue(BigInteger.valueOf((int)value), pType.getBitWidth()); + return addExpression(id, exprFactory.makeIntToPtrCast(pValue,pType)); } else if (type instanceof ArrayType aType) { List elements = mockConstantArrayElements(aType.getElementType(), value); Expression construction = exprFactory.makeArray(aType, elements);