Use conditional expressions throughout compiler
7c8cce71d571e106a78617403a2a1ba84b44decca0b04dd55df99b73d67529a5
These were made available be the recent seed update.
1 parent
610f0e95
lib/std/arch/rv64/isel.rad
+24 -30
| 672 | 672 | selectBinOp(s, rd, rs1, b, BinOp::Add, super::SCRATCH2); |
|
| 673 | 673 | } |
|
| 674 | 674 | } |
|
| 675 | 675 | case il::BinOp::Sub => { |
|
| 676 | 676 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 677 | - | if typ == il::Type::W32 { |
|
| 678 | - | emit::emit(s.e, encode::subw(rd, rs1, rs2)); |
|
| 679 | - | } else { |
|
| 680 | - | emit::emit(s.e, encode::sub(rd, rs1, rs2)); |
|
| 681 | - | } |
|
| 677 | + | emit::emit(s.e, |
|
| 678 | + | encode::subw(rd, rs1, rs2) |
|
| 679 | + | if typ == il::Type::W32 else |
|
| 680 | + | encode::sub(rd, rs1, rs2)); |
|
| 682 | 681 | } |
|
| 683 | 682 | case il::BinOp::Mul => { |
|
| 684 | 683 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 685 | - | if typ == il::Type::W32 { |
|
| 686 | - | emit::emit(s.e, encode::mulw(rd, rs1, rs2)); |
|
| 687 | - | } else { |
|
| 688 | - | emit::emit(s.e, encode::mul(rd, rs1, rs2)); |
|
| 689 | - | } |
|
| 684 | + | emit::emit(s.e, |
|
| 685 | + | encode::mulw(rd, rs1, rs2) |
|
| 686 | + | if typ == il::Type::W32 else |
|
| 687 | + | encode::mul(rd, rs1, rs2)); |
|
| 690 | 688 | } |
|
| 691 | 689 | case il::BinOp::Sdiv => { |
|
| 692 | 690 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 693 | 691 | emitTrapIfZero(s, rs2); |
|
| 694 | - | if typ == il::Type::W32 { |
|
| 695 | - | emit::emit(s.e, encode::divw(rd, rs1, rs2)); |
|
| 696 | - | } else { |
|
| 697 | - | emit::emit(s.e, encode::div(rd, rs1, rs2)); |
|
| 698 | - | } |
|
| 692 | + | emit::emit(s.e, |
|
| 693 | + | encode::divw(rd, rs1, rs2) |
|
| 694 | + | if typ == il::Type::W32 else |
|
| 695 | + | encode::div(rd, rs1, rs2)); |
|
| 699 | 696 | } |
|
| 700 | 697 | case il::BinOp::Udiv => { |
|
| 701 | 698 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 702 | 699 | emitTrapIfZero(s, rs2); |
|
| 703 | - | if typ == il::Type::W32 { |
|
| 704 | - | emit::emit(s.e, encode::divuw(rd, rs1, rs2)); |
|
| 705 | - | } else { |
|
| 706 | - | emit::emit(s.e, encode::divu(rd, rs1, rs2)); |
|
| 707 | - | } |
|
| 700 | + | emit::emit(s.e, |
|
| 701 | + | encode::divuw(rd, rs1, rs2) |
|
| 702 | + | if typ == il::Type::W32 else |
|
| 703 | + | encode::divu(rd, rs1, rs2)); |
|
| 708 | 704 | } |
|
| 709 | 705 | case il::BinOp::Srem => { |
|
| 710 | 706 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 711 | 707 | emitTrapIfZero(s, rs2); |
|
| 712 | - | if typ == il::Type::W32 { |
|
| 713 | - | emit::emit(s.e, encode::remw(rd, rs1, rs2)); |
|
| 714 | - | } else { |
|
| 715 | - | emit::emit(s.e, encode::rem(rd, rs1, rs2)); |
|
| 716 | - | } |
|
| 708 | + | emit::emit(s.e, |
|
| 709 | + | encode::remw(rd, rs1, rs2) |
|
| 710 | + | if typ == il::Type::W32 else |
|
| 711 | + | encode::rem(rd, rs1, rs2)); |
|
| 717 | 712 | } |
|
| 718 | 713 | case il::BinOp::Urem => { |
|
| 719 | 714 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 720 | 715 | emitTrapIfZero(s, rs2); |
|
| 721 | - | if typ == il::Type::W32 { |
|
| 722 | - | emit::emit(s.e, encode::remuw(rd, rs1, rs2)); |
|
| 723 | - | } else { |
|
| 724 | - | emit::emit(s.e, encode::remu(rd, rs1, rs2)); |
|
| 725 | - | } |
|
| 716 | + | emit::emit(s.e, |
|
| 717 | + | encode::remuw(rd, rs1, rs2) |
|
| 718 | + | if typ == il::Type::W32 else |
|
| 719 | + | encode::remu(rd, rs1, rs2)); |
|
| 726 | 720 | } |
|
| 727 | 721 | case il::BinOp::And => |
|
| 728 | 722 | selectBinOp(s, rd, rs1, b, BinOp::And, super::SCRATCH2), |
|
| 729 | 723 | case il::BinOp::Or => |
|
| 730 | 724 | selectBinOp(s, rd, rs1, b, BinOp::Or, super::SCRATCH2), |
lib/std/arch/rv64/printer.rad
+1 -4
| 22 | 22 | "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" |
|
| 23 | 23 | ]; |
|
| 24 | 24 | ||
| 25 | 25 | /// Get register name from number. |
|
| 26 | 26 | fn regName(n: u8) -> *[u8] { |
|
| 27 | - | if n >= 32 { |
|
| 28 | - | return "?"; |
|
| 29 | - | } |
|
| 30 | - | return REG_NAMES[n as u32]; |
|
| 27 | + | return "?" if n >= 32 else REG_NAMES[n as u32]; |
|
| 31 | 28 | } |
|
| 32 | 29 | ||
| 33 | 30 | /// Get register name from Reg. |
|
| 34 | 31 | fn regNameR(r: super::Reg) -> *[u8] { |
|
| 35 | 32 | return regName(r.n); |
lib/std/fmt.rad
+4 -16
| 39 | 39 | ||
| 40 | 40 | /// Format a i32 by writing it to the provided buffer. |
|
| 41 | 41 | pub fn formatI32(val: i32, buffer: *mut [u8]) -> *[u8] { |
|
| 42 | 42 | debug::assert(buffer.len >= I32_STR_LEN); |
|
| 43 | 43 | ||
| 44 | - | let mut x: u32 = 0; |
|
| 45 | - | let mut i: u32 = buffer.len; |
|
| 46 | 44 | let neg: bool = val < 0; |
|
| 47 | - | ||
| 48 | - | if neg { |
|
| 49 | - | x = -val as u32; |
|
| 50 | - | } else { |
|
| 51 | - | x = val as u32; |
|
| 52 | - | } |
|
| 45 | + | let mut x: u32 = -val as u32 if neg else val as u32; |
|
| 46 | + | let mut i: u32 = buffer.len; |
|
| 53 | 47 | // Handle the zero case separately to ensure a single '0' is written. |
|
| 54 | 48 | if x == 0 { |
|
| 55 | 49 | i -= 1; |
|
| 56 | 50 | buffer[i] = '0'; |
|
| 57 | 51 | } else { |
| 92 | 86 | ||
| 93 | 87 | /// Format a i64 by writing it to the provided buffer. |
|
| 94 | 88 | pub fn formatI64(val: i64, buffer: *mut [u8]) -> *[u8] { |
|
| 95 | 89 | debug::assert(buffer.len >= I64_STR_LEN); |
|
| 96 | 90 | ||
| 97 | - | let mut x: u64 = 0; |
|
| 98 | - | let mut i: u32 = buffer.len; |
|
| 99 | 91 | let neg: bool = val < 0; |
|
| 100 | - | ||
| 101 | - | if neg { |
|
| 102 | - | x = -val as u64; |
|
| 103 | - | } else { |
|
| 104 | - | x = val as u64; |
|
| 105 | - | } |
|
| 92 | + | let mut x: u64 = -val as u64 if neg else val as u64; |
|
| 93 | + | let mut i: u32 = buffer.len; |
|
| 106 | 94 | if x == 0 { |
|
| 107 | 95 | i -= 1; |
|
| 108 | 96 | buffer[i] = '0'; |
|
| 109 | 97 | } else { |
|
| 110 | 98 | while x != 0 { |
lib/std/lang/ast/printer.rad
+9 -18
| 75 | 75 | case super::TypeSig::Opaque => return sexpr::sym("opaque"), |
|
| 76 | 76 | case super::TypeSig::Bool => return sexpr::sym("bool"), |
|
| 77 | 77 | case super::TypeSig::Integer { width, sign } => return sexpr::sym(intTypeName(width, sign)), |
|
| 78 | 78 | case super::TypeSig::Array { itemType, length } => |
|
| 79 | 79 | return sexpr::list(a, "array", &[toExpr(a, itemType), toExpr(a, length)]), |
|
| 80 | - | case super::TypeSig::Slice { itemType, mutable } => { |
|
| 81 | - | if mutable { |
|
| 82 | - | return sexpr::list(a, "slice", &[sexpr::sym("mut"), toExpr(a, itemType)]); |
|
| 83 | - | } |
|
| 84 | - | return sexpr::list(a, "slice", &[toExpr(a, itemType)]); |
|
| 85 | - | } |
|
| 86 | - | case super::TypeSig::Pointer { valueType, mutable } => { |
|
| 87 | - | if mutable { |
|
| 88 | - | return sexpr::list(a, "ptr", &[sexpr::sym("mut"), toExpr(a, valueType)]); |
|
| 89 | - | } |
|
| 90 | - | return sexpr::list(a, "ptr", &[toExpr(a, valueType)]); |
|
| 91 | - | } |
|
| 80 | + | case super::TypeSig::Slice { itemType, mutable } => |
|
| 81 | + | return sexpr::list(a, "slice", &[sexpr::sym("mut"), toExpr(a, itemType)]) if mutable |
|
| 82 | + | else sexpr::list(a, "slice", &[toExpr(a, itemType)]), |
|
| 83 | + | case super::TypeSig::Pointer { valueType, mutable } => |
|
| 84 | + | return sexpr::list(a, "ptr", &[sexpr::sym("mut"), toExpr(a, valueType)]) if mutable |
|
| 85 | + | else sexpr::list(a, "ptr", &[toExpr(a, valueType)]), |
|
| 92 | 86 | case super::TypeSig::Optional { valueType } => |
|
| 93 | 87 | return sexpr::list(a, "?", &[toExpr(a, valueType)]), |
|
| 94 | 88 | case super::TypeSig::Nominal(name) => return toExpr(a, name), |
|
| 95 | 89 | case super::TypeSig::Record { fields, .. } => |
|
| 96 | 90 | return sexpr::list(a, "record", nodeListToExprs(a, &fields)), |
| 273 | 267 | return sexpr::list(a, "[]", &[toExpr(a, container), toExpr(a, index)]), |
|
| 274 | 268 | case super::NodeValue::FieldAccess(acc) => |
|
| 275 | 269 | return sexpr::list(a, ".", &[toExpr(a, acc.parent), toExpr(a, acc.child)]), |
|
| 276 | 270 | case super::NodeValue::ScopeAccess(acc) => |
|
| 277 | 271 | return sexpr::list(a, "::", &[toExpr(a, acc.parent), toExpr(a, acc.child)]), |
|
| 278 | - | case super::NodeValue::AddressOf(addr) => { |
|
| 279 | - | if addr.mutable { |
|
| 280 | - | return sexpr::list(a, "&mut", &[toExpr(a, addr.target)]); |
|
| 281 | - | } |
|
| 282 | - | return sexpr::list(a, "&", &[toExpr(a, addr.target)]); |
|
| 283 | - | } |
|
| 272 | + | case super::NodeValue::AddressOf(addr) => |
|
| 273 | + | return sexpr::list(a, "&mut", &[toExpr(a, addr.target)]) if addr.mutable |
|
| 274 | + | else sexpr::list(a, "&", &[toExpr(a, addr.target)]), |
|
| 284 | 275 | case super::NodeValue::Deref(target) => |
|
| 285 | 276 | return sexpr::list(a, "deref", &[toExpr(a, target)]), |
|
| 286 | 277 | case super::NodeValue::As(cast) => |
|
| 287 | 278 | return sexpr::list(a, "as", &[toExpr(a, cast.value), toExpr(a, cast.type)]), |
|
| 288 | 279 | case super::NodeValue::ArrayLit(elems) => |
lib/std/lang/gen/bitset.rad
+2 -8
| 136 | 136 | let numWordsA = wordsFor(a.len); |
|
| 137 | 137 | let numWordsB = wordsFor(b.len); |
|
| 138 | 138 | let maxWords = max(numWordsA, numWordsB); |
|
| 139 | 139 | ||
| 140 | 140 | for i in 0..maxWords { |
|
| 141 | - | let mut wordA: u32 = 0; |
|
| 142 | - | let mut wordB: u32 = 0; |
|
| 143 | - | if i < numWordsA { |
|
| 144 | - | wordA = a.bits[i]; |
|
| 145 | - | } |
|
| 146 | - | if i < numWordsB { |
|
| 147 | - | wordB = b.bits[i]; |
|
| 148 | - | } |
|
| 141 | + | let wordA = a.bits[i] if i < numWordsA else 0; |
|
| 142 | + | let wordB = b.bits[i] if i < numWordsB else 0; |
|
| 149 | 143 | if wordA != wordB { |
|
| 150 | 144 | return false; |
|
| 151 | 145 | } |
|
| 152 | 146 | } |
|
| 153 | 147 | return true; |
lib/std/lang/gen/regalloc/spill.rad
+2 -8
| 178 | 178 | fn fillCosts(func: *il::Fn, costs: *mut [SpillCost]) { |
|
| 179 | 179 | for b in 0..func.blocks.len { |
|
| 180 | 180 | let block = &func.blocks[b]; |
|
| 181 | 181 | ||
| 182 | 182 | // Exponential weight for loop depth, capped to avoid overflow. |
|
| 183 | - | let mut depth = block.loopDepth; |
|
| 184 | - | if depth > MAX_LOOP_WEIGHT { |
|
| 185 | - | depth = MAX_LOOP_WEIGHT; |
|
| 186 | - | } |
|
| 183 | + | let depth = MAX_LOOP_WEIGHT if block.loopDepth > MAX_LOOP_WEIGHT else block.loopDepth; |
|
| 187 | 184 | let weight: u32 = 1 << depth; |
|
| 188 | 185 | ||
| 189 | 186 | // Count block parameter definitions. |
|
| 190 | 187 | for p in block.params { |
|
| 191 | 188 | if p.value.n < costs.len { |
| 225 | 222 | c.entries[j] = c.entries[j - 1]; |
|
| 226 | 223 | j -= 1; |
|
| 227 | 224 | } |
|
| 228 | 225 | c.entries[j] = key; |
|
| 229 | 226 | } |
|
| 230 | - | let mut toSpill = excess; |
|
| 231 | - | if toSpill > c.n { |
|
| 232 | - | toSpill = c.n; |
|
| 233 | - | } |
|
| 227 | + | let toSpill = c.n if excess > c.n else excess; |
|
| 234 | 228 | for i in 0..toSpill { |
|
| 235 | 229 | bitset::set(spilled, c.entries[i].reg); |
|
| 236 | 230 | bitset::clear(source, c.entries[i].reg); |
|
| 237 | 231 | } |
|
| 238 | 232 | } |
lib/std/lang/lower.rad
+31 -98
| 1072 | 1072 | // Functions for building the data section from const/static |
|
| 1073 | 1073 | // declarations and inline literals. |
|
| 1074 | 1074 | ||
| 1075 | 1075 | /// Convert a constant integer payload to a signed 64-bit value. |
|
| 1076 | 1076 | fn constIntToI64(intVal: resolver::ConstInt) -> i64 { |
|
| 1077 | - | let mut value = intVal.magnitude as i64; |
|
| 1078 | - | if intVal.negative { |
|
| 1079 | - | value = 0 - value; |
|
| 1080 | - | } |
|
| 1081 | - | return value; |
|
| 1077 | + | return (0 - intVal.magnitude as i64) if intVal.negative else intVal.magnitude as i64; |
|
| 1082 | 1078 | } |
|
| 1083 | 1079 | ||
| 1084 | 1080 | /// Convert a scalar constant value to an i64. |
|
| 1085 | 1081 | /// String constants are not handled here and should be checked before calling. |
|
| 1086 | 1082 | /// Panics if a non-scalar value is passed. |
|
| 1087 | 1083 | fn constToScalar(val: resolver::ConstValue) -> i64 { |
|
| 1088 | 1084 | match val { |
|
| 1089 | - | case resolver::ConstValue::Bool(b) => { |
|
| 1090 | - | if b { |
|
| 1091 | - | return 1; |
|
| 1092 | - | } else { |
|
| 1093 | - | return 0; |
|
| 1094 | - | } |
|
| 1095 | - | } |
|
| 1085 | + | case resolver::ConstValue::Bool(b) => return 1 if b else 0, |
|
| 1096 | 1086 | case resolver::ConstValue::Char(c) => return c as i64, |
|
| 1097 | 1087 | case resolver::ConstValue::Int(i) => return constIntToI64(i), |
|
| 1098 | 1088 | else => panic, |
|
| 1099 | 1089 | } |
|
| 1100 | 1090 | } |
| 1399 | 1389 | let fieldInfo = recInfo.fields[i]; |
|
| 1400 | 1390 | let fieldOffset = fieldInfo.offset as u32; |
|
| 1401 | 1391 | ||
| 1402 | 1392 | // Slot extends to the next field's offset, |
|
| 1403 | 1393 | // or record size for the last field. |
|
| 1404 | - | let mut slotEnd = layout.size; |
|
| 1405 | - | if i + 1 < recInfo.fieldsLen { |
|
| 1406 | - | slotEnd = recInfo.fields[i + 1].offset as u32; |
|
| 1407 | - | } |
|
| 1394 | + | let slotEnd = recInfo.fields[i + 1].offset as u32 if i + 1 < recInfo.fieldsLen else layout.size; |
|
| 1408 | 1395 | let slotSize = slotEnd - fieldOffset; |
|
| 1409 | 1396 | ||
| 1410 | 1397 | try lowerConstDataInto(self, valueNode, fieldInfo.fieldType, slotSize, dataPrefix, b); |
|
| 1411 | 1398 | } |
|
| 1412 | 1399 | } |
| 2876 | 2863 | fn lowerParams( |
|
| 2877 | 2864 | self: *mut FnLowerer, |
|
| 2878 | 2865 | fnType: resolver::FnType, |
|
| 2879 | 2866 | astParams: ast::NodeList |
|
| 2880 | 2867 | ) -> *[il::Param] throws (LowerError) { |
|
| 2881 | - | let mut offset: u32 = 0; |
|
| 2882 | - | if self.returnReg != nil { |
|
| 2883 | - | offset = 1; |
|
| 2884 | - | } |
|
| 2868 | + | let offset: u32 = 1 if self.returnReg != nil else 0; |
|
| 2885 | 2869 | let totalLen = fnType.paramTypesLen + offset; |
|
| 2886 | 2870 | ||
| 2887 | 2871 | if totalLen == 0 { |
|
| 2888 | 2872 | return &[]; |
|
| 2889 | 2873 | } |
| 2997 | 2981 | let optTy = resolver::typeFor(self.low.resolver, opt) else { |
|
| 2998 | 2982 | throw LowerError::MissingType(opt); |
|
| 2999 | 2983 | }; |
|
| 3000 | 2984 | // Handle `nil == nil` or `nil != nil`. |
|
| 3001 | 2985 | if optTy == resolver::Type::Nil { |
|
| 3002 | - | if isEq { |
|
| 3003 | - | return il::Val::Imm(1); |
|
| 3004 | - | } else { |
|
| 3005 | - | return il::Val::Imm(0); |
|
| 3006 | - | } |
|
| 2986 | + | return il::Val::Imm(1) if isEq else il::Val::Imm(0); |
|
| 3007 | 2987 | } |
|
| 3008 | 2988 | let val = try lowerExpr(self, opt); |
|
| 3009 | 2989 | let cmpReg = try optionalNilReg(self, val, optTy); |
|
| 3010 | 2990 | ||
| 3011 | 2991 | // Null-pointer-optimized types compare a 64-bit pointer against zero. |
|
| 3012 | 2992 | // Aggregate optionals compare an 8-bit tag byte against zero. |
|
| 3013 | - | let mut cmpType = il::Type::W8; |
|
| 3014 | - | if resolver::isOptionalPointer(optTy) { |
|
| 3015 | - | cmpType = il::Type::W64; |
|
| 3016 | - | } |
|
| 2993 | + | let cmpType = il::Type::W64 if resolver::isOptionalPointer(optTy) else il::Type::W8; |
|
| 3017 | 2994 | ||
| 3018 | - | if isEq { |
|
| 3019 | - | return emitTypedBinOp(self, il::BinOp::Eq, cmpType, il::Val::Reg(cmpReg), il::Val::Imm(0)); |
|
| 3020 | - | } else { |
|
| 3021 | - | return emitTypedBinOp(self, il::BinOp::Ne, cmpType, il::Val::Reg(cmpReg), il::Val::Imm(0)); |
|
| 3022 | - | } |
|
| 2995 | + | let op = il::BinOp::Eq if isEq else il::BinOp::Ne; |
|
| 2996 | + | return emitTypedBinOp(self, op, cmpType, il::Val::Reg(cmpReg), il::Val::Imm(0)); |
|
| 3023 | 2997 | } |
|
| 3024 | 2998 | ||
| 3025 | 2999 | /// Load the payload value from a tagged value aggregate at the given offset. |
|
| 3026 | 3000 | fn tvalPayloadVal(self: *mut FnLowerer, base: il::Reg, payload: resolver::Type, valOffset: i32) -> il::Val { |
|
| 3027 | 3001 | if payload == resolver::Type::Void { |
| 3959 | 3933 | /// Emit a tag comparison for void variant equality/inequality. |
|
| 3960 | 3934 | fn emitTagCmp(self: *mut FnLowerer, op: ast::BinaryOp, val: il::Val, tagIdx: i64, valType: resolver::Type) -> il::Val |
|
| 3961 | 3935 | throws (LowerError) |
|
| 3962 | 3936 | { |
|
| 3963 | 3937 | let reg = try emitValToReg(self, val); |
|
| 3964 | - | let mut tag: il::Val = undefined; |
|
| 3965 | 3938 | ||
| 3966 | 3939 | // For all-void unions, the value *is* the tag, not a pointer. |
|
| 3940 | + | let mut tag: il::Val = undefined; |
|
| 3967 | 3941 | if resolver::isVoidUnion(valType) { |
|
| 3968 | 3942 | tag = il::Val::Reg(reg); |
|
| 3969 | 3943 | } else { |
|
| 3970 | 3944 | tag = loadTag(self, reg, TVAL_TAG_OFFSET, il::Type::W8); |
|
| 3971 | 3945 | } |
|
| 3972 | - | if op == ast::BinaryOp::Eq { |
|
| 3973 | - | return emitTypedBinOp(self, il::BinOp::Eq, il::Type::W8, tag, il::Val::Imm(tagIdx)); |
|
| 3974 | - | } |
|
| 3975 | - | return emitTypedBinOp(self, il::BinOp::Ne, il::Type::W8, tag, il::Val::Imm(tagIdx)); |
|
| 3946 | + | let binOp = il::BinOp::Eq if op == ast::BinaryOp::Eq else il::BinOp::Ne; |
|
| 3947 | + | return emitTypedBinOp(self, binOp, il::Type::W8, tag, il::Val::Imm(tagIdx)); |
|
| 3976 | 3948 | } |
|
| 3977 | 3949 | ||
| 3978 | 3950 | /// Logical "and" between two values. Returns the result in a register. |
|
| 3979 | 3951 | fn emitLogicalAnd(self: *mut FnLowerer, left: ?il::Val, right: il::Val) -> il::Val { |
|
| 3980 | 3952 | let prev = left else { |
| 5078 | 5050 | ||
| 5079 | 5051 | // Emit condition check. |
|
| 5080 | 5052 | match *iter { |
|
| 5081 | 5053 | case ForIter::Range { valVar, endVal, valType, unsigned, .. } => { |
|
| 5082 | 5054 | let curVal = try useVar(self, valVar); |
|
| 5083 | - | let mut cmp = il::CmpOp::Slt; |
|
| 5084 | - | if unsigned { |
|
| 5085 | - | cmp = il::CmpOp::Ult; |
|
| 5086 | - | } |
|
| 5055 | + | let cmp = il::CmpOp::Ult if unsigned else il::CmpOp::Slt; |
|
| 5087 | 5056 | try emitBrCmp(self, cmp, valType, curVal, endVal, bodyBlock, endBlock); |
|
| 5088 | 5057 | } |
|
| 5089 | 5058 | case ForIter::Collection { idxVar, lengthVal, .. } => { |
|
| 5090 | 5059 | let curIdx = try useVar(self, idxVar); |
|
| 5091 | 5060 | try emitBrCmp(self, il::CmpOp::Slt, il::Type::W32, curIdx, lengthVal, bodyBlock, endBlock); |
| 5426 | 5395 | fn cmpOpFrom(op: ast::BinaryOp, unsigned: bool) -> ?il::CmpOp { |
|
| 5427 | 5396 | match op { |
|
| 5428 | 5397 | case ast::BinaryOp::Eq => return il::CmpOp::Eq, |
|
| 5429 | 5398 | case ast::BinaryOp::Ne => return il::CmpOp::Ne, |
|
| 5430 | 5399 | case ast::BinaryOp::Lt, ast::BinaryOp::Gt, |
|
| 5431 | - | ast::BinaryOp::Gte, ast::BinaryOp::Lte => { |
|
| 5432 | - | if unsigned { |
|
| 5433 | - | return il::CmpOp::Ult; |
|
| 5434 | - | } else { |
|
| 5435 | - | return il::CmpOp::Slt; |
|
| 5436 | - | } |
|
| 5437 | - | } |
|
| 5400 | + | ast::BinaryOp::Gte, ast::BinaryOp::Lte => |
|
| 5401 | + | return il::CmpOp::Ult if unsigned else il::CmpOp::Slt, |
|
| 5438 | 5402 | else => return nil, |
|
| 5439 | 5403 | } |
|
| 5440 | 5404 | } |
|
| 5441 | 5405 | ||
| 5442 | 5406 | /// Lower a binary operation. |
| 5541 | 5505 | case ast::BinaryOp::Mul => { |
|
| 5542 | 5506 | emit(self, il::Instr::BinOp { op: il::BinOp::Mul, typ, dst, a, b }); |
|
| 5543 | 5507 | needsExt = true; |
|
| 5544 | 5508 | } |
|
| 5545 | 5509 | case ast::BinaryOp::Div => { |
|
| 5546 | - | if unsigned { |
|
| 5547 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Udiv, typ, dst, a, b }); |
|
| 5548 | - | } else { |
|
| 5549 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Sdiv, typ, dst, a, b }); |
|
| 5550 | - | } |
|
| 5510 | + | let op = il::BinOp::Udiv if unsigned else il::BinOp::Sdiv; |
|
| 5511 | + | emit(self, il::Instr::BinOp { op, typ, dst, a, b }); |
|
| 5551 | 5512 | needsExt = true; |
|
| 5552 | 5513 | } |
|
| 5553 | 5514 | case ast::BinaryOp::Mod => { |
|
| 5554 | - | if unsigned { |
|
| 5555 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Urem, typ, dst, a, b }); |
|
| 5556 | - | } else { |
|
| 5557 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Srem, typ, dst, a, b }); |
|
| 5558 | - | } |
|
| 5515 | + | let op = il::BinOp::Urem if unsigned else il::BinOp::Srem; |
|
| 5516 | + | emit(self, il::Instr::BinOp { op, typ, dst, a, b }); |
|
| 5559 | 5517 | needsExt = true; |
|
| 5560 | 5518 | } |
|
| 5561 | 5519 | case ast::BinaryOp::BitAnd => emit(self, il::Instr::BinOp { op: il::BinOp::And, typ, dst, a, b }), |
|
| 5562 | 5520 | case ast::BinaryOp::BitOr => emit(self, il::Instr::BinOp { op: il::BinOp::Or, typ, dst, a, b }), |
|
| 5563 | 5521 | case ast::BinaryOp::BitXor => emit(self, il::Instr::BinOp { op: il::BinOp::Xor, typ, dst, a, b }), |
|
| 5564 | 5522 | case ast::BinaryOp::Shl => { |
|
| 5565 | 5523 | emit(self, il::Instr::BinOp { op: il::BinOp::Shl, typ, dst, a, b }); |
|
| 5566 | 5524 | needsExt = true; |
|
| 5567 | 5525 | } |
|
| 5568 | 5526 | case ast::BinaryOp::Shr => { |
|
| 5569 | - | if unsigned { |
|
| 5570 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Ushr, typ, dst, a, b }); |
|
| 5571 | - | } else { |
|
| 5572 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Sshr, typ, dst, a, b }); |
|
| 5573 | - | } |
|
| 5527 | + | let op = il::BinOp::Ushr if unsigned else il::BinOp::Sshr; |
|
| 5528 | + | emit(self, il::Instr::BinOp { op, typ, dst, a, b }); |
|
| 5574 | 5529 | } |
|
| 5575 | 5530 | case ast::BinaryOp::Eq => emit(self, il::Instr::BinOp { op: il::BinOp::Eq, typ, dst, a, b }), |
|
| 5576 | 5531 | case ast::BinaryOp::Ne => emit(self, il::Instr::BinOp { op: il::BinOp::Ne, typ, dst, a, b }), |
|
| 5577 | 5532 | case ast::BinaryOp::Lt => { |
|
| 5578 | - | if unsigned { |
|
| 5579 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Ult, typ, dst, a, b }); |
|
| 5580 | - | } else { |
|
| 5581 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Slt, typ, dst, a, b }); |
|
| 5582 | - | } |
|
| 5533 | + | let op = il::BinOp::Ult if unsigned else il::BinOp::Slt; |
|
| 5534 | + | emit(self, il::Instr::BinOp { op, typ, dst, a, b }); |
|
| 5583 | 5535 | } |
|
| 5584 | 5536 | case ast::BinaryOp::Gt => { // `a > b` = `b < a` |
|
| 5585 | - | if unsigned { |
|
| 5586 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Ult, typ, dst, a: b, b: a }); |
|
| 5587 | - | } else { |
|
| 5588 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Slt, typ, dst, a: b, b: a }); |
|
| 5589 | - | } |
|
| 5537 | + | let op = il::BinOp::Ult if unsigned else il::BinOp::Slt; |
|
| 5538 | + | emit(self, il::Instr::BinOp { op, typ, dst, a: b, b: a }); |
|
| 5590 | 5539 | } |
|
| 5591 | 5540 | case ast::BinaryOp::Lte => { // `a <= b` = `b >= a` |
|
| 5592 | - | if unsigned { |
|
| 5593 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Uge, typ, dst, a: b, b: a }); |
|
| 5594 | - | } else { |
|
| 5595 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Sge, typ, dst, a: b, b: a }); |
|
| 5596 | - | } |
|
| 5541 | + | let op = il::BinOp::Uge if unsigned else il::BinOp::Sge; |
|
| 5542 | + | emit(self, il::Instr::BinOp { op, typ, dst, a: b, b: a }); |
|
| 5597 | 5543 | } |
|
| 5598 | 5544 | case ast::BinaryOp::Gte => { |
|
| 5599 | - | if unsigned { |
|
| 5600 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Uge, typ, dst, a, b }); |
|
| 5601 | - | } else { |
|
| 5602 | - | emit(self, il::Instr::BinOp { op: il::BinOp::Sge, typ, dst, a, b }); |
|
| 5603 | - | } |
|
| 5545 | + | let op = il::BinOp::Uge if unsigned else il::BinOp::Sge; |
|
| 5546 | + | emit(self, il::Instr::BinOp { op, typ, dst, a, b }); |
|
| 5604 | 5547 | } |
|
| 5605 | 5548 | // Logical xor on booleans is equivalent to not equal. |
|
| 5606 | 5549 | case ast::BinaryOp::Xor => emit(self, il::Instr::BinOp { op: il::BinOp::Ne, typ, dst, a, b }), |
|
| 5607 | 5550 | // Short-circuit ops are handled elsewhere. |
|
| 5608 | 5551 | case ast::BinaryOp::And, ast::BinaryOp::Or => panic, |
| 6081 | 6024 | let needsRetBuf = isThrowing or (isAggregateType(retTy) and not isSmallAggregate(retTy)); |
|
| 6082 | 6025 | ||
| 6083 | 6026 | // Lower function value and arguments, reserving an extra slot for the |
|
| 6084 | 6027 | // hidden return buffer when needed. |
|
| 6085 | 6028 | let callee = try lowerCallee(self, call.callee); |
|
| 6086 | - | let mut offset: u32 = 0; |
|
| 6087 | - | if needsRetBuf { |
|
| 6088 | - | offset = 1; |
|
| 6089 | - | } |
|
| 6029 | + | let offset: u32 = 1 if needsRetBuf else 0; |
|
| 6090 | 6030 | let args = try allocVals(self, call.args.len + offset); |
|
| 6091 | 6031 | for i in 0..call.args.len { |
|
| 6092 | 6032 | args[i + offset] = try lowerExpr(self, call.args.list[i]); |
|
| 6093 | 6033 | } |
|
| 6094 | 6034 |
| 6336 | 6276 | } |
|
| 6337 | 6277 | case ast::NodeValue::ScopeAccess(_) => { |
|
| 6338 | 6278 | val = try lowerScopeAccess(self, node); |
|
| 6339 | 6279 | } |
|
| 6340 | 6280 | case ast::NodeValue::Number(lit) => { |
|
| 6341 | - | let mut mag = lit.magnitude as i64; |
|
| 6342 | - | if lit.negative { |
|
| 6343 | - | mag = -mag; |
|
| 6344 | - | } |
|
| 6281 | + | let mag = -(lit.magnitude as i64) if lit.negative else lit.magnitude as i64; |
|
| 6345 | 6282 | val = il::Val::Imm(mag); |
|
| 6346 | 6283 | } |
|
| 6347 | 6284 | case ast::NodeValue::Bool(b) => { |
|
| 6348 | - | if b { |
|
| 6349 | - | val = il::Val::Imm(1); |
|
| 6350 | - | } else { |
|
| 6351 | - | val = il::Val::Imm(0); |
|
| 6352 | - | } |
|
| 6285 | + | val = il::Val::Imm(1) if b else il::Val::Imm(0); |
|
| 6353 | 6286 | } |
|
| 6354 | 6287 | case ast::NodeValue::Char(c) => { |
|
| 6355 | 6288 | val = il::Val::Imm(c as i64); |
|
| 6356 | 6289 | } |
|
| 6357 | 6290 | case ast::NodeValue::Nil => { |
lib/std/lang/parser.rad
+2 -8
| 1601 | 1601 | p: *mut Parser, |
|
| 1602 | 1602 | mode: RecordFieldMode |
|
| 1603 | 1603 | ) -> ast::NodeList |
|
| 1604 | 1604 | throws (ParseError) |
|
| 1605 | 1605 | { |
|
| 1606 | - | let mut terminator: scanner::TokenKind = undefined; |
|
| 1606 | + | let terminator = scanner::TokenKind::RBrace if mode == RecordFieldMode::Labeled |
|
| 1607 | + | else scanner::TokenKind::RParen; |
|
| 1607 | 1608 | let mut fields = ast::nodeList(p.arena, MAX_RECORD_FIELDS); |
|
| 1608 | - | ||
| 1609 | - | match mode { |
|
| 1610 | - | case RecordFieldMode::Labeled => |
|
| 1611 | - | terminator = scanner::TokenKind::RBrace, |
|
| 1612 | - | case RecordFieldMode::Unlabeled => |
|
| 1613 | - | terminator = scanner::TokenKind::RParen, |
|
| 1614 | - | } |
|
| 1615 | 1609 | while not check(p, terminator) { |
|
| 1616 | 1610 | let mut recordField: ast::NodeValue = undefined; |
|
| 1617 | 1611 | match mode { |
|
| 1618 | 1612 | case RecordFieldMode::Labeled => { |
|
| 1619 | 1613 | // Allow optional `let` keyword before field name. |
lib/std/lang/resolver.rad
+6 -32
| 633 | 633 | } |
|
| 634 | 634 | ||
| 635 | 635 | /// Unwrap a pointer type for pattern matching. |
|
| 636 | 636 | pub fn unwrapMatchSubject(ty: Type) -> MatchSubject { |
|
| 637 | 637 | if let case Type::Pointer { target, mutable } = ty { |
|
| 638 | - | let mut by = MatchBy::Ref; |
|
| 639 | - | if mutable { |
|
| 640 | - | by = MatchBy::MutRef; |
|
| 641 | - | } |
|
| 638 | + | let by = MatchBy::MutRef if mutable else MatchBy::Ref; |
|
| 642 | 639 | return MatchSubject { effectiveTy: *target, by }; |
|
| 643 | 640 | } |
|
| 644 | 641 | return MatchSubject { effectiveTy: ty, by: MatchBy::Value }; |
|
| 645 | 642 | } |
|
| 646 | 643 |
| 5298 | 5295 | } |
|
| 5299 | 5296 | case ast::TypeSig::Bool => { |
|
| 5300 | 5297 | return Type::Bool; |
|
| 5301 | 5298 | } |
|
| 5302 | 5299 | case ast::TypeSig::Integer { width, sign } => { |
|
| 5300 | + | let u = sign == ast::Signedness::Unsigned; |
|
| 5303 | 5301 | match width { |
|
| 5304 | - | case 1 => { |
|
| 5305 | - | if sign == ast::Signedness::Unsigned { |
|
| 5306 | - | return Type::U8; |
|
| 5307 | - | } else { |
|
| 5308 | - | return Type::I8; |
|
| 5309 | - | } |
|
| 5310 | - | } |
|
| 5311 | - | case 2 => { |
|
| 5312 | - | if sign == ast::Signedness::Unsigned { |
|
| 5313 | - | return Type::U16; |
|
| 5314 | - | } else { |
|
| 5315 | - | return Type::I16; |
|
| 5316 | - | } |
|
| 5317 | - | } |
|
| 5318 | - | case 4 => { |
|
| 5319 | - | if sign == ast::Signedness::Unsigned { |
|
| 5320 | - | return Type::U32; |
|
| 5321 | - | } else { |
|
| 5322 | - | return Type::I32; |
|
| 5323 | - | } |
|
| 5324 | - | } |
|
| 5325 | - | case 8 => { |
|
| 5326 | - | if sign == ast::Signedness::Unsigned { |
|
| 5327 | - | return Type::U64; |
|
| 5328 | - | } else { |
|
| 5329 | - | return Type::I64; |
|
| 5330 | - | } |
|
| 5331 | - | } |
|
| 5302 | + | case 1 => return Type::U8 if u else Type::I8, |
|
| 5303 | + | case 2 => return Type::U16 if u else Type::I16, |
|
| 5304 | + | case 4 => return Type::U32 if u else Type::I32, |
|
| 5305 | + | case 8 => return Type::U64 if u else Type::I64, |
|
| 5332 | 5306 | else => { |
|
| 5333 | 5307 | panic "resolveTypeSig: invalid integer width"; |
|
| 5334 | 5308 | } |
|
| 5335 | 5309 | } |
|
| 5336 | 5310 | } |
lib/std/lang/resolver/printer.rad
+1 -5
| 381 | 381 | case super::ErrorKind::OptionalMatchMissingNil => { |
|
| 382 | 382 | io::print("optional match non-exhaustive: missing nil case"); |
|
| 383 | 383 | } |
|
| 384 | 384 | case super::ErrorKind::BoolMatchMissing(val) => { |
|
| 385 | 385 | io::print("bool match non-exhaustive: missing case for `"); |
|
| 386 | - | if val { |
|
| 387 | - | io::print("true"); |
|
| 388 | - | } else { |
|
| 389 | - | io::print("false"); |
|
| 390 | - | } |
|
| 386 | + | io::print("true" if val else "false"); |
|
| 391 | 387 | io::print("`"); |
|
| 392 | 388 | } |
|
| 393 | 389 | case super::ErrorKind::MatchNonExhaustive => { |
|
| 394 | 390 | io::print("match non-exhaustive: requires `else` or binding catch-all"); |
|
| 395 | 391 | } |
lib/std/lang/sexpr.rad
+1 -4
| 98 | 98 | pub fn write(out: *mut Output, s: *[u8]) { |
|
| 99 | 99 | match *out { |
|
| 100 | 100 | case Output::Stdout => io::print(s), |
|
| 101 | 101 | case Output::Buffer { buf, pos } => { |
|
| 102 | 102 | let remaining = buf.len - *pos; |
|
| 103 | - | let mut toWrite = s.len; |
|
| 104 | - | if toWrite > remaining { |
|
| 105 | - | toWrite = remaining; |
|
| 106 | - | } |
|
| 103 | + | let toWrite = remaining if s.len > remaining else s.len; |
|
| 107 | 104 | for i in 0..toWrite { |
|
| 108 | 105 | buf[*pos] = s[i]; |
|
| 109 | 106 | *pos += 1; |
|
| 110 | 107 | } |
|
| 111 | 108 | } |
lib/std/mem.rad
+1 -4
| 73 | 73 | /// Returns `-1` when `a < b`, `1` when `a > b`, and `0` when equal. |
|
| 74 | 74 | pub fn cmp(a: *[u8], b: *[u8]) -> i32 { |
|
| 75 | 75 | let aLen = a.len; |
|
| 76 | 76 | let bLen = b.len; |
|
| 77 | 77 | ||
| 78 | - | let mut common = aLen; |
|
| 79 | - | if bLen < common { |
|
| 80 | - | common = bLen; |
|
| 81 | - | } |
|
| 78 | + | let common = bLen if bLen < aLen else aLen; |
|
| 82 | 79 | for i in 0..common { |
|
| 83 | 80 | let aByte = a[i]; |
|
| 84 | 81 | let bByte = b[i]; |
|
| 85 | 82 | if aByte < bByte { |
|
| 86 | 83 | return -1; |