// #target: macos-x64 module test; import std; import libc; struct Doc { Head *head; } struct Head { char[]* title; } struct Summary { char[]* title; bool ok; } fn void Summary.print(Summary *s, CFile out) { // We don't have a native printf in C3 yet, so use libc, // which is not all that nice for the strings but... char[] title = s.title ? *s.title : "missing"; libc::fprintf(out, "Summary({ .title = %.*s, .ok = %s})", (int)title.len, title.ptr, s.ok ? (char*)"true" : (char*)"false"); } fn bool contains(char[] haystack, char[] needle) { usize len = haystack.len; usize needle_len = needle.len; if (len < needle_len) return false; if (!needle_len) return true; len -= needle_len - 1; for (usize i = 0; i < len; i++) { if (libc::memcmp(&haystack[i], needle.ptr, needle_len) == 0) { return true; } } return false; } macro dupe(value) { $typeof(&value) temp = mem::alloc($sizeof(value)); if (!temp) return ReadError.OUT_OF_MEMORY!; *temp = value; return temp; } fault ReadError { BAD_READ, OUT_OF_MEMORY } fn Doc! readDoc(char[] url) { if (contains(url, "fail")) return ReadError.BAD_READ!; if (contains(url, "head-missing")) return { .head = null }; if (contains(url, "title-missing")) return { dupe(Head { .title = null })? }; if (contains(url, "title-empty")) return { dupe(Head { .title = dupe((char[])"")? })? }; // Not particularly elegant due to missing string functions. int len = libc::snprintf(null, 0, "Title of %.*s", (int)url.len, url.ptr); char* str = mem::alloc(len + 1); if (!str) return ReadError.OUT_OF_MEMORY!; libc::snprintf(str, len + 1, "Title of %.*s", (int)url.len, url.ptr); return { dupe(Head { .title = dupe(str[..len - 1])? })? }; } fn Summary buildSummary(Doc doc) { return Summary { .title = doc.head ? doc.head.title : null, .ok = true, }; } fn Summary readAndBuildSummary(char[] url) { return buildSummary(readDoc(url)) ?? Summary { .title = null, .ok = false }; /* // or Summary summary = buildSummary(readDoc(url)); if (catch summary) return Summary { .title = null, .ok = false }; return summary; // or Summary summary = buildSummary(readDoc(url)); if (try summary) return summary; return Summary { .title = null, .ok = false }; */ } fault TitleResult { TITLE_MISSING } fn bool! isTitleNonEmpty(Doc doc) { if (!doc.head) return TitleResult.TITLE_MISSING!; char[]* head = doc.head.title; if (!head) return TitleResult.TITLE_MISSING!; return (*head).len > 0; } fn bool! readWhetherTitleNonEmpty(char[] url) { return isTitleNonEmpty(readDoc(url)); } fn char* bool_to_string(bool b) { return b ? "true" : "false"; } fn char* nameFromError(anyerr e) { switch (e) { case TitleResult.TITLE_MISSING: return "no title"; case ReadError.BAD_READ: return "bad read"; case ReadError.OUT_OF_MEMORY: return "out of memory"; default: return "unknown error"; } } fn void main() { const char[][] URLS = { "good", "title-empty", "title-missing", "head-missing", "fail" }; foreach (char[] url : URLS) { // Yes, it's pretty onerous to print strings for the moment in C3 libc::printf(`Checking "https://%.*s/":` "\n", (int)url.len, url.ptr); Summary summary = readAndBuildSummary(url); libc::printf(" Summary: "); summary.print(libc::stdout()); libc::printf("\n"); char[] title_sure = summary.title ? *summary.title : ""; libc::printf(" Title: %.*s\n", (int)title_sure.len, title_sure.ptr); bool! has_title = readWhetherTitleNonEmpty(url); // This looks a bit less than elegant, but as you see it's mostly due to having to // use printf here. libc::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? nameFromError(catch(has_title)), (has_title ?? false) ? (char*)"true" : (char*)"false"); } } /* #expect: test.ll define void @test_Summary_print(%Summary* %0, i8* %1) #0 { entry: %title = alloca %"char[]", align 8 %2 = getelementptr inbounds %Summary, %Summary* %0, i32 0, i32 0 %3 = load %"char[]"*, %"char[]"** %2, align 8 %ptrbool = icmp ne %"char[]"* %3, null br i1 %ptrbool, label %cond.lhs, label %cond.rhs cond.lhs: ; preds = %entry %4 = getelementptr inbounds %Summary, %Summary* %0, i32 0, i32 0 %5 = load %"char[]"*, %"char[]"** %4, align 8 %6 = load %"char[]", %"char[]"* %5, align 8 br label %cond.phi cond.rhs: ; preds = %entry br label %cond.phi cond.phi: ; preds = %cond.rhs, %cond.lhs %val = phi %"char[]" [ %6, %cond.lhs ], [ { i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.28, i32 0, i32 0), i64 7 }, %cond.rhs ] store %"char[]" %val, %"char[]"* %title, align 8 %7 = getelementptr inbounds %"char[]", %"char[]"* %title, i32 0, i32 1 %8 = load i64, i64* %7, align 8 %uisitrunc = trunc i64 %8 to i32 %9 = getelementptr inbounds %"char[]", %"char[]"* %title, i32 0, i32 0 %10 = load i8*, i8** %9, align 8 %11 = getelementptr inbounds %Summary, %Summary* %0, i32 0, i32 1 %12 = load i8, i8* %11, align 8 %13 = trunc i8 %12 to i1 %ternary = select i1 %13, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.30, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.31, i32 0, i32 0) %14 = call i32 (i8*, i8*, ...) @fprintf(i8* %1, i8* getelementptr inbounds ([36 x i8], [36 x i8]* @.str.29, i32 0, i32 0), i32 %uisitrunc, i8* %10, i8* %ternary) ret void } ; Function Attrs: nounwind define zeroext i8 @test_contains(i8* %0, i64 %1, i8* %2, i64 %3) #0 { entry: %haystack = alloca %"char[]", align 8 %needle = alloca %"char[]", align 8 %len = alloca i64, align 8 %needle_len = alloca i64, align 8 %i = alloca i64, align 8 %pair = bitcast %"char[]"* %haystack to { i8*, i64 }* %4 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 store i8* %0, i8** %4, align 8 %5 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 store i64 %1, i64* %5, align 8 %pair1 = bitcast %"char[]"* %needle to { i8*, i64 }* %6 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 0 store i8* %2, i8** %6, align 8 %7 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair1, i32 0, i32 1 store i64 %3, i64* %7, align 8 %8 = getelementptr inbounds %"char[]", %"char[]"* %haystack, i32 0, i32 1 %9 = load i64, i64* %8, align 8 store i64 %9, i64* %len, align 8 %10 = getelementptr inbounds %"char[]", %"char[]"* %needle, i32 0, i32 1 %11 = load i64, i64* %10, align 8 store i64 %11, i64* %needle_len, align 8 %12 = load i64, i64* %len, align 8 %13 = load i64, i64* %needle_len, align 8 %lt = icmp ult i64 %12, %13 br i1 %lt, label %if.then, label %if.exit if.then: ; preds = %entry ret i8 0 if.exit: ; preds = %entry %14 = load i64, i64* %needle_len, align 8 %not = icmp eq i64 %14, 0 br i1 %not, label %if.then2, label %if.exit3 if.then2: ; preds = %if.exit ret i8 1 if.exit3: ; preds = %if.exit %15 = load i64, i64* %len, align 8 %16 = load i64, i64* %needle_len, align 8 %sub = sub i64 %16, 1 %sub4 = sub i64 %15, %sub store i64 %sub4, i64* %len, align 8 store i64 0, i64* %i, align 8 br label %loop.cond loop.cond: ; preds = %if.exit7, %if.exit3 %17 = load i64, i64* %i, align 8 %18 = load i64, i64* %len, align 8 %lt5 = icmp ult i64 %17, %18 br i1 %lt5, label %loop.body, label %loop.exit loop.body: ; preds = %loop.cond %19 = getelementptr inbounds %"char[]", %"char[]"* %haystack, i32 0, i32 0 %20 = load i8*, i8** %19, align 8 %21 = load i64, i64* %i, align 8 %ptroffset = getelementptr inbounds i8, i8* %20, i64 %21 %22 = getelementptr inbounds %"char[]", %"char[]"* %needle, i32 0, i32 0 %23 = load i8*, i8** %22, align 8 %24 = load i64, i64* %needle_len, align 8 %25 = call i32 @memcmp(i8* %ptroffset, i8* %23, i64 %24) %eq = icmp eq i32 %25, 0 br i1 %eq, label %if.then6, label %if.exit7 if.then6: ; preds = %loop.body ret i8 1 if.exit7: ; preds = %loop.body %26 = load i64, i64* %i, align 8 %add = add i64 %26, 1 store i64 %add, i64* %i, align 8 br label %loop.cond loop.exit: ; preds = %loop.cond ret i8 0 } ; Function Attrs: nounwind define i64 @test_readDoc(%Doc* %0, i8* %1, i64 %2) #0 { entry: %url = alloca %"char[]", align 8 %taddr = alloca %"char[]", align 8 %taddr5 = alloca %"char[]", align 8 %reterr = alloca i64, align 8 %literal = alloca %Doc, align 8 %taddr12 = alloca %"char[]", align 8 %reterr16 = alloca i64, align 8 %literal17 = alloca %Doc, align 8 %error_var = alloca i64, align 8 %value = alloca %Head, align 8 %literal18 = alloca %Head, align 8 %temp = alloca %Head*, align 8 %taddr24 = alloca %"char[]", align 8 %reterr28 = alloca i64, align 8 %literal29 = alloca %Doc, align 8 %error_var30 = alloca i64, align 8 %value31 = alloca %Head, align 8 %literal32 = alloca %Head, align 8 %error_var33 = alloca i64, align 8 %value34 = alloca %"char[]", align 8 %temp35 = alloca %"char[]"*, align 8 %temp42 = alloca %Head*, align 8 %len = alloca i32, align 4 %str = alloca i8*, align 8 %reterr56 = alloca i64, align 8 %literal57 = alloca %Doc, align 8 %error_var58 = alloca i64, align 8 %value59 = alloca %Head, align 8 %literal60 = alloca %Head, align 8 %error_var61 = alloca i64, align 8 %value62 = alloca %"char[]", align 8 %temp63 = alloca %"char[]"*, align 8 %temp70 = alloca %Head*, align 8 %pair = bitcast %"char[]"* %url to { i8*, i64 }* %3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 store i8* %1, i8** %3, align 8 %4 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 store i64 %2, i64* %4, align 8 %5 = bitcast %"char[]"* %url to { i8*, i64 }* %6 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %5, i32 0, i32 0 %lo = load i8*, i8** %6, align 8 %7 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %5, i32 0, i32 1 %hi = load i64, i64* %7, align 8 store %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), i64 4 }, %"char[]"* %taddr, align 8 %8 = bitcast %"char[]"* %taddr to { i8*, i64 }* %9 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %8, i32 0, i32 0 %lo1 = load i8*, i8** %9, align 8 %10 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %8, i32 0, i32 1 %hi2 = load i64, i64* %10, align 8 %11 = call i8 @test_contains(i8* %lo, i64 %hi, i8* %lo1, i64 %hi2) %12 = trunc i8 %11 to i1 br i1 %12, label %if.then, label %if.exit if.then: ; preds = %entry ret i64 ptrtoint (%.fault* @"test_ReadError$BAD_READ" to i64) if.exit: ; preds = %entry %13 = bitcast %"char[]"* %url to { i8*, i64 }* %14 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %13, i32 0, i32 0 %lo3 = load i8*, i8** %14, align 8 %15 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %13, i32 0, i32 1 %hi4 = load i64, i64* %15, align 8 store %"char[]" { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.3, i32 0, i32 0), i64 12 }, %"char[]"* %taddr5, align 8 %16 = bitcast %"char[]"* %taddr5 to { i8*, i64 }* %17 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %16, i32 0, i32 0 %lo6 = load i8*, i8** %17, align 8 %18 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %16, i32 0, i32 1 %hi7 = load i64, i64* %18, align 8 %19 = call i8 @test_contains(i8* %lo3, i64 %hi4, i8* %lo6, i64 %hi7) %20 = trunc i8 %19 to i1 br i1 %20, label %if.then8, label %if.exit9 if.then8: ; preds = %if.exit %21 = getelementptr inbounds %Doc, %Doc* %literal, i32 0, i32 0 store %Head* null, %Head** %21, align 8 %22 = bitcast %Doc* %0 to i8* %23 = bitcast %Doc* %literal to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 %23, i32 8, i1 false) ret i64 0 if.exit9: ; preds = %if.exit %24 = bitcast %"char[]"* %url to { i8*, i64 }* %25 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %24, i32 0, i32 0 %lo10 = load i8*, i8** %25, align 8 %26 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %24, i32 0, i32 1 %hi11 = load i64, i64* %26, align 8 store %"char[]" { i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.4, i32 0, i32 0), i64 13 }, %"char[]"* %taddr12, align 8 %27 = bitcast %"char[]"* %taddr12 to { i8*, i64 }* %28 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %27, i32 0, i32 0 %lo13 = load i8*, i8** %28, align 8 %29 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %27, i32 0, i32 1 %hi14 = load i64, i64* %29, align 8 %30 = call i8 @test_contains(i8* %lo10, i64 %hi11, i8* %lo13, i64 %hi14) %31 = trunc i8 %30 to i1 br i1 %31, label %if.then15, label %if.exit21 if.then15: ; preds = %if.exit9 %32 = getelementptr inbounds %Doc, %Doc* %literal17, i32 0, i32 0 %33 = getelementptr inbounds %Head, %Head* %literal18, i32 0, i32 0 store %"char[]"* null, %"char[]"** %33, align 8 %34 = load %Head, %Head* %literal18, align 8 store %Head %34, %Head* %value, align 8 %35 = call i8* @std_core_mem_alloc(i64 8, i64 0) %ptrptr = bitcast i8* %35 to %Head* store %Head* %ptrptr, %Head** %temp, align 8 %36 = load %Head*, %Head** %temp, align 8 %not = icmp eq %Head* %36, null br i1 %not, label %if.then19, label %if.exit20 if.then19: ; preds = %if.then15 store i64 ptrtoint (%.fault* @"test_ReadError$OUT_OF_MEMORY" to i64), i64* %error_var, align 8 br label %guard_block if.exit20: ; preds = %if.then15 %37 = load %Head*, %Head** %temp, align 8 %38 = bitcast %Head* %37 to i8* %39 = bitcast %Head* %value to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %38, i8* align 8 %39, i32 8, i1 false) br label %noerr_block guard_block: ; preds = %if.then19 %40 = load i64, i64* %error_var, align 8 ret i64 %40 noerr_block: ; preds = %if.exit20 %41 = load %Head*, %Head** %temp, align 8 store %Head* %41, %Head** %32, align 8 %42 = bitcast %Doc* %0 to i8* %43 = bitcast %Doc* %literal17 to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %42, i8* align 8 %43, i32 8, i1 false) ret i64 0 if.exit21: ; preds = %if.exit9 %44 = bitcast %"char[]"* %url to { i8*, i64 }* %45 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 0 %lo22 = load i8*, i8** %45, align 8 %46 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 1 %hi23 = load i64, i64* %46, align 8 store %"char[]" { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.5, i32 0, i32 0), i64 11 }, %"char[]"* %taddr24, align 8 %47 = bitcast %"char[]"* %taddr24 to { i8*, i64 }* %48 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %47, i32 0, i32 0 %lo25 = load i8*, i8** %48, align 8 %49 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %47, i32 0, i32 1 %hi26 = load i64, i64* %49, align 8 %50 = call i8 @test_contains(i8* %lo22, i64 %hi23, i8* %lo25, i64 %hi26) %51 = trunc i8 %50 to i1 br i1 %51, label %if.then27, label %if.exit49 if.then27: ; preds = %if.exit21 %52 = getelementptr inbounds %Doc, %Doc* %literal29, i32 0, i32 0 %53 = bitcast %Head* %literal32 to %"char[]"** store %"char[]"* null, %"char[]"** %53, align 8 %54 = getelementptr inbounds %Head, %Head* %literal32, i32 0, i32 0 store %"char[]" zeroinitializer, %"char[]"* %value34, align 8 %55 = call i8* @std_core_mem_alloc(i64 16, i64 0) %ptrptr36 = bitcast i8* %55 to %"char[]"* store %"char[]"* %ptrptr36, %"char[]"** %temp35, align 8 %56 = load %"char[]"*, %"char[]"** %temp35, align 8 %not37 = icmp eq %"char[]"* %56, null br i1 %not37, label %if.then38, label %if.exit39 if.then38: ; preds = %if.then27 store i64 ptrtoint (%.fault* @"test_ReadError$OUT_OF_MEMORY" to i64), i64* %error_var33, align 8 br label %guard_block40 if.exit39: ; preds = %if.then27 %57 = load %"char[]"*, %"char[]"** %temp35, align 8 %58 = bitcast %"char[]"* %57 to i8* %59 = bitcast %"char[]"* %value34 to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %58, i8* align 8 %59, i32 16, i1 false) br label %noerr_block41 guard_block40: ; preds = %if.then38 %60 = load i64, i64* %error_var33, align 8 ret i64 %60 noerr_block41: ; preds = %if.exit39 %61 = load %"char[]"*, %"char[]"** %temp35, align 8 store %"char[]"* %61, %"char[]"** %54, align 8 %62 = load %Head, %Head* %literal32, align 8 store %Head %62, %Head* %value31, align 8 %63 = call i8* @std_core_mem_alloc(i64 8, i64 0) %ptrptr43 = bitcast i8* %63 to %Head* store %Head* %ptrptr43, %Head** %temp42, align 8 %64 = load %Head*, %Head** %temp42, align 8 %not44 = icmp eq %Head* %64, null br i1 %not44, label %if.then45, label %if.exit46 if.then45: ; preds = %noerr_block41 store i64 ptrtoint (%.fault* @"test_ReadError$OUT_OF_MEMORY" to i64), i64* %error_var30, align 8 br label %guard_block47 if.exit46: ; preds = %noerr_block41 %65 = load %Head*, %Head** %temp42, align 8 %66 = bitcast %Head* %65 to i8* %67 = bitcast %Head* %value31 to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %66, i8* align 8 %67, i32 8, i1 false) br label %noerr_block48 guard_block47: ; preds = %if.then45 %68 = load i64, i64* %error_var30, align 8 ret i64 %68 noerr_block48: ; preds = %if.exit46 %69 = load %Head*, %Head** %temp42, align 8 store %Head* %69, %Head** %52, align 8 %70 = bitcast %Doc* %0 to i8* %71 = bitcast %Doc* %literal29 to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %70, i8* align 8 %71, i32 8, i1 false) ret i64 0 if.exit49: ; preds = %if.exit21 %72 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 1 %73 = load i64, i64* %72, align 8 %uisitrunc = trunc i64 %73 to i32 %74 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 0 %75 = load i8*, i8** %74, align 8 %76 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.7, i32 0, i32 0), i32 %uisitrunc, i8* %75) store i32 %76, i32* %len, align 4 %77 = load i32, i32* %len, align 4 %siuiext = sext i32 %77 to i64 %add = add i64 %siuiext, 1 %78 = call i8* @std_core_mem_alloc(i64 %add, i64 0) store i8* %78, i8** %str, align 8 %79 = load i8*, i8** %str, align 8 %not50 = icmp eq i8* %79, null br i1 %not50, label %if.then51, label %if.exit52 if.then51: ; preds = %if.exit49 ret i64 ptrtoint (%.fault* @"test_ReadError$OUT_OF_MEMORY" to i64) if.exit52: ; preds = %if.exit49 %80 = load i8*, i8** %str, align 8 %81 = load i32, i32* %len, align 4 %siuiext53 = sext i32 %81 to i64 %add54 = add i64 %siuiext53, 1 %82 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 1 %83 = load i64, i64* %82, align 8 %uisitrunc55 = trunc i64 %83 to i32 %84 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 0 %85 = load i8*, i8** %84, align 8 %86 = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %80, i64 %add54, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.8, i32 0, i32 0), i32 %uisitrunc55, i8* %85) %87 = getelementptr inbounds %Doc, %Doc* %literal57, i32 0, i32 0 %88 = bitcast %Head* %literal60 to %"char[]"** store %"char[]"* null, %"char[]"** %88, align 8 %89 = getelementptr inbounds %Head, %Head* %literal60, i32 0, i32 0 %90 = load i8*, i8** %str, align 8 %91 = load i32, i32* %len, align 4 %sub = sub i32 %91, 1 %sisiext = sext i32 %sub to i64 %92 = add i64 %sisiext, 1 %size = sub i64 %92, 0 %ptroffset = getelementptr inbounds i8, i8* %90, i64 0 %93 = insertvalue %"char[]" undef, i8* %ptroffset, 0 %94 = insertvalue %"char[]" %93, i64 %size, 1 store %"char[]" %94, %"char[]"* %value62, align 8 %95 = call i8* @std_core_mem_alloc(i64 16, i64 0) %ptrptr64 = bitcast i8* %95 to %"char[]"* store %"char[]"* %ptrptr64, %"char[]"** %temp63, align 8 %96 = load %"char[]"*, %"char[]"** %temp63, align 8 %not65 = icmp eq %"char[]"* %96, null br i1 %not65, label %if.then66, label %if.exit67 if.then66: ; preds = %if.exit52 store i64 ptrtoint (%.fault* @"test_ReadError$OUT_OF_MEMORY" to i64), i64* %error_var61, align 8 br label %guard_block68 if.exit67: ; preds = %if.exit52 %97 = load %"char[]"*, %"char[]"** %temp63, align 8 %98 = bitcast %"char[]"* %97 to i8* %99 = bitcast %"char[]"* %value62 to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %98, i8* align 8 %99, i32 16, i1 false) br label %noerr_block69 guard_block68: ; preds = %if.then66 %100 = load i64, i64* %error_var61, align 8 ret i64 %100 noerr_block69: ; preds = %if.exit67 %101 = load %"char[]"*, %"char[]"** %temp63, align 8 store %"char[]"* %101, %"char[]"** %89, align 8 %102 = load %Head, %Head* %literal60, align 8 store %Head %102, %Head* %value59, align 8 %103 = call i8* @std_core_mem_alloc(i64 8, i64 0) %ptrptr71 = bitcast i8* %103 to %Head* store %Head* %ptrptr71, %Head** %temp70, align 8 %104 = load %Head*, %Head** %temp70, align 8 %not72 = icmp eq %Head* %104, null br i1 %not72, label %if.then73, label %if.exit74 if.then73: ; preds = %noerr_block69 store i64 ptrtoint (%.fault* @"test_ReadError$OUT_OF_MEMORY" to i64), i64* %error_var58, align 8 br label %guard_block75 if.exit74: ; preds = %noerr_block69 %105 = load %Head*, %Head** %temp70, align 8 %106 = bitcast %Head* %105 to i8* %107 = bitcast %Head* %value59 to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %106, i8* align 8 %107, i32 8, i1 false) br label %noerr_block76 guard_block75: ; preds = %if.then73 %108 = load i64, i64* %error_var58, align 8 ret i64 %108 noerr_block76: ; preds = %if.exit74 %109 = load %Head*, %Head** %temp70, align 8 store %Head* %109, %Head** %87, align 8 %110 = bitcast %Doc* %0 to i8* %111 = bitcast %Doc* %literal57 to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %110, i8* align 8 %111, i32 8, i1 false) ret i64 0 } ; Function Attrs: nounwind define { %"char[]"*, i8 } @test_buildSummary(%Head* %0) #0 { entry: %doc = alloca %Doc, align 8 %literal = alloca %Summary, align 8 %tempcoerce = alloca { %"char[]"*, i8 }, align 8 %1 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0 store %Head* %0, %Head** %1, align 8 %2 = getelementptr inbounds %Summary, %Summary* %literal, i32 0, i32 0 store %"char[]"* null, %"char[]"** %2, align 8 %3 = getelementptr inbounds %Summary, %Summary* %literal, i32 0, i32 1 store i8 0, i8* %3, align 8 %4 = getelementptr inbounds %Summary, %Summary* %literal, i32 0, i32 0 %5 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0 %6 = load %Head*, %Head** %5, align 8 %ptrbool = icmp ne %Head* %6, null br i1 %ptrbool, label %cond.lhs, label %cond.rhs cond.lhs: ; preds = %entry %7 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0 %8 = load %Head*, %Head** %7, align 8 %9 = getelementptr inbounds %Head, %Head* %8, i32 0, i32 0 %10 = load %"char[]"*, %"char[]"** %9, align 8 %ptrptr = bitcast %"char[]"* %10 to i8* br label %cond.phi cond.rhs: ; preds = %entry br label %cond.phi cond.phi: ; preds = %cond.rhs, %cond.lhs %val = phi i8* [ %ptrptr, %cond.lhs ], [ null, %cond.rhs ] %ptrptr1 = bitcast i8* %val to %"char[]"* store %"char[]"* %ptrptr1, %"char[]"** %4, align 8 %11 = getelementptr inbounds %Summary, %Summary* %literal, i32 0, i32 1 store i8 1, i8* %11, align 8 %12 = bitcast { %"char[]"*, i8 }* %tempcoerce to i8* %13 = bitcast %Summary* %literal to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %12, i8* align 8 %13, i32 16, i1 false) %14 = load { %"char[]"*, i8 }, { %"char[]"*, i8 }* %tempcoerce, align 8 ret { %"char[]"*, i8 } %14 } ; Function Attrs: nounwind define { %"char[]"*, i8 } @test_readAndBuildSummary(i8* %0, i64 %1) #0 { entry: %url = alloca %"char[]", align 8 %retparam = alloca %Doc, align 8 %result = alloca %Summary, align 8 %literal = alloca %Summary, align 8 %taddr = alloca %Summary, align 8 %tempcoerce = alloca { %"char[]"*, i8 }, align 8 %pair = bitcast %"char[]"* %url to { i8*, i64 }* %2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 store i8* %0, i8** %2, align 8 %3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 store i64 %1, i64* %3, align 8 %4 = bitcast %"char[]"* %url to { i8*, i64 }* %5 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %4, i32 0, i32 0 %lo = load i8*, i8** %5, align 8 %6 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %4, i32 0, i32 1 %hi = load i64, i64* %6, align 8 %7 = call i64 @test_readDoc(%Doc* %retparam, i8* %lo, i64 %hi) %not_err = icmp eq i64 %7, 0 br i1 %not_err, label %after.errcheck, label %else_block after.errcheck: ; preds = %entry %8 = getelementptr inbounds %Doc, %Doc* %retparam, i32 0, i32 0 %9 = load %Head*, %Head** %8, align 8 %10 = call { %"char[]"*, i8 } @test_buildSummary(%Head* %9) %11 = bitcast %Summary* %result to { %"char[]"*, i8 }* store { %"char[]"*, i8 } %10, { %"char[]"*, i8 }* %11, align 8 %12 = load %Summary, %Summary* %result, align 8 br label %phi_block else_block: ; preds = %entry %13 = getelementptr inbounds %Summary, %Summary* %literal, i32 0, i32 0 store %"char[]"* null, %"char[]"** %13, align 8 %14 = getelementptr inbounds %Summary, %Summary* %literal, i32 0, i32 1 store i8 0, i8* %14, align 8 %15 = load %Summary, %Summary* %literal, align 8 br label %phi_block phi_block: ; preds = %else_block, %after.errcheck %val = phi %Summary [ %12, %after.errcheck ], [ %15, %else_block ] store %Summary %val, %Summary* %taddr, align 8 %16 = bitcast { %"char[]"*, i8 }* %tempcoerce to i8* %17 = bitcast %Summary* %taddr to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %16, i8* align 8 %17, i32 16, i1 false) %18 = load { %"char[]"*, i8 }, { %"char[]"*, i8 }* %tempcoerce, align 8 ret { %"char[]"*, i8 } %18 } ; Function Attrs: nounwind define i64 @test_isTitleNonEmpty(i8* %0, %Head* %1) #0 { entry: %doc = alloca %Doc, align 8 %head = alloca %"char[]"*, align 8 %reterr = alloca i64, align 8 %2 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0 store %Head* %1, %Head** %2, align 8 %3 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0 %4 = load %Head*, %Head** %3, align 8 %not = icmp eq %Head* %4, null br i1 %not, label %if.then, label %if.exit if.then: ; preds = %entry ret i64 ptrtoint (%.fault* @"test_TitleResult$TITLE_MISSING" to i64) if.exit: ; preds = %entry %5 = getelementptr inbounds %Doc, %Doc* %doc, i32 0, i32 0 %6 = load %Head*, %Head** %5, align 8 %7 = getelementptr inbounds %Head, %Head* %6, i32 0, i32 0 %8 = load %"char[]"*, %"char[]"** %7, align 8 store %"char[]"* %8, %"char[]"** %head, align 8 %9 = load %"char[]"*, %"char[]"** %head, align 8 %not1 = icmp eq %"char[]"* %9, null br i1 %not1, label %if.then2, label %if.exit3 if.then2: ; preds = %if.exit ret i64 ptrtoint (%.fault* @"test_TitleResult$TITLE_MISSING" to i64) if.exit3: ; preds = %if.exit %10 = load %"char[]"*, %"char[]"** %head, align 8 %11 = getelementptr inbounds %"char[]", %"char[]"* %10, i32 0, i32 1 %12 = load i64, i64* %11, align 8 %lt = icmp ult i64 0, %12 %13 = zext i1 %lt to i8 store i8 %13, i8* %0, align 1 ret i64 0 } ; Function Attrs: nounwind define i64 @test_readWhetherTitleNonEmpty(i8* %0, i8* %1, i64 %2) #0 { entry: %url = alloca %"char[]", align 8 %reterr = alloca i64, align 8 %retparam = alloca i8, align 1 %retparam1 = alloca %Doc, align 8 %pair = bitcast %"char[]"* %url to { i8*, i64 }* %3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 store i8* %1, i8** %3, align 8 %4 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1 store i64 %2, i64* %4, align 8 %5 = bitcast %"char[]"* %url to { i8*, i64 }* %6 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %5, i32 0, i32 0 %lo = load i8*, i8** %6, align 8 %7 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %5, i32 0, i32 1 %hi = load i64, i64* %7, align 8 %8 = call i64 @test_readDoc(%Doc* %retparam1, i8* %lo, i64 %hi) %not_err = icmp eq i64 %8, 0 br i1 %not_err, label %after.errcheck, label %error error: ; preds = %entry store i64 %8, i64* %reterr, align 8 br label %err_retblock after.errcheck: ; preds = %entry %9 = getelementptr inbounds %Doc, %Doc* %retparam1, i32 0, i32 0 %10 = load %Head*, %Head** %9, align 8 %11 = call i64 @test_isTitleNonEmpty(i8* %retparam, %Head* %10) %not_err2 = icmp eq i64 %11, 0 br i1 %not_err2, label %after.errcheck4, label %error3 error3: ; preds = %after.errcheck store i64 %11, i64* %reterr, align 8 br label %err_retblock after.errcheck4: ; preds = %after.errcheck %12 = load i8, i8* %retparam, align 1 store i8 %12, i8* %0, align 1 ret i64 0 err_retblock: ; preds = %error3, %error %13 = load i64, i64* %reterr, align 8 ret i64 %13 } ; Function Attrs: nounwind define i8* @test_bool_to_string(i8 zeroext %0) #0 { entry: %1 = trunc i8 %0 to i1 %ternary = select i1 %1, %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.9, i32 0, i32 0), i64 4 }, %"char[]" { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.10, i32 0, i32 0), i64 5 } %2 = extractvalue %"char[]" %ternary, 0 ret i8* %2 } ; Function Attrs: nounwind define i8* @test_nameFromError(i64 %0) #0 { entry: %switch = alloca i64, align 8 store i64 %0, i64* %switch, align 8 br label %switch.entry switch.entry: ; preds = %entry %1 = load i64, i64* %switch, align 8 %eq = icmp eq i64 ptrtoint (%.fault* @"test_TitleResult$TITLE_MISSING" to i64), %1 br i1 %eq, label %switch.case, label %next_if switch.case: ; preds = %switch.entry ret i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.11, i32 0, i32 0) next_if: ; preds = %switch.entry %eq1 = icmp eq i64 ptrtoint (%.fault* @"test_ReadError$BAD_READ" to i64), %1 br i1 %eq1, label %switch.case2, label %next_if3 switch.case2: ; preds = %next_if ret i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.12, i32 0, i32 0) next_if3: ; preds = %next_if %eq4 = icmp eq i64 ptrtoint (%.fault* @"test_ReadError$OUT_OF_MEMORY" to i64), %1 br i1 %eq4, label %switch.case5, label %next_if6 switch.case5: ; preds = %next_if3 ret i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.13, i32 0, i32 0) next_if6: ; preds = %next_if3 br label %switch.default switch.default: ; preds = %next_if6 ret i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.14, i32 0, i32 0) } ; Function Attrs: nounwind define void @test_main() #0 { entry: %URLS = alloca %"char[][]", align 8 %literal = alloca [5 x %"char[]"], align 16 %anon = alloca i64, align 8 %anon1 = alloca %"char[][]", align 8 %anon2 = alloca i64, align 8 %url = alloca %"char[]", align 8 %summary = alloca %Summary, align 8 %result = alloca %Summary, align 8 %title_sure = alloca %"char[]", align 8 %has_title = alloca i8, align 1 %has_title.f = alloca i64, align 8 %retparam = alloca i8, align 1 %0 = getelementptr inbounds [5 x %"char[]"], [5 x %"char[]"]* %literal, i64 0, i64 0 store %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.15, i32 0, i32 0), i64 4 }, %"char[]"* %0, align 8 %1 = getelementptr inbounds [5 x %"char[]"], [5 x %"char[]"]* %literal, i64 0, i64 1 store %"char[]" { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.16, i32 0, i32 0), i64 11 }, %"char[]"* %1, align 8 %2 = getelementptr inbounds [5 x %"char[]"], [5 x %"char[]"]* %literal, i64 0, i64 2 store %"char[]" { i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.17, i32 0, i32 0), i64 13 }, %"char[]"* %2, align 8 %3 = getelementptr inbounds [5 x %"char[]"], [5 x %"char[]"]* %literal, i64 0, i64 3 store %"char[]" { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.18, i32 0, i32 0), i64 12 }, %"char[]"* %3, align 8 %4 = getelementptr inbounds [5 x %"char[]"], [5 x %"char[]"]* %literal, i64 0, i64 4 store %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.19, i32 0, i32 0), i64 4 }, %"char[]"* %4, align 8 %5 = bitcast [5 x %"char[]"]* %literal to %"char[]"* %6 = insertvalue %"char[][]" undef, %"char[]"* %5, 0 %7 = insertvalue %"char[][]" %6, i64 5, 1 store %"char[][]" %7, %"char[][]"* %URLS, align 8 store i64 0, i64* %anon, align 8 %8 = bitcast %"char[][]"* %anon1 to i8* %9 = bitcast %"char[][]"* %URLS to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %8, i8* align 8 %9, i32 16, i1 false) %10 = getelementptr inbounds %"char[][]", %"char[][]"* %anon1, i32 0, i32 1 %11 = load i64, i64* %10, align 8 store i64 %11, i64* %anon2, align 8 br label %loop.cond loop.cond: ; preds = %phi_block11, %entry %12 = load i64, i64* %anon, align 8 %13 = load i64, i64* %anon2, align 8 %lt = icmp ult i64 %12, %13 br i1 %lt, label %loop.body, label %loop.exit loop.body: ; preds = %loop.cond %14 = getelementptr inbounds %"char[][]", %"char[][]"* %anon1, i32 0, i32 0 %15 = load %"char[]"*, %"char[]"** %14, align 8 %16 = load i64, i64* %anon, align 8 %ptroffset = getelementptr inbounds %"char[]", %"char[]"* %15, i64 %16 %17 = bitcast %"char[]"* %url to i8* %18 = bitcast %"char[]"* %ptroffset to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %17, i8* align 8 %18, i32 16, i1 false) %19 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 1 %20 = load i64, i64* %19, align 8 %uisitrunc = trunc i64 %20 to i32 %21 = getelementptr inbounds %"char[]", %"char[]"* %url, i32 0, i32 0 %22 = load i8*, i8** %21, align 8 %23 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.20, i32 0, i32 0), i32 %uisitrunc, i8* %22) %24 = bitcast %"char[]"* %url to { i8*, i64 }* %25 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %24, i32 0, i32 0 %lo = load i8*, i8** %25, align 8 %26 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %24, i32 0, i32 1 %hi = load i64, i64* %26, align 8 %27 = call { %"char[]"*, i8 } @test_readAndBuildSummary(i8* %lo, i64 %hi) %28 = bitcast %Summary* %result to { %"char[]"*, i8 }* store { %"char[]"*, i8 } %27, { %"char[]"*, i8 }* %28, align 8 %29 = bitcast %Summary* %summary to i8* %30 = bitcast %Summary* %result to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %29, i8* align 8 %30, i32 16, i1 false) %31 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.21, i32 0, i32 0)) %32 = load i8*, i8** @__stdoutp, align 8 call void @test_Summary_print(%Summary* %summary, i8* %32) %33 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.22, i32 0, i32 0)) %34 = getelementptr inbounds %Summary, %Summary* %summary, i32 0, i32 0 %35 = load %"char[]"*, %"char[]"** %34, align 8 %ptrbool = icmp ne %"char[]"* %35, null br i1 %ptrbool, label %cond.lhs, label %cond.rhs cond.lhs: ; preds = %loop.body %36 = getelementptr inbounds %Summary, %Summary* %summary, i32 0, i32 0 %37 = load %"char[]"*, %"char[]"** %36, align 8 %38 = load %"char[]", %"char[]"* %37, align 8 br label %cond.phi cond.rhs: ; preds = %loop.body br label %cond.phi cond.phi: ; preds = %cond.rhs, %cond.lhs %val = phi %"char[]" [ %38, %cond.lhs ], [ zeroinitializer, %cond.rhs ] store %"char[]" %val, %"char[]"* %title_sure, align 8 %39 = getelementptr inbounds %"char[]", %"char[]"* %title_sure, i32 0, i32 1 %40 = load i64, i64* %39, align 8 %uisitrunc3 = trunc i64 %40 to i32 %41 = getelementptr inbounds %"char[]", %"char[]"* %title_sure, i32 0, i32 0 %42 = load i8*, i8** %41, align 8 %43 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.24, i32 0, i32 0), i32 %uisitrunc3, i8* %42) %44 = bitcast %"char[]"* %url to { i8*, i64 }* %45 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 0 %lo4 = load i8*, i8** %45, align 8 %46 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 1 %hi5 = load i64, i64* %46, align 8 %47 = call i64 @test_readWhetherTitleNonEmpty(i8* %retparam, i8* %lo4, i64 %hi5) %not_err = icmp eq i64 %47, 0 br i1 %not_err, label %after.errcheck, label %error error: ; preds = %cond.phi store i64 %47, i64* %has_title.f, align 8 br label %after_assign after.errcheck: ; preds = %cond.phi %48 = load i8, i8* %retparam, align 1 store i8 %48, i8* %has_title, align 1 store i64 0, i64* %has_title.f, align 8 br label %after_assign after_assign: ; preds = %after.errcheck, %error %49 = load i64, i64* %has_title.f, align 8 %not_err6 = icmp eq i64 %49, 0 br i1 %not_err6, label %after_check, label %else_block after_check: ; preds = %after_assign %50 = load i8, i8* %has_title, align 1 %51 = call i8* @test_bool_to_string(i8 %50) br label %phi_block else_block: ; preds = %after_assign %52 = load i64, i64* %has_title.f, align 8 %53 = call i8* @test_nameFromError(i64 %52) br label %phi_block phi_block: ; preds = %else_block, %after_check %val7 = phi i8* [ %51, %after_check ], [ %53, %else_block ] %54 = load i64, i64* %has_title.f, align 8 %not_err8 = icmp eq i64 %54, 0 br i1 %not_err8, label %after_check9, label %else_block10 after_check9: ; preds = %phi_block %55 = load i8, i8* %has_title, align 1 %56 = trunc i8 %55 to i1 br label %phi_block11 else_block10: ; preds = %phi_block br label %phi_block11 phi_block11: ; preds = %else_block10, %after_check9 %val12 = phi i1 [ %56, %after_check9 ], [ false, %else_block10 ] %ternary = select i1 %val12, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.26, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.27, i32 0, i32 0) %57 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.25, i32 0, i32 0), i8* %val7, i8* %ternary) %58 = load i64, i64* %anon, align 8 %add = add i64 %58, 1 store i64 %add, i64* %anon, align 8 br label %loop.cond loop.exit: ; preds = %loop.cond ret void }