Skip to content

Instantly share code, notes, and snippets.

@jspahrsummers
Created April 16, 2012 18:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jspahrsummers/2400614 to your computer and use it in GitHub Desktop.
Save jspahrsummers/2400614 to your computer and use it in GitHub Desktop.
Guessing game written in LLVM assembly
; 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