llvm2alive: add support for fwrite
the spec is a bit too verbose for my taste.. not ideal for sure
MODIFY
llvm_util/known_fns.cpp
llvm_util/known_fns.cpp
@@ -52,6 +52,14 @@ known_call(llvm::CallInst &i, const llvm::TargetLibraryInfo &TLI,
param_attrs[i].set(attr);
};
+ auto fputc_attr = [&]() {
+ attrs.set(FnAttrs::NoUndef);
+ attrs.set(FnAttrs::NoThrow);
+ set_param(0, ParamAttrs::NoUndef);
+ set_param(1, ParamAttrs::NoUndef);
+ set_param(1, ParamAttrs::NoCapture);
+ };
+
auto decl = i.getCalledFunction();
llvm::LibFunc libfn;
if (!decl || !TLI.getLibFunc(*decl, libfn) || !TLI.has(libfn))
@@ -102,14 +110,48 @@ known_call(llvm::CallInst &i, const llvm::TargetLibraryInfo &TLI,
parse_fmath(i)));
}
+ case llvm::LibFunc_fwrite: {
+ auto size = getInt(*args[1]);
+ auto count = getInt(*args[2]);
+ if (size && count) {
+ auto bytes = *size * *count;
+ // size_t fwrite(const void *ptr, 0, 0, FILE *stream) -> 0
+ if (bytes == 0)
+ RETURN_KNOWN(
+ make_unique<UnaryOp>(*ty, value_name(i),
+ *make_intconst(0, ty->bits()), UnaryOp::Copy));
+
+ // (void)fwrite(const void *ptr, 1, 1, FILE *stream) ->
+ // (void)fputc(int c, FILE *stream))
+ if (bytes == 1 && i.use_empty() && TLI.has(llvm::LibFunc_fputc)) {
+ fputc_attr();
+ auto &byteTy = get_int_type(8); // FIXME
+ auto &i32 = get_int_type(32);
+ auto call
+ = make_unique<FnCall>(i32, value_name(i), "@fputc", move(attrs));
+ auto load
+ = make_unique<Load>(byteTy, value_name(i) + "#load", *args[0], 1);
+ auto load_zext
+ = make_unique<ConversionOp>(i32, value_name(i) + "#zext", *load,
+ ConversionOp::ZExt);
+ call->addArg(*load_zext, move(param_attrs[0]));
+ call->addArg(*args[3], move(param_attrs[1]));
+ BB.addInstr(move(load));
+ BB.addInstr(move(load_zext));
+ RETURN_KNOWN(move(call));
+ }
+ }
+ attrs.set(FnAttrs::NoUndef);
+ attrs.set(FnAttrs::NoThrow);
+ set_param(0, ParamAttrs::NoCapture);
+ set_param(3, ParamAttrs::NoCapture);
+ RETURN_KNOWN_ATTRS();
+ }
+
case llvm::LibFunc_fputc:
case llvm::LibFunc_fputc_unlocked:
case llvm::LibFunc_fstat:
- attrs.set(FnAttrs::NoUndef);
- attrs.set(FnAttrs::NoThrow);
- set_param(0, ParamAttrs::NoUndef);
- set_param(1, ParamAttrs::NoUndef);
- set_param(1, ParamAttrs::NoCapture);
+ fputc_attr();
RETURN_KNOWN_ATTRS();
case llvm::LibFunc_fseek:

ADD
tests/alive-tv/libcalls/fwrite-1.srctgt.ll
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type opaque
+%struct._IO_codecvt = type opaque
+%struct._IO_wide_data = type opaque
+
+@.str = private unnamed_addr constant [5 x i8] c"xpto\00", align 1
+
+define i64 @src(%struct._IO_FILE* %f) {
+ %call = call i64 @fwrite(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i64 1, i64 0, %struct._IO_FILE* %f)
+ ret i64 %call
+}
+
+define i64 @tgt(%struct._IO_FILE* %f) {
+ ret i64 0
+}
+
+declare i64 @fwrite(i8*, i64, i64, %struct._IO_FILE*)

ADD
tests/alive-tv/libcalls/fwrite-2.srctgt.ll
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type opaque
+%struct._IO_codecvt = type opaque
+%struct._IO_wide_data = type opaque
+
+@.str = private unnamed_addr constant [5 x i8] c"xpto\00", align 1
+
+define void @src(%struct._IO_FILE* %f) {
+ %call = call i64 @fwrite(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i64 1, i64 1, %struct._IO_FILE* %f)
+ ret void
+}
+
+define void @tgt(%struct._IO_FILE* %f) {
+ %call = call i32 @fputc(i32 120, %struct._IO_FILE* %f)
+ ret void
+}
+
+declare i64 @fwrite(i8*, i64, i64, %struct._IO_FILE*)
+declare i32 @fputc(i32, %struct._IO_FILE*)

llvm2alive: add support for fwrite
the spec is a bit too verbose for my taste.. not ideal for sure