Created
April 16, 2012 18:44
-
-
Save jspahrsummers/2400614 to your computer and use it in GitHub Desktop.
Guessing game written in LLVM assembly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; run this with one of the following: | |
; | |
; lli guessing-game.ll | |
; llc guessing-game.ll && clang -o guessing-game guessing-game.s && ./guessing-game | |
; | |
; note: you may need to 'brew install llvm' first | |
; type representing a FILE handle in C (like stdin) | |
%FILE = type opaque | |
; define all the constant strings used in the program | |
; | |
; i've also defined type aliases for each one, since we'll need the exact types in order | |
; to cast these constants to generic i8* values below | |
%guessStr_t = type [38 x i8] | |
@guessStr = private unnamed_addr constant %guessStr_t c"Guess a number in the range [1,100]: \00" | |
%tooLowStr_t = type [11 x i8] | |
@tooLowStr = private unnamed_addr constant %tooLowStr_t c"Too low!\0A\0A\00" | |
%tooHighStr_t = type [12 x i8] | |
@tooHighStr = private unnamed_addr constant %tooHighStr_t c"Too high!\0A\0A\00" | |
%correctStr_t = type [10 x i8] | |
@correctStr = private unnamed_addr constant %correctStr_t c"Correct!\0A\00" | |
%errorStr_t = type [20 x i8] | |
@errorStr = private unnamed_addr constant %errorStr_t c"An error occurred!\0A\00" | |
%modeStr_t = type [2 x i8] | |
@modeStr = private unnamed_addr constant %modeStr_t c"r\00" | |
; declare prototypes for all the external functions called from the program | |
; | |
; as above, these functions all have type aliases, as the 'call' instruction requires the full | |
; type of the function being called | |
declare i32 @arc4random_uniform (i32) | |
%arc4random_uniform_fp = type i32 (i32)* | |
declare %FILE* @fdopen (i32, i8*) | |
%fdopen_fp = type %FILE* (i32, i8*)* | |
declare i8* @fgets (i8* noalias, i32, %FILE* noalias) | |
%fgets_fp = type i8* (i8*, i32, %FILE*)* | |
declare i32 @printf (i8*, ...) | |
%printf_fp = type i32 (i8*, ...)* | |
declare i64 @strtol (i8* noalias, i8** noalias, i32) | |
%strtol_fp = type i64 (i8*, i8**, i32)* | |
declare void @abort () | |
%abort_fp = type void ()* | |
define i32 @main () { | |
; generate a random number in the range [1,100] | |
%answerMinusOne = call %arc4random_uniform_fp @arc4random_uniform(i32 100) | |
%answer32 = add i32 %answerMinusOne, 1 | |
%answer = sext i32 %answer32 to i64 | |
; small (stack-allocated) temporary buffer for user input | |
%buffer = alloca i8, i32 10 | |
; "open" stdin using its underlying file descriptor | |
%modeStr = getelementptr inbounds %modeStr_t* @modeStr, i64 0, i64 0 | |
%stdin = call %fdopen_fp @fdopen(i32 0, i8* %modeStr) | |
; bail out if any error occurred | |
%stdinIsNull = icmp eq %FILE* %stdin, null | |
br i1 %stdinIsNull, label %error, label %guessLoop | |
guessLoop: | |
; prompt the user for a guess | |
%guessStr = getelementptr inbounds %guessStr_t* @guessStr, i64 0, i64 0 | |
call %printf_fp @printf(i8* %guessStr) | |
; read in a line of user input (bailing on any error) | |
%readString = call %fgets_fp @fgets (i8* %buffer, i32 10, %FILE* %stdin) | |
%readStringIsNull = icmp eq i8* %readString, null | |
br i1 %readStringIsNull, label %error, label %checkGuessTooLow | |
checkGuessTooLow: | |
; convert the string of user input to an i64 | |
%guess = call %strtol_fp @strtol (i8* %readString, i8** null, i32 10) | |
; check whether it's less than the answer | |
%guessTooLow = icmp slt i64 %guess, %answer | |
br i1 %guessTooLow, label %tooLow, label %checkGuessTooHigh | |
checkGuessTooHigh: | |
; check whether it's greater than the answer | |
%guessTooHigh = icmp sgt i64 %guess, %answer | |
br i1 %guessTooHigh, label %tooHigh, label %correct | |
; the user's answer was too low | |
tooLow: | |
%tooLowStr = getelementptr inbounds %tooLowStr_t* @tooLowStr, i64 0, i64 0 | |
call %printf_fp @printf(i8* %tooLowStr) | |
br label %guessLoop | |
; the user's answer was too high | |
tooHigh: | |
%tooHighStr = getelementptr inbounds %tooHighStr_t* @tooHighStr, i64 0, i64 0 | |
call %printf_fp @printf(i8* %tooHighStr) | |
br label %guessLoop | |
; the user's answer was just right | |
correct: | |
%correctStr = getelementptr inbounds %correctStr_t* @correctStr, i64 0, i64 0 | |
call %printf_fp @printf(i8* %correctStr) | |
ret i32 0 | |
error: | |
; print out an error message | |
%errorStr = getelementptr inbounds %errorStr_t* @errorStr, i64 0, i64 0 | |
call %printf_fp @printf(i8* %errorStr) | |
; and abort | |
call %abort_fp @abort() | |
unreachable | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment