| ... | @@ -210,6 +210,10 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { | ... | @@ -210,6 +210,10 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 210 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); | 210 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); |
| 211 | LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); | 211 | LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); |
| 212 | | 212 | |
| | 213 | TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1); |
| | 214 | TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); |
| | 215 | assert(op1_type == op2_type); |
| | 216 | |
| 213 | switch (node->data.bin_op_expr.bin_op) { | 217 | switch (node->data.bin_op_expr.bin_op) { |
| 214 | case BinOpTypeBinOr: | 218 | case BinOpTypeBinOr: |
| 215 | add_debug_source_node(g, node); | 219 | add_debug_source_node(g, node); |
| ... | @@ -224,29 +228,51 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { | ... | @@ -224,29 +228,51 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 224 | add_debug_source_node(g, node); | 228 | add_debug_source_node(g, node); |
| 225 | return LLVMBuildShl(g->builder, val1, val2, ""); | 229 | return LLVMBuildShl(g->builder, val1, val2, ""); |
| 226 | case BinOpTypeBitShiftRight: | 230 | case BinOpTypeBitShiftRight: |
| 227 | // TODO implement type system so that we know whether to do | | |
| 228 | // logical or arithmetic shifting here. | | |
| 229 | // signed -> arithmetic, unsigned -> logical | | |
| 230 | add_debug_source_node(g, node); | 231 | add_debug_source_node(g, node); |
| 231 | return LLVMBuildLShr(g->builder, val1, val2, ""); | 232 | if (op1_type->is_signed_int) { |
| | 233 | return LLVMBuildAShr(g->builder, val1, val2, ""); |
| | 234 | } else { |
| | 235 | return LLVMBuildLShr(g->builder, val1, val2, ""); |
| | 236 | } |
| 232 | case BinOpTypeAdd: | 237 | case BinOpTypeAdd: |
| 233 | add_debug_source_node(g, node); | 238 | add_debug_source_node(g, node); |
| 234 | return LLVMBuildAdd(g->builder, val1, val2, ""); | 239 | if (op1_type->is_float) { |
| | 240 | return LLVMBuildFAdd(g->builder, val1, val2, ""); |
| | 241 | } else { |
| | 242 | return LLVMBuildNSWAdd(g->builder, val1, val2, ""); |
| | 243 | } |
| 235 | case BinOpTypeSub: | 244 | case BinOpTypeSub: |
| 236 | add_debug_source_node(g, node); | 245 | add_debug_source_node(g, node); |
| 237 | return LLVMBuildSub(g->builder, val1, val2, ""); | 246 | if (op1_type->is_float) { |
| | 247 | return LLVMBuildFSub(g->builder, val1, val2, ""); |
| | 248 | } else { |
| | 249 | return LLVMBuildNSWSub(g->builder, val1, val2, ""); |
| | 250 | } |
| 238 | case BinOpTypeMult: | 251 | case BinOpTypeMult: |
| 239 | // TODO types so we know float vs int | | |
| 240 | add_debug_source_node(g, node); | 252 | add_debug_source_node(g, node); |
| 241 | return LLVMBuildMul(g->builder, val1, val2, ""); | 253 | if (op1_type->is_float) { |
| | 254 | return LLVMBuildFMul(g->builder, val1, val2, ""); |
| | 255 | } else { |
| | 256 | return LLVMBuildNSWMul(g->builder, val1, val2, ""); |
| | 257 | } |
| 242 | case BinOpTypeDiv: | 258 | case BinOpTypeDiv: |
| 243 | // TODO types so we know float vs int and signed vs unsigned | | |
| 244 | add_debug_source_node(g, node); | 259 | add_debug_source_node(g, node); |
| 245 | return LLVMBuildSDiv(g->builder, val1, val2, ""); | 260 | if (op1_type->is_float) { |
| | 261 | return LLVMBuildFDiv(g->builder, val1, val2, ""); |
| | 262 | } else if (op1_type->is_signed_int) { |
| | 263 | return LLVMBuildSDiv(g->builder, val1, val2, ""); |
| | 264 | } else { |
| | 265 | return LLVMBuildUDiv(g->builder, val1, val2, ""); |
| | 266 | } |
| 246 | case BinOpTypeMod: | 267 | case BinOpTypeMod: |
| 247 | // TODO types so we know float vs int and signed vs unsigned | | |
| 248 | add_debug_source_node(g, node); | 268 | add_debug_source_node(g, node); |
| 249 | return LLVMBuildSRem(g->builder, val1, val2, ""); | 269 | if (op1_type->is_float) { |
| | 270 | return LLVMBuildFRem(g->builder, val1, val2, ""); |
| | 271 | } else if (op1_type->is_signed_int) { |
| | 272 | return LLVMBuildSRem(g->builder, val1, val2, ""); |
| | 273 | } else { |
| | 274 | return LLVMBuildURem(g->builder, val1, val2, ""); |
| | 275 | } |
| 250 | case BinOpTypeBoolOr: | 276 | case BinOpTypeBoolOr: |
| 251 | case BinOpTypeBoolAnd: | 277 | case BinOpTypeBoolAnd: |
| 252 | case BinOpTypeCmpEq: | 278 | case BinOpTypeCmpEq: |
| ... | @@ -281,16 +307,43 @@ static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed | ... | @@ -281,16 +307,43 @@ static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed |
| 281 | } | 307 | } |
| 282 | } | 308 | } |
| 283 | | 309 | |
| | 310 | static LLVMRealPredicate cmp_op_to_real_predicate(BinOpType cmp_op) { |
| | 311 | switch (cmp_op) { |
| | 312 | case BinOpTypeCmpEq: |
| | 313 | return LLVMRealOEQ; |
| | 314 | case BinOpTypeCmpNotEq: |
| | 315 | return LLVMRealONE; |
| | 316 | case BinOpTypeCmpLessThan: |
| | 317 | return LLVMRealOLT; |
| | 318 | case BinOpTypeCmpGreaterThan: |
| | 319 | return LLVMRealOGT; |
| | 320 | case BinOpTypeCmpLessOrEq: |
| | 321 | return LLVMRealOLE; |
| | 322 | case BinOpTypeCmpGreaterOrEq: |
| | 323 | return LLVMRealOGE; |
| | 324 | default: |
| | 325 | zig_unreachable(); |
| | 326 | } |
| | 327 | } |
| | 328 | |
| 284 | static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) { | 329 | static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) { |
| 285 | assert(node->type == NodeTypeBinOpExpr); | 330 | assert(node->type == NodeTypeBinOpExpr); |
| 286 | | 331 | |
| 287 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); | 332 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); |
| 288 | LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); | 333 | LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); |
| 289 | | 334 | |
| 290 | // TODO implement type system so that we know whether to do signed or unsigned comparison here | 335 | TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1); |
| 291 | LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, true); | 336 | TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); |
| | 337 | assert(op1_type == op2_type); |
| | 338 | |
| 292 | add_debug_source_node(g, node); | 339 | add_debug_source_node(g, node); |
| 293 | return LLVMBuildICmp(g->builder, pred, val1, val2, ""); | 340 | if (op1_type->is_float) { |
| | 341 | LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op); |
| | 342 | return LLVMBuildFCmp(g->builder, pred, val1, val2, ""); |
| | 343 | } else { |
| | 344 | LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, op1_type->is_signed_int); |
| | 345 | return LLVMBuildICmp(g->builder, pred, val1, val2, ""); |
| | 346 | } |
| 294 | } | 347 | } |
| 295 | | 348 | |
| 296 | static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { | 349 | static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { |
| ... | @@ -847,12 +900,26 @@ static void define_primitive_types(CodeGen *g) { | ... | @@ -847,12 +900,26 @@ static void define_primitive_types(CodeGen *g) { |
| 847 | buf_init_from_str(&entry->name, "i32"); | 900 | buf_init_from_str(&entry->name, "i32"); |
| 848 | entry->size_in_bits = 32; | 901 | entry->size_in_bits = 32; |
| 849 | entry->align_in_bits = 32; | 902 | entry->align_in_bits = 32; |
| | 903 | entry->is_signed_int = true; |
| 850 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), | 904 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| 851 | entry->size_in_bits, entry->align_in_bits, | 905 | entry->size_in_bits, entry->align_in_bits, |
| 852 | LLVMZigEncoding_DW_ATE_signed()); | 906 | LLVMZigEncoding_DW_ATE_signed()); |
| 853 | g->type_table.put(&entry->name, entry); | 907 | g->type_table.put(&entry->name, entry); |
| 854 | g->builtin_types.entry_i32 = entry; | 908 | g->builtin_types.entry_i32 = entry; |
| 855 | } | 909 | } |
| | 910 | { |
| | 911 | TypeTableEntry *entry = new_type_table_entry(); |
| | 912 | entry->type_ref = LLVMFloatType(); |
| | 913 | buf_init_from_str(&entry->name, "f32"); |
| | 914 | entry->size_in_bits = 32; |
| | 915 | entry->align_in_bits = 32; |
| | 916 | entry->is_float = true; |
| | 917 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| | 918 | entry->size_in_bits, entry->align_in_bits, |
| | 919 | LLVMZigEncoding_DW_ATE_float()); |
| | 920 | g->type_table.put(&entry->name, entry); |
| | 921 | g->builtin_types.entry_f32 = entry; |
| | 922 | } |
| 856 | { | 923 | { |
| 857 | TypeTableEntry *entry = new_type_table_entry(); | 924 | TypeTableEntry *entry = new_type_table_entry(); |
| 858 | entry->type_ref = LLVMVoidType(); | 925 | entry->type_ref = LLVMVoidType(); |
| ... | @@ -918,6 +985,8 @@ static void init(CodeGen *g, Buf *source_path) { | ... | @@ -918,6 +985,8 @@ static void init(CodeGen *g, Buf *source_path) { |
| 918 | g->builder = LLVMCreateBuilder(); | 985 | g->builder = LLVMCreateBuilder(); |
| 919 | g->dbuilder = LLVMZigCreateDIBuilder(g->module, true); | 986 | g->dbuilder = LLVMZigCreateDIBuilder(g->module, true); |
| 920 | | 987 | |
| | 988 | LLVMZigSetFastMath(g->builder, true); |
| | 989 | |
| 921 | | 990 | |
| 922 | define_primitive_types(g); | 991 | define_primitive_types(g); |
| 923 | | 992 | |
| ... | @@ -1058,6 +1127,8 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) { | ... | @@ -1058,6 +1127,8 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) { |
| 1058 | } else if (type_entry == g->builtin_types.entry_i32) { | 1127 | } else if (type_entry == g->builtin_types.entry_i32) { |
| 1059 | g->c_stdint_used = true; | 1128 | g->c_stdint_used = true; |
| 1060 | buf_init_from_str(out_buf, "int32_t"); | 1129 | buf_init_from_str(out_buf, "int32_t"); |
| | 1130 | } else if (type_entry == g->builtin_types.entry_f32) { |
| | 1131 | buf_init_from_str(out_buf, "float"); |
| 1061 | } else if (type_entry == g->builtin_types.entry_unreachable) { | 1132 | } else if (type_entry == g->builtin_types.entry_unreachable) { |
| 1062 | buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void"); | 1133 | buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void"); |
| 1063 | } else if (type_entry == g->builtin_types.entry_bool) { | 1134 | } else if (type_entry == g->builtin_types.entry_bool) { |